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) cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake) include(cmake/color.cmake)
set(BLT_VERSION 5.2.22) set(BLT_VERSION 5.4.6)
set(BLT_TARGET BLT) 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_UBSAN "Enable the ub sanitizer" OFF)
option(ENABLE_TSAN "Enable the thread data race 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_STD "Build the BLT standard utilities." ON)
option(BUILD_PROFILING "Build the BLT profiler extension" ON) option(BUILD_PROFILING "Build the BLT profiler extension" ON)
option(BUILD_FS "Build the BLT FS utilities including the NBT + eNBT 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_ERROR "Disable blt::logging BLT_ERROR macro" OFF)
option(BLT_DISABLE_FATAL "Disable blt::logging BLT_FATAL 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}) if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS) add_compile_definitions(BLT_DISABLE_STATS)
endif () endif ()
@ -90,6 +108,7 @@ endif ()
#include zlib if the user has it. #include zlib if the user has it.
find_package(ZLIB QUIET) find_package(ZLIB QUIET)
find_package(CURL QUIET)
if (${ZLIB_FOUND}) if (${ZLIB_FOUND})
include_directories(${ZLIB_INCLUDE_DIRS}) 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.") message("ZLIB was not found, this is fine however if you wish you use gzip with NBT it is required.")
endif () 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(include/)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/config/) 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) target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
endif () 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("BLT ${Yellow}${BLT_VERSION}${ColourReset} Successfully included!")
message("Installing to ${CMAKE_INSTALL_LIBDIR} with headers at ${CMAKE_INSTALL_INCLUDEDIR}") 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_link_libraries(${name}-${type} PRIVATE BLT)
if (NOT MSVC)
target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment) target_compile_options(${name}-${type} PRIVATE -Wall -Wextra -Wpedantic -Wno-comment)
target_link_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}) target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
if (${TRACK_ALLOCATIONS}) if (${TRACK_ALLOCATIONS})
@ -205,8 +238,14 @@ if (${BUILD_TESTS})
blt_add_test(blt_iterator tests/iterator_tests.cpp test) blt_add_test(blt_iterator tests/iterator_tests.cpp test)
blt_add_test(blt_argparse tests/argparse_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_logging tests/logger_tests.cpp test)
blt_add_test(blt_variant tests/variant_tests.cpp test)
message("Built tests") message("Built tests")
endif () endif ()
project(BLT) 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}") message(STATUS "GCC libs: ${Green}stdc++fs${ColourReset}")
target_compile_options(${PROJECT_NAME} PRIVATE -Wall -Wextra -Wpedantic -fdiagnostics-color=always) 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} PRIVATE -Wall -Wextra -Wpedantic -fdiagnostics-color=always)
if (NOT WIN32)
target_link_options(${PROJECT_NAME} PUBLIC -rdynamic) target_link_options(${PROJECT_NAME} PUBLIC -rdynamic)
endif()
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs) target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
include(GNUInstallDirs) include(GNUInstallDirs)
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel") 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 #define BLT_FS_FWDDECL_H
#include <blt/std/types.h> #include <blt/std/types.h>
#include <cstdio>
namespace blt::fs 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 * @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(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 class writer_t
{ {
public: 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; virtual ~writer_t() = default;
explicit 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 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 * Optional flush command which syncs the underlying objects
*/ */

View File

@ -33,10 +33,6 @@ namespace blt::fs
public: public:
explicit fstream_reader_t(std::istream& stream); 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; i64 read(char* buffer, size_t bytes) override;
private: private:
@ -48,14 +44,14 @@ namespace blt::fs
public: public:
explicit fstream_writer_t(std::ostream& stream); 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; i64 write(const char* buffer, size_t bytes) override;
void flush() 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 virtual ~fstream_writer_t() override // NOLINT
{ {
flush(); flush();

View File

@ -82,14 +82,14 @@ namespace blt
} }
template <typename Iter> 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: 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): enumerate_iterator_container(Iter begin, Iter end, blt::size_t size):
iterator::iterator_container<iterator::enumerate_wrapper<Iter>>( blt::iterator::iterator_container<blt::iterator::enumerate_wrapper<Iter>>(
iterator::enumerate_wrapper<Iter>{0, std::move(begin)}, iterator::enumerate_wrapper<Iter>{size, std::move(end)}) 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/common.h>
#include <blt/iterator/zip.h> #include <blt/iterator/zip.h>
#include <blt/iterator/enumerate.h> #include <blt/iterator/enumerate.h>
#include <blt/iterator/flatten.h>
#include <type_traits> #include <type_traits>
#include <iterator> #include <iterator>
#include <tuple> #include <tuple>

View File

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

View File

@ -39,6 +39,8 @@ namespace blt::logging
template <typename... Args> template <typename... Args>
std::string log(std::string fmt, Args&&... args) std::string log(std::string fmt, Args&&... args)
{ {
if (fmt.empty())
return fmt;
auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{}; auto sequence = std::make_integer_sequence<size_t, sizeof...(Args)>{};
m_arg_print_funcs.clear(); m_arg_print_funcs.clear();
m_arg_print_funcs.resize(sizeof...(Args)); m_arg_print_funcs.resize(sizeof...(Args));
@ -138,6 +140,7 @@ namespace blt::logging
[[nodiscard]] size_t find_ending_brace(size_t begin) const; [[nodiscard]] size_t find_ending_brace(size_t begin) const;
void setup_stream(const fmt_spec_t& spec) const; void setup_stream(const fmt_spec_t& spec) const;
std::string process_string(std::string_view str);
void process_strings(); void process_strings();
static void handle_type(std::ostream& stream, const fmt_spec_t& spec); 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(); 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> template <typename T, blt::u32 size>
@ -428,6 +428,50 @@ namespace blt
return true; 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> template <typename T, typename G, blt::u32 size>
inline constexpr bool operator!=(const vec<T, size>& left, const vec<G, size>& right) inline constexpr bool operator!=(const vec<T, size>& left, const vec<G, size>& right)
{ {

View File

@ -23,22 +23,47 @@
namespace blt namespace blt
{ {
#define BLT_MAKE_GETTER(TYPE, NAME) \ #define BLT_MAKE_GETTER_LVALUE(TYPE, NAME) \
TYPE& get_##NAME() { return NAME; } \ TYPE& get_##NAME() { return NAME; }
#define BLT_MAKE_GETTER_CLVALUE(TYPE, NAME) \
const TYPE& get_##NAME() const { return 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) \ auto& set_##NAME(const TYPE& new_##NAME) \
{ \ { \
NAME = new_##NAME; \ NAME = new_##NAME; \
return *this; \ return *this; \
} \ }
#define BLT_MAKE_SETTER_RVALUE(TYPE, NAME) \
auto& set_##NAME(TYPE&& new_##NAME) \ auto& set_##NAME(TYPE&& new_##NAME) \
{ \ { \
NAME = std::move(new_##NAME); \ NAME = std::move(new_##NAME); \
return *this; \ 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) \ #define BLT_MAKE_GETTER_AND_SETTER(TYPE, NAME) \
BLT_MAKE_GETTER(TYPE, NAME) \ BLT_MAKE_GETTER(TYPE, NAME) \
BLT_MAKE_SETTER(TYPE, NAME) BLT_MAKE_SETTER(TYPE, NAME)

View File

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

View File

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

View File

@ -29,7 +29,7 @@
#include <blt/std/mmap.h> #include <blt/std/mmap.h>
#include <blt/compatibility.h> #include <blt/compatibility.h>
#include <stdexcept> #include <stdexcept>
#include "logging.h" #include "blt/logging/logging.h"
#include <cstdlib> #include <cstdlib>
#include <atomic> #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() static constexpr std::size_t make_storage_ones()
{ {
#ifdef __EMSCRIPTEN__
return ~static_cast<size_t>(0);
#else
std::size_t result = 0; std::size_t result = 0;
for (std::size_t i = START_BIT; i < END_BIT; i++) for (std::size_t i = START_BIT; i < END_BIT; i++)
result |= 1ul << i; result |= 1ul << i;
return result; return result;
#endif
} }
static constexpr std::size_t make_ptr_ones() static constexpr std::size_t make_ptr_ones()
{ {
#ifdef __EMSCRIPTEN__
return ~static_cast<size_t>(0);
#else
std::size_t result = 0; std::size_t result = 0;
for (std::size_t i = 0; i < START_BIT; i++) for (std::size_t i = 0; i < START_BIT; i++)
result |= 1ul << i; result |= 1ul << i;
return result; return result;
#endif
} }
bit_storage(): bits(0) bit_storage(): bits(0)
@ -263,16 +271,20 @@ namespace blt::mem
pointer_storage& bit(const std::size_t index, const bool b) noexcept pointer_storage& bit(const std::size_t index, const bool b) noexcept
{ {
#ifndef __EMSCRIPTEN__
if (index >= bit_storage::END_BIT) if (index >= bit_storage::END_BIT)
return *this; return *this;
ptr_bits &= ~(1ul << (bit_storage::START_BIT + index)); ptr_bits &= ~(1ul << (bit_storage::START_BIT + index));
ptr_bits |= (static_cast<std::uintptr_t>(b) << (bit_storage::START_BIT + index)); ptr_bits |= (static_cast<std::uintptr_t>(b) << (bit_storage::START_BIT + index));
#endif
return *this; return *this;
} }
template<typename T, std::enable_if_t<!std::is_same_v<T, bit_storage>, bool> = false> template<typename T, std::enable_if_t<!std::is_same_v<T, bit_storage>, bool> = false>
pointer_storage& storage(const T& type) 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_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; static constexpr std::uintptr_t store_bits = (2 << (bit_storage::AVAILABLE_BITS - 1)) - 1;
std::uintptr_t bit_store = 0; std::uintptr_t bit_store = 0;
@ -280,12 +292,15 @@ namespace blt::mem
std::memcpy(&bit_store, &type, sizeof(T)); std::memcpy(&bit_store, &type, sizeof(T));
store.bits |= bit_store & store_bits; store.bits |= bit_store & store_bits;
storage(store); storage(store);
#endif
return *this; return *this;
} }
pointer_storage& storage(const bit_storage bits) noexcept 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)); ptr_bits = ((ptr_bits & PTR_ALL_ONES) | (static_cast<std::uintptr_t>(bits.bits) << bit_storage::START_BIT));
#endif
return *this; 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 <mutex>
#include <chrono> #include <chrono>
#include <optional> #include <optional>
#include <blt/std/logging.h> #include <blt/logging/logging.h>
#include <condition_variable> #include <condition_variable>
namespace blt namespace blt
{ {
class barrier class barrier_t
{ {
public: 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() thread_count(threads), threads_waiting(0), use_count(0), exit_cond(exit_cond), count_mutex(), cv()
{ {
if (threads == 0) if (threads == 0)
throw std::runtime_error("Barrier thread count cannot be 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() void wait()
{ {
@ -101,7 +101,7 @@ namespace blt
// improves performance by not blocking the thread for n iterations of the loop. // 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. // 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 <cstdint>
#include <cstddef> #include <cstddef>
#include <blt/std/defines.h>
#ifndef NO_BLT_NAMESPACE_ON_TYPES #ifndef NO_BLT_NAMESPACE_ON_TYPES
namespace blt namespace blt

View File

@ -67,31 +67,6 @@ namespace blt
return typeid(T).name(); 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__) #if defined(__GNUC__) || defined(__llvm__)
#define BLT_UNREACHABLE __builtin_unreachable() #define BLT_UNREACHABLE __builtin_unreachable()
#define BLT_ATTRIB_NO_INLINE __attribute__ ((noinline)) #define BLT_ATTRIB_NO_INLINE __attribute__ ((noinline))
@ -134,6 +109,15 @@ namespace blt
(void) hell; (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> template<typename T>
BLT_ATTRIB_NO_INLINE const T& black_box_ret(const T& val) 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 <stack>
#include <queue> #include <queue>
#include <algorithm> #include <algorithm>
#include <blt/std/variant.h>
inline constexpr char SEPARATOR = '-'; inline constexpr char SEPARATOR = '-';
inline constexpr char CONNECTOR = '+'; 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) 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} fstream_writer_t::fstream_writer_t(std::ostream& stream): m_stream{&stream}
@ -42,4 +43,25 @@ namespace blt::fs
{ {
m_stream->flush(); 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; static global_context_t global_context;
#ifdef BLT_LOGGING_THREAD_SAFE
static std::mutex global_logging_mutex;
#endif
struct logging_thread_context_t struct logging_thread_context_t
{ {
@ -108,13 +111,30 @@ namespace blt::logging
m_stream << std::noshowpos; 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() void logger_t::process_strings()
{ {
auto spec_it = m_fmt_specs.begin(); auto spec_it = m_fmt_specs.begin();
auto str_it = m_string_sections.begin(); auto str_it = m_string_sections.begin();
for (; spec_it != m_fmt_specs.end(); ++spec_it, ++str_it) 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; auto arg_pos = spec_it->arg_id;
if (arg_pos == -1) if (arg_pos == -1)
arg_pos = static_cast<i64>(m_arg_pos++); arg_pos = static_cast<i64>(m_arg_pos++);
@ -122,7 +142,7 @@ namespace blt::logging
setup_stream(*spec_it); setup_stream(*spec_it);
m_arg_print_funcs[arg_pos](m_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) 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() 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) if (begin == std::string::npos)
return {}; return {};
const auto end = find_ending_brace(begin); const auto end = find_ending_brace(begin);
if (end == std::string::npos) if (end == std::string::npos)
{ {
std::stringstream ss; 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()); throw std::runtime_error(ss.str());
} }
m_last_fmt_pos = end + 1; m_last_fmt_pos = end + 1;
@ -218,6 +240,9 @@ namespace blt::logging
void print(std::string str) void print(std::string str)
{ {
#ifdef BLT_LOGGING_THREAD_SAFE
std::scoped_lock lock{global_logging_mutex};
#endif
const auto& config = get_global_config(); const auto& config = get_global_config();
bool should_print = true; bool should_print = true;
if (!config.get_injectors().empty()) if (!config.get_injectors().empty())
@ -238,6 +263,9 @@ namespace blt::logging
void newline() void newline()
{ {
#ifdef BLT_LOGGING_THREAD_SAFE
std::scoped_lock lock{global_logging_mutex};
#endif
std::cout << std::endl; std::cout << std::endl;
} }

View File

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

View File

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

View File

@ -313,7 +313,7 @@ namespace blt::argparse
break; break;
case action_t::COUNT: case action_t::COUNT:
set_nargs(0); set_nargs(0);
as_type<size_t>(); as_type<u64>();
break; break;
case action_t::EXTEND: case action_t::EXTEND:
set_nargs(nargs_t::ALL); set_nargs(nargs_t::ALL);
@ -1176,14 +1176,14 @@ namespace blt::argparse
argument_parser_t parser; argument_parser_t parser;
parser.add_flag("-a").set_action(action_t::STORE_TRUE); parser.add_flag("-a").set_action(action_t::STORE_TRUE);
parser.add_flag("+b").set_action(action_t::STORE_FALSE); 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 std::vector<std::string> args = {"./program", "-a", "+b", "/c", "42"};
const auto parsed_args = parser.parse(args); 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>("-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<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 // Test: Invalid flag prefixes
@ -1208,12 +1208,12 @@ namespace blt::argparse
void test_compound_flags() void test_compound_flags()
{ {
argument_parser_t parser; 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 std::vector<std::string> args = {"./program", "-vvv"};
const auto parsed_args = parser.parse(args); 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() 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));
}