File: binaryconversionprivate.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 (220 lines) | stat: -rw-r--r-- 10,806 bytes parent folder | download | duplicates (2)
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
// assert that CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL is defined; a value of:
// - 0 means to define functions for BE namespace
// - 1 means to define functions for LE namespace
#ifndef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL
#error "Do not include binaryconversionprivate.h directly."
#else

// define macro if swapping byte order is required
#if (CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0 && defined(CONVERSION_UTILITIES_BYTE_ORDER_LITTLE_ENDIAN))                                 \
    || (CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 1 && defined(CONVERSION_UTILITIES_BYTE_ORDER_BIG_ENDIAN))
#define CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL_NEEDS_SWAP
#endif

// disable warnings about sign conversions when using GCC or Clang
#ifdef __GNUC__
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wsign-conversion"
#endif

/*!
 * \brief Returns a 16-bit signed integer converted from two bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::int16_t toInt16(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return static_cast<std::int16_t>((static_cast<std::int16_t>(value[0]) << 8 & 0xFF00) | (static_cast<std::int16_t>(value[1]) & 0x00FF));
#else
    return static_cast<std::int16_t>((static_cast<std::int16_t>(value[1]) << 8 & 0xFF00) | (static_cast<std::int16_t>(value[0]) & 0x00FF));
#endif
}

/*!
 * \brief Returns a 16-bit unsigned integer converted from two bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::uint16_t toUInt16(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return static_cast<std::uint16_t>((static_cast<std::uint16_t>(value[0]) << 8 & 0xFF00) | (static_cast<std::uint16_t>(value[1]) & 0x00FF));
#else
    return static_cast<std::uint16_t>((static_cast<std::uint16_t>(value[1]) << 8 & 0xFF00) | (static_cast<std::uint16_t>(value[0]) & 0x00FF));
#endif
}

/*!
 * \brief Returns a 32-bit signed integer converted from four bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::int32_t toInt32(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return static_cast<std::int32_t>((static_cast<std::int32_t>(value[0]) << 24 & 0xFF000000)
        | (static_cast<std::int32_t>(value[1]) << 16 & 0x00FF0000) | (static_cast<std::int32_t>(value[2]) << 8 & 0x0000FF00)
        | (static_cast<std::int32_t>(value[3]) & 0x000000FF));
#else
    return static_cast<std::int32_t>((static_cast<std::int32_t>(value[3]) << 24 & 0xFF000000)
        | (static_cast<std::int32_t>(value[2]) << 16 & 0x00FF0000) | (static_cast<std::int32_t>(value[1]) << 8 & 0x0000FF00)
        | (static_cast<std::int32_t>(value[0]) & 0x000000FF));
#endif
}

/*!
 * \brief Returns a 32-bit unsigned integer converted from three bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t toUInt24(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return (static_cast<std::uint32_t>(value[0]) << 16 & 0x00FF0000) | (static_cast<std::uint32_t>(value[1]) << 8 & 0x0000FF00)
        | (static_cast<std::uint32_t>(value[2]) & 0x000000FF);
#else
    return (static_cast<std::uint32_t>(value[2]) << 16 & 0x00FF0000) | (static_cast<std::uint32_t>(value[1]) << 8 & 0x0000FF00)
        | (static_cast<std::uint32_t>(value[0]) & 0x000000FF);
#endif
}

/*!
 * \brief Returns a 32-bit unsigned integer converted from four bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::uint32_t toUInt32(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return (static_cast<std::uint32_t>(value[0]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[1]) << 16 & 0x00FF0000)
        | (static_cast<std::uint32_t>(value[2]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[3]) & 0x000000FF);
#else
    return (static_cast<std::uint32_t>(value[3]) << 24 & 0xFF000000) | (static_cast<std::uint32_t>(value[2]) << 16 & 0x00FF0000)
        | (static_cast<std::uint32_t>(value[1]) << 8 & 0x0000FF00) | (static_cast<std::uint32_t>(value[0]) & 0x000000FF);
#endif
}

/*!
 * \brief Returns a 64-bit signed integer converted from eight bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::int64_t toInt64(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return (static_cast<std::int64_t>(value[0]) << 56 & 0xFF00000000000000) | (static_cast<std::int64_t>(value[1]) << 48 & 0x00FF000000000000)
        | (static_cast<std::int64_t>(value[2]) << 40 & 0x0000FF0000000000) | (static_cast<std::int64_t>(value[3]) << 32 & 0x000000FF00000000)
        | (static_cast<std::int64_t>(value[4]) << 24 & 0x00000000FF000000) | (static_cast<std::int64_t>(value[5]) << 16 & 0x0000000000FF0000)
        | (static_cast<std::int64_t>(value[6]) << 8 & 0x000000000000FF00) | (static_cast<std::int64_t>(value[7]) & 0x00000000000000FF);
#else
    return (static_cast<std::int64_t>(value[7]) << 56 & 0xFF00000000000000) | (static_cast<std::int64_t>(value[6]) << 48 & 0x00FF000000000000)
        | (static_cast<std::int64_t>(value[5]) << 40 & 0x0000FF0000000000) | (static_cast<std::int64_t>(value[4]) << 32 & 0x000000FF00000000)
        | (static_cast<std::int64_t>(value[3]) << 24 & 0x00000000FF000000) | (static_cast<std::int64_t>(value[2]) << 16 & 0x0000000000FF0000)
        | (static_cast<std::int64_t>(value[1]) << 8 & 0x000000000000FF00) | (static_cast<std::int64_t>(value[0]) & 0x00000000000000FF);
#endif
}

/*!
 * \brief Returns a 64-bit unsigned integer converted from eight bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT constexpr std::uint64_t toUInt64(const char *value)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    return (static_cast<std::uint64_t>(value[0]) << 56 & 0xFF00000000000000) | (static_cast<std::uint64_t>(value[1]) << 48 & 0x00FF000000000000)
        | (static_cast<std::uint64_t>(value[2]) << 40 & 0x0000FF0000000000) | (static_cast<std::uint64_t>(value[3]) << 32 & 0x000000FF00000000)
        | (static_cast<std::uint64_t>(value[4]) << 24 & 0x00000000FF000000) | (static_cast<std::uint64_t>(value[5]) << 16 & 0x0000000000FF0000)
        | (static_cast<std::uint64_t>(value[6]) << 8 & 0x000000000000FF00) | (static_cast<std::uint64_t>(value[7]) & 0x00000000000000FF);
#else
    return (static_cast<std::uint64_t>(value[7]) << 56 & 0xFF00000000000000) | (static_cast<std::uint64_t>(value[6]) << 48 & 0x00FF000000000000)
        | (static_cast<std::uint64_t>(value[5]) << 40 & 0x0000FF0000000000) | (static_cast<std::uint64_t>(value[4]) << 32 & 0x000000FF00000000)
        | (static_cast<std::uint64_t>(value[3]) << 24 & 0x00000000FF000000) | (static_cast<std::uint64_t>(value[2]) << 16 & 0x0000000000FF0000)
        | (static_cast<std::uint64_t>(value[1]) << 8 & 0x000000000000FF00) | (static_cast<std::uint64_t>(value[0]) & 0x00000000000000FF);
#endif
}

/*!
 * \brief Returns a 32-bit floating point number converted from four bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT inline float toFloat32(const char *value)
{
    const auto val = toInt32(value);
    const auto *const c = reinterpret_cast<const char *>(&val);
    return *reinterpret_cast<const float *>(c);
}

/*!
 * \brief Returns a 64-bit floating point number converted from eight bytes at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT inline double toFloat64(const char *value)
{
    const auto val = toInt64(value);
    const auto *const c = reinterpret_cast<const char *>(&val);
    return *reinterpret_cast<const double *>(c);
}

/*!
 * \brief Returns the specified (unsigned) integer converted from the specified char array.
 * \remarks
 * - The \a value must point to a sequence of characters that is at least as long as the specified integer type.
 * - This function is potentially faster than the width-specific toInt…() because the width-specific functions use
 *   custom code that may not be optimized by the compiler. (Only GCC optimized it but not Clang and MSVC.) Note
 *   that the width-specific functions cannot be changed as they are constexpr and thus cannot use memcpy().
 */
