diff --git a/CMakeLists.txt b/CMakeLists.txt index e437735..c6ff5e7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,7 +1,7 @@ cmake_minimum_required(VERSION 3.20) include(cmake/color.cmake) -set(BLT_VERSION 0.16.6) +set(BLT_VERSION 0.16.7) set(BLT_TEST_VERSION 0.0.1) set(BLT_TARGET BLT) diff --git a/README.md b/README.md index e763cbf..3f68e13 100644 --- a/README.md +++ b/README.md @@ -25,7 +25,25 @@ A C++17 common utilities library to make thing easy! - Computes a rolling average in a dynamically allocated array. - Useful for average FPS over a period of time - ### fixed_point.h - - + - Provides a 64bit fixed point number with 2^32 bits of precision on each side of the decimal + - Mostly optimal assembly, avoids sign extension by using 64 bit numbers + - Requires your compiler to support 128 bit numbers + - Docs: TODO + - ### fixed_point_vector.h + - Not finished due to complications in the vector type, this is a TODO + - ### log_util.h + - provides overloads for logging math types + - ### math.h + - blt::toRadians + - to radians function (from deg) + - blt::f_randi + - fast random integer from seed + - blt::fsqrt + - fast inverse square root algorithm, floats only + - blt::pow + - power function + - blt::round_up + - rounds up to a variable number of decimal places # Specialties ## blt::logging.v2 diff --git a/include/blt/fs/filesystem.h b/include/blt/fs/filesystem.h new file mode 100644 index 0000000..17bdbd2 --- /dev/null +++ b/include/blt/fs/filesystem.h @@ -0,0 +1,163 @@ +/* + * + * Copyright (C) 2024 Brett Terpstra + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef BLT_FILESYSTEM_H +#define BLT_FILESYSTEM_H + +#include +#include + +namespace blt::fs +{ + /** + * A simple interface which provides a way of reading the next block of data from a resource. + * The interface provides a single function "read" which will read a specified number of bytes into the buffer. + * The implementation for this could be fstreams, zlib deflate, or any method filesystem access. + * Reading of a large number of bytes ( > block size) is guaranteed to not significantly increase the read time and will likely result in a + * direct passthrough to the underlying system. Small reads will be buffered, hence the name "block" reader. + */ + class block_reader + { + protected: + // 32768 block size seems the fastest on my system + unsigned long m_bufferSize; + public: + explicit block_reader(size_t bufferSize): m_bufferSize(bufferSize) + {} + + /** + * Reads bytes from the internal filesystem implementation + * @param buffer buffer to copy the read bytes into + * @param bytes number of bytes to read + * @return status code. non-zero return codes indicates a failure has occurred. + */ + virtual int read(char* buffer, size_t bytes) = 0; + + virtual size_t gcount() = 0; + + virtual char get() + { + char c[1]; + read(c, 1); + return c[0]; + } + }; + + /** + * A buffered block writer without a definite backend implementation. Exactly the same as a block_reader but for writing to the filesystem. + */ + class block_writer + { + protected: + unsigned long m_bufferSize; + public: + explicit block_writer(unsigned long bufferSize): m_bufferSize(bufferSize) + {} + + /** + * Writes the bytes to the filesystem backend implementation + * @param buffer bytes to write + * @param bytes number of bytes to write + * @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. + */ + virtual void flush() = 0; + }; + + /** + * fstream implementation of the block reader. + */ + class fstream_block_reader : public block_reader + { + private: + std::fstream& m_stream; + char* m_buffer = nullptr; + size_t readIndex = 0; + public: + explicit fstream_block_reader(std::fstream& stream, size_t bufferSize = 131072); + + explicit fstream_block_reader(fstream_block_reader& copy) = delete; + + explicit fstream_block_reader(fstream_block_reader&& move) = delete; + + fstream_block_reader& operator=(const fstream_block_reader& copy) = delete; + + fstream_block_reader& operator=(const fstream_block_reader&& move) = delete; + + int read(char* buffer, size_t bytes) override; + + size_t gcount() final + { + return m_stream.gcount(); + } + + ~fstream_block_reader() + { + delete[] m_buffer; + } + }; + + class fstream_block_writer : public block_writer + { + private: + 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 = 131072): + block_writer(bufferSize), m_stream(stream), m_buffer(new char[bufferSize]) + {} + + explicit fstream_block_writer(fstream_block_writer& copy) = delete; + + explicit fstream_block_writer(fstream_block_writer&& move) = delete; + + fstream_block_writer& operator=(const fstream_block_writer& copy) = delete; + + fstream_block_writer& operator=(const fstream_block_writer&& move) = delete; + + int write(char* buffer, size_t bytes) override; + + inline void flush() override + { + flush_internal(); + } + + ~fstream_block_writer() + { + flush_internal(); + delete[] m_buffer; + } + }; +} + +#endif //BLT_FILESYSTEM_H diff --git a/include/blt/math/math.h b/include/blt/math/math.h index a2e73a8..708d6b0 100644 --- a/include/blt/math/math.h +++ b/include/blt/math/math.h @@ -57,10 +57,11 @@ namespace blt #pragma GCC diagnostic pop #endif - - static inline constexpr double pow(int b, int p) + + template + static inline constexpr R pow(B b, P p) { - int collection = 1; + R collection = 1; for (int i = 0; i < p; i++) collection *= b; return collection; @@ -79,7 +80,7 @@ namespace blt return value; else { - constexpr double multiplier = pow(10, decimal_places); + constexpr double multiplier = pow(10.0, decimal_places); return ((int) (value * multiplier) + 1) / multiplier; } } diff --git a/libraries/parallel-hashmap b/libraries/parallel-hashmap index 67c2461..7ef2e73 160000 --- a/libraries/parallel-hashmap +++ b/libraries/parallel-hashmap @@ -1 +1 @@ -Subproject commit 67c24619e4f5ab2097b74cc397732c17a25d6944 +Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5 diff --git a/src/blt/fs/filesystem.cpp b/src/blt/fs/filesystem.cpp index 1cc2ef4..7fa829b 100644 --- a/src/blt/fs/filesystem.cpp +++ b/src/blt/fs/filesystem.cpp @@ -1,54 +1,79 @@ /* - * Created by Brett on 29/01/23. - * Licensed under GNU General Public License V3.0 - * See LICENSE file for license detail + * + * Copyright (C) 2024 Brett Terpstra + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ #include #include -#include "blt/std/logging.h" +#include -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) - m_stream.read(m_buffer, (long) m_bufferSize); - if (readIndex + bytes >= m_bufferSize) { - // copy out all the data from the current buffer - auto bytesLeft = m_bufferSize - readIndex; - memcpy(buffer, m_buffer + readIndex, bytesLeft); - readIndex = 0; - // now to prevent large scale reading in small blocks, we should just read the entire thing into the buffer. - m_stream.read(buffer + bytesLeft, (long) (bytes - bytesLeft)); - } else { - // but in the case that the size of the data read is small, we should read in blocks and copy from that buffer - // that should be quicker since file operations are slow. - std::memcpy(buffer, m_buffer + readIndex, bytes); - readIndex += bytes; +namespace 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(); } - return 0; -} - -int blt::fs::fstream_block_writer::write(char* buffer, size_t bytes) { - if (writeIndex + bytes >= m_bufferSize) { - // in an attempt to stay efficient we write out the old buffer and the new buffer - // since there is a good chance there is more than a buffer's worth of data being written - // otherwise the buffer is almost full and can be written anyway. (this might be bad for performance especially if the FS wants round numbers) + + int fstream_block_reader::read(char* buffer, size_t bytes) + { + if (readIndex == 0) + m_stream.read(m_buffer, (long) m_bufferSize); + if (readIndex + bytes >= m_bufferSize) + { + // copy out all the data from the current buffer + auto bytesLeft = m_bufferSize - readIndex; + memcpy(buffer, m_buffer + readIndex, bytesLeft); + readIndex = 0; + // now to prevent large scale reading in small blocks, we should just read the entire thing into the buffer. + m_stream.read(buffer + bytesLeft, (long) (bytes - bytesLeft)); + } else + { + // but in the case that the size of the data read is small, we should read in blocks and copy from that buffer + // that should be quicker since file operations are slow. + std::memcpy(buffer, m_buffer + readIndex, bytes); + readIndex += bytes; + } + return 0; + } + + int fstream_block_writer::write(char* buffer, size_t bytes) + { + if (writeIndex + bytes >= m_bufferSize) + { + // in an attempt to stay efficient we write out the old buffer and the new buffer + // since there is a good chance there is more than a buffer's worth of data being written + // otherwise the buffer is almost full and can be written anyway. (this might be bad for performance especially if the FS wants round numbers) + m_stream.write(m_buffer, (long) writeIndex); + writeIndex = 0; + m_stream.write(buffer, (long) bytes); + } else + { + std::memcpy(m_buffer + writeIndex, buffer, bytes); + writeIndex += bytes; + } + return 0; + } + + void fstream_block_writer::flush_internal() + { m_stream.write(m_buffer, (long) writeIndex); writeIndex = 0; - m_stream.write(buffer, (long) bytes); - } else { - std::memcpy(m_buffer + writeIndex, buffer, bytes); - writeIndex += bytes; } - return 0; -} - -void blt::fs::fstream_block_writer::flush_internal() { - m_stream.write(m_buffer, (long) writeIndex); - writeIndex = 0; -} + +} \ No newline at end of file