diff options
| author | gingerBill <bill@gingerbill.org> | 2022-05-12 19:35:07 +0100 |
|---|---|---|
| committer | gingerBill <bill@gingerbill.org> | 2022-05-12 19:35:07 +0100 |
| commit | f27f5955495725b02be137ec896a4601ece7ff57 (patch) | |
| tree | 28a17621a9086c9e8c6f58737c09b7660c85e73e /core/encoding | |
| parent | bc183101077b1e962ee647999fb462fad15376b1 (diff) | |
Add `core:encoding/endian`
Diffstat (limited to 'core/encoding')
| -rw-r--r-- | core/encoding/endian/doc.odin | 23 | ||||
| -rw-r--r-- | core/encoding/endian/endian.odin | 153 |
2 files changed, 176 insertions, 0 deletions
diff --git a/core/encoding/endian/doc.odin b/core/encoding/endian/doc.odin new file mode 100644 index 000000000..754ffa583 --- /dev/null +++ b/core/encoding/endian/doc.odin @@ -0,0 +1,23 @@ +/* + Package endian implements sa simple translation between bytes and numbers with + specific endian encodings. + + buf: [100]u8 + put_u16(buf[:], .Little, 16) or_return + + You may ask yourself, why isn't `byte_order` platform Endianness by default, so we can write: + put_u16(buf[:], 16) or_return + + The answer is that very few file formats are written in native/platform endianness. Most of them specify the endianness of + each of their fields, or use a header field which specifies it for the entire file. + + e.g. a file which specifies it at the top for all fields could do this: + file_order := .Little if buf[0] == 0 else .Big + field := get_u16(buf[1:], file_order) or_return + + If on the other hand a field is *always* Big-Endian, you're wise to explicitly state it for the benefit of the reader, + be that your future self or someone else. + + field := get_u16(buf[:], .Big) or_return +*/ +package encoding_endian diff --git a/core/encoding/endian/endian.odin b/core/encoding/endian/endian.odin new file mode 100644 index 000000000..08bde3139 --- /dev/null +++ b/core/encoding/endian/endian.odin @@ -0,0 +1,153 @@ +package encoding_endian + +Byte_Order :: enum u8 { + Little, + Big, +} + +PLATFORM_BYTE_ORDER :: Byte_Order.Little when ODIN_ENDIAN == .Little else Byte_Order.Big + +get_u16 :: proc(b: []byte, order: Byte_Order) -> (v: u16, ok: bool) { + if len(b) < 2 { + return 0, false + } + #no_bounds_check if order == .Little { + v = u16(b[0]) | u16(b[1])<<8 + } else { + v = u16(b[1]) | u16(b[0])<<8 + } + return v, true +} +get_u32 :: proc(b: []byte, order: Byte_Order) -> (v: u32, ok: bool) { + if len(b) < 4 { + return 0, false + } + #no_bounds_check if order == .Little { + v = u32(b[0]) | u32(b[1])<<8 | u32(b[2])<<16 | u32(b[3])<<24 + } else { + v = u32(b[3]) | u32(b[2])<<8 | u32(b[1])<<16 | u32(b[0])<<24 + } + return v, true +} + +get_u64 :: proc(b: []byte, order: Byte_Order) -> (v: u64, ok: bool) { + if len(b) < 8 { + return 0, false + } + #no_bounds_check if order == .Little { + v = u64(b[0]) | u64(b[1])<<8 | u64(b[2])<<16 | u64(b[3])<<24 | + u64(b[4])<<32 | u64(b[5])<<40 | u64(b[6])<<48 | u64(b[7])<<56 + } else { + v = u64(b[7]) | u64(b[6])<<8 | u64(b[5])<<16 | u64(b[4])<<24 | + u64(b[3])<<32 | u64(b[2])<<40 | u64(b[1])<<48 | u64(b[0])<<56 + } + return v, true +} + +get_i16 :: proc(b: []byte, order: Byte_Order) -> (i16, bool) { + v, ok := get_u16(b, order) + return i16(v), ok +} +get_i32 :: proc(b: []byte, order: Byte_Order) -> (i32, bool) { + v, ok := get_u32(b, order) + return i32(v), ok +} +get_i64 :: proc(b: []byte, order: Byte_Order) -> (i64, bool) { + v, ok := get_u64(b, order) + return i64(v), ok +} + +get_f16 :: proc(b: []byte, order: Byte_Order) -> (f16, bool) { + v, ok := get_u16(b, order) + return transmute(f16)v, ok +} +get_f32 :: proc(b: []byte, order: Byte_Order) -> (f32, bool) { + v, ok := get_u32(b, order) + return transmute(f32)v, ok +} +get_f64 :: proc(b: []byte, order: Byte_Order) -> (f64, bool) { + v, ok := get_u64(b, order) + return transmute(f64)v, ok +} + + +put_u16 :: proc(b: []byte, order: Byte_Order, v: u16) -> bool { + if len(b) < 2 { + return false + } + #no_bounds_check if order == .Little { + b[0] = byte(v) + b[1] = byte(v >> 8) + } else { + b[0] = byte(v >> 8) + b[1] = byte(v) + } + return true +} +put_u32 :: proc(b: []byte, order: Byte_Order, v: u32) -> bool { + if len(b) < 4 { + return false + } + #no_bounds_check if order == .Little { + b[0] = byte(v) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + } else { + b[0] = byte(v >> 24) + b[1] = byte(v >> 16) + b[2] = byte(v >> 8) + b[3] = byte(v) + } + return true +} +put_u64 :: proc(b: []byte, order: Byte_Order, v: u64) -> bool { + if len(b) < 8 { + return false + } + #no_bounds_check if order == .Little { + b[0] = byte(v >> 0) + b[1] = byte(v >> 8) + b[2] = byte(v >> 16) + b[3] = byte(v >> 24) + b[4] = byte(v >> 32) + b[5] = byte(v >> 40) + b[6] = byte(v >> 48) + b[7] = byte(v >> 56) + } else { + b[0] = byte(v >> 56) + b[1] = byte(v >> 48) + b[2] = byte(v >> 40) + b[3] = byte(v >> 32) + b[4] = byte(v >> 24) + b[5] = byte(v >> 16) + b[6] = byte(v >> 8) + b[7] = byte(v) + } + return true +} + +put_i16 :: proc(b: []byte, order: Byte_Order, v: i16) -> bool { + return put_u16(b, order, u16(v)) +} + +put_i32 :: proc(b: []byte, order: Byte_Order, v: i32) -> bool { + return put_u32(b, order, u32(v)) +} + +put_i64 :: proc(b: []byte, order: Byte_Order, v: i64) -> bool { + return put_u64(b, order, u64(v)) +} + + +put_f16 :: proc(b: []byte, order: Byte_Order, v: f16) -> bool { + return put_u16(b, order, transmute(u16)v) +} + +put_f32 :: proc(b: []byte, order: Byte_Order, v: f32) -> bool { + return put_u32(b, order, transmute(u32)v) +} + +put_f64 :: proc(b: []byte, order: Byte_Order, v: f64) -> bool { + return put_u64(b, order, transmute(u64)v) +} |