template <class T, Traits::EnableIf<std::is_integral<T>> * = nullptr> CPP_UTILITIES_EXPORT inline T toInt(const char *value)
{
    auto dst = T();
    std::memcpy(&dst, value, sizeof(T));
#ifdef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL_NEEDS_SWAP
    dst = swapOrder(dst);
#endif
    return dst;
}

/*!
 * \brief Stores the specified 24-bit unsigned integer value at a specified position in a char array.
 * \remarks Ignores the most significant byte.
 */
CPP_UTILITIES_EXPORT inline void getBytes24(std::uint32_t value, char *outputbuffer)
{
#if CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL == 0
    outputbuffer[0] = static_cast<char>((value >> 16) & 0xFF);
    outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
    outputbuffer[2] = static_cast<char>((value) & 0xFF);
#else
    outputbuffer[2] = static_cast<char>((value >> 16) & 0xFF);
    outputbuffer[1] = static_cast<char>((value >> 8) & 0xFF);
    outputbuffer[0] = static_cast<char>((value) & 0xFF);
#endif
}

/*!
 * \brief Stores the specified (unsigned) integer value in a char array.
 * \remarks
 * - The \a value outputbuffer must point to a sequence of characters that is at least as long as the specified integer type.
 * - This function is potentially faster than the width-specific toInt…() because the width-specific functions use
 *   custom code that may not be optimized by the compiler. (Only GCC optimized it but not Clang and MSVC.)
 */
template <class T, Traits::EnableIf<std::is_integral<T>> * = nullptr> CPP_UTILITIES_EXPORT inline void getBytes(T value, char *outputbuffer)
{
#ifdef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL_NEEDS_SWAP
    value = swapOrder(value);
#endif
    std::memcpy(outputbuffer, &value, sizeof(T));
}

/*!
 * \brief Stores the specified 32-bit floating point value at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT inline void getBytes(float value, char *outputbuffer)
{
    auto *c = reinterpret_cast<char *>(&value);
    auto i = *reinterpret_cast<std::int32_t *>(c);
    getBytes(i, outputbuffer);
}

/*!
 * \brief Stores the specified 64-bit floating point value at a specified position in a char array.
 */
CPP_UTILITIES_EXPORT inline void getBytes(double value, char *outputbuffer)
{
    auto *c = reinterpret_cast<char *>(&value);
    auto i = *reinterpret_cast<std::int64_t *>(c);
    getBytes(i, outputbuffer);
}

#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif

#undef CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL_NEEDS_SWAP

#endif // CONVERSION_UTILITIES_BINARY_CONVERSION_INTERNAL