free fun
parent
c4a29ade19
commit
dad09f5f1b
|
@ -1,6 +1,6 @@
|
||||||
cmake_minimum_required(VERSION 3.20)
|
cmake_minimum_required(VERSION 3.20)
|
||||||
include(cmake/color.cmake)
|
include(cmake/color.cmake)
|
||||||
set(BLT_VERSION 5.1.12)
|
set(BLT_VERSION 5.1.13)
|
||||||
|
|
||||||
set(BLT_TARGET BLT)
|
set(BLT_TARGET BLT)
|
||||||
|
|
||||||
|
|
|
@ -19,144 +19,48 @@
|
||||||
#ifndef BLT_FILESYSTEM_H
|
#ifndef BLT_FILESYSTEM_H
|
||||||
#define BLT_FILESYSTEM_H
|
#define BLT_FILESYSTEM_H
|
||||||
|
|
||||||
#include <fstream>
|
#include <iosfwd>
|
||||||
#include <ios>
|
#include <blt/fs/fwddecl.h>
|
||||||
|
|
||||||
namespace blt::fs
|
namespace blt::fs
|
||||||
{
|
{
|
||||||
/**
|
/**
|
||||||
* A simple interface which provides a way of reading the next block of data from a resource.
|
* reader_t wrapper for fstream
|
||||||
* 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
|
class fstream_reader_t final : public reader_t
|
||||||
{
|
{
|
||||||
protected:
|
|
||||||
// 32768 block size seems the fastest on my system
|
|
||||||
unsigned long m_bufferSize;
|
|
||||||
public:
|
public:
|
||||||
explicit block_reader(size_t bufferSize): m_bufferSize(bufferSize)
|
explicit fstream_reader_t(std::istream& stream);
|
||||||
{}
|
|
||||||
|
|
||||||
/**
|
explicit fstream_reader_t(fstream_reader_t& copy) = delete;
|
||||||
* 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;
|
fstream_reader_t& operator=(const fstream_reader_t& copy) = delete;
|
||||||
|
|
||||||
virtual char get()
|
i64 read(char* buffer, size_t bytes) override;
|
||||||
{
|
|
||||||
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:
|
private:
|
||||||
std::fstream& m_stream;
|
std::istream* 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
|
class fstream_writer_t final : public writer_t
|
||||||
{
|
{
|
||||||
private:
|
|
||||||
std::fstream& m_stream;
|
|
||||||
char* m_buffer;
|
|
||||||
size_t writeIndex = 0;
|
|
||||||
|
|
||||||
void flush_internal();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit fstream_block_writer(std::fstream& stream, size_t bufferSize = 131072):
|
explicit fstream_writer_t(std::ostream& stream);
|
||||||
block_writer(bufferSize), m_stream(stream), m_buffer(new char[bufferSize])
|
|
||||||
{}
|
|
||||||
|
|
||||||
explicit fstream_block_writer(fstream_block_writer& copy) = delete;
|
explicit fstream_writer_t(fstream_writer_t& copy) = delete;
|
||||||
|
|
||||||
explicit fstream_block_writer(fstream_block_writer&& move) = delete;
|
fstream_writer_t& operator=(const fstream_writer_t& copy) = delete;
|
||||||
|
|
||||||
fstream_block_writer& operator=(const fstream_block_writer& copy) = delete;
|
i64 write(char* buffer, size_t bytes) override;
|
||||||
|
|
||||||
fstream_block_writer& operator=(const fstream_block_writer&& move) = delete;
|
void flush() override;
|
||||||
|
|
||||||
int write(char* buffer, size_t bytes) override;
|
virtual ~fstream_writer_t() override // NOLINT
|
||||||
|
|
||||||
inline void flush() override
|
|
||||||
{
|
{
|
||||||
flush_internal();
|
flush();
|
||||||
}
|
}
|
||||||
|
|
||||||
~fstream_block_writer()
|
private:
|
||||||
{
|
std::ostream* m_stream;
|
||||||
flush_internal();
|
|
||||||
delete[] m_buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,77 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BLT_FS_FWDDECL_H
|
||||||
|
#define BLT_FS_FWDDECL_H
|
||||||
|
|
||||||
|
#include <blt/std/types.h>
|
||||||
|
|
||||||
|
namespace blt::fs
|
||||||
|
{
|
||||||
|
/**
|
||||||
|
* A simple interface which provides a way of reading the next block of data from a resource. This is designed to replace the overly complex
|
||||||
|
* std::ostream
|
||||||
|
*/
|
||||||
|
class reader_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~reader_t() = default;
|
||||||
|
explicit reader_t() = default;
|
||||||
|
|
||||||
|
reader_t(const reader_t&) = delete;
|
||||||
|
reader_t& operator=(const reader_t&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Reads bytes from the internal filesystem implementation
|
||||||
|
* @param buffer buffer to copy the read bytes into
|
||||||
|
* @param bytes number of bytes to read
|
||||||
|
* @return number of bytes read, or negative value if error. Errors are not required and can just return 0
|
||||||
|
*/
|
||||||
|
virtual i64 read(char* buffer, size_t bytes) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A block writer without a definite backend implementation. Exactly the same as a block_reader but for writing to the filesystem.
|
||||||
|
* this is designed to replace the overly complex std::istream
|
||||||
|
*/
|
||||||
|
class writer_t
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
virtual ~writer_t() = default;
|
||||||
|
explicit writer_t() = default;
|
||||||
|
|
||||||
|
writer_t(const writer_t&) = delete;
|
||||||
|
writer_t& operator=(const writer_t&) = delete;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Writes the bytes to the filesystem backend implementation
|
||||||
|
* @param buffer bytes to write
|
||||||
|
* @param bytes number of bytes to write
|
||||||
|
* @return number of bytes, or negative value if error. Zero is also a valid return, not indicating error in itself but can be the result of one.
|
||||||
|
*/
|
||||||
|
virtual i64 write(char* buffer, size_t bytes) = 0;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Optional flush command which syncs the underlying objects
|
||||||
|
*/
|
||||||
|
virtual void flush()
|
||||||
|
{};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //BLT_FS_FWDDECL_H
|
|
@ -22,19 +22,19 @@
|
||||||
|
|
||||||
namespace blt::nbt {
|
namespace blt::nbt {
|
||||||
|
|
||||||
void writeUTF8String(blt::fs::block_writer& stream, const std::string& str);
|
void writeUTF8String(blt::fs::writer_t& stream, const std::string& str);
|
||||||
|
|
||||||
std::string readUTF8String(blt::fs::block_reader& stream);
|
std::string readUTF8String(blt::fs::reader_t& stream);
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline static void writeData(blt::fs::block_writer& out, const T& d){
|
inline static void writeData(blt::fs::writer_t& out, const T& d){
|
||||||
char data[sizeof(T)];
|
char data[sizeof(T)];
|
||||||
mem::toBytes(d, data);
|
mem::toBytes(d, data);
|
||||||
out.write(data, sizeof(T));
|
out.write(data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
inline static void readData(blt::fs::block_reader& in, T& d) {
|
inline static void readData(blt::fs::reader_t& in, T& d) {
|
||||||
char data[sizeof(T)];
|
char data[sizeof(T)];
|
||||||
in.read(data, sizeof(T));
|
in.read(data, sizeof(T));
|
||||||
mem::fromBytes(data, &d);
|
mem::fromBytes(data, &d);
|
||||||
|
@ -63,12 +63,12 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
explicit tag_t(nbt_tag type): type(type) {};
|
explicit tag_t(nbt_tag type): type(type) {};
|
||||||
explicit tag_t(nbt_tag type, std::string name): type(type), name(std::move(name)) {}
|
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 writePayload(blt::fs::writer_t& out) = 0;
|
||||||
virtual void readPayload(blt::fs::block_reader& in) = 0;
|
virtual void readPayload(blt::fs::reader_t& in) = 0;
|
||||||
void writeName(blt::fs::block_writer& out) {
|
void writeName(blt::fs::writer_t& out) {
|
||||||
writeUTF8String(out, name);
|
writeUTF8String(out, name);
|
||||||
}
|
}
|
||||||
void readName(blt::fs::block_reader& in) {
|
void readName(blt::fs::reader_t& in) {
|
||||||
name = readUTF8String(in);
|
name = readUTF8String(in);
|
||||||
}
|
}
|
||||||
[[nodiscard]] inline nbt_tag getType() const {
|
[[nodiscard]] inline nbt_tag getType() const {
|
||||||
|
@ -87,11 +87,11 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
explicit tag(nbt_tag type): tag_t(type) {}
|
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)) {}
|
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 {
|
void writePayload(blt::fs::writer_t& out) override {
|
||||||
if constexpr(std::is_arithmetic<T>::value)
|
if constexpr(std::is_arithmetic<T>::value)
|
||||||
writeData(out, t);
|
writeData(out, t);
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) override {
|
void readPayload(blt::fs::reader_t& in) override {
|
||||||
if constexpr(std::is_arithmetic<T>::value)
|
if constexpr(std::is_arithmetic<T>::value)
|
||||||
readData(in, t);
|
readData(in, t);
|
||||||
}
|
}
|
||||||
|
@ -102,9 +102,9 @@ namespace blt::nbt {
|
||||||
|
|
||||||
class tag_end : public tag<char> {
|
class tag_end : public tag<char> {
|
||||||
public:
|
public:
|
||||||
void writePayload(blt::fs::block_writer&) final {}
|
void writePayload(blt::fs::writer_t&) final {}
|
||||||
// nothing to read
|
// nothing to read
|
||||||
void readPayload(blt::fs::block_reader&) final {}
|
void readPayload(blt::fs::reader_t&) final {}
|
||||||
};
|
};
|
||||||
|
|
||||||
class tag_byte : public tag<int8_t> {
|
class tag_byte : public tag<int8_t> {
|
||||||
|
@ -147,13 +147,13 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
tag_byte_array(): tag(nbt_tag::BYTE_ARRAY) {}
|
tag_byte_array(): tag(nbt_tag::BYTE_ARRAY) {}
|
||||||
tag_byte_array(const std::string& name, const std::vector<int8_t>& v): tag(nbt_tag::BYTE_ARRAY, name, v) {}
|
tag_byte_array(const std::string& name, const std::vector<int8_t>& v): tag(nbt_tag::BYTE_ARRAY, name, v) {}
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
auto length = (int32_t) t.size();
|
auto length = (int32_t) t.size();
|
||||||
writeData(out, length);
|
writeData(out, length);
|
||||||
// TODO on the writer (remove need for cast + more std::fstream functions)
|
// TODO on the writer (remove need for cast + more std::fstream functions)
|
||||||
out.write(reinterpret_cast<char*>(t.data()), length);
|
out.write(reinterpret_cast<char*>(t.data()), length);
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
int32_t length;
|
int32_t length;
|
||||||
readData(in, length);
|
readData(in, length);
|
||||||
t.reserve(length);
|
t.reserve(length);
|
||||||
|
@ -165,10 +165,10 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
tag_string(): tag(nbt_tag::STRING) {}
|
tag_string(): tag(nbt_tag::STRING) {}
|
||||||
tag_string(const std::string& name, const std::string& s): tag(nbt_tag::STRING, name, s) {}
|
tag_string(const std::string& name, const std::string& s): tag(nbt_tag::STRING, name, s) {}
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
writeUTF8String(out, t);
|
writeUTF8String(out, t);
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
t = readUTF8String(in);
|
t = readUTF8String(in);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -177,13 +177,13 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
tag_int_array(): tag(nbt_tag::INT_ARRAY) {}
|
tag_int_array(): tag(nbt_tag::INT_ARRAY) {}
|
||||||
tag_int_array(const std::string& name, const std::vector<int32_t>& v): tag(nbt_tag::INT_ARRAY, name, v) {}
|
tag_int_array(const std::string& name, const std::vector<int32_t>& v): tag(nbt_tag::INT_ARRAY, name, v) {}
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
auto length = (int32_t) t.size();
|
auto length = (int32_t) t.size();
|
||||||
writeData(out, length);
|
writeData(out, length);
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
writeData(out, t[i]);
|
writeData(out, t[i]);
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
int32_t length;
|
int32_t length;
|
||||||
readData(in, length);
|
readData(in, length);
|
||||||
t.reserve(length);
|
t.reserve(length);
|
||||||
|
@ -196,13 +196,13 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
tag_long_array(): tag(nbt_tag::LONG_ARRAY) {}
|
tag_long_array(): tag(nbt_tag::LONG_ARRAY) {}
|
||||||
tag_long_array(const std::string& name, const std::vector<int64_t>& v): tag(nbt_tag::LONG_ARRAY, name, v) {}
|
tag_long_array(const std::string& name, const std::vector<int64_t>& v): tag(nbt_tag::LONG_ARRAY, name, v) {}
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
auto length = (int32_t) t.size();
|
auto length = (int32_t) t.size();
|
||||||
writeData(out, length);
|
writeData(out, length);
|
||||||
for (int i = 0; i < length; i++)
|
for (int i = 0; i < length; i++)
|
||||||
writeData(out, t[i]);
|
writeData(out, t[i]);
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
int32_t length;
|
int32_t length;
|
||||||
readData(in, length);
|
readData(in, length);
|
||||||
t.reserve(length);
|
t.reserve(length);
|
||||||
|
@ -262,7 +262,7 @@ namespace blt::nbt {
|
||||||
public:
|
public:
|
||||||
tag_list(): tag(nbt_tag::LIST) {}
|
tag_list(): tag(nbt_tag::LIST) {}
|
||||||
tag_list(const std::string& name, const std::vector<tag_t*>& v): tag(nbt_tag::LIST, name, v) {}
|
tag_list(const std::string& name, const std::vector<tag_t*>& v): tag(nbt_tag::LIST, name, v) {}
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
if (t.empty())
|
if (t.empty())
|
||||||
writeData(out, (char)nbt_tag::END);
|
writeData(out, (char)nbt_tag::END);
|
||||||
else
|
else
|
||||||
|
@ -273,7 +273,7 @@ namespace blt::nbt {
|
||||||
v->writePayload(out);
|
v->writePayload(out);
|
||||||
}
|
}
|
||||||
|
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
char id;
|
char id;
|
||||||
int32_t length;
|
int32_t length;
|
||||||
readData(in, id);
|
readData(in, id);
|
||||||
|
@ -356,7 +356,7 @@ namespace blt::nbt {
|
||||||
t[tag->getName()] = tag;
|
t[tag->getName()] = tag;
|
||||||
}
|
}
|
||||||
|
|
||||||
void writePayload(blt::fs::block_writer& out) final {
|
void writePayload(blt::fs::writer_t& out) final {
|
||||||
for (const auto& v : t){
|
for (const auto& v : t){
|
||||||
auto tag = v.second;
|
auto tag = v.second;
|
||||||
out.put((char) tag->getType());
|
out.put((char) tag->getType());
|
||||||
|
@ -365,7 +365,7 @@ namespace blt::nbt {
|
||||||
}
|
}
|
||||||
out.put('\0');
|
out.put('\0');
|
||||||
}
|
}
|
||||||
void readPayload(blt::fs::block_reader& in) final {
|
void readPayload(blt::fs::reader_t& in) final {
|
||||||
char type;
|
char type;
|
||||||
while ((type = in.get()) != (char)nbt_tag::END){
|
while ((type = in.get()) != (char)nbt_tag::END){
|
||||||
auto* v = _internal_::toType(type);
|
auto* v = _internal_::toType(type);
|
||||||
|
@ -390,10 +390,10 @@ namespace blt::nbt {
|
||||||
|
|
||||||
class NBTReader {
|
class NBTReader {
|
||||||
private:
|
private:
|
||||||
blt::fs::block_reader& reader;
|
blt::fs::reader_t& reader;
|
||||||
tag_compound* root = nullptr;
|
tag_compound* root = nullptr;
|
||||||
public:
|
public:
|
||||||
explicit NBTReader(blt::fs::block_reader& reader): reader(reader) {}
|
explicit NBTReader(blt::fs::reader_t& reader): reader(reader) {}
|
||||||
|
|
||||||
void read();
|
void read();
|
||||||
|
|
||||||
|
@ -419,9 +419,9 @@ namespace blt::nbt {
|
||||||
|
|
||||||
class NBTWriter {
|
class NBTWriter {
|
||||||
private:
|
private:
|
||||||
blt::fs::block_writer& writer;
|
blt::fs::writer_t& writer;
|
||||||
public:
|
public:
|
||||||
explicit NBTWriter(blt::fs::block_writer& writer): writer(writer) {}
|
explicit NBTWriter(blt::fs::writer_t& 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!
|
* 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.
|
* @param root root NBT tag to write, this function assumes ownership of this pointer.
|
||||||
|
|
|
@ -19,11 +19,11 @@
|
||||||
#ifndef BLT_LOGGING_FMT_TOKENIZER_H
|
#ifndef BLT_LOGGING_FMT_TOKENIZER_H
|
||||||
#define BLT_LOGGING_FMT_TOKENIZER_H
|
#define BLT_LOGGING_FMT_TOKENIZER_H
|
||||||
|
|
||||||
|
#include <functional>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <blt/std/types.h>
|
#include <blt/std/types.h>
|
||||||
#include <functional>
|
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
#pragma once
|
||||||
|
/*
|
||||||
|
* 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 <https://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef BLT_LOGGING_FWDDECL_H
|
||||||
|
#define BLT_LOGGING_FWDDECL_H
|
||||||
|
|
||||||
|
namespace blt::logging
|
||||||
|
{
|
||||||
|
struct logger_t;
|
||||||
|
enum class fmt_token_type : u8;
|
||||||
|
enum class fmt_align_t : u8;
|
||||||
|
enum class fmt_sign_t : u8;
|
||||||
|
enum class fmt_type_t : u8;
|
||||||
|
struct fmt_spec_t;
|
||||||
|
struct fmt_token_t;
|
||||||
|
class fmt_tokenizer_t;
|
||||||
|
class fmt_parser_t;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif //BLT_LOGGING_FWDDECL_H
|
|
@ -19,14 +19,15 @@
|
||||||
#ifndef BLT_LOGGING_LOGGING_H
|
#ifndef BLT_LOGGING_LOGGING_H
|
||||||
#define BLT_LOGGING_LOGGING_H
|
#define BLT_LOGGING_LOGGING_H
|
||||||
|
|
||||||
|
#include <cstring>
|
||||||
|
#include <functional>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <cstring>
|
|
||||||
#include <functional>
|
|
||||||
#include <blt/logging/fmt_tokenizer.h>
|
#include <blt/logging/fmt_tokenizer.h>
|
||||||
#include <blt/std/utility.h>
|
#include <blt/logging/fwddecl.h>
|
||||||
#include <blt/meta/is_streamable.h>
|
#include <blt/meta/is_streamable.h>
|
||||||
|
#include <blt/std/utility.h>
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
|
|
|
@ -19,15 +19,16 @@
|
||||||
#ifndef BLT_LOGGING_LOGGING_CONFIG_H
|
#ifndef BLT_LOGGING_LOGGING_CONFIG_H
|
||||||
#define BLT_LOGGING_LOGGING_CONFIG_H
|
#define BLT_LOGGING_LOGGING_CONFIG_H
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <string>
|
|
||||||
#include <blt/std/types.h>
|
|
||||||
#include <blt/logging/ansi.h>
|
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <ostream>
|
||||||
|
#include <string>
|
||||||
|
#include <vector>
|
||||||
|
#include <blt/logging/logging.h>
|
||||||
|
#include <blt/std/types.h>
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
enum class log_level_t
|
enum class log_level_t : u8
|
||||||
{
|
{
|
||||||
TRACE,
|
TRACE,
|
||||||
DEBUG,
|
DEBUG,
|
||||||
|
@ -41,17 +42,24 @@ namespace blt::logging
|
||||||
|
|
||||||
class logging_config_t
|
class logging_config_t
|
||||||
{
|
{
|
||||||
|
friend logger_t;
|
||||||
public:
|
public:
|
||||||
std::optional<std::string> log_file_path;
|
std::vector<std::ostream*> log_outputs = get_default_log_outputs();
|
||||||
std::string log_format = "";
|
std::string log_format = get_default_log_format();
|
||||||
std::array<std::string, LOG_LEVEL_COUNT> log_level_colors = {
|
std::array<std::string, LOG_LEVEL_COUNT> log_level_colors = get_default_log_level_colors();
|
||||||
|
std::array<std::string, LOG_LEVEL_COUNT> log_level_names = get_default_log_level_names();
|
||||||
};
|
|
||||||
log_level_t level = log_level_t::TRACE;
|
log_level_t level = log_level_t::TRACE;
|
||||||
bool use_color = true;
|
bool use_color = true;
|
||||||
bool log_to_console = true;
|
// if true prints the whole path to the file (eg /home/user/.../.../project/src/source.cpp:line#)
|
||||||
|
bool print_full_name = false;
|
||||||
|
// this will attempt to use the maximum possible size for each printed element, then align to that.
|
||||||
|
// This creates output where the user message always starts at the same column.
|
||||||
|
bool ensure_alignment = true;
|
||||||
private:
|
private:
|
||||||
|
static std::string get_default_log_format();
|
||||||
|
static std::vector<std::ostream*> get_default_log_outputs();
|
||||||
|
static std::array<std::string, LOG_LEVEL_COUNT> get_default_log_level_colors();
|
||||||
|
static std::array<std::string, LOG_LEVEL_COUNT> get_default_log_level_names();
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -21,59 +21,25 @@
|
||||||
|
|
||||||
namespace blt::fs
|
namespace blt::fs
|
||||||
{
|
{
|
||||||
|
fstream_reader_t::fstream_reader_t(std::istream& stream): m_stream{&stream}
|
||||||
|
{}
|
||||||
|
|
||||||
fstream_block_reader::fstream_block_reader(std::fstream& stream, size_t bufferSize):
|
i64 fstream_reader_t::read(char* buffer, const size_t bytes)
|
||||||
block_reader(bufferSize), m_stream(stream), m_buffer(new char[bufferSize])
|
|
||||||
{
|
{
|
||||||
if (!m_stream.good() || m_stream.fail())
|
return m_stream->readsome(buffer, static_cast<std::streamsize>(bytes));
|
||||||
BLT_WARN("Provided std::fstream is not good! Clearing!");
|
|
||||||
m_stream.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fstream_block_reader::read(char* buffer, size_t bytes)
|
fstream_writer_t::fstream_writer_t(std::ostream& stream): m_stream{&stream}
|
||||||
|
{}
|
||||||
|
|
||||||
|
i64 fstream_writer_t::write(char* buffer, size_t bytes)
|
||||||
{
|
{
|
||||||
if (readIndex == 0)
|
m_stream->write(buffer, static_cast<std::streamsize>(bytes));
|
||||||
m_stream.read(m_buffer, (long) m_bufferSize);
|
return static_cast<i64>(bytes);
|
||||||
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)
|
void fstream_writer_t::flush()
|
||||||
{
|
{
|
||||||
if (writeIndex + bytes >= m_bufferSize)
|
m_stream->flush();
|
||||||
{
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
|
@ -10,13 +10,13 @@
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
|
|
||||||
namespace blt::nbt {
|
namespace blt::nbt {
|
||||||
void writeUTF8String(blt::fs::block_writer& stream, const std::string& str) {
|
void writeUTF8String(blt::fs::writer_t& stream, const std::string& str) {
|
||||||
blt::string::utf8_string str8 = blt::string::createUTFString(str);
|
blt::string::utf8_string str8 = blt::string::createUTFString(str);
|
||||||
stream.write(str8.characters, str8.size);
|
stream.write(str8.characters, str8.size);
|
||||||
delete[] str8.characters;
|
delete[] str8.characters;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string readUTF8String(blt::fs::block_reader& stream) {
|
std::string readUTF8String(blt::fs::reader_t& stream) {
|
||||||
int16_t utflen;
|
int16_t utflen;
|
||||||
|
|
||||||
readData(stream, utflen);
|
readData(stream, utflen);
|
||||||
|
|
|
@ -16,6 +16,7 @@
|
||||||
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
* along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
#include <blt/logging/logging_config.h>
|
#include <blt/logging/logging_config.h>
|
||||||
|
#include <blt/logging/ansi.h>
|
||||||
|
|
||||||
namespace blt::logging
|
namespace blt::logging
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,7 +23,7 @@
|
||||||
#include <blt/std/utility.h>
|
#include <blt/std/utility.h>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
#include <fstream>
|
||||||
|
|
||||||
struct some_silly_type_t
|
struct some_silly_type_t
|
||||||
{};
|
{};
|
||||||
|
@ -89,6 +89,43 @@ std::pair<bool, std::string> compare_strings(const std::string& s1, const std::s
|
||||||
return {true, ""};
|
return {true, ""};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct seqbuf final : std::streambuf
|
||||||
|
{
|
||||||
|
seqbuf(std::streambuf* destBuf, std::size_t& charCount) : m_dest(destBuf), m_count(charCount)
|
||||||
|
{}
|
||||||
|
|
||||||
|
protected:
|
||||||
|
int_type overflow(int_type ch) override
|
||||||
|
{
|
||||||
|
if (traits_type::eq_int_type(ch, traits_type::eof()))
|
||||||
|
return traits_type::eof();
|
||||||
|
++m_count;
|
||||||
|
blt::logging::println("We are printing a character {:c}", ch);
|
||||||
|
return m_dest->sputc(static_cast<char>(ch));
|
||||||
|
}
|
||||||
|
|
||||||
|
std::streamsize xsputn(const char* s, std::streamsize count) override
|
||||||
|
{
|
||||||
|
blt::logging::println("We are printing a series of characters {} {}", count, std::string_view{s, static_cast<size_t>(count)});
|
||||||
|
m_count += static_cast<std::size_t>(count);
|
||||||
|
return m_dest->sputn(s, count);
|
||||||
|
}
|
||||||
|
|
||||||
|
int_type underflow() override
|
||||||
|
{
|
||||||
|
return m_dest->sgetc();
|
||||||
|
}
|
||||||
|
|
||||||
|
int sync() override
|
||||||
|
{
|
||||||
|
return m_dest->pubsync();
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::streambuf* m_dest;
|
||||||
|
std::size_t& m_count;
|
||||||
|
};
|
||||||
|
|
||||||
int main()
|
int main()
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
@ -153,16 +190,28 @@ int main()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
blt::logging::println("{}This is a color now with background{}",
|
blt::logging::println("{}This is a color now with background{}",
|
||||||
build(color::color_mode::BOLD, fg(color::color8::CYAN), color::color_mode::DIM, bg(color::color8::YELLOW)),
|
build(color::color_mode::BOLD, fg(color::color8::RED), color::color_mode::DIM, bg(color::color_rgb(0, 100, 255))),
|
||||||
build(color::color_mode::RESET_ALL));
|
build(color::color_mode::RESET_ALL));
|
||||||
|
|
||||||
std::cout << "\033[2J";
|
|
||||||
|
|
||||||
|
std::ofstream os("test.txt");
|
||||||
|
size_t charCount = 0;
|
||||||
|
seqbuf hi{os.rdbuf(), charCount};
|
||||||
|
dynamic_cast<std::ostream&>(os).rdbuf(&hi);
|
||||||
|
os << "This is a println with a stream" << std::endl;
|
||||||
|
os << "This is a mixed print " << 25 << " with multiple types " << 34.23340 << std::endl;
|
||||||
|
os << "What about just a new line character?\n";
|
||||||
|
|
||||||
|
blt::logging::println("Logged {} characters", charCount);
|
||||||
|
|
||||||
|
/*std::cout << "\033[2J";
|
||||||
constexpr int totalRows = 24;
|
constexpr int totalRows = 24;
|
||||||
std::cout << "\033[1;" << (totalRows - 1) << "r";
|
// std::cout << "\033[1;" << (totalRows - 1) << "r";
|
||||||
|
std::cout << use_mode(ansi::mode::color80x25_text);
|
||||||
|
|
||||||
for (int i = 1; i <= 10; ++i)
|
for (int i = 1; i <= 10; ++i)
|
||||||
{
|
{
|
||||||
|
|
||||||
std::cout << "\033[1;1H";
|
std::cout << "\033[1;1H";
|
||||||
std::cout << "printed line " << i << std::endl;
|
std::cout << "printed line " << i << std::endl;
|
||||||
std::cout << "\033[" << totalRows << ";1H";
|
std::cout << "\033[" << totalRows << ";1H";
|
||||||
|
@ -170,7 +219,7 @@ int main()
|
||||||
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
std::this_thread::sleep_for(std::chrono::milliseconds(500));
|
||||||
}
|
}
|
||||||
|
|
||||||
std::cout << "\033[r";
|
std::cout << "\033[r";*/
|
||||||
|
|
||||||
// blt::logging::println("This is println {}\twith a std::endl in the middle of it");
|
// blt::logging::println("This is println {}\twith a std::endl in the middle of it");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue