1 /** 2 Endianess Helpers 3 4 Copyright: 5 Copyright © 2023-2025, Kitsunebi Games 6 Copyright © 2023-2025, Inochi2D Project 7 8 License: $(LINK2 http://www.boost.org/LICENSE_1_0.txt, Boost License 1.0) 9 Authors: Luna Nielsen 10 */ 11 module nulib.memory.endian; 12 import numem.core.traits; 13 14 /** 15 Endianness 16 */ 17 enum Endianess { 18 bigEndian = 0, 19 littleEndian = 1 20 } 21 22 /** 23 The endianness of the target system being compiled for. 24 */ 25 version(BigEndian) enum NATIVE_ENDIAN = Endianess.bigEndian; 26 else enum NATIVE_ENDIAN = Endianess.littleEndian; 27 28 /** 29 The opposite endianness of what the system being compiled for 30 has. 31 */ 32 enum Endianess ALT_ENDIAN = cast(Endianess)!NATIVE_ENDIAN; 33 34 /** 35 Network order endianness. 36 37 Networking gear generally uses a big-endian memory order. 38 */ 39 enum Endianess NETWORK_ORDER = Endianess.bigEndian; 40 41 /** 42 Flips the endianness of the given value. 43 44 Params: 45 in_ = the bytes to flip. 46 47 Returns: 48 The input with the byte order reversed. 49 */ 50 T nu_flip_bytes(T)(T in_) @system @nogc nothrow { 51 ubyte swapTmp; // temp byte for swapping. 52 53 ubyte[T.sizeof] bytes = *(cast(ubyte[T.sizeof]*)&in_); 54 static foreach(i; 0..T.sizeof/2) { 55 56 swapTmp = bytes[i]; 57 bytes[i] = bytes[$-(i+1)]; 58 bytes[$-(i+1)] = swapTmp; 59 } 60 return *(cast(T*)&bytes); 61 } 62 63 /** 64 Converts big endian type to system endianness. 65 */ 66 T nu_betoh(T)(T in_) @trusted @nogc nothrow { 67 return etoh!(T, Endianess.bigEndian)(in_); 68 } 69 70 /** 71 Converts a range of big endian values to the system 72 endianness. 73 74 Params: 75 in_ = the range to flip the individual values within. 76 77 Returns: 78 A slice of the input, pointing to the same memory. 79 */ 80 T[] nu_betoh(T)(T[] in_) @trusted @nogc nothrow { 81 foreach_reverse(ref element; in_) 82 element = nu_betoh(element); 83 84 return in_; 85 } 86 87 /** 88 Converts little endian type to system endianness. 89 */ 90 T nu_letoh(T)(T in_) @trusted @nogc nothrow { 91 return etoh!(T, Endianess.littleEndian)(in_); 92 } 93 94 /** 95 Converts a slice of little endian values to the system 96 endianness. 97 98 Params: 99 in_ = the range to flip the individual values within. 100 101 Returns: 102 A slice of the input, pointing to the same memory. 103 */ 104 T[] nu_letoh(T)(T[] in_) @trusted @nogc nothrow { 105 foreach_reverse(ref element; in_) 106 element = nu_letoh(element); 107 108 return in_; 109 } 110 111 /** 112 Converts bytes between system and the given endianness. 113 114 This essentially flips the byte-order within the type if 115 the given endianness does not match the system endiannes. 116 117 Params: 118 in_ = the range to flip the individual values within. 119 endian = The endianness to convert between. 120 121 Returns: 122 A slice of the input, pointing to the same memory. 123 */ 124 T[] nu_etoh(T)(T[] in_, Endianess endian) @trusted @nogc nothrow { 125 if (endian != NATIVE_ENDIAN) 126 foreach_reverse(ref element; in_) 127 element = nu_flip_bytes!T(element); 128 129 return in_; 130 } 131 132 /** 133 Converts bytes between system and the given endianness. 134 135 This essentially flips the byte-order within the type if 136 the given endianness does not match the system endiannes. 137 138 Params: 139 in_ = the range to flip the individual values within. 140 141 Returns: 142 A slice of the input, pointing to the same memory. 143 */ 144 T[] nu_etoh(T, Endianess endian)(T[] in_) @trusted @nogc nothrow { 145 static if (endian != NATIVE_ENDIAN) 146 foreach_reverse(ref element; in_) 147 element = nu_flip_bytes!T(element); 148 149 return in_; 150 } 151 152 /** 153 Converts bytes between system and the given endianness. 154 155 This essentially flips the byte-order within the type if 156 the given endianness does not match the system endiannes. 157 158 Params: 159 in_ = The value to potentially flip. 160 161 Returns: 162 If $(D endian) does not match $(D NATIVE_ENDIAN), 163 returns the input with the byte order reversed, 164 otherwise returns the original value. 165 */ 166 T nu_etoh(T, Endianess endian)(T in_) @system @nogc nothrow { 167 static if (endian != NATIVE_ENDIAN) 168 return nu_flip_bytes!T(in_); 169 else 170 return in_; 171 } 172 173 /** 174 Converts bytes between system and the given endianness. 175 176 This essentially flips the byte-order within the type if 177 the given endianness does not match the system endiannes. 178 179 Params: 180 in_ = The value to potentially flip. 181 endian = The endianness to convert between. 182 183 Returns: 184 If $(D endian) does not match $(D NATIVE_ENDIAN), 185 returns the input with the byte order reversed, 186 otherwise returns the original value. 187 */ 188 T nu_etoh(T)(T in_, Endianess endian) @system @nogc nothrow { 189 if (endian != NATIVE_ENDIAN) 190 return nu_flip_bytes!T(in_); 191 else 192 return in_; 193 } 194 195 /** 196 Converts between network order endianness and the system endiannes. 197 198 Params: 199 in_ = The value to potentially flip. 200 201 Returns: 202 If $(D NATIVE_ENDIAN) does not match $(D NETWORK_ORDER), 203 returns the input with the byte order reversed, 204 otherwise returns the original value. 205 */ 206 pragma(inline, true) 207 T nu_ntoh(T)(T in_) @trusted @nogc nothrow 208 if (__traits(isScalar, T)) { 209 return nu_etoh!(T, NETWORK_ORDER)(in_); 210 }