Compare commits
45 Commits
4fab2595bc
...
8f3cbcb2fd
Author | SHA1 | Date |
---|---|---|
|
8f3cbcb2fd | |
|
f0e9475dcc | |
|
8d3a088049 | |
|
7e68950a16 | |
|
606def7c10 | |
|
bc34be9496 | |
|
e5a3c9d669 | |
|
fb092422a8 | |
|
f245b7531e | |
|
2bac310e55 | |
|
dcd4bf17ee | |
|
57ddcafcda | |
|
a1bc8cf1c2 | |
|
90cf177c57 | |
|
6cdfab39cf | |
|
6161d9b794 | |
|
b6fc170399 | |
|
e2dc35fea9 | |
|
c241085afb | |
|
1b4ad25bcf | |
|
78c219cc67 | |
|
09d1a82268 | |
|
322a533fd9 | |
|
2d9b96f115 | |
|
3cdceda227 | |
|
4c3e3951b3 | |
|
3f83c04b8c | |
|
685753b217 | |
|
0fed009bdf | |
|
729a16ab57 | |
|
284743c683 | |
|
8b23715ddd | |
|
0ebbc198c5 | |
|
4f9f61d63a | |
|
9a05c86b02 | |
|
8922a9e78c | |
|
79148a8506 | |
|
ebf0a80774 | |
|
2822522484 | |
|
24de97acdd | |
|
f8cf71e152 | |
|
0bd3519e7e | |
|
19f9dead27 | |
|
6d44477958 | |
|
2f8a0bba91 |
|
@ -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 ()
|
|
@ -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")
|
||||
|
|
|
@ -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";
|
||||
}
|
|
@ -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
|
|
@ -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
|
||||
*/
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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)})
|
||||
{
|
||||
}
|
||||
};
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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)...})
|
||||
{}
|
||||
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
|
||||
#include <cstdint>
|
||||
#include <cstddef>
|
||||
#include <blt/std/defines.h>
|
||||
|
||||
#ifndef NO_BLT_NAMESPACE_ON_TYPES
|
||||
namespace blt
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -12,6 +12,7 @@
|
|||
#include <stack>
|
||||
#include <queue>
|
||||
#include <algorithm>
|
||||
#include <blt/std/variant.h>
|
||||
|
||||
inline constexpr char SEPARATOR = '-';
|
||||
inline constexpr char CONNECTOR = '+';
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -9,6 +9,7 @@
|
|||
#include <blt/iterator/iterator.h>
|
||||
#include <algorithm>
|
||||
#include "blt/std/utility.h"
|
||||
#include <blt/std/variant.h>
|
||||
|
||||
namespace blt
|
||||
{
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
|
@ -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));
|
||||
}
|
Loading…
Reference in New Issue