diff --git a/io/include/io/read.h b/io/include/io/read.h index d73c794..32190d4 100644 --- a/io/include/io/read.h +++ b/io/include/io/read.h @@ -2,6 +2,7 @@ #include "helper.h" #include #include +#include namespace io { // This exists to allow for specialization and clearer errors @@ -35,19 +36,11 @@ namespace io { return value; } + template <> + float read(std::istream& is); + template<> - size_t read(std::istream& is) { - size_t value = 0; - uint8_t length = io::read(is); - if (length & 0b10000000) { - value = read_bytes(is, length & 0b01111111); - } else { - value = length; - } - return value; - } - - + size_t read(std::istream& is); template requires std::is_convertible_v T read(std::istream& is, size_t length) { diff --git a/io/include/io/write.h b/io/include/io/write.h index 0557409..38a02db 100644 --- a/io/include/io/write.h +++ b/io/include/io/write.h @@ -31,25 +31,12 @@ namespace io { write_bytes(os, value, sizeof(T)); } + template <> + void write(std::ostream& os, float value); + // Special implementation for size_t (also uint64_t, so maybe this is not that smart) template <> - void write(std::ostream& os, size_t value) { - // Check if we need more then one byte - if (value > 0b01111111) { - // Calculate how many bytes we need to store the number - uint8_t length = 0; - auto x = value; - while (x != 0) { - x >>= 8; - length++; - } - - write(os, length | 0b10000000); - write_bytes(os, value, length); - } else { - write(os, value); - } - } + void write(std::ostream& os, size_t value); template requires std::is_convertible_v void write(std::ostream& os, T value, bool store_length = true) { diff --git a/io/src/read.cpp b/io/src/read.cpp new file mode 100644 index 0000000..1b22f4d --- /dev/null +++ b/io/src/read.cpp @@ -0,0 +1,27 @@ +#include "io/read.h" + +namespace io { + template<> + float read(std::istream& is) { + union { + uint32_t a; + float b; + } u; + + u.a = read_bytes(is, sizeof(uint32_t)); + + return u.b; + } + + template<> + size_t read(std::istream& is) { + size_t value = 0; + uint8_t length = io::read(is); + if (length & 0b10000000) { + value = read_bytes(is, length & 0b01111111); + } else { + value = length; + } + return value; + } +} diff --git a/io/src/write.cpp b/io/src/write.cpp index 4b37887..555fc8b 100644 --- a/io/src/write.cpp +++ b/io/src/write.cpp @@ -1,3 +1,34 @@ #include "io/write.h" -// We do not implement anything without templates +namespace io { + template<> + void write(std::ostream& os, float value) { + union { + uint32_t a; + float b; + } u; + + u.b = value; + write_bytes(os, u.a, sizeof(uint32_t)); + } + + // Special implementation for size_t (also uint64_t, so maybe this is not that smart) + template<> + void write(std::ostream& os, size_t value) { + // Check if we need more then one byte + if (value > 0b01111111) { + // Calculate how many bytes we need to store the number + uint8_t length = 0; + auto x = value; + while (x != 0) { + x >>= 8; + length++; + } + + write(os, length | 0b10000000); + write_bytes(os, value, length); + } else { + write(os, value); + } + } +} diff --git a/test/src/test.cpp b/test/src/test.cpp index bb67435..dce3c62 100644 --- a/test/src/test.cpp +++ b/test/src/test.cpp @@ -74,6 +74,24 @@ int main() { return io::read(f) == 80085; }()); + Test("Write for float", [] { + std::fstream f("test.bin", std::ios::trunc | std::ios::in | std::ios::out); + io::write(f, 123.654f); + + bool succes = 4 == f.tellg(); f.seekg(0); char c; + f.read(&c,1); succes &= (c & 0xff) == 0x42; + f.read(&c,1); succes &= (c & 0xff) == 0xf7; + f.read(&c,1); succes &= (c & 0xff) == 0x4e; + f.read(&c,1); succes &= (c & 0xff) == 0xd9; + return succes; + }()); + + Test("Read for float", [] { + std::ifstream f("test.bin"); + return io::read(f) == 123.654f; + }()); + + Test("Write for short size_t", [] { std::fstream f("test.bin", std::ios::trunc | std::ios::in | std::ios::out); io::write(f, 12);