Compare commits

...

45 Commits

Author SHA1 Message Date
Brett 8f3cbcb2fd partial variant 2025-04-22 00:41:16 -04:00
Brett f0e9475dcc silly boy 2025-04-21 15:00:57 -04:00
Brett 8d3a088049 more types 2025-04-21 13:12:22 -04:00
Brett 7e68950a16 Merge remote-tracking branch 'refs/remotes/origin/main' 2025-04-21 01:23:49 -04:00
Brett 606def7c10 some variant detail 2025-04-21 01:23:39 -04:00
Brett bc34be9496 take args 2025-04-20 20:46:12 -04:00
Brett e5a3c9d669 why is it still virtual 2025-04-20 16:20:50 -04:00
Brett fb092422a8 this variant is funny 2025-04-19 22:26:25 -04:00
Brett f245b7531e basic custom variant fixing some issues with the STL. currently unstable and untested. 2025-04-19 20:36:51 -04:00
Brett 2bac310e55 silly variant 2025-04-19 17:57:53 -04:00
Brett dcd4bf17ee more config options 2025-04-19 16:38:57 -04:00
Brett 57ddcafcda config changes 2025-04-19 16:29:16 -04:00
Brett a1bc8cf1c2 meow 2025-04-17 20:48:54 -04:00
Brett 90cf177c57 fix curl requirement 2025-04-17 02:18:49 -04:00
Brett 6cdfab39cf hi 2025-04-17 01:20:00 -04:00
Brett 6161d9b794 uwu 2025-04-12 18:27:48 -04:00
Brett b6fc170399 can't seem to use fetch api 2025-04-11 16:27:55 -04:00
Brett e2dc35fea9 requests feature with cURL and emscript 2025-04-11 16:05:28 -04:00
Brett c241085afb todo emscript for ptr_storage 2025-04-11 15:16:54 -04:00
Brett 1b4ad25bcf silly 2025-04-11 14:44:45 -04:00
Brett 78c219cc67 io changes 2025-04-11 12:42:38 -04:00
Brett 09d1a82268 changes 2025-04-09 01:14:07 -04:00
Brett 322a533fd9 fix default nix 2025-04-07 02:05:42 -04:00
Brett 2d9b96f115 silly 2025-04-06 22:05:00 -04:00
Brett 3cdceda227 more silly 2025-04-06 20:29:38 -04:00
Brett 4c3e3951b3 silly 2025-04-06 20:28:14 -04:00
Brett 3f83c04b8c otel 2025-04-06 17:27:45 -04:00
Brett 685753b217 Merge remote-tracking branch 'origin' 2025-04-06 17:23:37 -04:00
Brett 0fed009bdf otel 2025-04-06 17:23:31 -04:00
Brett 729a16ab57 logging? 2025-04-03 00:42:09 -04:00
Brett 284743c683 add range to f_equal 2025-04-02 18:33:47 -04:00
Brett 8b23715ddd logger patch hack 2025-04-01 19:58:06 -04:00
Brett 0ebbc198c5 fix bump 2025-03-31 17:53:18 -04:00
Brett 4f9f61d63a silly 2025-03-31 17:52:04 -04:00
Brett 9a05c86b02 length function 2025-03-25 19:30:35 -04:00
Brett 8922a9e78c silly bounding boxes 2025-03-25 18:37:39 -04:00
Brett 79148a8506 compairsion operators on vectors 2025-03-19 19:38:29 -04:00
Brett ebf0a80774 fix empty log 2025-03-13 19:44:17 -04:00
Brett 2822522484 zip needs limits now? 2025-03-13 14:58:11 -04:00
Brett 24de97acdd stupid error 2025-03-13 14:57:16 -04:00
Tri11Paragon f8cf71e152 add flatten to iterator 2025-03-13 13:59:23 -07:00
Tri11Paragon 0bd3519e7e fix for windows 2025-03-13 13:47:44 -07:00
Tri11Paragon 19f9dead27 Merge commit '6d44477' 2025-03-13 13:06:37 -07:00
Tri11Paragon 6d44477958 add msvc check 2025-03-13 13:06:18 -07:00
Brett 2f8a0bba91 fix missing logging depend 2025-03-12 23:57:08 -04:00
33 changed files with 1412 additions and 73 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake)
set(BLT_VERSION 5.2.22)
set(BLT_VERSION 5.4.6)
set(BLT_TARGET BLT)
@ -12,6 +12,9 @@ option(ENABLE_ADDRSAN "Enable the address sanitizer" OFF)
option(ENABLE_UBSAN "Enable the ub sanitizer" OFF)
option(ENABLE_TSAN "Enable the thread data race sanitizer" OFF)
option(BLT_LOGGING_THREAD_SAFE "Make sure logging is thread synced" ON)
option(BLT_DEBUG_OTEL "Use Open Telemetry for debugging" OFF)
option(BUILD_STD "Build the BLT standard utilities." ON)
option(BUILD_PROFILING "Build the BLT profiler extension" ON)
option(BUILD_FS "Build the BLT FS utilities including the NBT + eNBT extension" ON)
@ -30,6 +33,21 @@ option(BLT_DISABLE_WARN "Disable blt::logging BLT_WARN macro" OFF)
option(BLT_DISABLE_ERROR "Disable blt::logging BLT_ERROR macro" OFF)
option(BLT_DISABLE_FATAL "Disable blt::logging BLT_FATAL macro" OFF)
if (BLT_DEBUG_OTEL)
message(STATUS "Searching in path '${CMAKE_PREFIX_PATH}'")
find_package(absl REQUIRED)
find_package(protobuf REQUIRED)
find_package(OpenSSL REQUIRED)
find_package(gRPC REQUIRED)
find_package(nlohmann_json CONFIG REQUIRED)
find_package(prometheus-cpp CONFIG REQUIRED)
find_package(opentelemetry-cpp CONFIG REQUIRED)
endif ()
if (BLT_LOGGING_THREAD_SAFE)
add_compile_definitions(BLT_LOGGING_THREAD_SAFE)
endif ()
if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS)
endif ()
@ -90,6 +108,7 @@ endif ()
#include zlib if the user has it.
find_package(ZLIB QUIET)
find_package(CURL QUIET)
if (${ZLIB_FOUND})
include_directories(${ZLIB_INCLUDE_DIRS})
@ -97,6 +116,13 @@ else ()
message("ZLIB was not found, this is fine however if you wish you use gzip with NBT it is required.")
endif ()
if (${CURL_FOUND})
message(STATUS "Linking cURL!")
include_directories(${CURL_INCLUDE_DIRS})
else ()
message(STATUS "cURL not found, some library features will be disabled!")
endif ()
include_directories(include/)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/config/)
@ -130,6 +156,11 @@ if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
endif ()
if (${CURL_FOUND})
target_include_directories(${BLT_TARGET} PUBLIC ${CURL_INCLUDE_DIRS})
target_link_libraries(${BLT_TARGET} PUBLIC ${CURL_LIBRARIES})
endif ()
message("BLT ${Yellow}${BLT_VERSION}${ColourReset} Successfully included!")
message("Installing to ${CMAKE_INSTALL_LIBDIR} with headers at ${CMAKE_INSTALL_INCLUDEDIR}")
@ -168,8 +199,10 @@ macro(blt_add_test name source type)
target_link_libraries(${name}-${type} PRIVATE BLT)
target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
target_link_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
if (NOT MSVC)
target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
target_link_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
endif()
target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
if (${TRACK_ALLOCATIONS})
@ -205,8 +238,14 @@ if (${BUILD_TESTS})
blt_add_test(blt_iterator tests/iterator_tests.cpp test)
blt_add_test(blt_argparse tests/argparse_tests.cpp test)
blt_add_test(blt_logging tests/logger_tests.cpp test)
blt_add_test(blt_variant tests/variant_tests.cpp test)
message("Built tests")
endif ()
project(BLT)
if (BLT_DEBUG_OTEL)
target_link_libraries(${BLT_TARGET} PUBLIC ${OPENTELEMETRY_CPP_LIBRARIES})
target_include_directories(${BLT_TARGET} PUBLIC ${OPENTELEMETRY_CPP_INCLUDE_DIRS})
endif ()

