diff --git a/.gitignore b/.gitignore index e148685..544a471 100755 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,6 @@ cmake-build-debug/ /cmake-build-release/ ./cmake-build-release/ cmake-build-release/ +cmake-build-relwithdebinfo/ +cmake-build-reldebug-asan/ +./cmake-build-relwithdebinfo/ diff --git a/CMakeLists.txt b/CMakeLists.txt index fcbf4fd..69b743f 100755 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,11 +1,15 @@ -cmake_minimum_required(VERSION 3.0) -project(BLT VERSION 0.6.0) +cmake_minimum_required(VERSION 3.5) +project(BLT VERSION 0.8.1) -set(CMAKE_CXX_STANDARD 17) +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) +option(BUILD_PARSE "Build the BLT parsers" ON) option(BUILD_TESTS "Build the BLT test set" OFF) option(BLT_DISABLE_LOGGING "Disable blt::logging (all macros and will safely disable logging function!)" OFF) option(BLT_DISABLE_TRACE "Disable blt::logging BLT_TRACE macro" OFF) @@ -35,6 +39,17 @@ else() set(NBT_FILES "") endif() +if(${BUILD_PARSE}) + file(GLOB_RECURSE PARSE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/parse/*.cpp") +else() + set(PARSE_FILES "") +endif() + +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) + message("Found Parallel Hashmaps") + include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) +endif() + #include zlib if the user has it. find_package(ZLIB QUIET) @@ -52,18 +67,22 @@ message("Profiler Files ${PROFILING_FILES}") message("Source: ${CMAKE_SOURCE_DIR}") message("Current Source: ${CMAKE_CURRENT_SOURCE_DIR}") -add_library(BLT ${STD_FILES} ${PROFILING_FILES} ${NBT_FILES}) +add_library(BLT ${STD_FILES} ${PROFILING_FILES} ${NBT_FILES} ${PARSE_FILES}) target_include_directories(BLT PUBLIC include/) target_include_directories(BLT PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config/) if(${ZLIB_FOUND}) target_link_libraries(BLT PUBLIC ZLIB::ZLIB) endif() +if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) + message("Including phmap") + target_include_directories(BLT PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) +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 +91,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 +106,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/README.md b/README.md index 55e0c1b..7428d83 100755 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# **BLT v0.6.0a** -A common utilities library I find useful +# **BLT v0.8.0a** +A C++20 common utilities library to make thing easy! ![Icon](icon_large.png) @@ -26,11 +26,10 @@ If you are using BLT as a CMake library (as you should!) this is done for you. - ## Data Structures - Queue / Stack - faster than std::queue / std::stack - - Binary Tree - - Hashmap (TODO) + - backed by a contiguous array - ## Utility - - Simple Random Interface - - No more worrying about min/max bounds! + - Simple Random Wrapper Interface + - Simple random functions based on the PCG Hash - ### String Functions - starts_with - ends_with @@ -40,14 +39,12 @@ If you are using BLT as a CMake library (as you should!) this is done for you. - split - trim - Logging - - Trace / Debug / Info / Warn / Error / Fatal - - Log to file - - Log to console with color! - - Easy to disable for release - - define BLT_DISABLE_LOGGING before including the logging.h file. + - See blt::logging section above - Time - Current time in nanoseconds (without all the c++ gobbledygook) + - Java's currentTimeMilliseconds + - nanoTime as well + - `std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count()` becomes `blt::system::nanoTime()` - Formatted time string with year/month/date + current time - ## Profiling - - Basic profiler - - WIP \ No newline at end of file + - Basic profiler with history and formatted output \ No newline at end of file diff --git a/include/blt/math/math.h b/include/blt/math/math.h index 3fc3b0b..7c2ff50 100755 --- a/include/blt/math/math.h +++ b/include/blt/math/math.h @@ -19,7 +19,9 @@ namespace blt { seed = (seed << 13) ^ seed; return ((seed * (seed * seed * 15731 + 789221) + 1376312589) & 0x7fffffff); } - + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wstrict-aliasing" /** * fast inverse sqrt */ @@ -35,6 +37,28 @@ namespace blt { y = y * (1.5f - (x * y * y)); return y; } + +#pragma GCC diagnostic pop + + + static inline constexpr double pow(int b, int p) { + int collection = 1; + for (int i = 0; i < p; i++) + collection *= b; + return collection; + } + + /** + * This is a fast rounding function and is not guaranteed to be 100% correct + * @tparam decimal_places + * @param value + * @return + */ + template + static inline double round_up(double value) { + constexpr double multiplier = pow(10, decimal_places); + return ((int)(value * multiplier) + 1) / multiplier; + } /*inline std::ostream& operator<<(std::ostream& out, const mat4x4& v) { return out << "\rMatrix4x4{" << v.m00() << ", " << v.m01() << ", " << v.m02() << ", " << v.m03() << "} \n"\ diff --git a/include/blt/nbt/nbt.h b/include/blt/nbt/nbt.h index 9ddbcf7..c3fb6e4 100755 --- a/include/blt/nbt/nbt.h +++ b/include/blt/nbt/nbt.h @@ -7,53 +7,460 @@ #ifndef BLT_TESTS_NBT_H #define BLT_TESTS_NBT_H +#include +#include +#include +#include +#include + #include "blt/std/format.h" #include "blt/std/filesystem.h" +#include "blt/std/logging.h" + +#include namespace blt::nbt { - void writeUTF8String(std::fstream& stream, const std::string& str); - std::string readUTF8String(std::fstream& stream); + void writeUTF8String(blt::fs::block_writer& stream, const std::string& str); - enum nbt_type { - tag_end = 0, - tag_byte = 1, - tag_short = 2, - tag_int = 3, - tag_long = 4, - tag_float = 5, - tag_double = 6, - tag_byte_array = 7, - tag_string = 8, - tag_list = 9, - tag_compound = 10, - tag_int_array = 11, - tag_long_array = 12 - }; + std::string readUTF8String(blt::fs::block_reader& stream); - class nbt_tag { - public: - virtual void readTag() = 0; - virtual void writeTag() = 0; - }; - - class NBTDecoder { - private: - blt::fs::block_reader* m_reader; - public: - explicit NBTDecoder(blt::fs::block_reader* reader): m_reader(reader) {} + // Used to grab the byte-data of any T element. Defaults to Big Endian, however can be configured to use little endian + template + inline static int toBytes(const T& in, char* out) { + std::memcpy(out, (void*) &in, sizeof(T)); + if constexpr (std::endian::native == std::endian::little) { + for (size_t i = 0; i < sizeof(T) / 2; i++) + std::swap(out[i], out[sizeof(T) - 1 - i]); + } + + return 0; + } + + // Used to cast the binary data of any T object, into a T object. + template + inline static int fromBytes(const char* in, T* out) { + memcpy(out, in, sizeof(T)); + + if constexpr (std::endian::native == std::endian::little) { + for (size_t i = 0; i < sizeof(T) / 2; i++) + std::swap(((char*) (out))[i], ((char*) (out))[sizeof(T) - 1 - i]); + } + + return 0; + } + + template + inline static void writeData(blt::fs::block_writer& out, const T& d){ + char data[sizeof(T)]; + toBytes(d, data); + out.write(data, sizeof(T)); + } + + template + inline static void readData(blt::fs::block_reader& in, T& d) { + char data[sizeof(T)]; + in.read(data, sizeof(T)); + fromBytes(data, &d); + } + + enum class nbt_tag : char { + END = 0, + BYTE = 1, + SHORT = 2, + INT = 3, + LONG = 4, + FLOAT = 5, + DOUBLE = 6, + BYTE_ARRAY = 7, + STRING = 8, + LIST = 9, + COMPOUND = 10, + INT_ARRAY = 11, + LONG_ARRAY = 12 }; - /** - * Reads the entire NBT file when the read() function is called. - */ + class tag_t { + protected: + nbt_tag type; + std::string name; + public: + explicit tag_t(nbt_tag type): type(type) {}; + explicit tag_t(nbt_tag type, std::string name): type(type), name(std::move(name)) {} + virtual void writePayload(blt::fs::block_writer& out) = 0; + virtual void readPayload(blt::fs::block_reader& in) = 0; + void writeName(blt::fs::block_writer& out) { + writeUTF8String(out, name); + } + void readName(blt::fs::block_reader& in) { + name = readUTF8String(in); + } + [[nodiscard]] inline nbt_tag getType() const { + return type; + } + [[nodiscard]] inline const std::string& getName() const { + return name; + } + virtual ~tag_t() = default; + }; + + template + class tag : public tag_t { + protected: + T t; + public: + explicit tag(nbt_tag type): tag_t(type) {} + tag(nbt_tag type, std::string name, T t): tag_t(type, std::move(name)), t(std::move(t)) {} + void writePayload(blt::fs::block_writer& out) override { + if constexpr(std::is_arithmetic::value) + writeData(out, t); + } + void readPayload(blt::fs::block_reader& in) override { + if constexpr(std::is_arithmetic::value) + readData(in, t); + } + [[nodiscard]] inline const T& get() const {return t;} + inline T& get() {return t;} + ~tag() override = default; + }; + + class tag_end : public tag { + public: + void writePayload(blt::fs::block_writer&) final {} + // nothing to read + void readPayload(blt::fs::block_reader&) final {} + }; + + class tag_byte : public tag { + public: + tag_byte(): tag(nbt_tag::BYTE) {} + tag_byte(const std::string& name, int8_t b): tag(nbt_tag::BYTE, name, b) {} + }; + + class tag_short : public tag { + public: + tag_short(): tag(nbt_tag::SHORT) {} + tag_short(const std::string& name, int16_t s): tag(nbt_tag::SHORT, name, s) {} + }; + + class tag_int : public tag { + public: + tag_int(): tag(nbt_tag::INT) {} + tag_int(const std::string& name, int32_t i): tag(nbt_tag::INT, name, i) {} + }; + + class tag_long : public tag { + public: + tag_long(): tag(nbt_tag::LONG) {} + tag_long(const std::string& name, int64_t l): tag(nbt_tag::LONG, name, l) {} + }; + + class tag_float : public tag { + public: + tag_float(): tag(nbt_tag::FLOAT) {} + tag_float(const std::string& name, float f): tag(nbt_tag::FLOAT, name, f) {} + }; + + class tag_double : public tag { + public: + tag_double(): tag(nbt_tag::DOUBLE) {} + tag_double(const std::string& name, double d): tag(nbt_tag::DOUBLE, name, d) {} + }; + + class tag_byte_array : public tag> { + public: + tag_byte_array(): tag(nbt_tag::BYTE_ARRAY) {} + tag_byte_array(const std::string& name, const std::vector& v): tag(nbt_tag::BYTE_ARRAY, name, v) {} + void writePayload(blt::fs::block_writer& out) final { + auto length = (int32_t) t.size(); + writeData(out, length); + // TODO on the writer (remove need for cast + more std::fstream functions) + out.write(reinterpret_cast(t.data()), length); + } + void readPayload(blt::fs::block_reader& in) final { + int32_t length; + readData(in, length); + t.reserve(length); + in.read(reinterpret_cast(t.data()), length); + } + }; + + class tag_string : public tag { + public: + tag_string(): tag(nbt_tag::STRING) {} + tag_string(const std::string& name, const std::string& s): tag(nbt_tag::STRING, name, s) {} + void writePayload(blt::fs::block_writer& out) final { + writeUTF8String(out, t); + } + void readPayload(blt::fs::block_reader& in) final { + t = readUTF8String(in); + } + }; + + class tag_int_array : public tag> { + public: + tag_int_array(): tag(nbt_tag::INT_ARRAY) {} + tag_int_array(const std::string& name, const std::vector& v): tag(nbt_tag::INT_ARRAY, name, v) {} + void writePayload(blt::fs::block_writer& out) final { + auto length = (int32_t) t.size(); + writeData(out, length); + for (int i = 0; i < length; i++) + writeData(out, t[i]); + } + void readPayload(blt::fs::block_reader& in) final { + int32_t length; + readData(in, length); + t.reserve(length); + for (int i = 0; i < length; i++) + readData(in, t[i]); + } + }; + + class tag_long_array : public tag> { + public: + tag_long_array(): tag(nbt_tag::LONG_ARRAY) {} + tag_long_array(const std::string& name, const std::vector& v): tag(nbt_tag::LONG_ARRAY, name, v) {} + void writePayload(blt::fs::block_writer& out) final { + auto length = (int32_t) t.size(); + writeData(out, length); + for (int i = 0; i < length; i++) + writeData(out, t[i]); + } + void readPayload(blt::fs::block_reader& in) final { + int32_t length; + readData(in, length); + t.reserve(length); + for (int i = 0; i < length; i++) + readData(in, t[i]); + } + }; + +#define BLT_NBT_POPULATE_VEC(type, vec, length) for (int i = 0; i < length; i++) vec.push_back(type); + + namespace _internal_ { + // EVIL HACK + static tag_t* newCompound(); + static tag_t* newList(); + static tag_t* toType(char id){ + switch ((nbt_tag) id) { + case nbt_tag::END: + return nullptr; + break; + case nbt_tag::BYTE: + return new blt::nbt::tag_byte; + case nbt_tag::SHORT: + return new blt::nbt::tag_short; + case nbt_tag::INT: + return new blt::nbt::tag_int; + case nbt_tag::LONG: + return new blt::nbt::tag_long; + case nbt_tag::FLOAT: + return new blt::nbt::tag_float; + case nbt_tag::DOUBLE: + return new blt::nbt::tag_double; + case nbt_tag::BYTE_ARRAY: + return new blt::nbt::tag_byte_array; + case nbt_tag::STRING: + return new blt::nbt::tag_string; + case nbt_tag::LIST: + return _internal_::newList(); + case nbt_tag::COMPOUND: + return _internal_::newCompound(); + case nbt_tag::INT_ARRAY: + return new blt::nbt::tag_int_array; + case nbt_tag::LONG_ARRAY: + return new blt::nbt::tag_long_array; + } + BLT_WARN("Tag Type not found!"); + return nullptr; + } + static HASHMAP toHashmap(const std::vector& v){ + HASHMAP tags; + for (const auto& t : v) + tags[t->getName()] = t; + return tags; + } + } + + class tag_list : public tag> { + public: + tag_list(): tag(nbt_tag::LIST) {} + tag_list(const std::string& name, const std::vector& v): tag(nbt_tag::LIST, name, v) {} + void writePayload(blt::fs::block_writer& out) final { + if (t.empty()) + writeData(out, (char)nbt_tag::END); + else + writeData(out, (char)t[0]->getType()); + auto length = (int32_t) t.size(); + writeData(out, length); + for (const auto& v : t) + v->writePayload(out); + } + + void readPayload(blt::fs::block_reader& in) final { + char id; + int32_t length; + readData(in, id); + readData(in, length); + if (length == 0 || id == 0) + return; + for (int i = 0; i < length; i++) { + auto v = _internal_::toType(id); + v->readPayload(in); + t.push_back(v); + } + } + + 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; + } + }; + + class tag_compound : public tag> { + public: + tag_compound(): tag(nbt_tag::COMPOUND) {} + 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; + out.put((char) tag->getType()); + tag->writeName(out); + tag->writePayload(out); + } + out.put('\0'); + } + void readPayload(blt::fs::block_reader& in) final { + char type; + while ((type = in.get()) != (char)nbt_tag::END){ + auto* v = _internal_::toType(type); + v->readName(in); + v->readPayload(in); + t[v->getName()] = v; + } + } + ~tag_compound() override { + for (auto& v : t) + delete v.second; + } + }; + + static tag_t* _internal_::newCompound(){ + return new blt::nbt::tag_compound; + } + + static tag_t* _internal_::newList() { + return new blt::nbt::tag_list; + } + class NBTReader { private: - std::string m_file; - + blt::fs::block_reader& reader; + tag_compound* root = nullptr; public: - explicit NBTReader(std::string file): m_file(std::move(file)) {} + explicit NBTReader(blt::fs::block_reader& reader): reader(reader) {} + + void read(); + + 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()) { + 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); + } + ~NBTReader() { + delete root; + } + }; + + class NBTWriter { + private: + blt::fs::block_writer& writer; + public: + explicit NBTWriter(blt::fs::block_writer& writer): writer(writer) {} + /** + * Write a compound tag and then DELETES the tag. If you don't wish for the memory to be freed, please use the reference version! + * @param root root NBT tag to write, this function assumes ownership of this pointer. + */ + void write(tag_compound* root){ + write(*root); + delete root; + } + void write(tag_compound& root){ + writer.put((char)nbt_tag::COMPOUND); + root.writeName(writer); + root.writePayload(writer); + } + ~NBTWriter() = default; }; } diff --git a/include/blt/parse/argparse.h b/include/blt/parse/argparse.h new file mode 100755 index 0000000..5625d27 --- /dev/null +++ b/include/blt/parse/argparse.h @@ -0,0 +1,382 @@ +/* + * Created by Brett on 06/08/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef BLT_TESTS_ARGPARSE_H +#define BLT_TESTS_ARGPARSE_H + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace blt +{ + typedef std::variant arg_data_internal_t; + typedef std::vector arg_data_vec_t; + typedef std::variant arg_data_t; + + enum class arg_action_t + { + STORE, + STORE_CONST, + STORE_TRUE, + STORE_FALSE, + APPEND, + APPEND_CONST, + COUNT, + HELP, + VERSION, + EXTEND + }; + + class arg_vector_t + { + friend class arg_parse; + + private: + std::vector flags; + std::string name; + + void validateFlags(); + + public: + arg_vector_t(std::vector flags): flags(std::move(flags)) + { + validateFlags(); + } + + arg_vector_t(std::initializer_list flags): flags(flags) + { + validateFlags(); + } + + arg_vector_t(const char* str); + + arg_vector_t(const std::string& str); + + [[nodiscard]] inline bool isFlag() const + { + return !flags.empty(); + } + + [[nodiscard]] inline bool contains(const std::string& str) + { + return std::any_of( + flags.begin(), flags.end(), [&str](const std::string& flag) -> bool { + return flag == str; + } + ) || str == name; + } + + // returns the first flag that starts with '--' otherwise return the first '-' flag + [[nodiscard]] std::string getFirstFullFlag(); + }; + + class arg_nargs_t + { + friend class arg_parse; + + private: + static constexpr int UNKNOWN = 0x1; + static constexpr int ALL = 0x2; + static constexpr int ALL_REQUIRED = 0x4; + // 0 means ignore + int args = 1; + // 0 indicates args is used + int flags = 0; + + void decode(char c); + + public: + arg_nargs_t() = default; + + arg_nargs_t(int args): args(args) + {} + + arg_nargs_t(char c); + + arg_nargs_t(std::string s); + + arg_nargs_t(const char* s); + + [[nodiscard]] bool takesArgs() const + { + return args > 0 || flags > 0; + } + }; + + struct arg_properties_t + { + private: + public: + arg_vector_t a_flags; + arg_action_t a_action = arg_action_t::STORE; + arg_nargs_t a_nargs = 1; + std::string a_const{}; + arg_data_internal_t a_default{}; + std::string a_dest{}; + std::string a_help{}; + std::string a_version{}; + std::string a_metavar{}; + bool a_required = true; + }; + + class arg_builder + { + arg_properties_t properties; + public: + arg_builder(const arg_vector_t& flags): properties(flags) + {} + + inline arg_properties_t build() + { + return properties; + } + + inline arg_builder& setAction(arg_action_t action) + { + properties.a_action = action; + return *this; + } + + inline arg_builder& setNArgs(const arg_nargs_t& nargs) + { + properties.a_nargs = nargs; + return *this; + } + + inline arg_builder& setConst(const std::string& a_const) + { + properties.a_const = a_const; + return *this; + } + + inline arg_builder& setDefault(const arg_data_internal_t& def) + { + properties.a_default = def; + return *this; + } + + inline arg_builder& setDest(const std::string& dest) + { + properties.a_dest = dest; + return *this; + } + + inline arg_builder& setHelp(const std::string& help) + { + properties.a_help = help; + return *this; + } + + inline arg_builder& setVersion(const std::string& version) + { + properties.a_version = version; + return *this; + } + + inline arg_builder& setMetavar(const std::string& metavar) + { + properties.a_metavar = metavar; + return *this; + } + + inline arg_builder& setRequired() + { + properties.a_required = true; + return *this; + } + + }; + + class arg_tokenizer + { + private: + std::vector args; + size_t currentIndex = 0; + public: + arg_tokenizer(std::vector args): args(std::move(args)) + {} + + // returns the current arg + inline const std::string& get() + { + return args[currentIndex]; + } + + // returns if we have next arg to process + inline bool hasNext() + { + return currentIndex + 1 < args.size(); + } + + inline bool hasCurrent() + { + return currentIndex < args.size(); + } + + // returns true if the current arg is a flag + inline bool isFlag() + { + return args[currentIndex].starts_with('-'); + } + + // returns true if we have next and the next arg is a flag + inline bool isNextFlag() + { + return hasNext() && args[currentIndex + 1].starts_with('-'); + } + + // advances to the next flag + inline size_t advance() + { + return currentIndex++; + } + }; + + class arg_parse + { + private: + struct + { + friend arg_parse; + private: + std::vector arg_properties_storage; + size_t max_line_length = 80; + // TODO: grouping like git's help + // pre/postfix applied to the help message + std::string prefix; + std::string postfix; + public: + std::vector name_associations; + HASHMAP flag_associations; + } user_args; + + struct arg_results + { + friend arg_parse; + private: + // stores dest value not the flag/name! + HASHSET found_args; + std::vector unrecognized_args; + public: + std::string program_name; + HASHMAP data; + + inline arg_data_t& operator[](const std::string& key) + { + return data[key]; + } + + inline auto begin() + { + return data.begin(); + } + + inline auto end() + { + return data.end(); + } + + inline bool contains(const std::string& key) + { + return data.find(key) != data.end(); + } + } loaded_args; + + private: + static std::string filename(const std::string& path); + static std::string getMetavar(const arg_properties_t* const& arg); + static std::string getFlagHelp(const arg_properties_t* const& arg); + + static bool takesArgs(const arg_properties_t* const& arg); + + /** + * prints out a new line if current line length is greater than max line length, using spacing to generate the next line's + * beginning spaces. + */ + void checkAndPrintFormattingLine(size_t& current_line_length, size_t spacing) const; + + // expects that the current flag has already been consumed (advanced past), leaves tokenizer in a state where the next element is 'current' + bool consumeArguments( + arg_tokenizer& tokenizer, const std::string& flag, const arg_properties_t& properties, std::vector& v_out + ) const; + + void handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos); + + void handleFlagArgument(arg_tokenizer& tokenizer); + + void processFlag(arg_tokenizer& tokenizer, const std::string& flag); + + public: + + template + static inline bool holds_alternative(const arg_data_t& v) + { + if constexpr (std::is_same_v) + return std::holds_alternative(v); + else + return std::holds_alternative(v) && std::holds_alternative(std::get(v)); + } + + template + static inline T& get(arg_data_t& v) + { + if constexpr (std::is_same_v) + return std::get(v); + else + return std::get(std::get(v)); + } + + public: + arg_parse(const std::string& helpMessage = "show this help menu and exit") + { + addArgument(arg_builder({"--help", "-h"}).setAction(arg_action_t::HELP).setHelp(helpMessage).build()); + }; + + void addArgument(const arg_properties_t& args); + + arg_results parse_args(int argc, const char** argv); + + arg_results parse_args(const std::vector& args); + + void printUsage() const; + + void printHelp() const; + + inline void setHelpPrefix(const std::string& str) + { + user_args.prefix = str; + } + + inline void setHelpPostfix(const std::string& str) + { + user_args.postfix = str; + } + + inline void setMaxLineLength(size_t size) + { + user_args.max_line_length = size; + } + + ~arg_parse() + { + for (auto* p : user_args.arg_properties_storage) + delete p; + } + }; + + std::string to_string(const blt::arg_data_t& v); + + std::string to_string(const blt::arg_data_internal_t& v); + +} + +#endif //BLT_TESTS_ARGPARSE_H diff --git a/include/blt/std/filesystem.h b/include/blt/std/filesystem.h index 70d1ee5..0906d00 100755 --- a/include/blt/std/filesystem.h +++ b/include/blt/std/filesystem.h @@ -34,6 +34,11 @@ namespace blt::fs { * @return status code. non-zero return codes indicates a failure has occurred. */ virtual int read(char* buffer, size_t bytes) = 0; + virtual char get(){ + char c[1]; + read(c, 1); + return c[0]; + } }; /** @@ -52,6 +57,11 @@ namespace blt::fs { * @return non-zero code if failure */ virtual int write(char* buffer, size_t bytes) = 0; + virtual int put(char c){ + char a[1]; + a[0] = c; + return write(a, 1); + } /** * Ensures that the internal buffer is written to the filesystem. @@ -65,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): - 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; @@ -91,8 +100,9 @@ namespace blt::fs { std::fstream& m_stream; char* m_buffer; size_t writeIndex = 0; + void flush_internal(); public: - explicit fstream_block_writer(std::fstream& stream, size_t bufferSize): + explicit fstream_block_writer(std::fstream& stream, size_t bufferSize = 131072): block_writer(bufferSize), m_stream(stream), m_buffer(new char[bufferSize]) {} explicit fstream_block_writer(fstream_block_writer& copy) = delete; @@ -104,9 +114,12 @@ namespace blt::fs { fstream_block_writer& operator=(const fstream_block_writer&& move) = delete; int write(char* buffer, size_t bytes) override; - void flush() override; + inline void flush() override { + flush_internal(); + } ~fstream_block_writer() { + flush_internal(); delete[] m_buffer; } }; diff --git a/include/blt/std/format.h b/include/blt/std/format.h index d29e3aa..370c91a 100755 --- a/include/blt/std/format.h +++ b/include/blt/std/format.h @@ -10,27 +10,9 @@ #include #include #include +#include namespace blt::string { - static inline constexpr double _static_pow(int p) { - int collection = 1; - for (int i = 0; i < p; i++) - collection *= 10; - return collection; - } - - /** - * This is a fast rounding function and is not guaranteed to be 100% correct - * @tparam decimal_places - * @param value - * @return - */ - template - static inline double round_up(double value) { - constexpr double multiplier = _static_pow(decimal_places); - return ((int)(value * multiplier) + 1) / multiplier; - } - static inline std::string fromBytes(unsigned long bytes){ if (bytes > 1073741824) { @@ -87,8 +69,7 @@ namespace blt::string { // taken from java, adapted for c++. static inline utf8_string createUTFString(const std::string& str) { - - const unsigned int strlen = (unsigned int) str.size(); + const auto strlen = (unsigned int) str.size(); unsigned int utflen = strlen; for (unsigned int i = 0; i < strlen; i++) { @@ -105,8 +86,8 @@ namespace blt::string { chars.characters = new char[chars.size]; int count = 0; - chars.characters[count++] = (char) ((utflen >> 0) & 0xFF); chars.characters[count++] = (char) ((utflen >> 8) & 0xFF); + chars.characters[count++] = (char) ((utflen >> 0) & 0xFF); unsigned int i = 0; for (i = 0; i < strlen; i++) { // optimized for initial run of ASCII diff --git a/include/blt/std/hash_map.h b/include/blt/std/hash_map.h deleted file mode 100755 index 6800e1c..0000000 --- a/include/blt/std/hash_map.h +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Created by Brett on 31/03/23. - * Licensed under GNU General Public License V3.0 - * See LICENSE file for license detail - */ - -#ifndef BLT_HASH_MAP_H -#define BLT_HASH_MAP_H - - -#endif //BLT_HASH_MAP_H diff --git a/include/blt/std/hashmap.h b/include/blt/std/hashmap.h new file mode 100755 index 0000000..8caf46b --- /dev/null +++ b/include/blt/std/hashmap.h @@ -0,0 +1,45 @@ +/* + * Created by Brett on 31/03/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ + +#ifndef BLT_HASH_MAP_H +#define BLT_HASH_MAP_H + +#ifndef HASHMAP + #if defined __has_include && __has_include() + + #include + #include + +template, + class Eq = phmap::priv::hash_default_eq, + class Alloc = phmap::priv::Allocator>> +using HASHMAP = phmap::flat_hash_map; +template, + class Eq = phmap::priv::hash_default_eq, + class Alloc = phmap::priv::Allocator> +using HASHSET = phmap::flat_hash_set; + #else + + #include + #include + +template, + typename Eq = std::equal_to, + typename Alloc = std::allocator>> +using HASHMAP = std::unordered_map; + +template, + typename Eq = std::equal_to, + typename Alloc = std::allocator> +using HASHSET = std::unordered_set; + #endif +#endif + +#endif //BLT_HASH_MAP_H diff --git a/include/blt/std/logging.h b/include/blt/std/logging.h index 81217ba..f3d1b9c 100755 --- a/include/blt/std/logging.h +++ b/include/blt/std/logging.h @@ -76,7 +76,7 @@ namespace blt::logging { // this is not thread safe! bool ensureAlignment = false; // should we log to file? - bool logToFile = true; + bool logToFile = false; // should we log to console? bool logToConsole = true; // where should we log? (empty for current binary directory) should end in a / if not empty! @@ -178,13 +178,14 @@ namespace blt::logging { size_t size; [[nodiscard]] static inline size_t hash(const tag& t) { - size_t h = t.tag[0]+ t.tag[1] * 3; - return h; + size_t h = t.tag[1] * 3 - t.tag[0]; + return h - 100; } - inline void expand(){ + // TODO: fix + void expand() { auto newSize = size * 2; - tag* newTags = new tag[newSize]; + auto newTags = new tag[newSize]; for (size_t i = 0; i < size; i++) newTags[i] = tags[i]; delete[] tags; @@ -193,19 +194,26 @@ namespace blt::logging { } public: tag_map(std::initializer_list initial_tags){ - tags = new tag[(size = 16)]; - for (auto& t : initial_tags) + size_t max = 0; + for (const auto& t : initial_tags) + max = std::max(max, hash(t)); + tags = new tag[(size = max+1)]; + 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){ + void insert(const tag& t) { auto h = hash(t); - if (h > size) - expand(); + //if (h > size) + // expand(); if (!tags[h].tag.empty()) std::cerr << "Tag not empty! " << tags[h].tag << "!!!\n"; tags[h] = t; - return *this; } tag& operator[](const std::string& name) const { @@ -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; @@ -522,6 +531,11 @@ namespace blt::logging { applyCFormatting(withoutLn, out, args); + if (level == log_level::NONE){ + std::cout << out << std::endl; + return; + } + std::string finalFormattedOutput = applyFormatString(out, level, file, line); if (loggingFormat.logToConsole) diff --git a/include/blt/std/memory.h b/include/blt/std/memory.h index 9f8f974..a12d189 100755 --- a/include/blt/std/memory.h +++ b/include/blt/std/memory.h @@ -58,39 +58,68 @@ namespace blt { * Creates an encapsulation of a T array which will be automatically deleted when this object goes out of scope. * This is a simple buffer meant to be used only inside of a function and not moved around, with a few minor exceptions. * The internal buffer is allocated on the heap. - * The operator * has been overloaded to return the internal buffer. (or just use scoped_buffer.buffer if you wish to be explicit) - * The operator & was not used because I think it is stupid to do so. - * "*" on a reference is fine however since it isn't used to dereference in the case. + * The operator * has been overloaded to return the internal buffer. * @tparam T type that is stored in buffer eg char */ template struct scoped_buffer { - T* buffer; - unsigned long size; - - explicit scoped_buffer(unsigned long size): size(size) { - buffer = new T[size]; - } - - scoped_buffer(scoped_buffer& copy) = delete; - - scoped_buffer(scoped_buffer&& move) = delete; - - scoped_buffer operator=(scoped_buffer& copyAssignment) = delete; - - scoped_buffer operator=(scoped_buffer&& moveAssignment) = delete; - - inline T& operator[](unsigned long index) const { - return buffer[index]; - } - - inline T* operator*(){ - return buffer; - } - - ~scoped_buffer() { - delete[] buffer; - } + private: + T* _buffer; + size_t _size; + public: + explicit scoped_buffer(size_t size): _size(size) { + _buffer = new T[size]; + } + + scoped_buffer(const scoped_buffer& copy) = delete; + + scoped_buffer(scoped_buffer&& move) noexcept { + _buffer = move._buffer; + _size = move.size(); + move._buffer = nullptr; + } + + scoped_buffer operator=(scoped_buffer& copyAssignment) = delete; + + scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept { + _buffer = moveAssignment._buffer; + _size = moveAssignment.size(); + moveAssignment._buffer = nullptr; + + return *this; + } + + inline T& operator[](unsigned long index) { + return _buffer[index]; + } + + inline const T& operator[](unsigned long index) const { + return _buffer[index]; + } + + inline T* operator*(){ + return _buffer; + } + + [[nodiscard]] inline size_t size() const { + return _size; + } + + inline T* ptr(){ + return _buffer; + } + + ptr_iterator begin(){ + return ptr_iterator{_buffer}; + } + + ptr_iterator end(){ + return ptr_iterator{&_buffer[_size]}; + } + + ~scoped_buffer() { + delete[] _buffer; + } }; template @@ -168,6 +197,7 @@ namespace blt { delete[] _values; } }; + } #endif //BLT_TESTS_MEMORY_H diff --git a/include/blt/std/random.h b/include/blt/std/random.h index 86ca8fd..f8bd993 100755 --- a/include/blt/std/random.h +++ b/include/blt/std/random.h @@ -9,7 +9,41 @@ #include -namespace blt { +namespace blt::random { + + static inline uint32_t PCG_Hash(uint32_t input) { + uint32_t state = input * 747796405u + 2891336453u; + uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u; + return (word >> 22u) ^ + word; + } + + static inline float randomFloat(uint32_t& seed){ + seed = PCG_Hash(seed); + return (float)seed / (float)std::numeric_limits::max(); + } + + /** + * @return random float without changing seed + */ + static inline float randomFloat_c(uint32_t seed){ + return randomFloat(seed); + } + + /** + * @param seed seed for random + * @param min inclusive min + * @param max exclusive max + * @return random int between min (inclusive) and max (exclusive) + */ + static inline int randomInt(uint32_t& seed, int min = 0, int max = 1){ + return (int)((randomFloat(seed) * (float)(max - min)) + (float)min); + } + + static inline int randomInt_c(uint32_t seed, int min = 0, int max = 1){ + return randomInt(seed, min, max); + } + /** * Creates a container class for generating random number distributions * @tparam T numeric type @@ -28,17 +62,19 @@ namespace blt { * @param max max value possible to generate. (default: 1) * @param seed seed to use in generating random values. (default: 0) */ - explicit random(T min = (T)0, T max = (T)1, long seed = 0): gen(std::mt19937(seed)){ + explicit random(T min = (T) 0, T max = (T) 1, long seed = 0): gen(std::mt19937(seed)) { distribution = new dist(min, max); } + /** * Note the min/max are inclusive and defaults to a **uniform** distribution. * @return random number between the defined min/max or the default of [0,1]. */ - T get(){ + T get() { return (*distribution)(gen); } - ~random(){ + + ~random() { delete distribution; } }; @@ -52,6 +88,7 @@ namespace blt { } }; + } #endif //BLT_RANDOM_H diff --git a/include/blt/std/string.h b/include/blt/std/string.h index e2e1542..97b5215 100755 --- a/include/blt/std/string.h +++ b/include/blt/std/string.h @@ -12,7 +12,6 @@ #include #include #include -#include namespace blt::string { @@ -140,6 +139,26 @@ namespace blt::string { return tokens; } + // https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string + static bool replace(std::string& str, const std::string& from, const std::string& to) { + size_t start_pos = str.find(from); + if(start_pos == std::string::npos) + return false; + str.replace(start_pos, from.length(), to); + return true; + } + + static void replaceAll(std::string& str, const std::string& from, const std::string& to) { + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } + } + + // taken from https://stackoverflow.com/questions/216823/how-to-trim-an-stdstring // would've preferred to use boost lib but instructions said to avoid external libs // trim from start (in place) diff --git a/include/blt/std/time.h b/include/blt/std/time.h index edeafcb..292a0ca 100755 --- a/include/blt/std/time.h +++ b/include/blt/std/time.h @@ -29,6 +29,14 @@ namespace blt::system { return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); } + static inline auto nanoTime() { + return getCurrentTimeNanoseconds(); + } + + static inline auto getCurrentTimeMilliseconds(){ + return std::chrono::duration_cast(std::chrono::high_resolution_clock::now().time_since_epoch()).count(); + } + /** * Standard time string is formatted as follows: * Year-Month-Date Hour:Min:Second diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap new file mode 160000 index 0000000..93201da --- /dev/null +++ b/libraries/parallel-hashmap @@ -0,0 +1 @@ +Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3 diff --git a/src/blt/nbt/nbt.cpp b/src/blt/nbt/nbt.cpp index b9bcfb9..fb8d297 100755 --- a/src/blt/nbt/nbt.cpp +++ b/src/blt/nbt/nbt.cpp @@ -4,18 +4,22 @@ * See LICENSE file for license detail */ #include +#include +#include + +#include namespace blt::nbt { - void writeUTF8String(std::fstream& stream, const std::string& str) { + void writeUTF8String(blt::fs::block_writer& stream, const std::string& str) { blt::string::utf8_string str8 = blt::string::createUTFString(str); stream.write(str8.characters, str8.size); delete[] str8.characters; } - std::string readUTF8String(std::fstream& stream) { - unsigned short utflen; + std::string readUTF8String(blt::fs::block_reader& stream) { + int16_t utflen; - stream.read(reinterpret_cast(&utflen), sizeof(utflen)); + readData(stream, utflen); blt::string::utf8_string str{}; str.size = utflen; @@ -23,8 +27,20 @@ namespace blt::nbt { stream.read(str.characters, str.size); - auto strOut = std::move(blt::string::getStringFromUTF8(str)); + auto strOut = blt::string::getStringFromUTF8(str); delete[] str.characters; return strOut; } + + void NBTReader::read() { + char t = reader.get(); + 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; + assert(root != nullptr); + root->readName(reader); + root->readPayload(reader); + } } \ No newline at end of file diff --git a/src/blt/parse/argparse.cpp b/src/blt/parse/argparse.cpp new file mode 100755 index 0000000..39d8d5d --- /dev/null +++ b/src/blt/parse/argparse.cpp @@ -0,0 +1,572 @@ +/* + * Created by Brett on 06/08/23. + * Licensed under GNU General Public License V3.0 + * See LICENSE file for license detail + */ +#include +#include +#include + +namespace blt +{ + + void arg_nargs_t::decode(char c) + { + if (c == '?') + flags = UNKNOWN; + else if (c == '+') + flags = ALL_REQUIRED; + else if (c == '*') + flags = ALL; + else + flags = 0; + } + + arg_nargs_t::arg_nargs_t(char c) + { + decode(c); + } + + arg_nargs_t::arg_nargs_t(std::string s) + { + decode(s[0]); + } + + arg_nargs_t::arg_nargs_t(const char* s) + { + decode(*s); + } + + class invalid_argument_exception : public std::runtime_error + { + public: + invalid_argument_exception(const std::string& str): std::runtime_error(str) + {} + }; + + void arg_vector_t::validateFlags() + { + for (const auto& flag : flags) + if (!flag.starts_with('-')) + throw invalid_argument_exception("Flag '" + flag + "' must start with - or --"); + } + + arg_vector_t::arg_vector_t(const char* str) + { + std::string as_string(str); + if (as_string.starts_with('-')) + flags.emplace_back(as_string); + else + name = as_string; + } + + arg_vector_t::arg_vector_t(const std::string& str) + { + if (str.starts_with('-')) + flags.emplace_back(str); + else + name = str; + } + + std::string arg_vector_t::getFirstFullFlag() + { + // assign flag so it always exists, will be first '-' flag if we fail to find a '--' flag + std::string flag = flags[0]; + // search for first '--' flag + for (const auto& f : flags) + if (f.starts_with("--")) + { + flag = f; + break; + } + return flag; + } + + std::string to_string(const arg_data_t& v) + { + if (holds_alternative(v)) + return to_string(std::get(v)); + else if (std::holds_alternative(v)) + { + const auto& vec = std::get(v); + if (vec.size() == 1) + return to_string(vec[0]); + if (vec.empty()) + return "Empty Vector"; + std::string str; + for (const auto& r : vec) + { + str += to_string(r); + str += ' '; + } + return "Vector of contents: " + str; + } + return "Empty"; + } + + std::string to_string(const arg_data_internal_t& v) + { + if (std::holds_alternative(v)) + { + return std::get(v); + } else if (std::holds_alternative(v)) + { + return std::get(v) ? "True" : "False"; + } + return std::to_string(std::get(v)); + } + + std::string arg_parse::filename(const std::string& path) + { + auto paths = blt::string::split(path, "/"); + auto final = paths[paths.size() - 1]; + if (final == "/") + return paths[paths.size() - 2]; + return final; + } + + void arg_parse::addArgument(const arg_properties_t& args) + { + auto properties = new arg_properties_t(args); + + // determine where to store the arg when parsing + if (properties->a_dest.empty()) + { + if (properties->a_flags.isFlag()) + properties->a_dest = properties->a_flags.getFirstFullFlag(); + else + properties->a_dest = properties->a_flags.name; + } + + if (properties->a_dest.starts_with("--")) + properties->a_dest = properties->a_dest.substr(2); + else if (properties->a_dest.starts_with('-')) + properties->a_dest = properties->a_dest.substr(1); + + // associate flags with their properties + for (const auto& flag : properties->a_flags.flags) + user_args.flag_associations[flag] = properties; + + // positional args uses index (vector) to store the properties + if (!properties->a_flags.isFlag()) + user_args.name_associations.push_back(properties); + + user_args.arg_properties_storage.push_back(properties); + } + + bool arg_parse::consumeArguments( + arg_tokenizer& tokenizer, const std::string& flag, const arg_properties_t& properties, std::vector& v_out + ) const + { + switch (properties.a_nargs.flags) + { + case 0: + for (int i = 0; i < properties.a_nargs.args; i++) + { + // if we don't have another arg to consume we have a problem! + if (!tokenizer.hasCurrent()) + { + // TODO: S + printUsage(); + std::cout << filename(loaded_args.program_name) << ": error: flag '" << flag << "' expected " << properties.a_nargs.args + << " argument(s) got " << i << " argument(s) instead!\n"; + return false; + } + // if we do have one, but it is a flag then we also have a problem! + if (tokenizer.isFlag()) + { + printUsage(); + std::cout << filename(loaded_args.program_name) << ": error: flag '" << flag << "' expected " << properties.a_nargs.args + << " argument(s) but found '" << tokenizer.get() << "' instead!\n"; + //BLT_WARN("Expected %d arguments, found flag instead!", properties.a_nargs.args); + return false; + } + // get the value and advance + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + case arg_nargs_t::UNKNOWN: + // no arg next + if (!tokenizer.hasCurrent() || tokenizer.isFlag()) + { + // python's default is to store const if around otherwise store default + if (!properties.a_const.empty()) + v_out.emplace_back(properties.a_const); + else // this should no longer be required with the changes to how defaults are handled + v_out.emplace_back(properties.a_default); + return true; + } + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + return true; + case arg_nargs_t::ALL: + while (tokenizer.hasCurrent() && !tokenizer.isFlag()) + { + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + case arg_nargs_t::ALL_REQUIRED: + if (tokenizer.hasCurrent() && tokenizer.isFlag()) + { + printUsage(); + std::cout << loaded_args.program_name << ": at least one argument is required for '" << flag << "'\n"; + return false; + } + while (tokenizer.hasCurrent() && !tokenizer.isFlag()) + { + v_out.emplace_back(tokenizer.get()); + tokenizer.advance(); + } + return true; + } + return false; + } + + void arg_parse::handlePositionalArgument(arg_tokenizer& tokenizer, size_t& last_pos) + { + auto index = last_pos++; + if (index >= user_args.name_associations.size()) + loaded_args.unrecognized_args.push_back(tokenizer.get()); + else + { + loaded_args.data[user_args.name_associations[index]->a_dest] = tokenizer.get(); + loaded_args.found_args.insert(user_args.name_associations[index]->a_dest); + } + tokenizer.advance(); + } + + void arg_parse::handleFlagArgument(arg_tokenizer& tokenizer) + { + auto flag = tokenizer.get(); + tokenizer.advance(); + + // token is a flag, figure out how to handle it + if (flag.starts_with("--")) + processFlag(tokenizer, flag); + else + { + // handle special args like -vvv + if (!flag.starts_with('-')) + std::cerr << "Flag processed but does not start with '-' (this is a serious error!)\n"; + // make sure the flag only contains the same character + auto type = flag[1]; + for (char c : flag.substr(1)) + { + if (c != type) + { + printUsage(); + std::cout << "found different characters in flag '" << flag.c_str() << "' expected '" << type << "' but found '" << c << "'\n"; + return; + } + } + // size without - + auto len = flag.size() - 1; + // get flag type + std::string str = "- "; + str[1] = flag[1]; + for (size_t i = 0; i < len; i++) + processFlag(tokenizer, str); + } + } + + void arg_parse::processFlag(arg_tokenizer& tokenizer, const std::string& flag) + { + auto flag_itr = user_args.flag_associations.find(flag); + if (flag_itr == user_args.flag_associations.end()) + { + loaded_args.unrecognized_args.push_back(flag); + return; + } + + const auto* const properties = user_args.flag_associations.at(flag); + + if (properties->a_dest.empty()) + { + loaded_args.unrecognized_args.push_back(flag); + return; + } + auto dest = properties->a_dest; + + loaded_args.found_args.insert(dest); + + switch (properties->a_action) + { + case arg_action_t::HELP: + printUsage(); + printHelp(); + break; + case arg_action_t::STORE: + { + arg_data_t& data = loaded_args.data[dest]; + arg_data_vec_t v; + if (!consumeArguments(tokenizer, flag, *properties, v)) + { + printHelp(); + return; + } + if (v.empty()) + data = ""; + else if (v.size() == 1) + data = v[0]; + else + data = v; + break; + } + case arg_action_t::STORE_CONST: + loaded_args.data[dest] = properties->a_const; + break; + case arg_action_t::STORE_FALSE: + loaded_args.data[dest] = false; + break; + case arg_action_t::STORE_TRUE: + loaded_args.data[dest] = true; + break; + case arg_action_t::COUNT: + { + auto& data = loaded_args.data[dest]; + if (!holds_alternative(data)) + data = 0; + data = get(data) + 1; + break; + } + case arg_action_t::EXTEND: + { + + break; + } + case arg_action_t::VERSION: + { + auto file = filename(loaded_args.program_name); + std::cout << file.c_str() << " " << properties->a_version << "\n"; + break; + } + case arg_action_t::APPEND_CONST: + { + auto& data = loaded_args.data[dest]; + if (!std::holds_alternative(data)) + { + data = arg_data_vec_t(); + } + auto& l = get(data); + l.emplace_back(properties->a_const); + break; + } + case arg_action_t::APPEND: + { + auto& data = loaded_args.data[dest]; + if (!holds_alternative(data)) + data = arg_data_vec_t(); + auto& l = get(data); + consumeArguments(tokenizer, flag, *properties, l); + break; + } + } + } + + arg_parse::arg_results arg_parse::parse_args(int argc, const char** argv) + { + std::vector args; + args.reserve(argc); + for (int i = 0; i < argc; i++) + args.emplace_back(argv[i]); + return parse_args(args); + } + + arg_parse::arg_results arg_parse::parse_args(const std::vector& args) + { + arg_tokenizer tokenizer(args); + loaded_args.program_name = tokenizer.get(); + tokenizer.advance(); + + size_t last_positional = 0; + while (tokenizer.hasCurrent()) + { + if (tokenizer.isFlag()) + handleFlagArgument(tokenizer); + else + handlePositionalArgument(tokenizer, last_positional); + } + + // load defaults for args which were not found + for (const auto* arg : user_args.arg_properties_storage) + { + if (!to_string(arg->a_default).empty() && !loaded_args.contains(arg->a_dest)) + loaded_args.data[arg->a_dest] = arg->a_default; + } + + // if there was no problems processing then return the loaded args + if (loaded_args.unrecognized_args.empty()) + return loaded_args; + + // otherwise construct a string detailing the unrecognized args + std::string unrec; + for (const auto& r : loaded_args.unrecognized_args) + { + unrec += '\''; + unrec += r; + unrec += '\''; + unrec += ' '; + } + // remove the last space caused by the for loop + unrec = unrec.substr(0, unrec.size() - 1); + printUsage(); + std::cout << loaded_args.program_name << ": error: unrecognized args: " << unrec << "\n"; + std::exit(0); + } + + bool arg_parse::takesArgs(const arg_properties_t* const& arg) + { + switch (arg->a_action) + { + case arg_action_t::STORE_CONST: + case arg_action_t::STORE_TRUE: + case arg_action_t::STORE_FALSE: + case arg_action_t::APPEND_CONST: + case arg_action_t::COUNT: + case arg_action_t::HELP: + case arg_action_t::VERSION: + return false; + case arg_action_t::STORE: + case arg_action_t::APPEND: + case arg_action_t::EXTEND: + return arg->a_nargs.takesArgs(); + } + return false; + } + + void arg_parse::printHelp() const + { + if (!user_args.prefix.empty()) + { + std::cout << "\n"; + std::cout << user_args.prefix; + } + std::cout << "\npositional arguments:\n"; + // spaces per tab + const size_t tab_size = 8; + size_t max_length = 0; + // search for longest pos arg length + for (const auto& arg : user_args.arg_properties_storage) + { + if (!arg->a_flags.isFlag()) + max_length = std::max(arg->a_flags.name.size(), max_length); + else { + auto tmp = getFlagHelp(arg); + max_length = std::max(tmp.size(), max_length); + } + } + for (const auto& arg : user_args.arg_properties_storage) + { + if (!arg->a_flags.isFlag()) + { + const auto& name = arg->a_flags.name; + std::cout << name; + auto size = std::max(static_cast(max_length) - static_cast(name.size()), 0l); + size += tab_size; + for (int64_t i = 0; i < size; i++) + std::cout << " "; + std::cout << arg->a_help << "\n"; + } + } + std::cout << "\noptions:\n"; + for (const auto& arg : user_args.arg_properties_storage) + { + if (arg->a_flags.isFlag()) + { + const auto& name = getFlagHelp(arg); + std::cout << name; + auto size = std::max(static_cast(max_length) - static_cast(name.size()), 0l); + size += tab_size; + for (int64_t i = 0; i < size; i++) + std::cout << " "; + std::cout << arg->a_help << "\n"; + } + } + if (!user_args.postfix.empty()) + { + std::cout << user_args.postfix; + std::cout << "\n"; + } + + std::exit(0); + } + + void arg_parse::printUsage() const + { + std::string usage = "Usage: " + loaded_args.program_name + " "; + std::cout << usage; + size_t current_line_length = 0; + + for (const auto& arg : user_args.arg_properties_storage) + { + auto meta = getMetavar(arg); + + std::string str = "["; + if (arg->a_flags.isFlag()) + { + str += arg->a_flags.getFirstFullFlag(); + if (takesArgs(arg)) + { + str += " "; + str += meta; + str += ""; + } + str += "]"; + str += ' '; + } else + { + str += "<"; + str += arg->a_flags.name; + str += ">] "; + } + + current_line_length += str.size(); + checkAndPrintFormattingLine(current_line_length, usage.size()); + + std::cout << str; + } + std::cout << "\n"; + } + + void arg_parse::checkAndPrintFormattingLine(size_t& current_line_length, size_t spacing) const + { + if (current_line_length > user_args.max_line_length) + { + std::cout << "\n"; + for (size_t i = 0; i < spacing; i++) + std::cout << " "; + current_line_length = 0; + } + } + + std::string arg_parse::getMetavar(const arg_properties_t* const& arg) + { + auto meta = arg->a_metavar; + + if (meta.empty()) + meta = blt::string::toUpperCase(arg->a_dest); + + return meta; + } + + std::string arg_parse::getFlagHelp(const arg_properties_t* const& arg) + { + auto meta = getMetavar(arg); + // bad that we have to create this twice! + std::string tmp; + for (const auto& flag : arg->a_flags.flags) + { + tmp += flag; + if (takesArgs(arg)) + { + tmp += ' '; + tmp += meta; + } + tmp += ", "; + } + tmp = tmp.substr(0, tmp.size()-2); + return tmp; + } +} \ No newline at end of file diff --git a/src/blt/std/filesystem.cpp b/src/blt/std/filesystem.cpp index 4384457..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) @@ -40,7 +48,7 @@ int blt::fs::fstream_block_writer::write(char* buffer, size_t bytes) { return 0; } -void blt::fs::fstream_block_writer::flush() { +void blt::fs::fstream_block_writer::flush_internal() { m_stream.write(m_buffer, (long) writeIndex); writeIndex = 0; } diff --git a/src/tests/hashmap_tests.h b/src/tests/hashmap_tests.h index 1a5157b..db7ef64 100755 --- a/src/tests/hashmap_tests.h +++ b/src/tests/hashmap_tests.h @@ -7,7 +7,7 @@ #ifndef BLT_TESTS_HASHMAP_TEXTS_H #define BLT_TESTS_HASHMAP_TEXTS_H -#include +#include inline static int test_hashmaps(){ diff --git a/src/tests/main.cpp b/src/tests/main.cpp index 5b45c52..371b801 100755 --- a/src/tests/main.cpp +++ b/src/tests/main.cpp @@ -1,61 +1,313 @@ #include -#include "binary_trees.h" -#include "logging.h" +//#include "binary_trees.h" +//#include "logging.h" #include "profiling_tests.h" #include "nbt_tests.h" -#include "queue_tests.h" -#include "blt/math/vectors.h" -#include "blt/math/matrix.h" -#include -#include "hashmap_tests.h" +#include "blt/parse/argparse.h" +//#include "queue_tests.h" +//#include "blt/math/vectors.h" +//#include "blt/math/matrix.h" +//#include +//#include "hashmap_tests.h" +//#include -int main() { - binaryTreeTest(); +std::function test{ + [](int i) -> int { + int acc = 1; + for (int j = 0; j < i; j++){ + acc += j * i; + } + return acc; + } +}; + +int test_as_func(int i){ + int acc = 1; + for (int j = 0; j < i; j++){ + acc += j * i; + } + return acc; +} + +inline int test_as_func_inline(int i){ + int acc = 1; + for (int j = 0; j < i; j++){ + acc += j * i; + } + return acc; +} + +std::function test_func_as_std(&test_as_func); + +class super_func { + public: + virtual int test(int i) = 0; + virtual ~super_func() = default; +}; + +class class_func : public super_func { + public: + int test(int i) override { + int acc = 1; + for (int j = 0; j < i; j++){ + acc += j * i; + } + return acc; + } +}; + +int (*func_func)(int) = [](int i) -> int { + int acc = 1; + for (int j = 0; j < i; j++){ + acc += j * i; + } + return acc; +}; + +int (*func_func_in)(int) = &test_as_func; + +int main(int argc, const char** argv) { + blt::arg_parse parser; + parser.addArgument(blt::arg_builder({"--poo", "-p"}).build()); + parser.addArgument(blt::arg_builder("--foo").setAction(blt::arg_action_t::STORE_TRUE).setDefault(false).build()); + parser.addArgument(blt::arg_builder({"--goo", "-g"}).build()); + parser.addArgument(blt::arg_builder({"--oop", "-o"}).build()); + parser.addArgument(blt::arg_builder("Sexy_pos").setHelp("I am helpful!").build()); - run_logging(); + auto args = parser.parse_args(argc, argv); + std::vector superArgs { + "BLT_TESTS", + "Sexy", + "-p", "I have poop", + "--help" + }; + auto args2 = parser.parse_args(superArgs); - runProfilingAndTableTests(); + for (const auto& a : args2.data){ + BLT_TRACE("['%s' = '%s']", a.first.c_str(), blt::to_string(a.second).c_str()); + } + BLT_TRACE(args2.program_name); +// +// 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); - 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; + { + 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(); } - BLT_TRACE("Hello Trace!"); - BLT_DEBUG("Hello Debug!"); - BLT_INFO("Hello Info!"); - BLT_WARN("Hello Warn!"); - BLT_ERROR("Hello Error!"); - BLT_FATAL("Hello Fatal!"); + 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(); + + auto shortTag = nbtReader.getTag("shortTest"); + BLT_TRACE("Got short: %d", shortTag->get()); return 0; } \ No newline at end of file diff --git a/src/tests/nbt_tests.h b/src/tests/nbt_tests.h index bb2580f..97afd02 100755 --- a/src/tests/nbt_tests.h +++ b/src/tests/nbt_tests.h @@ -14,12 +14,12 @@ #include inline bool readLargeBlockUsingNBTBufferedReader(const std::string& file, const blt::scoped_buffer& bufferToCompare, size_t bufferSize) { - blt::scoped_buffer read_buffer{bufferToCompare.size}; + blt::scoped_buffer read_buffer{bufferToCompare.size()}; std::fstream largeBlockInputLarge(file, std::ios::in | std::ios::binary); blt::fs::fstream_block_reader byteLargeBlockInputLarge(largeBlockInputLarge, bufferSize); - byteLargeBlockInputLarge.read(read_buffer.buffer, bufferToCompare.size); - for (unsigned int i = 0; i < bufferToCompare.size; i++) { - if (read_buffer[i] != bufferToCompare.buffer[i]) + byteLargeBlockInputLarge.read(*read_buffer, bufferToCompare.size()); + for (unsigned int i = 0; i < bufferToCompare.size(); i++) { + if (read_buffer[i] != bufferToCompare[i]) return false; } largeBlockInputLarge.close(); @@ -29,7 +29,7 @@ inline bool readLargeBlockUsingNBTBufferedReader(const std::string& file, const inline bool readIndividualUsingNBTBufferedReader(const std::string& file, const blt::scoped_buffer& bufferToCompare, size_t bufferSize) { std::fstream largeBlockInput(file, std::ios::in | std::ios::binary); blt::fs::fstream_block_reader byteLargeBlockInput(largeBlockInput, bufferSize); - for (unsigned int i = 0; i < bufferToCompare.size; i++) { + for (unsigned int i = 0; i < bufferToCompare.size(); i++) { char byte; byteLargeBlockInput.read(&byte, 1); if (byte != bufferToCompare[i]) { @@ -52,11 +52,11 @@ inline void nbt_read_tests(){ bool fstream_large_correct = true; for (int i = 0; i < bufferSize; i++) - buffer.buffer[i] = i+1; + buffer[i] = i + 1; BLT_START_INTERVAL("nbt read", "Raw Write"); std::fstream largeOutput("HeyThere.txt", std::ios::out | std::ios::binary); - largeOutput.write(buffer.buffer, bufferSize); + largeOutput.write(*buffer, bufferSize); largeOutput.flush(); largeOutput.close(); BLT_END_INTERVAL("nbt read", "Raw Write"); @@ -129,7 +129,7 @@ inline void nbt_write_tests(){ blt::scoped_buffer read_buffer{bufferSize}; for (int i = 0; i < bufferSize; i++) - buffer.buffer[i] = i+1; + buffer[i] = i + 1; std::fstream fileOutput("IAmAFile.txt", std::ios::binary | std::ios::out); for (int i = 0; i < 8; i++) { @@ -139,11 +139,11 @@ inline void nbt_write_tests(){ blt::fs::fstream_block_writer writer(fileOutput, size); BLT_START_INTERVAL("nbt write block", profiler_string); - writer.write(buffer.buffer, buffer.size); + writer.write(*buffer, buffer.size()); BLT_END_INTERVAL("nbt write block", profiler_string); BLT_START_INTERVAL("nbt write individual", profiler_string); for (int j = 0; j < bufferSize; j++) { - writer.write(&buffer.buffer[j], 1); + writer.write(&buffer[j], 1); } BLT_END_INTERVAL("nbt write individual", profiler_string); } @@ -155,7 +155,7 @@ inline void nbt_write_tests(){ auto size = (size_t) std::pow(2, 11 + i); auto size_str = std::to_string(size); bool results = true; - fileInput.read(read_buffer.buffer, bufferSize); + fileInput.read(*read_buffer, bufferSize); for (int j = 0; j < bufferSize; j++) { if (buffer[j] != read_buffer[j]) { results = false; @@ -166,7 +166,7 @@ inline void nbt_write_tests(){ BLT_INFO("NBT %s Block Write Correctly? %s;\n", size_str.c_str(), results ? "True" : "False"); results = true; - fileInput.read(read_buffer.buffer, bufferSize); + fileInput.read(*read_buffer, bufferSize); for (int j = 0; j < bufferSize; j++) { if (buffer[j] != read_buffer[j]) { results = false; @@ -193,7 +193,7 @@ inline void nbt_tests(){ testOutput.write(testByte, 3); testOutput.write(reinterpret_cast(&testShort), sizeof(short)); testOutput.write(reinterpret_cast(&testInt), sizeof(int)); - blt::nbt::writeUTF8String(testOutput, "HelloHowManyCanWeFit!"); + //blt::nbt::writeUTF8String(testOutput, "HelloHowManyCanWeFit!"); //testOutput.flush(); testOutput.close(); @@ -207,10 +207,10 @@ inline void nbt_tests(){ testInput.read(testByteIn, 3); testInput.read(reinterpret_cast(&testShortIn), sizeof(short)); testInput.read(reinterpret_cast(&testIntIn), sizeof(int)); - std::string strIn = blt::nbt::readUTF8String(testInput); + //std::string strIn = blt::nbt::readUTF8String(testInput); testInput.close(); - BLT_INFO("%d, %c, %d, %d, %d, %s", testByteIn[0], testByteIn[1], testByteIn[2], testShortIn, testIntIn, strIn.c_str()); + //BLT_INFO("%d, %c, %d, %d, %d, %s", testByteIn[0], testByteIn[1], testByteIn[2], testShortIn, testIntIn, strIn.c_str()); nbt_read_tests(); nbt_write_tests(); diff --git a/src/tests/queue_tests.h b/src/tests/queue_tests.h index 052b670..758c4e8 100755 --- a/src/tests/queue_tests.h +++ b/src/tests/queue_tests.h @@ -129,7 +129,7 @@ static inline void random_access() { } static inline void test_queues() { - blt::random rand{1, 100}; + blt::random::random rand{1, 100}; for (int& value : values){ value = rand.get();