Skip to content

Commit d35b7de

Browse files
committed
Move endianness utilities to new endian.h header
1 parent 058a52f commit d35b7de

File tree

7 files changed

+182
-138
lines changed

7 files changed

+182
-138
lines changed

src/common.h

Lines changed: 0 additions & 125 deletions
Original file line numberDiff line numberDiff line change
@@ -305,131 +305,6 @@ struct fmt::formatter<human_readible>
305305
}
306306
};
307307

308-
//! Endianness indicator
309-
enum class Endian
310-
{
311-
Little = 0,
312-
Intel = Little,
313-
Big = 1,
314-
Motorola = Big
315-
};
316-
317-
//! Returns 1 if architecture is little endian, 0 in case of big endian.
318-
inline bool is_little_endian()
319-
{
320-
unsigned int x = 1;
321-
char *c = (char *)&x;
322-
return bool((int)*c);
323-
}
324-
325-
inline Endian host_endian() { return is_little_endian() ? Endian::Little : Endian::Big; }
326-
327-
template <typename T>
328-
T swap_bytes(T value)
329-
{
330-
T result;
331-
auto value_bytes = reinterpret_cast<unsigned char *>(&value);
332-
auto result_bytes = reinterpret_cast<unsigned char *>(&result);
333-
334-
for (size_t i = 0; i < sizeof(T); ++i) result_bytes[i] = value_bytes[sizeof(T) - 1 - i];
335-
336-
return result;
337-
}
338-
339-
/*!
340-
* @brief Read a value of type T from a byte array and convert to host endianness.
341-
*
342-
* Reads sizeof(T) bytes from the given pointer and interprets them as type T,
343-
* performing byte swapping if the data endianness differs from the machine's.
344-
*
345-
* @tparam T The type to read (e.g., float, double, uint32_t)
346-
* @param ptr Pointer to the byte array to read from
347-
* @param data_endian The endianness of the data in the byte array
348-
* @return The value of type T in host endianness
349-
*/
350-
template <typename T>
351-
T read_as(const unsigned char *ptr, Endian data_endian)
352-
{
353-
T value;
354-
memcpy(&value, ptr, sizeof(T));
355-
356-
// Only swap bytes if necessary
357-
if (data_endian != host_endian())
358-
value = swap_bytes(value);
359-
360-
return value;
361-
}
362-
363-
/*!
364-
* @brief Read an array of values of type T from a byte array and convert to host endianness.
365-
*
366-
* Reads count * sizeof(T) bytes from the input pointer and interprets them as an array of type T,
367-
* performing byte swapping on each element if the data endianness differs from the machine's.
368-
*
369-
* @tparam T The type to read (e.g., float, double, uint32_t, int32_t)
370-
* @param output Pointer to the output array where results will be written
371-
* @param input Pointer to the input byte array to read from
372-
* @param count Number of elements to read
373-
* @param data_endian The endianness of the data in the input byte array
374-
*/
375-
template <typename T>
376-
void read_array(T *output, const unsigned char *input, size_t count, Endian data_endian)
377-
{
378-
// First, copy all bytes at once
379-
memcpy(output, input, count * sizeof(T));
380-
381-
// Only swap bytes if necessary
382-
if (data_endian != host_endian())
383-
for (size_t i = 0; i < count; i++) output[i] = swap_bytes(output[i]);
384-
}
385-
386-
/*!
387-
* @brief Write a value of type T to a byte array with specified endianness.
388-
*
389-
* Writes sizeof(T) bytes to the given pointer, performing byte swapping if the target
390-
* endianness differs from the machine's endianness.
391-
*
392-
* @tparam T The type to write (e.g., float, double, uint32_t)
393-
* @param ptr Pointer to the byte array to write to
394-
* @param value The value to write
395-
* @param target_endian The desired endianness for the data in the byte array
396-
*/
397-
template <typename T>
398-
void write_as(unsigned char *ptr, T value, Endian target_endian)
399-
{
400-
// Swap bytes if target endianness doesn't match machine endianness
401-
if (target_endian != host_endian())
402-
value = swap_bytes(value);
403-
404-
memcpy(ptr, &value, sizeof(T));
405-
}
406-
407-
/*!
408-
* @brief Write an array of values of type T to a byte array with specified endianness.
409-
*
410-
* Writes count * sizeof(T) bytes to the output pointer, performing byte swapping on each
411-
* element if the target endianness differs from the machine's.
412-
*
413-
* @tparam T The type to write (e.g., float, double, uint32_t, int32_t)
414-
* @param output Pointer to the output byte array to write to
415-
* @param input Pointer to the input array of values
416-
* @param count Number of elements to write
417-
* @param target_endian The desired endianness for the data in the output byte array
418-
*/
419-
template <typename T>
420-
void write_array(unsigned char *output, const T *input, size_t count, Endian target_endian)
421-
{
422-
// First, copy all bytes at once
423-
memcpy(output, input, count * sizeof(T));
424-
425-
// Only swap bytes if necessary
426-
if (target_endian != host_endian())
427-
{
428-
T *output_typed = reinterpret_cast<T *>(output);
429-
for (size_t i = 0; i < count; i++) output_typed[i] = swap_bytes(output_typed[i]);
430-
}
431-
}
432-
433308
template <typename T>
434309
inline T sqr(T x)
435310
{

src/endian.h

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
//
2+
// Copyright (C) Wojciech Jarosz. All rights reserved.
3+
// Use of this source code is governed by a BSD-style license that can
4+
// be found in the LICENSE.txt file.
5+
//
6+
7+
#pragma once
8+
9+
#include <cstddef>
10+
#include <cstdint>
11+
12+
//! Endianness indicator
13+
enum class Endian
14+
{
15+
Little = 0,
16+
Intel = Little,
17+
Big = 1,
18+
Motorola = Big
19+
};
20+
21+
//! Returns 1 if architecture is little endian, 0 in case of big endian.
22+
inline bool is_little_endian()
23+
{
24+
unsigned int x = 1;
25+
char *c = (char *)&x;
26+
return bool((int)*c);
27+
}
28+
29+
inline Endian host_endian() { return is_little_endian() ? Endian::Little : Endian::Big; }
30+
31+
template <typename T>
32+
inline T swap_bytes(T value)
33+
{
34+
#if defined(_MSC_VER)
35+
#pragma intrinsic(_byteswap_ushort)
36+
#pragma intrinsic(_byteswap_ulong)
37+
#pragma intrinsic(_byteswap_uint64)
38+
39+
#define byte_swap_16 _byteswap_ushort
40+
#define byte_swap_32 _byteswap_ulong
41+
#define byte_swap_64 _byteswap_uint64
42+
#else
43+
#define byte_swap_16 __builtin_bswap16
44+
#define byte_swap_32 __builtin_bswap32
45+
#define byte_swap_64 __builtin_bswap64
46+
#endif
47+
48+
if constexpr (sizeof(T) == 1)
49+
{
50+
return value;
51+
}
52+
else if constexpr (sizeof(T) == 2)
53+
{
54+
uint16_t swapped = byte_swap_16(*reinterpret_cast<uint16_t *>(&value));
55+
return *reinterpret_cast<T *>(&swapped);
56+
}
57+
else if constexpr (sizeof(T) == 4)
58+
{
59+
uint32_t swapped = byte_swap_32(*reinterpret_cast<uint32_t *>(&value));
60+
return *reinterpret_cast<T *>(&swapped);
61+
}
62+
else if constexpr (sizeof(T) == 8)
63+
{
64+
uint64_t swapped = byte_swap_64(*reinterpret_cast<uint64_t *>(&value));
65+
return *reinterpret_cast<T *>(&swapped);
66+
}
67+
else
68+
{
69+
static_assert(sizeof(T) == 1 || sizeof(T) == 2 || sizeof(T) == 4 || sizeof(T) == 8,
70+
"Unsupported type size for byte swapping.");
71+
}
72+
#undef byte_swap_16
73+
#undef byte_swap_32
74+
#undef byte_swap_64
75+
}
76+
77+
/*!
78+
* @brief Read a value of type T from a byte array and convert to host endianness.
79+
*
80+
* Reads sizeof(T) bytes from the given pointer and interprets them as type T,
81+
* performing byte swapping if the data endianness differs from the machine's.
82+
*
83+
* @tparam T The type to read (e.g., float, double, uint32_t)
84+
* @param ptr Pointer to the byte array to read from
85+
* @param data_endian The endianness of the data in the byte array
86+
* @return The value of type T in host endianness
87+
*/
88+
template <typename T>
89+
T read_as(const unsigned char *ptr, Endian data_endian)
90+
{
91+
T value;
92+
memcpy(&value, ptr, sizeof(T));
93+
94+
// Only swap bytes if necessary
95+
if (data_endian != host_endian())
96+
value = swap_bytes(value);
97+
98+
return value;
99+
}
100+
101+
/*!
102+
* @brief Read an array of values of type T from a byte array and convert to host endianness.
103+
*
104+
* Reads count * sizeof(T) bytes from the input pointer and interprets them as an array of type T,
105+
* performing byte swapping on each element if the data endianness differs from the machine's.
106+
*
107+
* @tparam T The type to read (e.g., float, double, uint32_t, int32_t)
108+
* @param output Pointer to the output array where results will be written
109+
* @param input Pointer to the input byte array to read from
110+
* @param count Number of elements to read
111+
* @param data_endian The endianness of the data in the input byte array
112+
*/
113+
template <typename T>
114+
void read_array(T *output, const unsigned char *input, size_t count, Endian data_endian)
115+
{
116+
// First, copy all bytes at once
117+
memcpy(output, input, count * sizeof(T));
118+
119+
// Only swap bytes if necessary
120+
if (data_endian != host_endian())
121+
for (size_t i = 0; i < count; i++) output[i] = swap_bytes(output[i]);
122+
}
123+
124+
/*!
125+
* @brief Write a value of type T to a byte array with specified endianness.
126+
*
127+
* Writes sizeof(T) bytes to the given pointer, performing byte swapping if the target
128+
* endianness differs from the machine's endianness.
129+
*
130+
* @tparam T The type to write (e.g., float, double, uint32_t)
131+
* @param ptr Pointer to the byte array to write to
132+
* @param value The value to write
133+
* @param target_endian The desired endianness for the data in the byte array
134+
*/
135+
template <typename T>
136+
void write_as(unsigned char *ptr, T value, Endian target_endian)
137+
{
138+
// Swap bytes if target endianness doesn't match machine endianness
139+
if (target_endian != host_endian())
140+
value = swap_bytes(value);
141+
142+
memcpy(ptr, &value, sizeof(T));
143+
}
144+
145+
/*!
146+
* @brief Write an array of values of type T to a byte array with specified endianness.
147+
*
148+
* Writes count * sizeof(T) bytes to the output pointer, performing byte swapping on each
149+
* element if the target endianness differs from the machine's.
150+
*
151+
* @tparam T The type to write (e.g., float, double, uint32_t, int32_t)
152+
* @param output Pointer to the output byte array to write to
153+
* @param input Pointer to the input array of values
154+
* @param count Number of elements to write
155+
* @param target_endian The desired endianness for the data in the output byte array
156+
*/
157+
template <typename T>
158+
void write_array(unsigned char *output, const T *input, size_t count, Endian target_endian)
159+
{
160+
// First, copy all bytes at once
161+
memcpy(output, input, count * sizeof(T));
162+
163+
// Only swap bytes if necessary
164+
if (target_endian != host_endian())
165+
{
166+
T *output_typed = reinterpret_cast<T *>(output);
167+
for (size_t i = 0; i < count; i++) output_typed[i] = swap_bytes(output_typed[i]);
168+
}
169+
}

src/fwd.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88

99
// #define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
1010

11-
#include "linalg.h" // IWYU pragma: export
11+
#include <linalg.h>
1212
#include <memory>
1313

1414
// Shortname for the linalg namespace

src/imageio/exif.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,18 @@
11
#include "exif.h"
2-
#include "common.h"
2+
#include "endian.h"
3+
#include "fwd.h"
34
#include "json.h"
45
#include <cstdint>
56
#include <cstdio>
67
#include <cstdlib>
78
#include <cstring> // for memcmp
8-
#include <iomanip>
99
#include <libexif/exif-byte-order.h>
1010
#include <libexif/exif-data.h>
1111
#include <libexif/exif-format.h>
1212
#include <libexif/exif-ifd.h>
1313
#include <libexif/exif-mnote-data.h>
1414
#include <libexif/exif-tag.h>
1515
#include <memory>
16-
#include <sstream>
1716
#include <stdexcept>
1817
#include <type_traits>
1918

src/imageio/jxl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@
55
//
66

77
#include "app.h"
8+
#include "endian.h"
89
#include "exif.h"
910
#include "image.h"
10-
#include "xmp.h"
1111
#include <cstdint>
1212
#include <cstdio>
1313
#include <cstring>

src/imageio/png.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -57,10 +57,10 @@ void save_png_image(const Image &img, std::ostream &os, std::string_view filenam
5757
#include <vector>
5858

5959
#include "common.h"
60+
#include "endian.h"
6061
#include "exif.h"
6162
#include "icc.h"
6263
#include "timer.h"
63-
#include "xmp.h"
6464

6565
#include "fonts.h"
6666
#include "imgui_ext.h"

src/imageio/tiff.cpp

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,8 @@
66

77
#include "tiff.h"
88
#include "app.h"
9-
#include "colorspace.h"
109
#include "common.h"
11-
#include "exif.h"
12-
#include "icc.h"
1310
#include "image.h"
14-
#include "timer.h"
15-
16-
#include "fonts.h"
17-
#include "imgui_ext.h"
1811

1912
using namespace std;
2013

@@ -54,6 +47,14 @@ void save_tiff_image(const Image &img, std::ostream &os, std::string_view filena
5447

5548
#else
5649

50+
#include "colorspace.h"
51+
#include "endian.h"
52+
#include "exif.h"
53+
#include "fonts.h"
54+
#include "icc.h"
55+
#include "imgui_ext.h"
56+
#include "timer.h"
57+
5758
#include <cstring>
5859
#include <half.h>
5960
#include <spdlog/fmt/fmt.h>

0 commit comments

Comments
 (0)