View File

@ -23,7 +23,9 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
message(STATUS "GCC libs: ${Green}stdc++fs${ColourReset}")
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -fdiagnostics-color=always)
target_link_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -fdiagnostics-color=always)
target_link_options(${PROJECT_NAME} PUBLIC -rdynamic)
if (NOT WIN32)
target_link_options(${PROJECT_NAME} PUBLIC -rdynamic)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
include(GNUInstallDirs)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")

44
default.nix Normal file
View File

@ -0,0 +1,44 @@
{ pkgs ? (import <nixpkgs> {
config.allowUnfree = true;
config.segger-jlink.acceptLicense = true;
}), ... }:
pkgs.mkShell
{
buildInputs = with pkgs; [
cmake
gcc
clang
emscripten
ninja
renderdoc
valgrind
gtest
opentelemetry-cpp
opentelemetry-cpp.dev
];
nativeBuildInputs = with pkgs; [
pkg-config
opentelemetry-cpp
opentelemetry-cpp.dev
];
propagatedBuildInputs = with pkgs; [
abseil-cpp
protobuf
grpc
prometheus-cpp
prometheus-cpp.dev
openssl
openssl.dev
opentelemetry-cpp
opentelemetry-cpp.dev
civetweb
civetweb.dev
c-ares
c-ares.dev
nlohmann_json
glibc
glibc.dev
curl
];
LD_LIBRARY_PATH="/run/opengl-driver/lib:/run/opengl-driver-32/lib";
}

View File

@ -0,0 +1,56 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_FS_CSTDIO_WRAPPERS_H
#define BLT_FS_CSTDIO_WRAPPERS_H
#include <blt/fs/fwddecl.h>
namespace blt::fs
{
class file_reader_t final : public reader_t
{
public:
explicit file_reader_t(void* file): m_file(file)
{
}
i64 read(char* buffer, size_t bytes) override;
private:
void* m_file;
};
class file_writer_t final : public writer_t
{
public:
explicit file_writer_t(void* file): m_file(file)
{
}
i64 write(const char* buffer, size_t bytes) override;
i64 tell() override;
void seek(i64 offset, seek_origin origin = seek_origin::seek_set) override;
private:
void* m_file;
};
}
#endif //BLT_FS_CSTDIO_WRAPPERS_H

View File

@ -20,6 +20,7 @@
#define BLT_FS_FWDDECL_H
#include <blt/std/types.h>
#include <cstdio>
namespace blt::fs
{
@ -43,6 +44,11 @@ namespace blt::fs
* @return number of bytes read, or negative value if error. Errors are not required and can just return 0
*/
virtual i64 read(char* buffer, size_t bytes) = 0;
virtual i64 read(void* buffer, const size_t bytes)
{
return this->read(static_cast<char*>(buffer), bytes);
}
};
/**
@ -52,6 +58,16 @@ namespace blt::fs
class writer_t
{
public:
enum class seek_origin
{
// Seek from current position
seek_cur = SEEK_CUR,
// Seek from end of file. Not valid on binary streams
seek_end = SEEK_END,
// Seek from start of file
seek_set = SEEK_SET
};
virtual ~writer_t() = default;
explicit writer_t() = default;
@ -66,6 +82,20 @@ namespace blt::fs
*/
virtual i64 write(const char* buffer, size_t bytes) = 0;
virtual i64 tell()
{
return 0;
}
virtual void seek(i64, seek_origin)
{
}
i64 write(const void* buffer, const size_t bytes)
{
return this->write(static_cast<const char*>(buffer), bytes);
}
/**
* Optional flush command which syncs the underlying objects
*/

View File

@ -33,10 +33,6 @@ namespace blt::fs
public:
explicit fstream_reader_t(std::istream& stream);
explicit fstream_reader_t(fstream_reader_t& copy) = delete;
fstream_reader_t& operator=(const fstream_reader_t& copy) = delete;
i64 read(char* buffer, size_t bytes) override;
private:
@ -48,14 +44,14 @@ namespace blt::fs
public:
explicit fstream_writer_t(std::ostream& stream);
explicit fstream_writer_t(fstream_writer_t& copy) = delete;
fstream_writer_t& operator=(const fstream_writer_t& copy) = delete;
i64 write(const char* buffer, size_t bytes) override;
void flush() override;
i64 tell() override;
void seek(i64 offset, seek_origin origin = seek_origin::seek_set) override;
virtual ~fstream_writer_t() override // NOLINT
{
flush();

View File

@ -82,14 +82,14 @@ namespace blt
}
template <typename Iter>
class enumerate_iterator_container : public iterator::iterator_container<iterator::enumerate_wrapper<Iter>>
class enumerate_iterator_container : public blt::iterator::iterator_container<blt::iterator::enumerate_wrapper<Iter>>
{
public:
using iterator::iterator_container<iterator::enumerate_wrapper<Iter>>::iterator_container;
using blt::iterator::iterator_container<blt::iterator::enumerate_wrapper<Iter>>::iterator_container;
enumerate_iterator_container(Iter begin, Iter end, blt::size_t size):
iterator::iterator_container<iterator::enumerate_wrapper<Iter>>(
iterator::enumerate_wrapper<Iter>{0, std::move(begin)}, iterator::enumerate_wrapper<Iter>{size, std::move(end)})
blt::iterator::iterator_container<blt::iterator::enumerate_wrapper<Iter>>(
blt::iterator::enumerate_wrapper<Iter>{0, std::move(begin)}, blt::iterator::enumerate_wrapper<Iter>{size, std::move(end)})
{
}
};

View File

@ -22,6 +22,7 @@
#include <blt/iterator/common.h>
#include <blt/iterator/zip.h>
#include <blt/iterator/enumerate.h>
#include <blt/iterator/flatten.h>
#include <type_traits>
#include <iterator>
#include <tuple>

View File

