Compare commits

..

49 Commits

Author SHA1 Message Date
Brett c8d12c21c6 update ignore 2023-11-21 01:57:45 -05:00
Brett 06f87c9734 fix missing cstring 2023-11-17 01:47:24 -05:00
Brett fd9fa5454d compiler support for blackbox 2023-11-14 01:05:28 -05:00
Brett 5472783bd7 it's still recursive but it's honest work 2023-11-13 15:32:39 -05:00
Brett 3d7abd2765 fix assert, working on loading 2023-11-13 15:15:27 -05:00
Brett 19baf8b048 include recursive 2023-11-13 14:27:51 -05:00
Brett 32e2d48cd3 worsen logging 2023-11-10 12:40:10 -05:00
Brett bd7976cf71 fix logging 2023-11-09 21:11:34 -05:00
Brett e912e7e272 ranges 2023-11-09 19:11:56 -05:00
Brett da7627dd3b memory 2023-11-09 19:07:24 -05:00
Brett e28f30bcec fix uninit error 2023-11-09 15:28:17 -05:00
Brett e81cddf6ba fix posargs 2023-11-08 21:31:53 -05:00
Brett 97dd77d9c9 i hate you (fixed arg_parse ambig 2023-11-08 21:22:54 -05:00
Brett 97860853cf size check 2023-11-08 20:25:47 -05:00
Brett 1ada8d3912 we sexy man 2023-11-08 18:50:16 -05:00
Brett a555b53a61 update memory to check for size bounds: 2023-11-06 18:35:09 -05:00
Brett 1a72728aeb warning fix 2023-11-06 00:43:44 -05:00
Brett 288076ed02 improve scoped_buffer, it now handles copying 2023-11-05 19:05:32 -05:00
Brett 15bcd37834 make argparse work on c++ 17 2023-11-02 16:02:40 -04:00
Brett 1d8f9b4bbd fix memory leak 2023-10-27 14:32:15 -04:00
Brett 585429e345 order 2023-10-27 14:31:11 -04:00
Brett 0eb6db500b holy const batman 2023-10-27 14:30:16 -04:00
Brett 52c5f2b7b3 make reference 2023-10-27 14:29:41 -04:00
Brett f639b4f83c add default constructor to scoped_buffer 2023-10-27 14:26:31 -04:00
Brett 55c497475e why 2023-10-27 01:11:05 -04:00
Brett 827ee4bd55 move CPP20 constexpr to compat 2023-10-27 00:00:01 -04:00
Brett 8d2bb93b2d fs hack 2023-10-26 20:06:03 -04:00
Brett 5d539c1a2f fs hack 2023-10-26 20:01:01 -04:00
Brett a3179d1a36 compat 2023-10-26 19:44:44 -04:00
Brett 0d6f396a15 fun2 2023-10-26 16:36:27 -04:00
Brett cf49d155de fun 2023-10-26 16:35:42 -04:00
Brett a3d35b8e04 add support for gcc 8.5 2023-10-26 16:27:39 -04:00
Brett bd07600f16 Merge remote-tracking branch 'refs/remotes/origin/main' 2023-10-26 16:15:32 -04:00
Brett e059f1a7ef CONSTEXPR 20 2023-10-26 16:15:14 -04:00
Brett 16ba4ed192 apparent a change 2023-10-26 01:29:45 -04:00
Brett fcceff189b CONSTEXPR c++20 string functions 2023-10-25 14:30:24 -04:00
Brett 96af65a675 move 2023-10-25 01:26:44 -04:00
Brett 82583a444d .data() 2023-10-25 01:26:26 -04:00
Brett 6252525091 .data() 2023-10-25 01:23:33 -04:00
Brett 4010df0e3f const ptr 2023-10-25 01:23:16 -04:00
Brett d59cfd0d4a backwards compat 2023-10-24 21:44:24 -04:00
Brett 63ae93c6e6 move around to bytes and make it faster 2023-10-24 21:43:22 -04:00
Brett 5a07594e42 fix assert 2023-10-15 17:48:10 -04:00
Brett 76b2d57f05 add split for char 2023-10-15 16:43:20 -04:00
Brett 88ef415f8b add missing return 2023-10-14 18:36:32 -04:00
Brett 4f4ed1918b add string char contains overload 2023-10-14 18:35:11 -04:00
Brett ce642a30b7 rename 2023-10-14 17:06:10 -04:00
Brett f55e7d931b add string numbers check 2023-10-14 17:05:51 -04:00
Brett fbd067e69e add ability for std::string in args.get<T> 2023-10-09 21:50:41 -04:00
16 changed files with 760 additions and 221 deletions

10
.gitignore vendored
View File

@ -1,9 +1 @@
/cmake-build-debug/ /cmake-build-*/
./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

@ -0,0 +1,42 @@
/*
* 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,10 +12,12 @@
#include <cstring> #include <cstring>
#include <type_traits> #include <type_traits>
#include <unordered_map> #include <unordered_map>
#include <algorithm>
#include "blt/std/format.h" #include "blt/std/format.h"
#include "blt/std/filesystem.h" #include "blt/std/filesystem.h"
#include "blt/std/logging.h" #include "blt/std/logging.h"
#include "blt/std/memory.h"
#include <blt/std/hashmap.h> #include <blt/std/hashmap.h>
@ -25,36 +27,10 @@ namespace blt::nbt {
std::string readUTF8String(blt::fs::block_reader& stream); 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> template<typename T>
inline static void writeData(blt::fs::block_writer& out, const T& d){ inline static void writeData(blt::fs::block_writer& out, const T& d){
char data[sizeof(T)]; char data[sizeof(T)];
toBytes(d, data); mem::toBytes(d, data);
out.write(data, sizeof(T)); out.write(data, sizeof(T));
} }
@ -62,7 +38,7 @@ namespace blt::nbt {
inline static void readData(blt::fs::block_reader& in, T& d) { inline static void readData(blt::fs::block_reader& in, T& d) {
char data[sizeof(T)]; char data[sizeof(T)];
in.read(data, sizeof(T)); in.read(data, sizeof(T));
fromBytes(data, &d); mem::fromBytes(data, &d);
} }
enum class nbt_tag : char { enum class nbt_tag : char {

View File

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

View File

@ -51,6 +51,11 @@ namespace blt
std::uint64_t count = 0; std::uint64_t count = 0;
std::string interval_name; 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 struct cycle_interval_t
@ -82,7 +87,8 @@ namespace blt
void startInterval(interval_t* interval); 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)); auto* p = createInterval(profiler, std::move(interval_name));
startInterval(p); startInterval(p);
return p; return p;

View File

@ -14,12 +14,53 @@ namespace blt
void b_assert_failed(const char* expression, const char* path, int line); void b_assert_failed(const char* expression, const char* path, int line);
void b_throw(const char* what, 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. // 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) #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. // prints error with stack trace then exits with failure.
#define BLT_ASSERT(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, __FILE__, __LINE__); std::exit(EXIT_FAILURE); } while (0) #define BLT_ASSERT(expr) do { \
if (!static_cast<bool>(expr)) { \
blt::b_assert_failed(#expr, __FILE__, __LINE__); \
std::exit(EXIT_FAILURE); \
} \
} while (0)
// prints as error but does not throw the exception. // prints as error but does not throw the exception.
#define blt_throw(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__);} while (0) #define blt_throw(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__);} while (0)
// prints as error with stack trace and throws the exception. // prints as error with stack trace and throws the exception.

View File

@ -14,18 +14,53 @@
#include <string> #include <string>
#include <blt/std/string.h> #include <blt/std/string.h>
#include <blt/std/logging.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); std::vector<std::string> getLinesFromFile(const std::string& path);
std::vector<std::string> recursiveShaderInclude(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 = {{'<', '>'}, {'"', '"'}});
static inline std::string loadShaderFile(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)
{
std::stringstream stringStream; std::stringstream stringStream;
auto lines = recursiveShaderInclude(path); auto lines = recursiveInclude(path);
for (const auto& line : lines) { for (const auto& line : lines)
{
// now process the defines, if they exist // now process the defines, if they exist
// if (line.starts_with("#define")) { // if (line.starts_with("#define")) {
// auto defineParts = String::split(line, " "); // auto defineParts = String::split(line, " ");

View File

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

View File

@ -10,12 +10,177 @@
#include <initializer_list> #include <initializer_list>
#include <iterator> #include <iterator>
#include <cstring> #include <cstring>
#include <type_traits>
#include "queue.h" #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
namespace blt 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> template<typename V>
struct ptr_iterator struct ptr_iterator
{ {
@ -77,36 +242,98 @@ namespace blt
/** /**
* Creates an encapsulation of a T array which will be automatically deleted when this object goes out of scope. * 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. * This is a simple buffer meant to be used only inside of a function and not copied around.
* The internal buffer is allocated on the heap. * The internal buffer is allocated on the heap.
* The operator * has been overloaded to return the internal buffer. * The operator * has been overloaded to return the internal buffer.
* @tparam T type that is stored in buffer eg char * @tparam T type that is stored in buffer eg char
*/ */
template<typename T> template<typename T, bool = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>>
struct scoped_buffer class scoped_buffer
{ {
private: private:
T* _buffer; T* _buffer = nullptr;
size_t _size; size_t _size;
public: public:
scoped_buffer(): _buffer(nullptr), _size(0)
{}
explicit scoped_buffer(size_t size): _size(size) explicit scoped_buffer(size_t size): _size(size)
{ {
_buffer = new T[size]; if (size > 0)
_buffer = new T[size];
else
_buffer = nullptr;
} }
scoped_buffer(const scoped_buffer& copy) = delete; 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(scoped_buffer&& move) noexcept scoped_buffer(scoped_buffer&& move) noexcept
{ {
delete[] _buffer;
_buffer = move._buffer; _buffer = move._buffer;
_size = move.size(); _size = move.size();
move._buffer = nullptr; move._buffer = nullptr;
} }
scoped_buffer operator=(scoped_buffer& copyAssignment) = delete;
scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept
{ {
delete[] _buffer;
_buffer = moveAssignment._buffer; _buffer = moveAssignment._buffer;
_size = moveAssignment.size(); _size = moveAssignment.size();
moveAssignment._buffer = nullptr; moveAssignment._buffer = nullptr;
@ -134,7 +361,22 @@ namespace blt
return _size; return _size;
} }
inline T* ptr() inline T*& ptr()
{
return _buffer;
}
inline const T* const& ptr() const
{
return _buffer;
}
inline const T* const& data() const
{
return _buffer;
}
inline T*& data()
{ {
return _buffer; return _buffer;
} }
@ -155,6 +397,16 @@ 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> template<typename T>
struct nullptr_initializer struct nullptr_initializer
{ {

View File

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

View File

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

View File

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

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

View File

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

View File

@ -248,4 +248,12 @@ namespace blt
blt::printProfile(profile, flags, sort, log_level); blt::printProfile(profile, flags, sort, log_level);
profiles.erase(profile_name); 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,83 +4,87 @@
* See LICENSE file for license detail * See LICENSE file for license detail
*/ */
#include <blt/std/loader.h> #include <blt/std/loader.h>
#include <blt/std/assert.h>
std::vector<std::string> blt::fs::getLinesFromFile(const std::string& path) { std::vector<std::string> blt::fs::getLinesFromFile(const std::string& path)
std::string shaderSource; {
std::ifstream shaderFile; std::string file = getFile(path);
if (!shaderFile.good()) // 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())
BLT_ERROR("Input stream not good!\n"); BLT_ERROR("Input stream not good!\n");
// ensure ifstream objects can throw exceptions: // ensure ifstream objects can throw exceptions:
shaderFile.exceptions(std::ifstream::failbit | std::ifstream::badbit); the_file.exceptions(std::ifstream::failbit | std::ifstream::badbit);
try { try
{
// open file // open file
shaderFile.open(path); the_file.open(path);
std::stringstream shaderStream; std::stringstream file_stream;
// read file's buffer contents into streams // read file's buffer contents into streams
shaderStream << shaderFile.rdbuf(); file_stream << the_file.rdbuf();
// close file handlers // close file handlers
shaderFile.close(); the_file.close();
// convert stream into std::string // convert stream into std::string
shaderSource = shaderStream.str(); file_contents = file_stream.str();
} catch (std::ifstream::failure& e) { } catch (std::ifstream::failure& e)
{
BLT_WARN("Unable to read file '%s'!\n", path.c_str()); BLT_WARN("Unable to read file '%s'!\n", path.c_str());
BLT_WARN("Exception: %s", e.what()); BLT_WARN("Exception: %s", e.what());
throw std::runtime_error("Failed to read file!\n"); 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;
} }