From 7b7d9df67b0ca6a7669bac57cfff9d7fa0d5e2a9 Mon Sep 17 00:00:00 2001 From: Brett Date: Fri, 28 Jul 2023 01:35:01 -0400 Subject: [PATCH] NBT appears to be completely working --- CMakeLists.txt | 25 ++- include/blt/nbt/nbt.h | 64 ++++++ include/blt/std/filesystem.h | 5 +- include/blt/std/logging.h | 21 +- src/blt/nbt/nbt.cpp | 4 +- src/blt/std/filesystem.cpp | 8 + src/tests/main.cpp | 401 +++++++++++++++++++---------------- 7 files changed, 327 insertions(+), 201 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a927605..5bec728 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,6 +3,9 @@ project(BLT VERSION 0.7.0) set(CMAKE_CXX_STANDARD 20) +option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF) +option(ENABLE_UBSAN "Enable the ub sanitizer" OFF) +option(ENABLE_TSAN "Enable the thread data race sanitizer" OFF) option(BUILD_STD "Build the BLT standard utilities." ON) option(BUILD_PROFILING "Build the BLT profiler extension" ON) option(BUILD_NBT "Build the BLT NBT + eNBT extension" ON) @@ -63,7 +66,7 @@ endif() if(MSVC) #target_compile_options(BLT PRIVATE /W4) else() - # perhaps we should warn on usused variables, but BLT will have lots of them. + # perhaps we should warn on unused variables, but BLT will have lots of them. target_compile_options(BLT PRIVATE -Wall -Wextra -Wpedantic) endif() @@ -72,11 +75,6 @@ message("BLT ${CMAKE_PROJECT_VERSION} Successfully included!") if(${BUILD_TESTS}) project(BLT_TESTS) - if(${CMAKE_BUILD_TYPE} MATCHES Debug AND LINUX) - add_compile_options(-fsanitize=address) - add_link_options(-fsanitize=address) - endif() - file(GLOB_RECURSE TESTS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/tests/*.cpp") add_executable(BLT_TESTS ${TESTS_FILES}) @@ -92,5 +90,20 @@ if(${BUILD_TESTS}) target_compile_options(BLT_TESTS PRIVATE -Wall -Wextra -Wpedantic) endif() + if (${ENABLE_ADDRSAN} MATCHES ON) + target_compile_options(BLT_TESTS PRIVATE -fsanitize=address) + target_link_options(BLT_TESTS PRIVATE -fsanitize=address) + endif () + + if (${ENABLE_UBSAN} MATCHES ON) + target_compile_options(BLT_TESTS PRIVATE -fsanitize=undefined) + target_link_options(BLT_TESTS PRIVATE -fsanitize=undefined) + endif () + + if (${ENABLE_TSAN} MATCHES ON) + target_compile_options(BLT_TESTS PRIVATE -fsanitize=thread) + target_link_options(BLT_TESTS PRIVATE -fsanitize=thread) + endif () + message("BLT tests included!") endif() diff --git a/include/blt/nbt/nbt.h b/include/blt/nbt/nbt.h index 3de0426..7448432 100755 --- a/include/blt/nbt/nbt.h +++ b/include/blt/nbt/nbt.h @@ -299,6 +299,7 @@ namespace blt::nbt { for (const auto& v : t) v->writePayload(out); } + void readPayload(blt::fs::block_reader& in) final { char id; int32_t length; @@ -312,6 +313,35 @@ namespace blt::nbt { t[i]->readPayload(in); } } + + inline void put(tag_t* tag) { + t.push_back(tag); + } + + inline tag_t*& operator[](size_t i){ + return t[i]; + } + + template + [[nodiscard]] T* getTag(size_t i){ + if constexpr (!std::is_base_of::value) { + static_assert("WARNING: provided type isn't of type tag. Cannot cast expression!"); + BLT_WARN("You have requested an invalid type. Please use types of tag_t when using getTag"); + return nullptr; + } + auto& tag = t[i]; + T t; + if (tag->getType() != t.getType()) { + BLT_WARN("Expected tag of type %d but got tag of type %d", (char)t.getType(), (char)tag->getType()); + throw std::runtime_error("Requested Tag does not match stored type!"); + } + return dynamic_cast(tag); + } + + [[nodiscard]] inline size_t size() const { + return t.size(); + } + ~tag_list() override { for (auto* p : t) delete p; @@ -324,6 +354,35 @@ namespace blt::nbt { tag_compound(const std::string& name, const std::vector& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {} tag_compound(const std::string& name, const std::initializer_list& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {} tag_compound(const std::string& name, const HASHMAP& v): tag(nbt_tag::COMPOUND, name, v) {} + + inline void put(tag_t* tag) { + t[tag->getName()] = tag; + } + + template + [[nodiscard]] T* getTag(const std::string& name){ + if constexpr (!std::is_base_of::value) { + static_assert("WARNING: provided type isn't of type tag. Cannot cast expression!"); + BLT_WARN("You have requested an invalid type. Please use types of tag_t when using getTag"); + return nullptr; + } + auto& tag = t[name]; + T t; + if (tag->getType() != t.getType()) { + BLT_WARN("Expected tag of type %d but got tag of type %d", (char)t.getType(), (char)tag->getType()); + throw std::runtime_error("Requested Tag does not match stored type!"); + } + return dynamic_cast(tag); + } + + inline tag_t*& operator[](const std::string& name){ + return t[name]; + } + + inline void operator()(tag_t* tag){ + t[tag->getName()] = tag; + } + void writePayload(blt::fs::block_writer& out) final { for (const auto& v : t){ auto tag = v.second; @@ -367,6 +426,11 @@ namespace blt::nbt { template [[nodiscard]] T* getTag(const std::string& name){ + if constexpr (!std::is_base_of::value) { + static_assert("WARNING: provided type isn't of type tag. Cannot cast expression!"); + BLT_WARN("You have requested an invalid type. Please use types of tag_t when using getTag"); + return nullptr; + } auto& tag = root->get()[name]; T t; if (tag->getType() != t.getType()) { diff --git a/include/blt/std/filesystem.h b/include/blt/std/filesystem.h index f5e4a9a..0906d00 100755 --- a/include/blt/std/filesystem.h +++ b/include/blt/std/filesystem.h @@ -75,11 +75,10 @@ namespace blt::fs { class fstream_block_reader : public block_reader { private: std::fstream& m_stream; - char* m_buffer; + char* m_buffer = nullptr; size_t readIndex = 0; public: - explicit fstream_block_reader(std::fstream& stream, size_t bufferSize = 131072): - block_reader(bufferSize), m_stream(stream), m_buffer(new char[bufferSize]) {} + explicit fstream_block_reader(std::fstream& stream, size_t bufferSize = 131072); explicit fstream_block_reader(fstream_block_reader& copy) = delete; diff --git a/include/blt/std/logging.h b/include/blt/std/logging.h index c835b46..9aaf29f 100755 --- a/include/blt/std/logging.h +++ b/include/blt/std/logging.h @@ -193,12 +193,20 @@ namespace blt::logging { } public: tag_map(std::initializer_list initial_tags){ - tags = new tag[(size = 16)]; - for (auto& t : initial_tags) + tags = new tag[(size = 32)]; + for (const auto& t : initial_tags) insert(t); } + tag_map(const tag_map& copy) { + tags = new tag[(size = copy.size)]; + for (size_t i = 0; i < size; i++) + tags[i] = copy.tags[i]; + } + tag_map& insert(const tag& t){ + if (t.tag.empty()) + return *this; auto h = hash(t); if (h > size) expand(); @@ -217,6 +225,7 @@ namespace blt::logging { ~tag_map(){ delete[] tags; + tags = nullptr; } }; @@ -290,7 +299,7 @@ namespace blt::logging { hashmap> loggingStreamLines; LogFileWriter writer; - const tag_map tagMap = { + const std::unique_ptr tagMap = std::make_unique(tag_map{ {"YEAR", [](const tag_func_param&) -> std::string { BLT_NOW(); return std::to_string(now->tm_year); @@ -374,8 +383,8 @@ namespace blt::logging { }}, {"STR", [](const tag_func_param& f) -> std::string { return f.formatted_string; - }}, - }; + }} + }); static inline std::vector split(std::string s, const std::string& delim) { size_t pos = 0; @@ -489,7 +498,7 @@ namespace blt::logging { tag_func_param param{ level, filename({file}), std::to_string(line), userStr, userStr }; - out += tagMap[tag].func(param); + out += (*tagMap)[tag].func(param); } else { out += c; out += nonTag; diff --git a/src/blt/nbt/nbt.cpp b/src/blt/nbt/nbt.cpp index da3b561..7aec1a6 100755 --- a/src/blt/nbt/nbt.cpp +++ b/src/blt/nbt/nbt.cpp @@ -33,8 +33,10 @@ namespace blt::nbt { void NBTReader::read() { char t = reader.get(); - if (t != (char)nbt_tag::COMPOUND) + if (t != (char)nbt_tag::COMPOUND) { + BLT_WARN("Found %d", t); throw std::runtime_error("Incorrectly formatted NBT data! Root tag must be a compound tag!"); + } root = new tag_compound; root->readName(reader); root->readPayload(reader); diff --git a/src/blt/std/filesystem.cpp b/src/blt/std/filesystem.cpp index f854ca3..1e61daa 100755 --- a/src/blt/std/filesystem.cpp +++ b/src/blt/std/filesystem.cpp @@ -5,6 +5,14 @@ */ #include #include +#include "blt/std/logging.h" + +blt::fs::fstream_block_reader::fstream_block_reader(std::fstream& stream, size_t bufferSize) : + block_reader(bufferSize), m_stream(stream), m_buffer(new char[bufferSize]) { + if (!m_stream.good() || m_stream.fail()) + BLT_WARN("Provided std::fstream is not good! Clearing!"); + m_stream.clear(); +} int blt::fs::fstream_block_reader::read(char* buffer, size_t bytes) { if (readIndex == 0) diff --git a/src/tests/main.cpp b/src/tests/main.cpp index f427661..942618d 100755 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -67,195 +67,226 @@ int (*func_func)(int) = [](int i) -> int { int (*func_func_in)(int) = &test_as_func; int main(int argc, char** argv) { +// +// if (argc > 1 && std::string(argv[1]) == "--no_color") { +// for (int i = (int)blt::logging::log_level::NONE; i < (int)blt::logging::log_level::FATAL; i++) { +// blt::logging::setLogColor((blt::logging::log_level)i, ""); +// } +// blt::logging::setLogOutputFormat("[${{TIME}}] [${{LOG_LEVEL}}] (${{FILE}}:${{LINE}}) ${{STR}}\n"); +// } +// +// auto* funy = new class_func; +// super_func* virtual_funy = new class_func; +// +// for (int _ = 0; _ < 10; _++ ) { +// int num_of_tests = 10000; +// int acc = 1; +// BLT_START_INTERVAL("Functions Test", "std::function (lambda)"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += test(i); +// } +// BLT_END_INTERVAL("Functions Test", "std::function (lambda)"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "std::function (normal)"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += test_func_as_std(i); +// } +// BLT_END_INTERVAL("Functions Test", "std::function (normal)"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "normal function"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += test_as_func(i); +// } +// BLT_END_INTERVAL("Functions Test", "normal function"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "(inline) normal function"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += test_as_func_inline(i); +// } +// BLT_END_INTERVAL("Functions Test", "(inline) normal function"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "virtual class direct"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += funy->test(i); +// } +// BLT_END_INTERVAL("Functions Test", "virtual class direct"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "virtual class"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += virtual_funy->test(i); +// } +// BLT_END_INTERVAL("Functions Test", "virtual class"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "funcptr lambda"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += func_func(i); +// } +// BLT_END_INTERVAL("Functions Test", "funcptr lambda"); +// BLT_TRACE(acc); +// +// BLT_START_INTERVAL("Functions Test", "c function ptr"); +// acc = 1; +// for (int i = 0; i < num_of_tests; i++) { +// acc += func_func_in(i); +// } +// BLT_END_INTERVAL("Functions Test", "c function ptr"); +// BLT_TRACE(acc); +// } +// +// BLT_PRINT_PROFILE("Functions Test", blt::logging::log_level::NONE, true); +// delete virtual_funy; +// delete funy; +// +// binaryTreeTest(); +// +// run_logging(); +// +// runProfilingAndTableTests(); +// +// blt::logging::flush(); +// +// nbt_tests(); +// +// BLT_TRACE0_STREAM << "Test Output!\n"; +// BLT_TRACE1_STREAM << 5 << "\n"; +// BLT_TRACE2_STREAM << 5 << "\n"; +// BLT_TRACE3_STREAM << 5 << "\n"; +// BLT_TRACE_STREAM << "TRACEY\n"; +// +// blt::logging::flush(); +// +// test_queues(); +// +// blt::vec4 v{2, 5, 1, 8}; +// blt::mat4x4 m{}; +// m.m(0,0, 1); +// m.m(0,2, 2); +// m.m(1, 1, 3); +// m.m(1, 3, 4); +// m.m(2, 2, 5); +// m.m(3, 0, 6); +// m.m(3, 3, 7); +// +// auto result = m * v; +// +// std::cout << result.x() << " " << result.y() << " " << result.z() << " " << result.w() << std::endl; +// +// if (test_hashmaps()){ +// BLT_FATAL("Hashmap test failed!"); +// return 1; +// } +// +// BLT_TRACE("Hello Trace!"); +// BLT_DEBUG("Hello Debug!"); +// BLT_INFO("Hello Info!"); +// BLT_WARN("Hello Warn!"); +// BLT_ERROR("Hello Error!"); +// BLT_FATAL("Hello Fatal!"); +// +// constexpr int size = 100; +// uint32_t vals[size]; +// +// for (uint32_t & val : vals) +// val = 0; +// +// uint32_t seed = 1023; +// for (int i = 0; i < 10000000; i++){ +// seed = seed * i; +// vals[blt::random::randomInt(seed, 0, size)] += 1; +// } +// +// uint32_t mean = 0; +// for (uint32_t& val : vals) +// mean += val; +// mean /= size; +// +// uint32_t std = 0; +// for (uint32_t& val : vals) { +// auto e = (val - mean); +// std += e * e; +// } +// +// auto stdev = sqrt((double)std / (double)size); +// +// BLT_INFO("STDDEV of # random values: %f", stdev); - if (argc > 1 && std::string(argv[1]) == "--no_color") { - for (int i = (int)blt::logging::log_level::NONE; i < (int)blt::logging::log_level::FATAL; i++) { - blt::logging::setLogColor((blt::logging::log_level)i, ""); - } - blt::logging::setLogOutputFormat("[${{TIME}}] [${{LOG_LEVEL}}] (${{FILE}}:${{LINE}}) ${{STR}}\n"); + { + std::fstream nbtFile("super_file.nbt", std::ios::out | std::ios::binary); + blt::fs::fstream_block_writer blockWriter(nbtFile); + blt::nbt::NBTWriter nbtWriter(blockWriter); + nbtWriter.write( + new blt::nbt::tag_compound( + "root", { + new blt::nbt::tag_byte("super_byte", 8), + new blt::nbt::tag_short("shortTest", 32767), + new blt::nbt::tag_compound( + "SEXY_COMPOUND", { + new blt::nbt::tag_list( + "my list", { + new blt::nbt::tag_long("", 1230), + new blt::nbt::tag_long("", 2), + new blt::nbt::tag_long("", 50340535), + new blt::nbt::tag_long("", 55), + new blt::nbt::tag_long("", 256), + new blt::nbt::tag_long("", 512), + new blt::nbt::tag_long("", 9999999999), + } + ), + new blt::nbt::tag_double("OMG IT'S A DOUBLE", 1320.04324), + new blt::nbt::tag_float("OMG IT'S A FLOAT", 12.04324), + new blt::nbt::tag_compound( + "Triple", { + new blt::nbt::tag_int("Test int", 32), + new blt::nbt::tag_byte_array( + "super array", { + 51, 23, 12, 04, 33, 53, 11, 22, 3, 93, 120 + } + ), + new blt::nbt::tag_string("I am a string", "I have stringy contents"), + new blt::nbt::tag_string("name", "Bananrama"), + new blt::nbt::tag_int_array( + "int array", { + 1230, 234023, 21300, 2309230, 2340230, 2, 1, 32, 3265, 12, 53, 123, 7, + 56, 12 + } + ), + new blt::nbt::tag_long_array( + "valid", { + 1230, 5320, 323200234402304, 230023, 23042034, 230230, 2301203, + 123010230, 12300123 + } + ) + } + ) + } + ) + } + )); + + blockWriter.flush(); + nbtFile.close(); } - auto* funy = new class_func; - super_func* virtual_funy = new class_func; + std::fstream nbtInputFile("super_file.nbt", std::ios::in | std::ios::binary); + blt::fs::fstream_block_reader blockReader(nbtInputFile); + blt::nbt::NBTReader nbtReader(blockReader); + nbtReader.read(); - for (int _ = 0; _ < 10; _++ ) { - int num_of_tests = 10000; - int acc = 1; - BLT_START_INTERVAL("Functions Test", "std::function (lambda)"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += test(i); - } - BLT_END_INTERVAL("Functions Test", "std::function (lambda)"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "std::function (normal)"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += test_func_as_std(i); - } - BLT_END_INTERVAL("Functions Test", "std::function (normal)"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "normal function"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += test_as_func(i); - } - BLT_END_INTERVAL("Functions Test", "normal function"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "(inline) normal function"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += test_as_func_inline(i); - } - BLT_END_INTERVAL("Functions Test", "(inline) normal function"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "virtual class direct"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += funy->test(i); - } - BLT_END_INTERVAL("Functions Test", "virtual class direct"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "virtual class"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += virtual_funy->test(i); - } - BLT_END_INTERVAL("Functions Test", "virtual class"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "funcptr lambda"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += func_func(i); - } - BLT_END_INTERVAL("Functions Test", "funcptr lambda"); - BLT_TRACE(acc); - - BLT_START_INTERVAL("Functions Test", "c function ptr"); - acc = 1; - for (int i = 0; i < num_of_tests; i++) { - acc += func_func_in(i); - } - BLT_END_INTERVAL("Functions Test", "c function ptr"); - BLT_TRACE(acc); - } - - BLT_PRINT_PROFILE("Functions Test", blt::logging::log_level::NONE, true); - delete virtual_funy; - - binaryTreeTest(); - - run_logging(); - - runProfilingAndTableTests(); - - blt::logging::flush(); - - nbt_tests(); - - BLT_TRACE0_STREAM << "Test Output!\n"; - BLT_TRACE1_STREAM << 5 << "\n"; - BLT_TRACE2_STREAM << 5 << "\n"; - BLT_TRACE3_STREAM << 5 << "\n"; - BLT_TRACE_STREAM << "TRACEY\n"; - - blt::logging::flush(); - - test_queues(); - - blt::vec4 v{2, 5, 1, 8}; - blt::mat4x4 m{}; - m.m(0,0, 1); - m.m(0,2, 2); - m.m(1, 1, 3); - m.m(1, 3, 4); - m.m(2, 2, 5); - m.m(3, 0, 6); - m.m(3, 3, 7); - - auto result = m * v; - - std::cout << result.x() << " " << result.y() << " " << result.z() << " " << result.w() << std::endl; - - if (test_hashmaps()){ - BLT_FATAL("Hashmap test failed!"); - return 1; - } - - BLT_TRACE("Hello Trace!"); - BLT_DEBUG("Hello Debug!"); - BLT_INFO("Hello Info!"); - BLT_WARN("Hello Warn!"); - BLT_ERROR("Hello Error!"); - BLT_FATAL("Hello Fatal!"); - - constexpr int size = 100; - uint32_t vals[size]; - - for (uint32_t & val : vals) - val = 0; - - uint32_t seed = 1023; - for (int i = 0; i < 10000000; i++){ - seed = seed * i; - vals[blt::random::randomInt(seed, 0, size)] += 1; - } - - uint32_t mean = 0; - for (uint32_t& val : vals) - mean += val; - mean /= size; - - uint32_t std = 0; - for (uint32_t& val : vals) { - auto e = (val - mean); - std += e * e; - } - - auto stdev = sqrt((double)std / (double)size); - - BLT_INFO("STDDEV of # random values: %f", stdev); - - std::fstream nbtFile("super_file.nbt", std::ios::out | std::ios::binary); - blt::fs::fstream_block_writer blockWriter(nbtFile); - blt::nbt::NBTWriter nbtWriter(blockWriter); - nbtWriter.write(new blt::nbt::tag_compound("root", { - new blt::nbt::tag_byte("super_byte", 8), - new blt::nbt::tag_short("shortTest", 32767), - new blt::nbt::tag_compound("SEXY_COMPOUND", { - new blt::nbt::tag_list("my list", { - new blt::nbt::tag_long("", 1230), - new blt::nbt::tag_long("", 2), - new blt::nbt::tag_long("", 50340535), - new blt::nbt::tag_long("", 55), - new blt::nbt::tag_long("", 256), - new blt::nbt::tag_long("", 512), - new blt::nbt::tag_long("", 9999999999), - }), - new blt::nbt::tag_double("OMG IT'S A DOUBLE", 1320.04324), - new blt::nbt::tag_float("OMG IT'S A FLOAT", 12.04324), - new blt::nbt::tag_compound("Triple", { - new blt::nbt::tag_int("Test int", 32), - new blt::nbt::tag_byte_array("super array", { - 51, 23, 12, 04, 33, 53, 11, 22, 3, 93, 120 - }), - new blt::nbt::tag_string("I am a string", "I have stringy contents"), - new blt::nbt::tag_string("name", "Bananrama"), - new blt::nbt::tag_int_array("int array", { - 1230, 234023, 21300, 2309230, 2340230, 2, 1, 32, 3265, 12, 53, 123, 7, 56, 12 - }), - new blt::nbt::tag_long_array("valid", { - 1230, 5320, 323200234402304, 230023, 23042034, 230230, 2301203, 123010230, 12300123 - }) - }) - }) - })); + auto shortTag = nbtReader.getTag("shortTest"); + BLT_TRACE("Got short: %d", shortTag->get()); return 0; } \ No newline at end of file