@ -21,6 +21,7 @@
#include <blt/iterator/common.h>
#include <tuple>
#include <limits>
namespace blt
{
@ -112,11 +113,11 @@ namespace blt
class zip_iterator_container : public iterator::iterator_container<iterator::zip_wrapper<Iter...>>
{
public:
using iterator::iterator_container<iterator::zip_wrapper<Iter...>>::iterator_container;
using blt::iterator::iterator_container<blt::iterator::zip_wrapper<Iter...>>::iterator_container;
explicit zip_iterator_container(iterator::iterator_pair<Iter>... iterator_pairs):
iterator::iterator_container<iterator::zip_wrapper<Iter...>>(iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.begin)...},
iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.end)...})
explicit zip_iterator_container(blt::iterator::iterator_pair<Iter>... iterator_pairs):
blt::iterator::iterator_container<blt::iterator::zip_wrapper<Iter...>>(blt::iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.begin)...},
blt::iterator::zip_wrapper<Iter...>{std::move(iterator_pairs.end)...})
{}
};

View File

@ -39,6 +39,8 @@ namespace blt::logging
template <typename... Args>
std::string log(std::string fmt, Args&&... args)
{
if (fmt.empty())
return fmt;
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
m_arg_print_funcs.clear();
m_arg_print_funcs.resize(sizeof...(Args));
@ -138,6 +140,7 @@ namespace blt::logging
[[nodiscard]] size_t find_ending_brace(size_t begin) const;
void setup_stream(const fmt_spec_t& spec) const;
std::string process_string(std::string_view str);
void process_strings();
static void handle_type(std::ostream& stream, const fmt_spec_t& spec);

170
include/blt/math/aabb.h Normal file
View File

@ -0,0 +1,170 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_MATH_AABB_H
#define BLT_MATH_AABB_H
#include <array>
#include <blt/math/vectors.h>
#include <blt/std/types.h>
namespace blt
{
// yes I could use the vector (see tower defense game commit log for this)
// this feels nicer
template <typename T = float>
class axis_t
{
public:
axis_t(const T min, const T max): m_min(min), m_max(max)
{}
[[nodiscard]] bool intersects(const T p) const
{
return p >= m_min && p <= m_max;
}
template <typename G>
[[nodiscard]] bool intersects(const axis_t<G>& other) const
{
return static_cast<T>(other.m_min) <= m_max && static_cast<T>(other.m_max) >= m_min;
}
[[nodiscard]] T min() const
{
return m_min;
}
[[nodiscard]] T max() const
{
return m_max;
}
[[nodiscard]] T length() const
{
return m_max - m_min;
}
private:
T m_min, m_max;
};
namespace detail
{
template <u32 Axis, typename T>
class axis_aligned_bounding_box_base_t
{
public:
[[nodiscard]] vec<T, Axis> get_center() const
{
vec<T, Axis> min;
for (u32 i = 0; i < Axis; i++)
min[i] = m_axes[i].min();
const auto center = get_size() / 2.0f;
return min + center;
}
[[nodiscard]] vec<T, Axis> get_size() const
{
vec<T, Axis> size;
for (u32 i = 0; i < Axis; i++)
size[i] = m_axes[i].length();
return size;
}
template <typename G>
[[nodiscard]] bool intersects(const axis_aligned_bounding_box_base_t<Axis, G>& other) const
{
for (u32 i = 0; i < Axis; i++)
if (!m_axes[i].intersects(other.m_axes[i]))
return false;
return true;
}
template <typename G>
[[nodiscard]] bool intersects(const vec<G, Axis>& point) const
{
for (u32 i = 0; i < Axis; i++)
if (!m_axes[i].intersects(point[i]))
return false;
return true;
}
axis_t<T>& operator[](u32 i)
{
return m_axes[i];
}
axis_t<T>& axis(u32 i)
{
if (i >= Axis)
throw std::out_of_range("Axis index out of range");
return m_axes[i];
}
protected:
std::array<axis_t<T>, Axis> m_axes;
};
}
template <u32 Axis, typename T>
class axis_aligned_bounding_box_t : public detail::axis_aligned_bounding_box_base_t<Axis, T>
{
public:
using detail::axis_aligned_bounding_box_base_t<Axis, T>::axis_aligned_bounding_box_base_t;
};
template <typename T>
class axis_aligned_bounding_box_t<2, T> : public detail::axis_aligned_bounding_box_base_t<2, T>
{
public:
using detail::axis_aligned_bounding_box_base_t<2, T>::axis_aligned_bounding_box_base_t;
[[nodiscard]] vec2 min() const
{
return {this->m_axes[0].min(), this->m_axes[1].min()};
}
[[nodiscard]] vec2 max() const
{
return {this->m_axes[0].max(), this->m_axes[1].max()};
}
};
template <typename T>
class axis_aligned_bounding_box_t<3, T> : public detail::axis_aligned_bounding_box_base_t<3, T>
{
public:
using detail::axis_aligned_bounding_box_base_t<2, T>::axis_aligned_bounding_box_base_t;
[[nodiscard]] vec3 min() const
{
return {this->m_axes[0].min(), this->m_axes[1].min(), this->m_axes[2].min()};
}
[[nodiscard]] vec3s max() const
{
return {this->m_axes[0].max(), this->m_axes[1].max(), this->m_axes[2].max()};
}
};
using aabb_2d_t = axis_aligned_bounding_box_t<2, float>;
using aabb_3d_t = axis_aligned_bounding_box_t<3, float>;
}
#endif //BLT_MATH_AABB_H

View File

@ -0,0 +1,28 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_MATH_BOUNDING_BOX_H
#define BLT_MATH_BOUNDING_BOX_H
#include <blt/math/aabb.h>
namespace blt {
}
#endif //BLT_MATH_BOUNDING_BOX_H

View File

@ -21,9 +21,9 @@ namespace blt
constexpr float EPSILON = std::numeric_limits<float>::epsilon();
static inline constexpr bool f_equal(float v1, float v2)
static constexpr bool f_equal(const float v1, const float v2, const float range = 1)
{
return v1 >= v2 - EPSILON && v1 <= v2 + EPSILON;
return v1 >= v2 - (EPSILON * range) && v1 <= v2 + (EPSILON * range);
}
template <typename T, blt::u32 size>
@ -428,6 +428,50 @@ namespace blt
return true;
}
template <typename T, typename G, u32 size>
constexpr bool operator>=(const vec<T, size>& left, const vec<G, size>& right)
{
for (u32 i = 0; i < size; i++)
{
if (left[i] < right[i])
return false;
}
return true;
}
template <typename T, typename G, u32 size>
constexpr bool operator>(const vec<T, size>& left, const vec<G, size>& right)
{
for (u32 i = 0; i < size; i++)
{
if (left[i] <= right[i])
return false;
}
return true;
}
template <typename T, typename G, u32 size>
constexpr bool operator<(const vec<T, size>& left, const vec<G, size>& right)
{
for (u32 i = 0; i < size; i++)
{
if (left[i] >= right[i])
return false;
}
return true;
}
template <typename T, typename G, u32 size>
constexpr bool operator<=(const vec<T, size>& left, const vec<G, size>& right)
{
for (u32 i = 0; i < size; i++)
{
if (left[i] > right[i])
return false;
}
return true;
}
template <typename T, typename G, blt::u32 size>
inline constexpr bool operator!=(const vec<T, size>& left, const vec<G, size>& right)
{

View File

@ -23,22 +23,47 @@
namespace blt
{
#define BLT_MAKE_GETTER(TYPE, NAME) \
TYPE& get_##NAME() { return NAME; } \
#define BLT_MAKE_GETTER_LVALUE(TYPE, NAME) \
TYPE& get_##NAME() { return NAME; }
#define BLT_MAKE_GETTER_CLVALUE(TYPE, NAME) \
const TYPE& get_##NAME() const { return NAME; }
#define BLT_MAKE_SETTER(TYPE, NAME) \
#define BLT_MAKE_GETTER_RVALUE(TYPE, NAME) \
TYPE get_##NAME() const { return NAME; }
#define BLT_MAKE_GETTER(TYPE, NAME) \
BLT_MAKE_GETTER_LVALUE(TYPE, NAME) \
BLT_MAKE_GETTER_CLVALUE(TYPE, NAME)
#define BLT_MAKE_SETTER_LVALUE(TYPE, NAME) \
auto& set_##NAME(const TYPE& new_##NAME) \
{ \
NAME = new_##NAME; \
return *this; \
} \
}
#define BLT_MAKE_SETTER_RVALUE(TYPE, NAME) \
auto& set_##NAME(TYPE&& new_##NAME) \
{ \
NAME = std::move(new_##NAME); \
return *this; \
}
#define BLT_MAKE_VALUE(TYPE, NAME) \
TYPE NAME; \
BLT_MAKE_GETTER_CLVALUE(TYPE, NAME) \
BLT_MAKE_SETTER_RVALUE(TYPE, NAME)
#define BLT_MAKE_VALUE_DEFAULT(TYPE, NAME, DEFAULT) \
TYPE NAME = DEFAULT; \
BLT_MAKE_GETTER_CLVALUE(TYPE, NAME) \
BLT_MAKE_SETTER_RVALUE(TYPE, NAME)
#define BLT_MAKE_SETTER(TYPE, NAME) \
BLT_MAKE_SETTER_LVALUE(TYPE, NAME) \
BLT_MAKE_SETTER_RVALUE(TYPE, NAME)
#define BLT_MAKE_GETTER_AND_SETTER(TYPE, NAME) \
BLT_MAKE_GETTER(TYPE, NAME) \
BLT_MAKE_SETTER(TYPE, NAME)

View File

@ -37,6 +37,7 @@
#include <blt/std/expected.h>
#include <blt/std/ranges.h>
#include <blt/std/utility.h>
#include <blt/std/variant.h>
namespace blt::argparse
{

View File

@ -223,8 +223,12 @@ namespace blt
std::string_view from_last()
{
if (!hasNext())
return std::string_view(&raw_string[last_read_index], raw_string.size() - last_read_index);
if (!hasNext()) {
auto size = raw_string.size() - last_read_index;
if (size > 0)
return std::string_view(&raw_string[last_read_index], size);
return "";
}
auto token = storage[getCurrentIndex()];
auto len = ((&token.token.back()) - &raw_string[last_read_index]);
auto str = std::string_view(&raw_string[last_read_index], len);

View File

@ -29,7 +29,7 @@
#include <blt/std/mmap.h>
#include <blt/compatibility.h>
#include <stdexcept>
#include "logging.h"
#include "blt/logging/logging.h"
#include <cstdlib>
#include <atomic>

27
include/blt/std/defines.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_DEFINES_H
#define BLT_DEFINES_H
#if defined(BLT_DEBUG_OTEL) && defined(__has_include) &&__has_include(<opentelemetry/version.h>)
#define BLT_DEBUG_OTEL_ENABLED 1
#endif
#endif //BLT_DEFINES_H

View File

@ -201,18 +201,26 @@ namespace blt::mem
static constexpr std::size_t make_storage_ones()
{
#ifdef __EMSCRIPTEN__
return ~static_cast<size_t>(0);
#else
std::size_t result = 0;
for (std::size_t i = START_BIT; i < END_BIT; i++)
result |= 1ul << i;
return result;
#endif
}
static constexpr std::size_t make_ptr_ones()
{
#ifdef __EMSCRIPTEN__
return ~static_cast<size_t>(0);
#else
std::size_t result = 0;
for (std::size_t i = 0; i < START_BIT; i++)
result |= 1ul << i;
return result;
#endif
}
bit_storage(): bits(0)
@ -263,16 +271,20 @@ namespace blt::mem
pointer_storage& bit(const std::size_t index, const bool b) noexcept
{
#ifndef __EMSCRIPTEN__
if (index >= bit_storage::END_BIT)
return *this;
ptr_bits &= ~(1ul << (bit_storage::START_BIT + index));
ptr_bits |= (static_cast<std::uintptr_t>(b) << (bit_storage::START_BIT + index));
#endif
return *this;
}
template<typename T, std::enable_if_t<!std::is_same_v<T, bit_storage>, bool> = false>
pointer_storage& storage(const T& type)
{
// TODO!! Emscript support!
#ifndef __EMSCRIPTEN__
static_assert(sizeof(T) <= sizeof(std::uintptr_t), "Type takes too many bits to be stored!");
static constexpr std::uintptr_t store_bits = (2 << (bit_storage::AVAILABLE_BITS - 1)) - 1;
std::uintptr_t bit_store = 0;
@ -280,12 +292,15 @@ namespace blt::mem
std::memcpy(&bit_store, &type, sizeof(T));
store.bits |= bit_store & store_bits;
storage(store);
#endif
return *this;
}
pointer_storage& storage(const bit_storage bits) noexcept
{
#ifndef __EMSCRIPTEN__
ptr_bits = ((ptr_bits & PTR_ALL_ONES) | (static_cast<std::uintptr_t>(bits.bits) << bit_storage::START_BIT));
#endif
return *this;
}

View File

@ -0,0 +1,31 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_STD_REQUESTS_H
#define BLT_STD_REQUESTS_H
#include <string>
namespace blt::requests
{
std::string send_get_request(const std::string& url);
}
#endif //BLT_STD_REQUESTS_H

View File

@ -31,31 +31,31 @@
#include <mutex>
#include <chrono>
#include <optional>
#include <blt/std/logging.h>
#include <blt/logging/logging.h>
#include <condition_variable>
namespace blt
{
class barrier
class barrier_t
{
public:
explicit barrier(blt::size_t threads, std::optional<std::reference_wrapper<std::atomic_bool>> exit_cond = {}):
explicit barrier_t(blt::size_t threads, std::optional<std::reference_wrapper<std::atomic_bool>> exit_cond = {}):
thread_count(threads), threads_waiting(0), use_count(0), exit_cond(exit_cond), count_mutex(), cv()
{
if (threads == 0)
throw std::runtime_error("Barrier thread count cannot be 0");
}
barrier(const barrier& copy) = delete;
barrier_t(const barrier_t& copy) = delete;
barrier(barrier&& move) = delete;
barrier_t(barrier_t&& move) = delete;
barrier& operator=(const barrier& copy) = delete;
barrier_t& operator=(const barrier_t& copy) = delete;
barrier& operator=(barrier&& move) = delete;
barrier_t& operator=(barrier_t&& move) = delete;
~barrier() = default;
~barrier_t() = default;
void wait()
{
@ -101,7 +101,7 @@ namespace blt
// improves performance by not blocking the thread for n iterations of the loop.
// If the condition is not met by the end of this loop we can block the thread.
static constexpr blt::size_t BUSY_LOOP_WAIT = 200;
static constexpr size_t BUSY_LOOP_WAIT = 200;
};
/**

View File

@ -21,6 +21,7 @@
#include <cstdint>
#include <cstddef>
#include <blt/std/defines.h>
#ifndef NO_BLT_NAMESPACE_ON_TYPES
namespace blt

View File

@ -67,31 +67,6 @@ namespace blt
return typeid(T).name();
}
//#define BLT_LAMBDA(type, var, code) [](const type& var) -> auto { return code; }
//#define BLT_LAMBDA(var, code) [](var) -> auto { return code; }
/*
* std::visit(blt::lambda_visitor{
* lambdas...
* }, data_variant);
*/
// TODO: WTF
template<class... TLambdas>
struct lambda_visitor : TLambdas ...
{
using TLambdas::operator()...;
};
#if __cplusplus < 202002L
// explicit deduction guide (not needed as of C++20)
template<class... TLambdas>
lambda_visitor(TLambdas...) -> lambda_visitor<TLambdas...>;
#endif
#if defined(__GNUC__) || defined(__llvm__)
#define BLT_UNREACHABLE __builtin_unreachable()
#define BLT_ATTRIB_NO_INLINE __attribute__ ((noinline))
@ -133,6 +108,15 @@ namespace blt
hell = (void*) &val;
(void) hell;
}
template<typename T>
BLT_ATTRIB_NO_INLINE T& black_box_ret(T& val)
{
static volatile void* hell;
hell = (void*) &val;
(void) hell;
return val;
}
template<typename T>
BLT_ATTRIB_NO_INLINE const T& black_box_ret(const T& val)

477
include/blt/std/variant.h Normal file
View File

@ -0,0 +1,477 @@
#pragma once
/*
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_STD_VARIANT_H
#define BLT_STD_VARIANT_H
#include <functional>
#include <optional>
#include <tuple>
#include <type_traits>
#include <variant>
#include <blt/std/types.h>
namespace blt
{
template <typename... Types>
class variant_t;
namespace detail
{
template <typename... Ts>
struct filter_void;
template <>
struct filter_void<>
{
using type = std::tuple<>;
};
template <typename T, typename... Ts>
struct filter_void<T, Ts...>
{
using type = std::conditional_t<std::is_same_v<T, void>, typename filter_void<Ts...>::type, decltype(std::tuple_cat(
std::declval<std::tuple<T>>(), std::declval<typename filter_void<Ts...>::type>()))>;
};
template <typename... Ts>
using filter_void_t = typename filter_void<Ts...>::type;
template <typename Type, typename... Ts>
struct filter_invoke;
template <typename Type>
struct filter_invoke<Type>
{
using type = std::tuple<>;
};
template <typename Type, typename T, typename... Ts>
struct filter_invoke<Type, T, Ts...>
{
using type = std::conditional_t<std::is_invocable_v<T, Type>, decltype(std::tuple_cat(
std::declval<std::tuple<T>>(), std::declval<typename filter_invoke<Ts...>::type>())),
typename filter_invoke<Ts...>::type>;
};
template <typename... Ts>
using filter_invoke_t = typename filter_invoke<Ts...>::type;
template <typename Type, typename Func>
struct member_func_meta
{
using can_invoke = std::is_invocable<Func, Type>;
using return_type = std::conditional_t<can_invoke::value, std::invoke_result_t<Func, Type>, void>;
};
template <typename T, typename Func, size_t Index>
struct passthrough_value
{
using type = T;
using func = Func;
constexpr static size_t index = Index;
bool has_value;
explicit passthrough_value(const bool has_value): has_value(has_value)
{}
explicit operator bool() const
{
return has_value;
}
};
template <typename Type, typename... Funcs>
struct first_invoke_member_func
{
template <size_t... Indexes>
constexpr static auto find_func(std::index_sequence<Indexes...>)
{
return (... || []() {
using Meta = member_func_meta<Type, Funcs>;
if constexpr (Meta::can_invoke::value)
{
return passthrough_value<typename Meta::return_type, Funcs, Indexes>{true};
}
return passthrough_value<typename Meta::return_type, Funcs, Indexes>{false};
}());
}
using result = decltype(find_func(std::index_sequence_for<Funcs...>()));
using return_type = typename result::type;
using func_type = typename result::func;
constexpr static size_t function_index = result::index;
};
template <typename FuncTuple, typename ArgTuple>
struct member_func_detail;
template <typename... Funcs, typename... Args>
struct member_func_detail<std::tuple<Funcs...>, std::tuple<Args...>>
{
using result_types = std::tuple<first_invoke_member_func<Args, Funcs...>...>;
using base_type = typename std::tuple_element_t<0, result_types>::return_type;
template <typename T>
using get_type = typename T::return_type;
template <typename T>
using is_base = std::is_same<T, base_type>;
template <typename T>
using is_base_or_void = std::disjunction<std::is_void<typename T::return_type>, is_base<typename T::return_type>>;
template <template<typename...> typename Functor, template<typename> typename PerType, size_t... Indexes>
constexpr static auto for_each_type(std::index_sequence<Indexes...>)
{
return std::declval<Functor<PerType<std::tuple_element_t<Indexes, result_types>>...>>;
}
constexpr static bool all_has_void = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, std::is_void>(
std::index_sequence_for<Args...>()))>>::value;
constexpr static bool all_has_ret = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, is_base>(
std::index_sequence_for<Args...>()))>>::value;
constexpr static bool all_has_ret_or_void = std::decay_t<std::invoke_result_t<decltype(for_each_type<std::conjunction, is_base_or_void>(
std::index_sequence_for<Args...>()))>>::value;
using non_void_types = typename std::decay_t<std::invoke_result_t<decltype(for_each_type<filter_void, get_type>(
std::index_sequence_for<Args...>()))>>::type;
template <size_t... Indexes>
static constexpr auto make_variant(std::index_sequence<Indexes...>)
{
using variant = variant_t<std::decay_t<std::tuple_element_t<Indexes, non_void_types>>...>;
return std::declval<variant>();
}
using make_return_type = std::conditional_t<all_has_void, void, std::conditional_t<
all_has_ret, base_type, std::conditional_t<
all_has_ret_or_void, std::optional<base_type>, std::conditional_t<
std::tuple_size_v<non_void_types> == 0, void, decltype(make_variant(
std::make_index_sequence<std::tuple_size_v<non_void_types>>{}))>>>>;
};
}
/*
* std::visit(blt::lambda_visitor{
* lambdas...
* }, data_variant);
*/
template <typename... TLambdas>
struct lambda_visitor : TLambdas...
{
using TLambdas::operator()...;
};
#if __cplusplus < 202002L
// explicit deduction guide (not needed as of C++20)
template <typename... TLambdas>
lambda_visitor(TLambdas...) -> lambda_visitor<TLambdas...>;
#endif
template <typename... Types>
class variant_t
{
public:
using value_type = std::variant<Types...>;
size_t variant_size = sizeof...(Types);
constexpr variant_t(): m_variant()
{}
constexpr variant_t(const variant_t& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant.m_variant)
{}
constexpr variant_t(variant_t&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant.m_variant))
{}
explicit constexpr variant_t(const value_type& variant) noexcept(std::is_nothrow_copy_constructible_v<value_type>): m_variant(variant)
{}
explicit constexpr variant_t(value_type&& variant) noexcept(std::is_nothrow_move_constructible_v<value_type>): m_variant(std::move(variant))
{}
explicit constexpr variant_t(Types&&... args) noexcept(std::is_nothrow_constructible_v<value_type, Types...>): m_variant(
std::forward<Types>(args)...)
{}
template <typename T, typename... C_Args>
explicit constexpr variant_t(std::in_place_type_t<T>, C_Args&&... args): m_variant(std::in_place_type<T>, std::forward<C_Args>(args)...)
{}
template <typename T, typename U, typename... C_Args>
constexpr explicit variant_t(std::in_place_type_t<T>, std::initializer_list<U> il, C_Args&&... args): m_variant(
std::in_place_type<T>, il, std::forward<C_Args>(args)...)
{}
template <size_t I, typename... C_Args>
explicit constexpr variant_t(std::in_place_index_t<I>, C_Args&&... args): m_variant(std::in_place_index<I>, std::forward<C_Args>(args)...)
{}
template <std::size_t I, typename U, typename... C_Args>
constexpr explicit variant_t(std::in_place_index_t<I>, std::initializer_list<U> il, C_Args&&... args): m_variant(
std::in_place_index<I>, il, std::forward<C_Args>(args)...)
{}
template <typename T, typename... Args>
T& emplace(Args&&... args)
{
return m_variant.template emplace<T>(std::forward<Args>(args)...);
}
template <typename T, typename U, typename... Args>
T& emplace(std::initializer_list<U> il, Args&&... args)
{
return m_variant.template emplace<T>(il, std::forward<Args>(args)...);
}
template <std::size_t I, typename... Args>
std::variant_alternative_t<I, value_type>& emplace(Args&&... args)
{
return m_variant.template emplace<I>(std::forward<Args>(args)...);
}
template <std::size_t I, typename U, typename... Args>
std::variant_alternative_t<I, value_type>& emplace(std::initializer_list<U> il, Args&&... args)
{
return m_variant.template emplace<I>(il, std::forward<Args>(args)...);
}
[[nodiscard]] constexpr std::size_t index() const noexcept
{
return m_variant.index();
}
[[nodiscard]] constexpr bool valueless_by_exception() const noexcept
{
return m_variant.valueless_by_exception();
}
template <typename T>
constexpr auto visit(T&& visitor) -> decltype(auto)
{
return std::visit(std::forward<T>(visitor), m_variant);
}
/**
* Automatic visitor generation
* @param visitees user lambdas
*/
template <typename... Visitee>
constexpr auto visit(
Visitee&&... visitees) -> typename detail::member_func_detail<std::tuple<Visitee...>, std::tuple<Types...>>::make_return_type
{
return std::visit(lambda_visitor{std::forward<Visitee>(visitees)...}, m_variant);
}
template <typename Default, typename... Visitee>
constexpr auto visit_value(Default&& default_value, Visitee&&... visitees) -> decltype(auto)
{
return std::visit(lambda_visitor{
std::forward<Visitee>(visitees)...,
[default_value=std::forward<Default>(default_value)](auto&& value) {
return std::forward<decltype(value)>(value);
}
});
}
template <typename MemberFunc, typename... Args>
constexpr auto call_member(const MemberFunc func,
Args&&... args) -> typename detail::member_func_detail<
std::tuple<MemberFunc>, std::tuple<Types...>>::make_return_type
{
return std::visit([func,...args=std::forward<Args>(args)](auto&& value) {
return ((value).*(func))(std::forward<Args>(args)...);
}, m_variant);
}
template <size_t I>
[[nodiscard]] constexpr bool has_index() const noexcept
{
return m_variant.index() == I;
}
template <typename T>
[[nodiscard]] constexpr bool has_type() const noexcept
{
return std::holds_alternative<T>(m_variant);
}
template <typename T>
[[nodiscard]] constexpr auto get() -> decltype(auto)
{
return std::get<T>(m_variant);
}
template <typename T>
[[nodiscard]] constexpr auto get() const -> decltype(auto)
{
return std::get<T>(m_variant);
}
template <size_t I>
[[nodiscard]] constexpr auto get() -> decltype(auto)
{
return std::get<I>(m_variant);
}
template <size_t I>
[[nodiscard]] constexpr auto get() const -> decltype(auto)
{
return std::get<I>(m_variant);
}
template <size_t I>
constexpr std::add_pointer_t<std::variant_alternative_t<I, value_type>> get_if() noexcept
{
return std::get_if<I>(m_variant);
}
template <size_t I>
constexpr std::add_pointer_t<const std::variant_alternative_t<I, value_type>> get_if() noexcept
{
return std::get_if<I>(m_variant);
}
template <typename T>
constexpr std::add_pointer_t<T> get_if() noexcept
{
return std::get_if<T>(m_variant);
}
template <typename T>
constexpr std::add_pointer_t<const T> get_if() noexcept
{
return std::get_if<T>(m_variant);
}
template <typename T>
constexpr T value_or(T&& t) const
{
if (has_type<T>())
return get<T>();
return std::forward<T>(t);
}
template <size_t I>
constexpr std::variant_alternative_t<I, value_type> value_or(const std::variant_alternative_t<I, value_type>& t) const
{
if (has_type<std::variant_alternative_t<I, value_type>>())
return get<I>();
return t;
}
template <size_t I>
constexpr std::variant_alternative_t<I, value_type> value_or(std::variant_alternative_t<I, value_type>&& t) const
{
if (has_type<std::variant_alternative_t<I, value_type>>())
return get<I>();
return t;
}
template <size_t>
constexpr const value_type& variant() const
{
return m_variant;
}
constexpr value_type& variant()
{
return m_variant;
}
[[nodiscard]] constexpr size_t size() const
{
return variant_size;
}
friend bool operator==(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant == rhs.m_variant;
}
friend bool operator!=(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant != rhs.m_variant;
}
friend bool operator<(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant < rhs.m_variant;
}
friend bool operator>(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant > rhs.m_variant;
}
friend bool operator<=(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant <= rhs.m_variant;
}
friend bool operator>=(const variant_t& lhs, const variant_t& rhs)
{
return lhs.m_variant >= rhs.m_variant;
}
private:
template <typename Derived, typename Base, typename ReturnType, typename... Args>
static auto cast_member_ptr(ReturnType (Base::*base_func)(Args...))
{
return reinterpret_cast<ReturnType (Derived::*)(Args...)>(base_func);
}
value_type m_variant;
};
namespace detail
{
template <typename>
class variant_is_base_of
{};
template <typename... Types>
class variant_is_base_of<variant_t<Types...>>
{
public:
using value_type = bool;
template <typename T>
static constexpr bool value = std::conjunction_v<std::is_base_of<T, Types>...>;
};
template <typename... Types>
class variant_is_base_of<std::variant<Types...>>
{
public:
using value_type = bool;
template <typename T>
static constexpr bool value = std::conjunction_v<std::is_base_of<T, Types>...>;
};
template <typename T>
static constexpr bool variant_is_base_of_v = variant_is_base_of<T>::value;
}
}
#endif //BLT_STD_VARIANT_H

View File

@ -12,6 +12,7 @@
#include <stack>
#include <queue>
#include <algorithm>
#include <blt/std/variant.h>
inline constexpr char SEPARATOR = '-';
inline constexpr char CONNECTOR = '+';

View File

@ -0,0 +1,42 @@
/*
* <Short Description>
* Copyright (C) 2025 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/>.
*/
#include <cstdio>
#include <blt/fs/cstdio_wrappers.h>
namespace blt::fs
{
i64 file_reader_t::read(char* buffer, const size_t bytes)
{
return fread(buffer, bytes, 1, static_cast<FILE*>(m_file));
}
i64 file_writer_t::write(const char* buffer, const size_t bytes)
{
return fwrite(buffer, bytes, 1, static_cast<FILE*>(m_file));
}
i64 file_writer_t::tell()
{
return ftell(static_cast<FILE*>(m_file));
}
void file_writer_t::seek(const i64 offset, const seek_origin origin)
{
fseek(static_cast<FILE*>(m_file), offset, static_cast<int>(origin));
}
}

View File

@ -26,7 +26,8 @@ namespace blt::fs
i64 fstream_reader_t::read(char* buffer, const size_t bytes)
{
return m_stream->readsome(buffer, static_cast<std::streamsize>(bytes));
m_stream->read(buffer, static_cast<std::streamsize>(bytes));
return m_stream->gcount();
}
fstream_writer_t::fstream_writer_t(std::ostream& stream): m_stream{&stream}
@ -42,4 +43,25 @@ namespace blt::fs
{
m_stream->flush();
}
i64 fstream_writer_t::tell()
{
return m_stream->tellp();
}
void fstream_writer_t::seek(const i64 offset, const seek_origin origin)
{
switch (origin)
{
case seek_origin::seek_cur:
m_stream->seekp(offset, std::ios_base::cur);
break;
case seek_origin::seek_end:
m_stream->seekp(offset, std::ios_base::end);
break;
case seek_origin::seek_set:
m_stream->seekp(offset, std::ios_base::beg);
break;
}
}
}

View File

@ -33,6 +33,9 @@ namespace blt::logging
};
static global_context_t global_context;
#ifdef BLT_LOGGING_THREAD_SAFE
static std::mutex global_logging_mutex;
#endif
struct logging_thread_context_t
{
@ -108,13 +111,30 @@ namespace blt::logging
m_stream << std::noshowpos;
}
std::string logger_t::process_string(const std::string_view str)
{
auto result = std::string(str);
size_t pos = 0;
while (pos = result.find('{', pos), pos != std::string::npos)
{
if (pos > 0 && result[pos - 1] == '\\')
{
auto before = result.substr(0, pos - 1);
auto after = result.substr(pos);
result = before + after;
} else
++pos;
}
return result;
}
void logger_t::process_strings()
{
auto spec_it = m_fmt_specs.begin();
auto str_it = m_string_sections.begin();
for (; spec_it != m_fmt_specs.end(); ++spec_it, ++str_it)
{
m_stream << *str_it;
m_stream << process_string(*str_it);
auto arg_pos = spec_it->arg_id;
if (arg_pos == -1)
arg_pos = static_cast<i64>(m_arg_pos++);
@ -122,7 +142,7 @@ namespace blt::logging
setup_stream(*spec_it);
m_arg_print_funcs[arg_pos](m_stream, *spec_it);
}
m_stream << *str_it;
m_stream << process_string(*str_it);
}
void logger_t::handle_type(std::ostream& stream, const fmt_spec_t& spec)
@ -197,14 +217,16 @@ namespace blt::logging
std::optional<std::pair<size_t, size_t>> logger_t::consume_to_next_fmt()
{
const auto begin = m_fmt.find('{', m_last_fmt_pos);
auto begin = m_fmt.find('{', m_last_fmt_pos);
while (begin != std::string::npos && begin > 0 && m_fmt[begin - 1] == '\\')
begin = m_fmt.find('{', begin + 1);;
if (begin == std::string::npos)
return {};
const auto end = find_ending_brace(begin);
if (end == std::string::npos)
{
std::stringstream ss;
ss << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast<i64>(begin) - 5, 0l));
ss << "Invalid format string, missing closing '}' near " << m_fmt.substr(std::min(static_cast<i64>(begin) - 5, static_cast<i64>(0)));
throw std::runtime_error(ss.str());
}
m_last_fmt_pos = end + 1;
@ -218,6 +240,9 @@ namespace blt::logging
void print(std::string str)
{
#ifdef BLT_LOGGING_THREAD_SAFE
std::scoped_lock lock{global_logging_mutex};
#endif
const auto& config = get_global_config();
bool should_print = true;
if (!config.get_injectors().empty())
@ -238,6 +263,9 @@ namespace blt::logging
void newline()
{
#ifdef BLT_LOGGING_THREAD_SAFE
std::scoped_lock lock{global_logging_mutex};
#endif
std::cout << std::endl;
}

View File

@ -17,8 +17,10 @@
*/
#include <cstdio>
#include <iostream>
#ifdef unix
#include <termios.h>
#include <unistd.h>
#endif
#include <blt/logging/ansi.h>
#include <blt/logging/fmt_tokenizer.h>
#include <blt/logging/logging.h>
@ -30,6 +32,7 @@ namespace blt::logging
{
vec2i get_cursor_position()
{
#ifdef unix
termios save{}, raw{};
tcgetattr(0, &save);
@ -68,12 +71,16 @@ namespace blt::logging
tcsetattr(0,TCSANOW, &save);
return vec2i{row, col};
#else
return {0,0};
#endif
}
#define SIZE 100
vec2i get_screen_size()
{
#ifdef unix
char in[SIZE] = "";
int each = 0;
int ch = 0;
@ -113,6 +120,9 @@ namespace blt::logging
return {rows, cols};
}
throw std::runtime_error("Could not get screen size");
#else
return {0,0};
#endif
}
i32 get_size_no_ansi(const std::string& str)

View File

@ -9,6 +9,7 @@
#include <blt/iterator/iterator.h>
#include <algorithm>
#include "blt/std/utility.h"
#include <blt/std/variant.h>
namespace blt
{

View File

@ -313,7 +313,7 @@ namespace blt::argparse
break;
case action_t::COUNT:
set_nargs(0);
as_type<size_t>();
as_type<u64>();
break;
case action_t::EXTEND:
set_nargs(nargs_t::ALL);
@ -1176,14 +1176,14 @@ namespace blt::argparse
argument_parser_t parser;
parser.add_flag("-a").set_action(action_t::STORE_TRUE);
parser.add_flag("+b").set_action(action_t::STORE_FALSE);
parser.add_flag("/c").as_type<int>().set_action(action_t::STORE);
parser.add_flag("/c").as_type<u32>().set_action(action_t::STORE);
const std::vector<std::string> args = {"./program", "-a", "+b", "/c", "42"};
const auto parsed_args = parser.parse(args);
BLT_ASSERT(parsed_args.get<bool>("-a") == true && "Flag '-a' should store `true`");
BLT_ASSERT(parsed_args.get<bool>("+b") == false && "Flag '+b' should store `false`");
BLT_ASSERT(parsed_args.get<int>("/c") == 42 && "Flag '/c' should store the value 42");
BLT_ASSERT(parsed_args.get<u32>("/c") == 42 && "Flag '/c' should store the value 42");
}
// Test: Invalid flag prefixes
@ -1208,12 +1208,12 @@ namespace blt::argparse
void test_compound_flags()
{
argument_parser_t parser;
parser.add_flag("-v").as_type<int>().set_action(action_t::COUNT);
parser.add_flag("-v").set_action(action_t::COUNT);
const std::vector<std::string> args = {"./program", "-vvv"};
const auto parsed_args = parser.parse(args);
BLT_ASSERT(parsed_args.get<size_t>("-v") == 3 && "Flag '-v' should count occurrences in compound form");
BLT_ASSERT(parsed_args.get<u64>("-v") == 3 && "Flag '-v' should count occurrences in compound form");
}
void test_combination_of_valid_and_invalid_flags()

121
src/blt/std/requests.cpp Normal file
View File

@ -0,0 +1,121 @@
/*
* <Short Description>
* Copyright (C) 2025 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/>.
*/
#include <stdexcept>
#include <blt/std/requests.h>
#ifdef __EMSCRIPTEN__
#include <emscripten.h>
#endif
#if defined(__has_include) && __has_include(<curl/curl.h>)
#include <curl/curl.h>
#define BLT_HAS_CURL
#endif
namespace blt::requests
{
#ifdef BLT_HAS_CURL
struct curl_init_t
{
curl_init_t()
{
const auto version_data = curl_version_info(CURLVERSION_NOW);
if (!(version_data->features & CURL_VERSION_THREADSAFE))
{
thread_safe = false;
}
curl_global_init(CURL_GLOBAL_ALL);
}
~curl_init_t()
{
curl_global_cleanup();
}
bool thread_safe = true;
};
struct curl_easy_init_t
{
curl_easy_init_t(): curl(curl_easy_init())
{
}
~curl_easy_init_t()
{
curl_easy_cleanup(curl);
}
CURL* curl;
};
void init()
{
static curl_init_t curl_init_obj;
}
CURL* easy_init()
{
thread_local curl_easy_init_t curl_easy_init_obj;
return curl_easy_init_obj.curl;
}
size_t write_to_string_func(const void* data, const size_t size, const size_t nmemb, void* user_data)
{
auto& str = *static_cast<std::string*>(user_data);
str.append(static_cast<const char*>(data), size * nmemb);
return size * nmemb;
};
#endif
std::string send_get_request(const std::string& url)
{
#ifdef __EMSCRIPTEN__
auto* str = static_cast<char*>(EM_ASM_PTR({
var xhr = new XMLHttpRequest();
xhr.open("GET", $0);
xhr.send();
return stringToNewUTF8(xhr.responseText);
}, url.c_str()));
std::string str_obj{str};
free(str);
return str_obj;
#else
#ifdef BLT_HAS_CURL
init();
auto curl = easy_init();
if (!curl)
throw std::runtime_error("Failed to initialize curl");
std::string response_string;
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(&response_string));
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &write_to_string_func);
const auto res = curl_easy_perform(curl);
if (res != CURLE_OK)
throw std::runtime_error(curl_easy_strerror(res));
return response_string;
#else
return "Missing cURL! Unable to fetch URL: '" + url + "'";
#endif
#endif
}
}

