Compare commits

..

No commits in common. "c8d12c21c673d9d1cbce82daf9b02e20477cd1b2" and "48095f5c418978708c53f6fbf074b2a0f1de007b" have entirely different histories.

16 changed files with 221 additions and 760 deletions

10
.gitignore vendored
View File

@ -1 +1,9 @@
/cmake-build-*/
/cmake-build-debug/
./cmake-build-debug/
cmake-build-debug/
/cmake-build-release/
./cmake-build-release/
cmake-build-release/
cmake-build-relwithdebinfo/
cmake-build-reldebug-asan/
./cmake-build-relwithdebinfo/

View File

@ -1,42 +0,0 @@
/*
* BLT C++ 20 / C++ 17 Compatability helper file
* Copyright (C) 2023 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 INSANE_DNS_COMPATIBILITY_H
#define INSANE_DNS_COMPATIBILITY_H
#if __cplusplus >= 202002L
#define BLT_CONTAINS(container, value) container.contains(value)
#define BLT_CPP20_CONSTEXPR constexpr
#define BLT_USE_CPP20
#else
#include <algorithm>
#define BLT_CONTAINS(container, value) std::find(container.begin(), container.end(), value) != container.end()
#define BLT_CPP20_CONSTEXPR
#undef BLT_USE_CPP20
#endif
#define INCLUDE_FS \
#if defined(CXX17_FILESYSTEM) || defined (CXX17_FILESYSTEM_LIBFS) \
#include <filesystem>\
#elif defined(CXX11_EXP_FILESYSTEM) || defined (CXX11_EXP_FILESYSTEM_LIBFS)\
#include <experimental/filesystem>\
#else\
#error Filesystem ops not supported!\
#endif
#endif //INSANE_DNS_COMPATIBILITY_H

View File

@ -12,12 +12,10 @@
#include <cstring>
#include <type_traits>
#include <unordered_map>
#include <algorithm>
#include "blt/std/format.h"
#include "blt/std/filesystem.h"
#include "blt/std/logging.h"
#include "blt/std/memory.h"
#include <blt/std/hashmap.h>
@ -27,10 +25,36 @@ namespace blt::nbt {
std::string readUTF8String(blt::fs::block_reader& stream);
// Used to grab the byte-data of any T element. Defaults to Big Endian, however can be configured to use little endian
template <typename T>
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 <typename T>
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<typename T>
inline static void writeData(blt::fs::block_writer& out, const T& d){
char data[sizeof(T)];
mem::toBytes(d, data);
toBytes(d, data);
out.write(data, sizeof(T));
}
@ -38,7 +62,7 @@ namespace blt::nbt {
inline static void readData(blt::fs::block_reader& in, T& d) {
char data[sizeof(T)];
in.read(data, sizeof(T));
mem::fromBytes(data, &d);
fromBytes(data, &d);
}
enum class nbt_tag : char {

View File

@ -13,7 +13,6 @@
#include <initializer_list>
#include <optional>
#include <blt/std/hashmap.h>
#include <blt/std/string.h>
#include <variant>
#include <algorithm>
#include <type_traits>
@ -50,27 +49,19 @@ namespace blt
void validateFlags();
public:
explicit arg_vector_t(std::vector<std::string> flags): flags(std::move(flags))
arg_vector_t(std::vector<std::string> flags): flags(std::move(flags))
{
validateFlags();
}
arg_vector_t(std::initializer_list<std::string> f): flags(f)
arg_vector_t(std::initializer_list<std::string> flags): flags(flags)
{
if (flags.size() == 1) {
if (!blt::string::starts_with(flags[0], '-'))
{
name = flags[0];
flags.clear();
return;
}
}
validateFlags();
}
explicit arg_vector_t(const char* str);
arg_vector_t(const char* str);
explicit arg_vector_t(const std::string& str);
arg_vector_t(const std::string& str);
[[nodiscard]] inline bool isFlag() const
{
@ -127,6 +118,7 @@ namespace blt
struct arg_properties_t
{
private:
public:
arg_vector_t a_flags;
arg_action_t a_action = arg_action_t::STORE;
@ -138,14 +130,6 @@ namespace blt
std::string a_version{};
std::string a_metavar{};
bool a_required = true;
arg_properties_t() = delete;
explicit arg_properties_t(arg_vector_t flags): a_flags(std::move(flags))
{}
explicit arg_properties_t(const std::string& pos_arg): a_flags(pos_arg)
{}
};
class arg_builder
@ -156,14 +140,11 @@ namespace blt
explicit arg_builder(const arg_vector_t& flags): properties(flags)
{}
explicit arg_builder(const std::string& pos_arg): properties(pos_arg)
{}
arg_builder(const std::initializer_list<std::string>& flags): properties(flags)
{}
template<typename... string_args>
explicit arg_builder(string_args... flags): properties(arg_vector_t{flags...})
explicit arg_builder(string_args... flags): properties({flags...})
{}
inline arg_properties_t build()
@ -256,13 +237,13 @@ namespace blt
// returns true if the current arg is a flag
inline bool isFlag()
{
return blt::string::starts_with(args[currentIndex], '-');
return args[currentIndex].starts_with('-');
}
// returns true if we have next and the next arg is a flag
inline bool isNextFlag()
{
return hasNext() && blt::string::starts_with(args[currentIndex + 1], '-');
return hasNext() && args[currentIndex + 1].starts_with('-');
}
// advances to the next flag
@ -325,7 +306,6 @@ namespace blt
return static_cast<T>(std::stoll(s));
return static_cast<T>(std::stoull(s));
}
private:
struct
{
@ -361,10 +341,7 @@ namespace blt
template<typename T>
inline T get(const std::string& key)
{
if constexpr (std::is_same_v<T, std::string>)
return blt::arg_parse::get<T>(data[key]);
else
return blt::arg_parse::get_cast<T>(data[key]);
return blt::arg_parse::get_cast<T>(data[key]);
}
inline auto begin()
@ -379,9 +356,9 @@ namespace blt
inline bool contains(const std::string& key)
{
if (blt::string::starts_with(key, "--"))
if (key.starts_with("--"))
return data.find(key.substr(2)) != data.end();
if (blt::string::starts_with(key, '-'))
if (key.starts_with('-'))
return data.find(key.substr(1)) != data.end();
return data.find(key) != data.end();
}

View File

@ -51,11 +51,6 @@ namespace blt
std::uint64_t count = 0;
std::string interval_name;
interval_t() = default;
interval_t(pf_time_t wallStart, pf_time_t wallEnd, pf_time_t wallTotal, pf_time_t threadStart, pf_time_t threadEnd, pf_time_t threadTotal,
pf_cycle_t cyclesStart, pf_cycle_t cyclesEnd, pf_cycle_t cyclesTotal, uint64_t count, std::string intervalName);
};
struct cycle_interval_t
@ -87,8 +82,7 @@ namespace blt
void startInterval(interval_t* interval);
inline interval_t* startInterval(profile_t& profiler, std::string interval_name)
{
inline interval_t* startInterval(profile_t& profiler, std::string interval_name){
auto* p = createInterval(profiler, std::move(interval_name));
startInterval(p);
return p;

View File

@ -14,53 +14,12 @@ namespace blt
void b_assert_failed(const char* expression, const char* path, int line);
void b_throw(const char* what, const char* path, int line);
#if defined(__GNUC__) || defined(__llvm__)
#define BLT_ATTRIB_NO_INLINE __attribute__ ((noinline))
#else
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define BLT_ATTRIB_NO_INLINE __declspec(noinline)
#else
#define BLT_ATTRIB_NO_INLINE
#endif
#endif
template<typename T>
void BLT_ATTRIB_NO_INLINE black_box_ref(const T& val){
volatile void* hell;
hell = (void*)&val;
}
template<typename T>
void BLT_ATTRIB_NO_INLINE black_box(T val){
volatile void* hell2;
hell2 = (void*)&val;
}
template<typename T>
const T& BLT_ATTRIB_NO_INLINE black_box_ref_ret(const T& val){
volatile void* hell;
hell = (void*)&val;
return val;
}
template<typename T>
T BLT_ATTRIB_NO_INLINE black_box_ret(T val){
volatile void* hell2;
hell2 = (void*)&val;
return val;
}
}
// prints error with stack trace if assertion fails. Does not stop execution.
#define blt_assert(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__) } while (0)
// prints error with stack trace then exits with failure.
#define BLT_ASSERT(expr) do { \
if (!static_cast<bool>(expr)) { \
blt::b_assert_failed(#expr, __FILE__, __LINE__); \
std::exit(EXIT_FAILURE); \
} \
} while (0)
#define BLT_ASSERT(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__); std::exit(EXIT_FAILURE); } while (0)
// prints as error but does not throw the exception.
#define blt_throw(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__);} while (0)
// prints as error with stack trace and throws the exception.

View File

@ -14,53 +14,18 @@
#include <string>
#include <blt/std/string.h>
#include <blt/std/logging.h>
#include <unordered_set>
namespace blt::fs
{
struct include_guard
{
char open = '<';
char close = '>';
};
std::string getFile(const std::string& path);
namespace blt::fs {
std::vector<std::string> getLinesFromFile(const std::string& path);
/**
* Recursively include files
* @param path initial file to load
* @param include_header the beginning of the line that should be used to recognize when a line is to be treated as an include
* @param guards characters used to identify the parts that specify the file path. if empty it will assume everything after the include header
* @return a list of lines in all files. added together in order.
*/
std::vector<std::string> recursiveInclude(const std::string& path, const std::string& include_header = "#include",
const std::vector<include_guard>& guards = {{'<', '>'}, {'"', '"'}});
std::vector<std::string> recursiveShaderInclude(const std::string& path);
static inline std::string loadBrainFuckFile(const std::string& path)
{
std::string buffer;
auto lines = recursiveInclude(path, "~", {});
for (auto& line : lines)
{
buffer += line;
buffer += '\n';
}
return buffer;
}
static inline std::string loadShaderFile(const std::string& path)
{
static inline std::string loadShaderFile(const std::string& path) {
std::stringstream stringStream;
auto lines = recursiveInclude(path);
auto lines = recursiveShaderInclude(path);
for (const auto& line : lines)
{
for (const auto& line : lines) {
// now process the defines, if they exist
// if (line.starts_with("#define")) {
// auto defineParts = String::split(line, " ");

View File

@ -10,19 +10,14 @@
#include <string>
#include <type_traits>
#include <functional>
#include <sstream>
#include <blt/config.h>
#include <iostream>
#include <cstdarg>
namespace blt::logging
{
namespace blt::logging {
template<typename K, typename V>
using hashmap = std::unordered_map<K, V>;
enum class log_level
{
enum class log_level {
// default
NONE,
// low level
@ -33,22 +28,19 @@ namespace blt::logging
WARN, ERROR, FATAL,
};
struct tag_func_param
{
struct tag_func_param {
blt::logging::log_level level;
const std::string& file, line, raw_string, formatted_string;
};
struct tag
{
struct tag {
// tag without the ${{ or }}
std::string tag;
// function to run: log level, file, line, and raw user input string are provided
std::function<std::string(const tag_func_param&)> func;
};
struct log_format
{
struct log_format {
/**
* the log output format is the string which will be used to create the log output string
*
@ -77,8 +69,7 @@ namespace blt::logging
*/
std::string logOutputFormat = "\033[94m[${{TIME}}]${{RC}} ${{LF}}[${{LOG_LEVEL}}]${{RC}} \033[35m(${{FILE}}:${{LINE}})${{RC}} ${{CNR}}${{STR}}${{RC}}\n";
std::string levelNames[11] = {"STDOUT", "TRACE0", "TRACE1", "TRACE2", "TRACE3", "TRACE", "DEBUG", "INFO", "WARN", "ERROR", "FATAL"};
std::string levelColors[11] = {"\033[0m", "\033[22;97m", "\033[97m", "\033[97m", "\033[97m", "\033[97m", "\033[36m", "\033[92m", "\033[93m",
"\033[91m", "\033[97;41m"};
std::string levelColors[11] = {"\033[0m", "\033[22;97m", "\033[97m", "\033[97m", "\033[97m", "\033[97m", "\033[36m", "\033[92m", "\033[93m", "\033[91m", "\033[97;41m"};
// if true prints the whole path to the file (eg /home/user/.../.../project/src/source.cpp:line#)
bool printFullFileName = false;
// the logging lib will keep track of the largest line found so far and try to keep the spacing accordingly
@ -105,94 +96,60 @@ namespace blt::logging
std::string lastFile;
};
struct logger
{
struct logger {
log_level level;
const char* file;
int line;
};
struct empty_logger
{
struct empty_logger {
};
void log_internal(const std::string& format, log_level level, const char* file, int line, std::va_list& args);
void log(const std::string& format, log_level level, const char* file, int line, ...);
void log_stream(const std::string& str, const logger& logger);
void log_stream_internal(const std::string& str, const logger& logger);
template<typename T>
inline static void log_stream(const T& t, const logger& logger)
{
if constexpr (std::is_arithmetic_v<T> && !std::is_same_v<T, char>)
{
log_stream_internal(std::to_string(t), logger);
} else if constexpr (std::is_same_v<T, std::string> || std::is_same_v<T, const char*>)
{
log_stream_internal(t, logger);
} else
{
std::stringstream stream;
stream << t;
log_stream_internal(stream.str(), logger);
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
inline void log(T t, log_level level, const char* file, int line) {
log(std::to_string(t), level, file, line);
}
template<typename T>
inline void log(T t, log_level level, const char* file, int line, ...)
{
std::va_list args;
va_start(args, line);
if constexpr (std::is_arithmetic_v<T>)
{
log_internal(std::to_string(t), level, file, line, args);
} else if constexpr (std::is_same_v<T, std::string>)
{
log_internal(t, level, file, line, args);
} else if constexpr (std::is_same_v<T, const char*>){
log_internal(std::string(t), level, file, line, args);
} else
{
std::stringstream stream;
stream << t;
log_internal(stream.str(), level, file, line, args);
}
va_end(args);
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
inline void log_stream(T t, const logger& logger) {
log_stream(std::to_string(t), logger);
}
template<typename T>
static inline const blt::logging::logger& operator<<(const blt::logging::logger& out, const T& t)
{
log_stream(t, out);
static inline const blt::logging::logger& operator<<(const blt::logging::logger& out, const std::string& str) {
log_stream(str, out);
return out;
}
template<typename T>
static inline const blt::logging::empty_logger& operator<<(const blt::logging::empty_logger& out, const T&)
{
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
static inline const blt::logging::logger& operator<<(const blt::logging::logger& out, T t) {
log_stream(std::to_string(t), out);
return out;
}
static inline const blt::logging::empty_logger& operator<<(const blt::logging::empty_logger& out, const std::string&) {
return out;
}
template<typename T, typename std::enable_if<std::is_arithmetic<T>::value>::type* = nullptr>
static inline const blt::logging::empty_logger& operator<<(const blt::logging::empty_logger& out, T) {
return out;
}
void flush();
void setThreadName(const std::string& name);
void setLogFormat(const log_format& format);
void setLogColor(log_level level, const std::string& newFormat);
void setLogName(log_level level, const std::string& newFormat);
void setLogOutputFormat(const std::string& newFormat);
void setLogToFile(bool shouldLogToFile);
void setLogToConsole(bool shouldLogToConsole);
void setLogPath(const std::string& path);
void setLogFileName(const std::string& fileName);
void setMaxFileSize(size_t fileSize);
}
@ -206,13 +163,7 @@ namespace blt::logging
#include <thread>
#include <cstdarg>
#include <iostream>
#if defined(CXX17_FILESYSTEM) || defined (CXX17_FILESYSTEM_LIBFS)
#include <filesystem>
#elif defined(CXX11_EXP_FILESYSTEM) || defined (CXX11_EXP_FILESYSTEM_LIBFS)
#include <experimental/filesystem>
#else
#include <filesystem>
#endif
#include <filesystem>
#include <ios>
#include <fstream>
@ -318,7 +269,7 @@ namespace blt::logging {
}
};
#define BLT_NOW() auto t = std::time(nullptr); auto now = std::localtime(&t)
#define BLT_NOW() auto t = std::time(nullptr); auto now = std::localtime(&t)
#define BLT_ISO_YEAR(S) auto S = std::to_string(now->tm_year + 1900); \
S += '-'; \
S += ensureHasDigits(now->tm_mon+1, 2); \
@ -486,7 +437,7 @@ namespace blt::logging {
return out;
}
void applyCFormatting(const std::string& format, std::string& output, std::va_list& args){
void applyCFormatting(const std::string& format, std::string& output, va_list& args){
// args must be copied because they will be consumed by the first vsnprintf
va_list args_copy;
va_copy(args_copy, args);
@ -566,7 +517,10 @@ namespace blt::logging {
return out;
}
void log_internal(const std::string& format, log_level level, const char* file, int line, std::va_list& args) {
void log(const std::string& format, log_level level, const char* file, int line, ...) {
va_list args;
va_start(args, line);
std::string withoutLn = format;
auto len = withoutLn.length();
@ -619,9 +573,11 @@ namespace blt::logging {
writer.writeLine(path, stripANSI(finalFormattedOutput));
}
//std::cout.flush();
va_end(args);
}
void log_stream_internal(const std::string& str, const logger& logger) {
void log_stream(const std::string& str, const logger& logger) {
auto& s = loggingStreamLines[std::this_thread::get_id()][logger.level];
s += str;
for (char c : str){

View File

@ -10,177 +10,12 @@
#include <initializer_list>
#include <iterator>
#include <cstring>
#include "queue.h"
#include <blt/std/assert.h>
#include <cstdint>
#include <type_traits>
#include <algorithm>
#include <utility>
#include <cstring>
#include <array>
#if defined(__clang__) || defined(__llvm__) || defined(__GNUC__) || defined(__GNUG__)
#include <byteswap.h>
#define SWAP16(val) bswap_16(val)
#define SWAP32(val) bswap_32(val)
#define SWAP64(val) bswap_64(val)
#if __cplusplus >= 202002L
#include <bit>
#define ENDIAN_LOOKUP(little_endian) (std::endian::native == std::endian::little && !little_endian) || \
(std::endian::native == std::endian::big && little_endian)
#else
#define ENDIAN_LOOKUP(little_endian) !little_endian
#endif
#elif defined(_MSC_VER)
#include <intrin.h>
#define SWAP16(val) _byteswap_ushort(val)
#define SWAP32(val) _byteswap_ulong(val)
#define SWAP64(val) _byteswap_uint64(val)
#define ENDIAN_LOOKUP(little_endian) !little_endian
#endif
#include "queue.h"
namespace blt
{
namespace mem
{
// Used to grab the byte-data of any T element. Defaults to Big Endian, however can be configured to use little endian
template<bool little_endian = false, typename BYTE_TYPE, typename T>
inline static int toBytes(const T& in, BYTE_TYPE* out)
{
if constexpr (!(std::is_same_v<BYTE_TYPE, std::int8_t> || std::is_same_v<BYTE_TYPE, std::uint8_t>))
static_assert("Must provide a signed/unsigned int8 type");
std::memcpy(out, (void*) &in, sizeof(T));
if constexpr (ENDIAN_LOOKUP(little_endian))
{
// TODO: this but better.
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. Assumes data is in big ending (configurable)
template<bool little_endian = false, typename BYTE_TYPE, typename T>
inline static int fromBytes(const BYTE_TYPE* in, T& out)
{
if constexpr (!(std::is_same_v<BYTE_TYPE, std::int8_t> || std::is_same_v<BYTE_TYPE, std::uint8_t>))
static_assert("Must provide a signed/unsigned int8 type");
std::array<BYTE_TYPE, sizeof(T)> data;
std::memcpy(data.data(), in, sizeof(T));
if constexpr (ENDIAN_LOOKUP(little_endian))
{
// if we need to swap find the best way to do so
if constexpr (std::is_same_v<T, int16_t> || std::is_same_v<T, uint16_t>)
out = SWAP16(*reinterpret_cast<T*>(data.data()));
else if constexpr (std::is_same_v<T, int32_t> || std::is_same_v<T, uint32_t>)
out = SWAP32(*reinterpret_cast<T*>(data.data()));
else if constexpr (std::is_same_v<T, int64_t> || std::is_same_v<T, uint64_t>)
out = SWAP64(*reinterpret_cast<T*>(data.data()));
else
{
std::reverse(data.begin(), data.end());
out = *reinterpret_cast<T*>(data.data());
}
}
return 0;
}
template<bool little_endian = false, typename BYTE_TYPE, typename T>
inline static int fromBytes(const BYTE_TYPE* in, T* out)
{
return fromBytes(in, *out);
}
}
template<typename T>
struct range_itr
{
private:
T current;
public:
using iterator_category = std::bidirectional_iterator_tag;
using difference_type = T;
using value_type = T;
using pointer = T*;
using reference = T&;
explicit range_itr(T current): current(current)
{}
value_type operator*() const
{ return current; }
value_type operator->()
{ return current; }
range_itr& operator++()
{
current++;
return *this;
}
range_itr& operator--()
{
current--;
return *this;
}
range_itr operator++(int)
{
auto tmp = *this;
++(*this);
return tmp;
}
range_itr operator--(int)
{
auto tmp = *this;
--(*this);
return tmp;
}
friend bool operator==(const range_itr& a, const range_itr& b)
{
return a.current == b.current;
}
friend bool operator!=(const range_itr& a, const range_itr& b)
{
return a.current != b.current;
}
};
template<typename T>
struct range
{
private:
T _begin;
T _end;
public:
range(T begin, T end): _begin(begin), _end(end)
{}
range_itr<T> begin()
{
return range_itr{_begin};
}
range_itr<T> end()
{
return range_itr{_end};
}
};
template<typename V>
struct ptr_iterator
{
@ -242,98 +77,36 @@ 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 copied around.
* 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.
* @tparam T type that is stored in buffer eg char
*/
template<typename T, bool = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>>
class scoped_buffer
template<typename T>
struct scoped_buffer
{
private:
T* _buffer = nullptr;
T* _buffer;
size_t _size;
public:
scoped_buffer(): _buffer(nullptr), _size(0)
{}
explicit scoped_buffer(size_t size): _size(size)
{
if (size > 0)
_buffer = new T[size];
else
_buffer = nullptr;
_buffer = new T[size];
}
scoped_buffer(const scoped_buffer& copy)
{
if (copy.size() == 0)
{
_buffer = nullptr;
_size = 0;
return;
}
_buffer = new T[copy.size()];
_size = copy._size;
if constexpr (std::is_trivially_copyable_v<T>)
{
std::memcpy(_buffer, copy._buffer, copy.size() * sizeof(T));
} else
{
if constexpr (std::is_copy_constructible_v<T> && !std::is_copy_assignable_v<T>)
{
for (size_t i = 0; i < this->_size; i++)
_buffer[i] = T(copy[i]);
} else
for (size_t i = 0; i < this->_size; i++)
_buffer[i] = copy[i];
}
}
scoped_buffer& operator=(const scoped_buffer& copy)
{
if (&copy == this)
return *this;
if (copy.size() == 0)
{
_buffer = nullptr;
_size = 0;
return *this;
}
delete[] this->_buffer;
_buffer = new T[copy.size()];
_size = copy._size;
if constexpr (std::is_trivially_copyable_v<T>)
{
std::memcpy(_buffer, copy._buffer, copy.size() * sizeof(T));
} else
{
if constexpr (std::is_copy_constructible_v<T> && !std::is_copy_assignable_v<T>)
{
for (size_t i = 0; i < this->_size; i++)
_buffer[i] = T(copy[i]);
} else
for (size_t i = 0; i < this->_size; i++)
_buffer[i] = copy[i];
}
return *this;
}
scoped_buffer(const scoped_buffer& copy) = delete;
scoped_buffer(scoped_buffer&& move) noexcept
{
delete[] _buffer;
_buffer = move._buffer;
_size = move.size();
move._buffer = nullptr;
}
scoped_buffer operator=(scoped_buffer& copyAssignment) = delete;
scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept
{
delete[] _buffer;
_buffer = moveAssignment._buffer;
_size = moveAssignment.size();
moveAssignment._buffer = nullptr;
@ -361,22 +134,7 @@ namespace blt
return _size;
}
inline T*& ptr()
{
return _buffer;
}
inline const T* const& ptr() const
{
return _buffer;
}
inline const T* const& data() const
{
return _buffer;
}
inline T*& data()
inline T* ptr()
{
return _buffer;
}
@ -397,16 +155,6 @@ namespace blt
}
};
template<typename T>
class scoped_buffer<T, false> : scoped_buffer<T, true>
{
using scoped_buffer<T, true>::scoped_buffer;
public:
scoped_buffer(const scoped_buffer& copy) = delete;
scoped_buffer operator=(scoped_buffer& copyAssignment) = delete;
};
template<typename T>
struct nullptr_initializer
{

View File

@ -12,14 +12,10 @@
#include <sstream>
#include <algorithm>
#include <vector>
#include <cctype>
#include <blt/compatibility.h>
namespace blt::string
{
namespace blt::string {
class StringBuffer
{
class StringBuffer {
private:
const size_t BLOCK_SIZE = 4096;
size_t front = 0;
@ -27,130 +23,68 @@ namespace blt::string
char* characterBuffer = nullptr;
void expand();
public:
void trim();
std::string str();
StringBuffer()
{
StringBuffer(){
characterBuffer = static_cast<char*>(malloc(BLOCK_SIZE));
size = BLOCK_SIZE;
}
StringBuffer& operator<<(char c);
StringBuffer& operator<<(const std::string& str)
{
StringBuffer& operator<<(const std::string& str) {
for (char c : str)
*this << c;
return *this;
}
template<typename T>
inline StringBuffer& operator<<(T t)
{
inline StringBuffer& operator<<(T t) {
*this << std::to_string(t);
return *this;
}
~StringBuffer()
{
~StringBuffer() {
free(characterBuffer);
}
};
static inline BLT_CPP20_CONSTEXPR bool starts_with(const std::string& string, const std::string& search)
{
#ifdef BLT_USE_CPP20
return string.starts_with(search);
#else
static inline bool starts_with(const std::string& string, const std::string& search){
if (search.length() > string.length())
return false;
auto chars = string.c_str();
auto search_chars = search.c_str();
for (unsigned int i = 0; i < search.length(); i++)
{
for (unsigned int i = 0; i < search.length(); i++){
if (chars[i] != search_chars[i])
return false;
}
return true;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool starts_with(const std::string& string, char search)
{
#ifdef BLT_USE_CPP20
return string.starts_with(search);
#else
if (string.empty())
return false;
return string[0] == search;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool ends_with(const std::string& string, const std::string& search)
{
#ifdef BLT_USE_CPP20
return string.ends_with(search);
#else
static inline bool ends_with(const std::string& string, const std::string& search){
if (search.length() > string.length())
return false;
auto chars = string.c_str();
auto search_chars = search.c_str();
auto startPosition = string.length() - search.length();
for (unsigned int i = 0; i < search.length(); i++)
{
for (unsigned int i = 0; i < search.length(); i++){
if (chars[startPosition + i] != search_chars[i])
return false;
}
return true;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool ends_with(const std::string& string, char search)
{
#ifdef BLT_USE_CPP20
return string.ends_with(search);
#else
if (string.empty())
return false;
return string[string.size() - 1] == search;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool contains(const std::string& string, const char search)
{
#if __cplusplus >= 202002L
return std::ranges::any_of(string, [search](const char c) -> bool {
return c == search;
});
#else
for (const char c : string)
{
if (c == search)
return true;
}
return false;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool contains(const std::string& string, const std::string& search)
{
static inline bool contains(const std::string& string, const std::string& search){
if (search.length() > string.length())
return false;
auto chars = string.c_str();
auto search_chars = search.c_str();
for (unsigned int i = 0; i < string.length(); i++)
{
if (chars[i] == search_chars[0])
{
for (unsigned int i = 0; i < string.length(); i++){
if (chars[i] == search_chars[0]) {
bool correct = true;
for (unsigned int j = 0; j < search.length(); j++)
{
if (chars[i + j] != search_chars[j])
{
for (unsigned int j = 0; j < search.length(); j++) {
if (chars[i + j] != search_chars[j]) {
correct = false;
break;
}
@ -161,21 +95,19 @@ namespace blt::string
}
return false;
}
/**
* Converts the string into lower case
* @param s string to lower case
* @return a string copy that is all lower case
*/
static inline BLT_CPP20_CONSTEXPR std::string toLowerCase(const std::string& s)
{
std::string str;
static inline std::string toLowerCase(const std::string& s) {
std::stringstream str;
std::for_each(
s.begin(), s.end(), [&str](unsigned char ch) {
str += (char) std::tolower(ch);
str << (char) std::tolower(ch);
}
);
return str;
return str.str();
}
/**
@ -183,25 +115,22 @@ namespace blt::string
* @param s string to upper case
* @return a string copy that is all upper case
*/
static inline BLT_CPP20_CONSTEXPR std::string toUpperCase(const std::string& s)
{
std::string str;
static inline std::string toUpperCase(const std::string& s) {
std::stringstream str;
std::for_each(
s.begin(), s.end(), [&str](unsigned char ch) {
str += (char) std::toupper(ch);
str << (char) std::toupper(ch);
}
);
return str;
return str.str();
}
// taken from https://stackoverflow.com/questions/14265581/parse-split-a-string-in-c-using-string-delimiter-standard-c
// extended to return a vector
static inline BLT_CPP20_CONSTEXPR std::vector<std::string> split(std::string s, const std::string& delim)
{
static inline std::vector<std::string> split(std::string s, const std::string& delim) {
size_t pos = 0;
std::vector<std::string> tokens;
while ((pos = s.find(delim)) != std::string::npos)
{
while ((pos = s.find(delim)) != std::string::npos) {
auto token = s.substr(0, pos);
tokens.push_back(token);
s.erase(0, pos + delim.length());
@ -210,37 +139,20 @@ namespace blt::string
return tokens;
}
static inline BLT_CPP20_CONSTEXPR std::vector<std::string> split(std::string s, char delim)
{
size_t pos = 0;
std::vector<std::string> tokens;
while ((pos = s.find(delim)) != std::string::npos)
{
auto token = s.substr(0, pos);
tokens.push_back(token);
s.erase(0, pos + 1);
}
tokens.push_back(s);
return tokens;
}
// https://stackoverflow.com/questions/3418231/replace-part-of-a-string-with-another-string
static inline BLT_CPP20_CONSTEXPR bool replace(std::string& str, const std::string& from, const std::string& to)
{
static inline 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)
if(start_pos == std::string::npos)
return false;
str.replace(start_pos, from.length(), to);
return true;
}
static inline BLT_CPP20_CONSTEXPR void replaceAll(std::string& str, const std::string& from, const std::string& to)
{
if (from.empty())
static inline 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)
{
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'
}
@ -250,8 +162,7 @@ namespace blt::string
// 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)
static inline BLT_CPP20_CONSTEXPR std::string& ltrim(std::string& s)
{
static inline std::string& ltrim(std::string& s) {
s.erase(
s.begin(), std::find_if(
s.begin(), s.end(), [](unsigned char ch) {
@ -262,8 +173,7 @@ namespace blt::string
}
// trim from end (in place)
static inline BLT_CPP20_CONSTEXPR std::string& rtrim(std::string& s)
{
static inline std::string& rtrim(std::string& s) {
s.erase(
std::find_if(
s.rbegin(), s.rend(), [](unsigned char ch) {
@ -274,50 +184,30 @@ namespace blt::string
}
// trim from both ends (in place)
static inline BLT_CPP20_CONSTEXPR std::string& trim(std::string& s)
{
static inline std::string& trim(std::string& s) {
ltrim(s);
rtrim(s);
return s;
}
// trim from start (copying)
static inline BLT_CPP20_CONSTEXPR std::string ltrim_copy(std::string s)
{
static inline std::string ltrim_copy(std::string s) {
ltrim(s);
return s;
}
// trim from end (copying)
static inline BLT_CPP20_CONSTEXPR std::string rtrim_copy(std::string s)
{
static inline std::string rtrim_copy(std::string s) {
rtrim(s);
return s;
}
// trim from both ends (copying)
static inline BLT_CPP20_CONSTEXPR std::string trim_copy(std::string s)
{
static inline std::string trim_copy(std::string s) {
trim(s);
return s;
}
static inline BLT_CPP20_CONSTEXPR bool is_numeric(const std::string& s)
{
#if __cplusplus >= 202002L
return std::ranges::all_of(s, [](char c) -> bool {
return std::isdigit(c);
});
#else
for (const char c : s)
{
if (!std::isdigit(c))
return false;
}
return true;
#endif
}
}
#endif //BLT_STRING_H

View File

@ -13,7 +13,6 @@
namespace blt::system
{
static inline std::string ensureHasDigits(int current, int digits)
{
std::string asString = std::to_string(current);

View File

@ -12,7 +12,6 @@
#include <blt/std/string.h>
#include <iomanip>
#include <sstream>
#include <cstring>
namespace blt::uuid
{
@ -85,7 +84,7 @@ namespace blt::uuid
std::stringstream ss;
ss << std::hex;
const char dash[] = {0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0};
const char dash[] = { 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1, 0, 0, 0, 0, 0 };
for (int i = 0; i < len; ++i)
{
@ -156,7 +155,7 @@ namespace blt::uuid
static uuid_t genV4()
{
std::random_device rd;
std::seed_seq seed{rd(), rd(), rd(), rd()};
std::seed_seq seed{ rd(), rd(), rd(), rd() };
std::mt19937_64 gen(seed);
std::uniform_int_distribution<int> dis(0, 15);
std::uniform_int_distribution<> dis2(8, 11);
@ -164,29 +163,24 @@ namespace blt::uuid
std::stringstream ss;
int i;
ss << std::hex;
for (i = 0; i < 8; i++)
{
for (i = 0; i < 8; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 4; i++)
{
for (i = 0; i < 4; i++) {
ss << dis(gen);
}
ss << "-4";
for (i = 0; i < 3; i++)
{
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
ss << dis2(gen);
for (i = 0; i < 3; i++)
{
for (i = 0; i < 3; i++) {
ss << dis(gen);
}
ss << "-";
for (i = 0; i < 12; i++)
{
for (i = 0; i < 12; i++) {
ss << dis(gen);
};
@ -194,6 +188,7 @@ namespace blt::uuid
}
}
#endif //BLT_UUID_H

@ -1 +1 @@
Subproject commit 401552da80b0971f818e648621260720ad40934e
Subproject commit 93201da2ba5a6aba0a6e57ada64973555629b3e3

View File

@ -54,7 +54,7 @@ namespace blt
arg_vector_t::arg_vector_t(const char* str)
{
std::string as_string(str);
if (blt::string::starts_with(str, '-'))
if (as_string.starts_with('-'))
flags.emplace_back(as_string);
else
name = as_string;
@ -62,7 +62,7 @@ namespace blt
arg_vector_t::arg_vector_t(const std::string& str)
{
if (blt::string::starts_with(str, '-'))
if (str.starts_with('-'))
flags.emplace_back(str);
else
name = str;

View File

@ -248,12 +248,4 @@ namespace blt
blt::printProfile(profile, flags, sort, log_level);
profiles.erase(profile_name);
}
interval_t::interval_t(pf_time_t wallStart, pf_time_t wallEnd, pf_time_t wallTotal, pf_time_t threadStart, pf_time_t threadEnd,
pf_time_t threadTotal, pf_cycle_t cyclesStart, pf_cycle_t cyclesEnd, pf_cycle_t cyclesTotal, uint64_t count,
std::string intervalName):
wall_start(wallStart), wall_end(wallEnd), wall_total(wallTotal), thread_start(threadStart), thread_end(threadEnd),
thread_total(threadTotal), cycles_start(cyclesStart), cycles_end(cyclesEnd), cycles_total(cyclesTotal), count(count),
interval_name(std::move(intervalName))
{}
}

View File

@ -4,87 +4,83 @@
* See LICENSE file for license detail
*/
#include <blt/std/loader.h>
#include <blt/std/assert.h>
std::vector<std::string> blt::fs::getLinesFromFile(const std::string& path)
{
std::string file = getFile(path);
// split the file into the lines, this way we can get out the #include statements.
return string::split(file, "\n");
}
std::vector<std::string> blt::fs::recursiveInclude(const std::string& path, const std::string& include_header,
const std::vector<include_guard>& guards)
{
std::string pathOnly = path.substr(0, path.find_last_of('/'));
auto mainLines = getLinesFromFile(path);
std::vector<std::string> return_lines;
for (auto& line : mainLines)
{
// if the line is an include statement then we want to add lines recursively.
auto include_pos = line.find(include_header);
if (include_pos != std::string::npos)
{
auto past_include = include_pos + include_header.size();
std::string file_to_include;
if (guards.empty())
{
file_to_include = line.substr(past_include);
} else
{
size_t index = past_include;
while (std::find_if(guards.begin(), guards.end(), [&](const include_guard& item) {
return index < line.size() && line[index] == item.open;
}) == guards.end())
index++;
index++;
BLT_ASSERT(index < line.size() && "Include found but no file was provided!");
while (std::find_if(guards.begin(), guards.end(), [&](const include_guard& item) {
return index < line.size() && line[index] == item.close;
}) == guards.end())
file_to_include += line[index++];
}
// ignore absolute paths TODO: path lib
//if (!blt::string::starts_with(blt::string::trim(file_to_include), '/'))
auto lines = recursiveInclude(file_to_include, include_header, guards);
for (const auto& i_line : lines)
return_lines.push_back(i_line);
} else
return_lines.push_back(line);
}
return return_lines;
}
std::string blt::fs::getFile(const std::string& path)
{
std::string file_contents;
std::ifstream the_file;
if (!the_file.good())
std::vector<std::string> blt::fs::getLinesFromFile(const std::string& path) {
std::string shaderSource;
std::ifstream shaderFile;
if (!shaderFile.good())
BLT_ERROR("Input stream not good!\n");
// ensure ifstream objects can throw exceptions:
the_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try
{
shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try {
// open file
the_file.open(path);
std::stringstream file_stream;
shaderFile.open(path);
std::stringstream shaderStream;
// read file's buffer contents into streams
file_stream << the_file.rdbuf();
shaderStream << shaderFile.rdbuf();
// close file handlers
the_file.close();
shaderFile.close();
// convert stream into std::string
file_contents = file_stream.str();
} catch (std::ifstream::failure& e)
{
shaderSource = shaderStream.str();
} catch (std::ifstream::failure& e) {
BLT_WARN("Unable to read file '%s'!\n", path.c_str());
BLT_WARN("Exception: %s", e.what());
throw std::runtime_error("Failed to read file!\n");
}
return file_contents;
// split the shader into the lines, this way we can get out the #include statements.
return string::split(shaderSource, "\n");
}
std::vector<std::string> blt::fs::recursiveShaderInclude(const std::string& path) {
std::string pathOnly = path.substr(0, path.find_last_of('/'));
auto mainLines = getLinesFromFile(path);
std::unordered_map<int, std::vector<std::string>> includes;
for (unsigned int i = 0; i < mainLines.size(); i++) {
auto& line = mainLines[i];
// if the line is an include statement then we want to add lines recursively.
if (string::starts_with(line, "#include")) {
std::vector<std::string> include_statement = string::split(line, "<");
if (include_statement.size() <= 1)
include_statement = string::split(line, "\"");
string::trim(line);
if (!(string::ends_with(line, ">") || string::ends_with(line, "\""))) {
BLT_FATAL("Shader file contains an invalid #include statement. (Missing terminator)\n");
std::abort();
}
try {
// filter out the > or " at the end of the include statement.
std::string file;
file = include_statement[1];
if (string::ends_with(include_statement[1], ">"))
file = file.substr(0, file.size() - 1);
BLT_TRACE("Recusing into %s/%s\n", pathOnly.c_str(), file.c_str());
includes.insert({i, recursiveShaderInclude((pathOnly + "/" + file))});
} catch (std::exception& e) {
BLT_FATAL("Shader file contains an invalid #include statement. (Missing < or \")\n");
BLT_FATAL("Exception: %s", e.what());
std::abort();
}
}
}
std::vector<std::string> returnLines;
// now combine all the loaded files while respecting the include's position in the file.
for (unsigned int i = 0; i < mainLines.size(); i++) {
if (!includes[i].empty()) {
auto includedFileLines = includes[i];
for (const auto& line : includedFileLines)
returnLines.push_back(line);
} else
returnLines.push_back(mainLines[i]);
}
return returnLines;
}