File: binaryconversion.h

package info (click to toggle)
martchus-cpp-utilities 5.33.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 1,396 kB
  • sloc: cpp: 12,679; awk: 18; ansic: 12; makefile: 10
file content (228 lines) | stat: -rw-r--r-- 9,108 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
#ifndef CONVERSION_UTILITIES_BINARY_CONVERSION_H
#define CONVERSION_UTILITIES_BINARY_CONVERSION_H

#include "../global.h"
#include "../misc/traits.h" // used in binaryconversionprivate.h

#include <cstdint>
#include <cstring> // used in binaryconversionprivate.h

// use helpers from bits header if available instead of custom code using bit operations
#if __cplusplus >= 202002L
#include <bit>
#endif

// detect byte order according to __BYTE_ORDER__
#if defined(__BYTE_ORDER__)
#if __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN false
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN true
#define CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN
#elif __BYTE_ORDER__ == __ORDER_PDP_ENDIAN__
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN false
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN false
#define CONVERSION_UTILITIES_BYTE_ORDER_MIDDLE_ENDIAN
#elif __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN true
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN false
#define CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN
#endif
#endif // defined(__BYTE_ORDER__)

// detect float byte order according to __FLOAT_WORD_ORDER__
#if defined(__FLOAT_WORD_ORDER__)
#if __FLOAT_WORD_ORDER__ == __ORDER_BIG_ENDIAN__
#define CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_BIG_ENDIAN
#elif __FLOAT_WORD_ORDER__ == __ORDER_PDP_ENDIAN__
#define CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_MIDDLE_ENDIAN
#elif __FLOAT_WORD_ORDER__ == __ORDER_LITTLE_ENDIAN__
#define CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_LITTLE_ENDIAN
#endif
#endif // defined(__FLOAT_WORD_ORDER__)

// detect (float) byte order according to other macros
#if !defined(__BYTE_ORDER__) || !defined(__FLOAT_WORD_ORDER__)

// assume little endian from the presence of several macros
#if defined(__i386) || defined(__i386__) || defined(_M_IX86) || defined(__x86_64) || defined(__x86_64__) || defined(__amd64) || defined(_M_X64)      \
    || defined(_M_ARM64) || defined(__LITTLE_ENDIAN__) || defined(_little_endian__) || defined(_LITTLE_ENDIAN) || defined(_WIN32_WCE)                \
    || defined(WINAPI_FAMILY)
#if !defined(__BYTE_ORDER__)
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN true
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN false
#define CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN
#endif
#if !defined(__FLOAT_WORD_ORDER__)
#define CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_LITTLE_ENDIAN
#endif

// assume big endian from the presence of several macros
#elif defined(__MIPSEB__) || defined(__s390__) || defined(__BIG_ENDIAN__) || defined(_big_endian__) || defined(_BIG_ENDIAN)
#if !defined(__BYTE_ORDER__)
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_LITTLE_ENDIAN false
#define CONVERSION_UTILITIES_IS_BYTE_ORDER_BIG_ENDIAN true
#define CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN
#endif
#if !defined(__FLOAT_WORD_ORDER__)
#define CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_BIG_ENDIAN
#endif

// fail if unable to detect endianness
#else
#error "Unable to determine byte order!"
#endif

#endif // !defined(__BYTE_ORDER__) || !defined(__FLOAT_WORD_ORDER__)

// fail if middle endian detected
#if defined(CONVERSION_UTILITIES_BYTE_ORDER_MIDDLE_ENDIAN) || defined(CONVERSION_UTILITIES_FLOAT_BYTE_ORDER_MIDDLE_ENDIAN)
#error "Middle endian byte order is not supported!"
#endif