135
tests/variant_tests.cpp Normal file
View File

@ -0,0 +1,135 @@
/*
* <Short Description>
* Copyright (C) 2025 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/>.
*/
#include <blt/std/variant.h>
#include <blt/logging/logging.h>
#include <blt/std/assert.h>
struct base_type
{
[[nodiscard]] virtual int simple() const = 0;
[[nodiscard]] virtual std::string to_string() const = 0;
virtual ~base_type() = default;
};
struct mutate_type : base_type
{
virtual void mutate(int i) = 0;
};
struct type1 final : base_type
{
[[nodiscard]] int simple() const override // NOLINT
{
return 1;
}
[[nodiscard]] std::string to_string() const override // NOLINT
{
return "Type1";
}
};
struct type2 final : base_type
{
[[nodiscard]] int simple() const override // NOLINT
{
return 2;
}
[[nodiscard]] std::string to_string() const override // NOLINT
{
return "Type2";
}
};
struct type3 final : base_type
{
[[nodiscard]] int simple() const override // NOLINT
{
return 3;
}
[[nodiscard]] std::string to_string() const override // NOLINT
{
return "Type3";
}
};
struct storing_type1 final : mutate_type
{
explicit storing_type1(const int i): internal(i)
{
}
[[nodiscard]] int simple() const override // NOLINT
{
return internal;
}
void mutate(const int i) override
{
internal = i;
}
[[nodiscard]] std::string to_string() const override // NOLINT
{
return "Storing Type: {" + std::to_string(internal) + "}";
}
int internal;
};
struct storing_type2 final : mutate_type
{
explicit storing_type2(const float i): internal(i * 2.2534f)
{
}
[[nodiscard]] int simple() const override // NOLINT
{
return static_cast<int>(internal);
}
void mutate(const int i) override
{
internal = static_cast<float>(i) * 2.2534f;
}
[[nodiscard]] std::string to_string() const override // NOLINT
{
return "Storing Type: {" + std::to_string(internal) + "}";
}
float internal;
};
int main()
{
blt::variant_t<type1, type2, type3> v1{type1{}};
blt::variant_t<type1, type2, type3> v2{type2{}};
blt::variant_t<type1, type2, type3> v3{type3{}};
BLT_TRACE("Variants to_string():");
BLT_TRACE("V1: {}", v1.call_member(&base_type::to_string));
BLT_TRACE("V2: {}", v2.call_member(&base_type::to_string));
BLT_TRACE("V3: {}", v3.call_member(&base_type::to_string));
}