From 197bb73a62675b14f0ddfc96e57cba9dc696630f Mon Sep 17 00:00:00 2001 From: Philip Nelson Date: Sat, 13 Jan 2024 21:52:02 -0800 Subject: [PATCH] Add buffer/push-* sized int and float --- src/core/buffer.c | 142 ++++++++++++++++++++++++++++++++++++++++ test/suite-buffer.janet | 40 +++++++++++ 2 files changed, 182 insertions(+) diff --git a/src/core/buffer.c b/src/core/buffer.c index b0fb4e90..5d9e7b3d 100644 --- a/src/core/buffer.c +++ b/src/core/buffer.c @@ -320,6 +320,143 @@ JANET_CORE_FN(cfun_buffer_chars, return argv[0]; } +static int should_reverse_bytes(const Janet *argv, int32_t argc) { + JanetKeyword order_kw = janet_getkeyword(argv, argc); + if (!janet_cstrcmp(order_kw, "le")) { +#if JANET_BIG_ENDIAN + return 1; +#endif + } else if (!janet_cstrcmp(order_kw, "be")) { +#if JANET_LITTLE_ENDIAN + return 1; +#endif + } else if (!janet_cstrcmp(order_kw, "native")) { + return 0; + } else { + janet_panicf("expected endianness :le, :be or :native, got %v", argv[1]); + } + return 0; +} + +static void reverse_u32(uint8_t bytes[4]) { + uint8_t temp; + temp = bytes[3]; + bytes[3] = bytes[0]; + bytes[0] = temp; + temp = bytes[2]; + bytes[2] = bytes[1]; + bytes[1] = temp; +} + +static void reverse_u64(uint8_t bytes[8]) { + uint8_t temp; + temp = bytes[7]; + bytes[7] = bytes[0]; + bytes[0] = temp; + temp = bytes[6]; + bytes[6] = bytes[1]; + bytes[1] = temp; + temp = bytes[5]; + bytes[5] = bytes[2]; + bytes[2] = temp; + temp = bytes[4]; + bytes[4] = bytes[3]; + bytes[3] = temp; +} + +JANET_CORE_FN(cfun_buffer_push_uint16, + "(buffer/push-uint16 buffer order data)", + "Push a 16 bit unsigned integer data onto the end of the buffer. " + "Returns the modified buffer.") { + janet_fixarity(argc, 3); + JanetBuffer *buffer = janet_getbuffer(argv, 0); + int reverse = should_reverse_bytes(argv, 1); + union { + uint16_t data; + uint8_t bytes[2]; + } u; + u.data = (uint16_t) janet_getinteger(argv, 2); + if (reverse) { + uint8_t temp = u.bytes[1]; + u.bytes[1] = u.bytes[0]; + u.bytes[0] = temp; + } + janet_buffer_push_u16(buffer, *(uint16_t *) u.bytes); + return argv[0]; +} + +JANET_CORE_FN(cfun_buffer_push_uint32, + "(buffer/push-uint32 buffer order data)", + "Push a 32 bit unsigned integer data onto the end of the buffer. " + "Returns the modified buffer.") { + janet_fixarity(argc, 3); + JanetBuffer *buffer = janet_getbuffer(argv, 0); + int reverse = should_reverse_bytes(argv, 1); + union { + uint32_t data; + uint8_t bytes[4]; + } u; + u.data = (uint32_t) janet_getinteger(argv, 2); + if (reverse) + reverse_u32(u.bytes); + janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes); + return argv[0]; +} + +JANET_CORE_FN(cfun_buffer_push_uint64, + "(buffer/push-uint64 buffer order data)", + "Push a 64 bit unsigned integer data onto the end of the buffer. " + "Returns the modified buffer.") { + janet_fixarity(argc, 3); + JanetBuffer *buffer = janet_getbuffer(argv, 0); + int reverse = should_reverse_bytes(argv, 1); + union { + uint64_t data; + uint8_t bytes[8]; + } u; + u.data = (uint64_t) janet_getuinteger64(argv, 2); + if (reverse) + reverse_u64(u.bytes); + janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes); + return argv[0]; +} + +JANET_CORE_FN(cfun_buffer_push_float32, + "(buffer/push-float32 buffer order data)", + "Push the underlying bytes of a 32 bit float data onto the end of the buffer. " + "Returns the modified buffer.") { + janet_fixarity(argc, 3); + JanetBuffer *buffer = janet_getbuffer(argv, 0); + int reverse = should_reverse_bytes(argv, 1); + union { + float data; + uint8_t bytes[4]; + } u; + u.data = (float) janet_getnumber(argv, 2); + if (reverse) + reverse_u32(u.bytes); + janet_buffer_push_u32(buffer, *(uint32_t *) u.bytes); + return argv[0]; +} + +JANET_CORE_FN(cfun_buffer_push_float64, + "(buffer/push-float64 buffer order data)", + "Push the underlying bytes of a 64 bit float data onto the end of the buffer. " + "Returns the modified buffer.") { + janet_fixarity(argc, 3); + JanetBuffer *buffer = janet_getbuffer(argv, 0); + int reverse = should_reverse_bytes(argv, 1); + union { + double data; + uint8_t bytes[8]; + } u; + u.data = janet_getnumber(argv, 2); + if (reverse) + reverse_u64(u.bytes); + janet_buffer_push_u64(buffer, *(uint64_t *) u.bytes); + return argv[0]; +} + static void buffer_push_impl(JanetBuffer *buffer, Janet *argv, int32_t argc_offset, int32_t argc) { for (int32_t i = argc_offset; i < argc; i++) { if (janet_checktype(argv[i], JANET_NUMBER)) { @@ -528,6 +665,11 @@ void janet_lib_buffer(JanetTable *env) { JANET_CORE_REG("buffer/push-byte", cfun_buffer_u8), JANET_CORE_REG("buffer/push-word", cfun_buffer_word), JANET_CORE_REG("buffer/push-string", cfun_buffer_chars), + JANET_CORE_REG("buffer/push-uint16", cfun_buffer_push_uint16), + JANET_CORE_REG("buffer/push-uint32", cfun_buffer_push_uint32), + JANET_CORE_REG("buffer/push-uint64", cfun_buffer_push_uint64), + JANET_CORE_REG("buffer/push-float32", cfun_buffer_push_float32), + JANET_CORE_REG("buffer/push-float64", cfun_buffer_push_float64), JANET_CORE_REG("buffer/push", cfun_buffer_push), JANET_CORE_REG("buffer/push-at", cfun_buffer_push_at), JANET_CORE_REG("buffer/popn", cfun_buffer_popn), diff --git a/test/suite-buffer.janet b/test/suite-buffer.janet index 5e38ffbc..7d585680 100644 --- a/test/suite-buffer.janet +++ b/test/suite-buffer.janet @@ -77,6 +77,46 @@ (buffer/push-string b5 "456" @"789") (assert (= "123456789" (string b5)) "buffer/push-buffer 2") +(def buffer-uint16-be @"") +(buffer/push-uint16 buffer-uint16-be :be 0x0102) +(assert (= "\x01\x02" (string buffer-uint16-be)) "buffer/push-uint16 big endian") + +(def buffer-uint16-le @"") +(buffer/push-uint16 buffer-uint16-le :le 0x0102) +(assert (= "\x02\x01" (string buffer-uint16-le)) "buffer/push-uint16 little endian") + +(def buffer-uint16-negative @"") +(buffer/push-uint16 buffer-uint16-negative :be -1) +(assert (= "\xff\xff" (string buffer-uint16-negative)) "buffer/push-uint16 negative") + +(def buffer-uint32-be @"") +(buffer/push-uint32 buffer-uint32-be :be 0x01020304) +(assert (= "\x01\x02\x03\x04" (string buffer-uint32-be)) "buffer/push-uint32 big endian") + +(def buffer-uint32-le @"") +(buffer/push-uint32 buffer-uint32-le :le 0x01020304) +(assert (= "\x04\x03\x02\x01" (string buffer-uint32-le)) "buffer/push-uint32 little endian") + +(def buffer-uint32-negative @"") +(buffer/push-uint32 buffer-uint32-negative :be -1) +(assert (= "\xff\xff\xff\xff" (string buffer-uint32-negative)) "buffer/push-uint32 negative") + +(def buffer-float32-be @"") +(buffer/push-float32 buffer-float32-be :be 1.234) +(assert (= "\x3f\x9d\xf3\xb6" (string buffer-float32-be)) "buffer/push-float32 big endian") + +(def buffer-float32-le @"") +(buffer/push-float32 buffer-float32-le :le 1.234) +(assert (= "\xb6\xf3\x9d\x3f" (string buffer-float32-le)) "buffer/push-float32 little endian") + +(def buffer-float64-be @"") +(buffer/push-float64 buffer-float64-be :be 1.234) +(assert (= "\x3f\xf3\xbe\x76\xc8\xb4\x39\x58" (string buffer-float64-be)) "buffer/push-float64 big endian") + +(def buffer-float64-le @"") +(buffer/push-float64 buffer-float64-le :le 1.234) +(assert (= "\x58\x39\xb4\xc8\x76\xbe\xf3\x3f" (string buffer-float64-le)) "buffer/push-float64 little endian") + # Buffer from bytes (assert (deep= @"" (buffer/from-bytes)) "buffer/from-bytes 1") (assert (deep= @"ABC" (buffer/from-bytes 65 66 67)) "buffer/from-bytes 2")