namespace CppUtilities {

/*!
 * \brief Returns the 8.8 fixed point representation converted from the specified 32-bit floating point number.
 */
CPP_UTILITIES_EXPORT constexpr std::uint16_t toFixed8(float float32value)
{
    return static_cast<std::uint16_t>(float32value * 256.0f);
}

/*!
 * \brief Returns a 32-bit floating point number converted from the specified 8.8 fixed point representation.
 */
CPP_UTILITIES_EXPORT constexpr float toFloat32(std::uint16_t fixed8value)
{
    return static_cast<float>(fixed8value) / 256.0f;
}

/*!
 * \brief Returns the 16.16 fixed point representation converted from the specified 32-bit floating point number.
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t toFixed16(float float32value)
{
    return static_cast<std::uint32_t>(float32value * 65536.0f);
}

/*!
 * \brief Returns a 32-bit floating point number converted from the specified 16.16 fixed point representation.
 */
CPP_UTILITIES_EXPORT constexpr float toFloat32(std::uint32_t fixed16value)
{
    return static_cast<float>(fixed16value) / 65536.0f;
}

/*!
 * \brief Returns a 32-bit synchsafe integer converted from a normal 32-bit integer.
 * \remarks Synchsafe integers appear in ID3 tags that are attached to an MP3 file.
 * \sa <a href="http://id3.org/id3v2.4.0-structure">ID3 tag version 2.4.0 - Main Structure</a>
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t toSynchsafeInt(std::uint32_t normalInt)
{
    return ((normalInt & 0x0000007fu)) | ((normalInt & 0x00003f80u) << 1) | ((normalInt & 0x001fc000u) << 2) | ((normalInt & 0x0fe00000u) << 3);
}

/*!
 * \brief Returns a normal 32-bit integer converted from a 32-bit synchsafe integer.
 * \remarks Synchsafe integers appear in ID3 tags that are attached to an MP3 file.
 * \sa <a href="http://id3.org/id3v2.4.0-structure">ID3 tag version 2.4.0 - Main Structure</a>
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t toNormalInt(std::uint32_t synchsafeInt)
{
    return ((synchsafeInt & 0x0000007fu)) | ((synchsafeInt & 0x00007f00u) >> 1) | ((synchsafeInt & 0x007f0000u) >> 2)
        | ((synchsafeInt & 0x7f000000u) >> 3);
}

// define helpers for byte swapping
#ifdef __cpp_lib_byteswap // in C++ 23 we can just use the stdlib
template <class T, Traits::EnableIf<std::is_integral<T>> * = nullptr> CPP_UTILITIES_EXPORT constexpr T swapOrder(T value)
{
    return std::byteswap(value);
}

#else // provide custom code for C++ 20 and older (will also be optimized by GCC and Clang to use bswap)

/*!
 * \brief Swaps the byte order of the specified 16-bit unsigned integer.
 */
CPP_UTILITIES_EXPORT constexpr std::uint16_t swapOrder(std::uint16_t value)
{
    return static_cast<std::uint16_t>(((value >> 8) & 0x00FF) | ((value << 8) & 0xFF00));
}

/*!
 * \brief Swaps the byte order of the specified 32-bit unsigned integer.
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t swapOrder(std::uint32_t value)
{
    return (value >> 24) | ((value & 0x00FF0000) >> 8) | ((value & 0x0000FF00) << 8) | (value << 24);
}

/*!
 * \brief Swaps the byte order of the specified 64-bit unsigned integer.
 */
CPP_UTILITIES_EXPORT constexpr std::uint64_t swapOrder(std::uint64_t value)
{
    return (value >> (7 * 8)) | ((value & 0x00FF000000000000) >> (5 * 8)) | ((value & 0x0000FF0000000000) >> (3 * 8))
        | ((value & 0x000000FF00000000) >> (1 * 8)) | ((value & 0x00000000FF000000) << (1 * 8)) | ((value & 0x0000000000FF0000) << (3 * 8))
        | ((value & 0x000000000000FF00) << (5 * 8)) | ((value) << (7 * 8));
}

/*!
 * \brief Swaps the byte order of the specified 16-bit integer.
 */
CPP_UTILITIES_EXPORT constexpr std::int16_t swapOrder(std::int16_t value)
{
    return static_cast<std::int16_t>(((static_cast<std::uint16_t>(value) >> 8) & 0x00FF) | ((static_cast<std::uint16_t>(value) << 8) & 0xFF00));
}

/*!
 * \brief Swaps the byte order of the specified 32-bit integer.
 */
CPP_UTILITIES_EXPORT constexpr std::int32_t swapOrder(std::int32_t value)
{
    return static_cast<std::int32_t>((static_cast<std::uint32_t>(value) >> 24) | ((static_cast<std::uint32_t>(value) & 0x00FF0000) >> 8)
        | ((static_cast<std::uint32_t>(value) & 0x0000FF00) << 8) | (static_cast<std::uint32_t>(value) << 24));
}

/*!
 * \brief Swaps the byte order of the specified 64-bit integer.
 */
CPP_UTILITIES_EXPORT constexpr std::int64_t swapOrder(std::int64_t value)
{
    return static_cast<std::int64_t>((static_cast<std::uint64_t>(value) >> (7 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x00FF000000000000) >> (5 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x0000FF0000000000) >> (3 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x000000FF00000000) >> (1 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x00000000FF000000) << (1 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x0000000000FF0000) << (3 * 8))
        | ((static_cast<std::uint64_t>(value) & 0x000000000000FF00) << (5 * 8)) | ((static_cast<std::uint64_t>(value)) << (7 * 8)));
}
#endif

/*!
 * \brief Encapsulates binary conversion functions using the big endian byte order.
 * \sa <a href="http://en.wikipedia.org/wiki/Endianness">Endianness - Wikipedia</a>
 */
namespace BE {

#define CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL 0
#include "./binaryconversionprivate.h"
#undef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL
} // namespace BE

/*!
 * \brief Encapsulates binary conversion functions using the little endian byte order.
 * \sa <a href="http://en.wikipedia.org/wiki/Endianness">Endianness - Wikipedia</a>
 */
namespace LE {

#define CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL 1
#include "./binaryconversionprivate.h"
#undef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL
} // namespace LE

} // namespace CppUtilities

#endif // CONVERSION_UTILITIES_BINARY_CONVERSION_H