Compare commits

...

144 Commits

Author SHA1 Message Date
Brett 7580fa544a zip iterator, random access 2024-09-28 18:31:49 -04:00
Brett fb3ed3aa5e new files 2024-09-28 16:50:19 -04:00
Brett 709401e4da breaking change. iterator is now in its own package 2024-09-28 16:43:46 -04:00
Brett aabb9d801d breaking change: iterator is now in blt/iterator 2024-09-28 16:40:57 -04:00
Brett 88e8e8fc5b zip storage. i am in hell 2024-09-27 18:18:02 -04:00
Brett 0ecee088f6 working on pair iterators 2024-09-27 15:12:08 -04:00
Brett 0d13e9738f make generic 2024-09-26 17:02:05 -04:00
Brett a0a2052479 Merge remote-tracking branch 'origin' 2024-09-26 13:51:20 -04:00
Brett 369ab664b6 iterator! 2024-09-26 13:51:07 -04:00
Brett 4a80161f33 docs 2024-09-26 02:53:11 -04:00
Brett 329eeb174b rust style iterators 2024-09-25 20:52:22 -04:00
Brett a27651b21d push 2024-09-25 03:15:01 -04:00
Brett c83f089e9c breaking change: enumerate is in its own file: std/iterator.h 2024-09-25 00:53:15 -04:00
Brett cacc082ce9 silly 2024-09-24 21:38:52 -04:00
Tri11Paragon bbd5641073 undo parker being annoying 2024-09-24 20:40:35 -04:00
Tri11Paragon 854e613a9b parker is stupid 2024-09-24 20:39:01 -04:00
Tri11Paragon 43be54097e Parker is being extra annoying 2024-09-24 20:37:54 -04:00
Brett 88506e5cce parker is being annoying 2024-09-24 20:35:43 -04:00
Brett a7412fccec ranges broken again. sfinae failing? 2024-09-24 15:37:17 -04:00
Brett 373cf5e0a2 better enumerator 2024-09-23 23:53:28 -04:00
Brett ce09a70241 semi working 2024-09-23 23:21:03 -04:00
Brett 7935e34ad4 let ctad do its thing 2024-09-23 19:41:02 -04:00
Brett b944b936f4 ranges broken a bit 2024-09-23 19:40:19 -04:00
Brett c5b8830ff0 redoing enumerator 2024-09-23 18:07:31 -04:00
Brett 0aa686a87a fix meta 2024-09-23 16:24:22 -04:00
Brett 209b97079c pairs 2024-09-23 15:51:39 -04:00
Brett 96b071e337 matrix 2024-09-23 14:45:32 -04:00
Brett 7300f895bb logging 2024-09-20 17:13:09 -04:00
Brett b5ea7a1e15 fix laptop 2024-09-20 12:49:24 -04:00
Brett 39fd5a73d6 normalize 2024-09-20 00:37:39 -04:00
Brett 1ceb71aac9 mag and normal 2024-09-19 23:48:58 -04:00
Brett 6646db8249 constexpr all the matrix 2024-09-19 17:39:06 -04:00
Brett a60380c898 log boxing 2024-09-19 17:20:27 -04:00
Brett e19a88c454 matrix fix 2024-09-19 15:12:38 -04:00
Brett ba10bd633e not going to merge 4x4 into generalized 2024-09-19 13:40:34 -04:00
Brett d1aaf4db94 working on generalized matrix 2024-09-19 02:01:18 -04:00
Brett 5375231ce5 fix missing string def 2024-09-16 16:48:05 -04:00
Brett e3c925ed11 fix ambuguity 2024-09-14 17:09:37 -04:00
Brett 494125214f new config function are more useful in pratice. 2024-09-14 16:35:09 -04:00
Brett 0869509c6a fix naming? 2024-09-08 20:15:17 -04:00
Brett cd9ec507d6 rename 2024-09-06 14:17:00 -04:00
Brett 56a3c2f836 meow 2024-09-06 00:22:04 -04:00
Brett 7410dfe0ff replaced format file 2024-09-05 17:18:30 -04:00
Brett 7198a8b0c3 silly little guy (fix the allocator) 2024-09-04 16:03:13 -04:00
Brett 82cc1aff96 mmap 2024-09-04 02:42:45 -04:00
Brett a7645d9dde silly 2024-09-02 12:38:50 -04:00
Brett ab482f1a1c cleanup and allocations 2024-09-01 21:55:29 -04:00
Brett 79e080cfd3 fix 2024-08-27 17:25:37 -04:00
Brett b6354bed78 move the gp random into blt 2024-08-27 16:31:27 -04:00
Brett 6632d04528 fix to rounding func 2024-08-23 22:26:43 -04:00
Brett 1b09483af0 new format for bytes, rounding functions / types, they don't work.
rounding up at least
2024-08-23 21:13:16 -04:00
Brett 675c4234bc rename, going to make a new allocator 2024-08-22 02:45:20 -04:00
Brett 9ce6c89ce0 no idea if this will work 2024-08-20 12:46:49 -04:00
Brett 78710a12cc atomic allocator might not be possible 2024-08-19 20:03:46 -04:00
Brett 72211e3d7b atomic allocator 2024-08-19 12:13:13 -04:00
Brett daa9757375 no work only paperclip 2024-08-18 19:59:28 -04:00
Brett a0a855463d mmap atomic 2024-08-18 14:00:45 -04:00
Brett 97990401e2 atomic use count 2024-08-17 19:55:55 -04:00
Brett 941aa6809c update span to have implict copy constructor 2024-08-16 18:36:36 -04:00
Brett 627f8022f2 fix expected on clang 2024-08-16 18:00:28 -04:00
Brett 6f06647a21 meow 2024-08-13 00:33:44 -04:00
Brett c7e3accb9d working on meta 2024-08-12 22:02:54 -04:00
Brett 644f426843 might've borked expected 2024-08-12 02:08:51 -04:00
Brett 92300bc6a2 meta 2024-08-11 18:47:58 -04:00
Brett 4327b34c84 check for func 2024-08-11 13:33:40 -04:00
Brett 99e735b760 silly 2024-08-09 23:38:25 -04:00
Brett 941aedb510 make const const again 2024-08-07 01:34:31 -04:00
Brett 42fa378200 fix the stupid iterator 2024-08-06 18:50:50 -04:00
Brett 785565f03e forgot to remove template types on reverse iterate 2024-08-06 18:40:41 -04:00
Brett 3e8b616bf9 fix lambda_helper 2024-08-06 03:44:20 -04:00
Brett f9938691ec reverse range iterate 2024-08-06 02:46:30 -04:00
Brett 8535480ad5 add some checks to the profiler 2024-08-05 02:14:41 -04:00
Brett 79ad108fab unreachable 2024-08-04 21:23:39 -04:00
Brett befd5e0ca1 include the abort anyways incase your linter is stupid 2024-08-03 19:51:20 -04:00
Brett e979447de0 when assertions fail throw an exception instead of aborting 2024-08-03 19:50:26 -04:00
Brett 6acbc24245 streamable meta 2024-08-03 17:44:58 -04:00
Brett fb17ff16c0 abort correctiono 2024-08-02 23:46:51 -04:00
Brett c3fdfbade6 versioning fix 2024-08-02 23:36:34 -04:00
Brett d579ddf1cc annoying hashmaps 2024-08-02 23:36:03 -04:00
Brett 7a551435a0 doctor give me exceptions 2024-08-02 23:30:17 -04:00
Brett f99e6b3db9 make expanding buffer externally expandable with copy! 2024-07-29 19:34:03 -04:00
Brett 5ab01e43df ref utility 2024-07-26 22:08:25 -04:00
Brett 394dff9cc4 newline in logger 2024-07-22 20:27:50 -04:00
Brett 4114de74db randomness silly 2024-07-21 20:28:08 -04:00
Brett 27d1b94493 enumerate on arrays 2024-07-21 18:46:15 -04:00
Brett cd5c98d748 minior vector change 2024-07-20 15:44:57 -04:00
Brett 7c49a8a854 slight name change
iterator enumeration was closer to iteration, name now reflects that
2024-07-20 13:31:58 -04:00
Brett 60f77961fb barrier 2024-07-14 14:08:51 -04:00
Brett 9a437ec75a make abort use abort() 2024-07-12 21:49:02 -04:00
Brett c5f3d9ba3b we need to make a profiler_v3 2024-07-11 19:09:41 -04:00
Brett 456eeb12ac add missing %s in abort message 2024-07-11 02:30:54 -04:00
Brett 4de3aeb87c meta 2024-07-10 20:41:26 -04:00
Brett b6048ed39c add default types to random functions 2024-07-09 18:21:32 -04:00
Brett 42dcfe069f randomness renaming 2024-07-09 18:07:12 -04:00
Brett c88f1c3e38 breaking changes to random 2024-07-09 14:11:07 -04:00
Brett 5e65416684 patch ranges 2024-07-02 13:13:13 -04:00
Brett 4776546e35 ranges! 2024-07-02 12:57:51 -04:00
Brett 57ddcfca1e svo vector 2024-06-30 13:54:10 -04:00
Brett 1caae86e43 unfinished svo vector 2024-06-30 13:26:54 -04:00
Brett bccd2f4ba3 make ptr_iterator fully conceptually a random acccess iterator 2024-06-30 12:44:35 -04:00
Brett f3451b57ab vector 2024-06-30 03:20:47 -04:00
Brett 7778efce5c docs 2024-06-29 23:18:32 -04:00
Brett 114a04500a hello add docs fix names 2024-06-29 20:18:49 -04:00
Brett 1328095603 add gnu attributes 2024-06-29 14:05:03 -04:00
Brett cdb91d8007 add null check 2024-06-26 18:55:11 -04:00
Brett 2a34be2e7b fix expanding buffer, memory allocation now accounts for 0 (default 16) 2024-06-24 13:52:15 -04:00
Brett ac163a34b9 abort 2024-06-24 01:05:44 -04:00
Brett cc788e98f4 using in the type 2024-06-23 20:53:53 -04:00
Brett 1ca46b9d7b integer type 2024-06-21 17:35:19 -04:00
Brett 9ad96191ff memory love, expanding buffer. might already have one of theses. should makes docs! 2024-06-19 21:16:58 -04:00
Brett 2266d64f04 add raw type string 2024-06-19 13:07:39 -04:00
Brett 8d3bfbcdc3 use pointer type 2024-06-04 14:00:05 -04:00
Brett 00f368eb23 pointer difference type 2024-06-04 13:59:32 -04:00
Brett bc68e6dd4a allocator changes, allow huge pages 2024-06-03 02:14:43 -04:00
Brett a8b2bc2d01 easing functions 2024-05-14 21:57:51 -04:00
Brett a3e187bd01 constexpr on vector functions 2024-05-14 21:31:59 -04:00
Brett 9bd19ed372 color interpolation 2024-05-14 21:30:28 -04:00
Brett 12169a7001 matrix functions for vec2 operations, defaults are logically assumed. 2024-05-13 21:31:05 -04:00
Brett 9c0fc81969 quick push to make sure branches are up to date 2024-05-11 20:41:32 -04:00
Brett f228cfbbe3 move template functions into cpp file 2024-05-11 17:44:37 -04:00
Brett fa5083b637 templating works for what i need
might be bugs in some functions
2024-05-11 13:39:21 -04:00
Brett 7cd736cf6c templating works for what i need
might be bugs in it still
2024-05-11 13:39:07 -04:00
Brett c3cd00cf04 broekn 2024-05-10 21:36:38 -04:00
Brett 83329f6736 freezing hands 2024-05-10 19:01:23 -04:00
Brett ce7c1357e0 working on templating 2024-05-10 12:56:48 -04:00
Brett 4ef3fe7573 template broken 2024-05-10 01:53:50 -04:00
Brett da82a40699 silly 2024-05-09 21:53:49 -04:00
Brett fa979a2fd4 silly 2024-05-09 21:53:08 -04:00
Brett b857bc96ef template engine 2024-05-09 13:51:25 -04:00
Brett 943fb84211 fix missing ; 2024-05-05 13:14:41 -04:00
Brett 9b86278a29 constexpr on vecs 2024-05-03 15:57:04 -04:00
Brett 3f0ea887cd allow any type that can be static_cast to type of vector in operators like +, -, *. / 2024-05-01 21:28:42 -04:00
Brett 37da0bd76d support vectors with 1/(vec<T>) 2024-05-01 21:25:29 -04:00
Brett 8a5794cfee vec silly 2024-05-01 21:12:16 -04:00
Brett e6b4c4a330 change mat4x4 internal structure, adjugate and inverse now works
determinant probably does not
2024-05-01 12:11:53 -04:00
Brett 0a04408e70 inverse and bed 2024-05-01 03:27:17 -04:00
Brett 133728b641 make color no longer transparent 2024-04-29 21:46:32 -04:00
Brett 86fd4a2a9a inline make color 2024-04-29 21:45:01 -04:00
Brett 69e6a505d6 make color 2024-04-29 21:35:16 -04:00
Brett c8ce910fe1 warnings 2024-04-26 01:16:46 -04:00
Brett 1772e9a6d7 fix system and warnings 2024-04-25 19:35:05 -04:00
Brett c6a54f5106 simd disable 2024-04-25 17:42:03 -04:00
Brett 325508e807 forgot .data on elements 2024-04-12 00:04:23 -04:00
Brett 898760e938 allow access to vector data insides 2024-04-12 00:03:56 -04:00
60 changed files with 5998 additions and 737 deletions

View File

@ -1,8 +1,6 @@
cmake_minimum_required(VERSION 3.20)
include(cmake/color.cmake)
set(BLT_VERSION 0.16.8)
set(BLT_TEST_VERSION 0.0.1)
set(BLT_VERSION 1.0.2)
set(BLT_TARGET BLT)
@ -18,6 +16,7 @@ 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)
option(BUILD_PARSE "Build the BLT parsers" ON)
option(BUILD_FORMAT "Build the BLT formatters" ON)
option(BUILD_TESTS "Build the BLT test set" OFF)
@ -34,37 +33,47 @@ if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS)
endif ()
find_program(MOLD "mold")
configure_file(include/blt/config.h.in config/blt/config.h @ONLY)
message("Enabling library compilation")
if (${BUILD_STD} OR ${BUILD_PROFILING})
message("-- Building ${Yellow}standard${ColourReset} cxx files")
message(STATUS "Building ${Yellow}standard${ColourReset} cxx files")
file(GLOB_RECURSE STD_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/std/*.cpp")
else ()
set(STD_FILES "")
endif ()
if (${BUILD_PROFILING})
message("-- Building ${Yellow}profiling${ColourReset} cxx files")
message(STATUS "Building ${Yellow}profiling${ColourReset} cxx files")
file(GLOB_RECURSE PROFILING_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/profiling/*.cpp")
else ()
set(PROFILING_FILES "")
endif ()
if (${BUILD_FS})
message("-- Building ${Yellow}filesystem${ColourReset} cxx files")
message(STATUS "Building ${Yellow}filesystem${ColourReset} cxx files")
file(GLOB_RECURSE FS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/fs/*.cpp")
else ()
set(FS_FILES "")
endif ()
if (${BUILD_PARSE})
message("-- Building ${Yellow}parser${ColourReset} cxx files")
message(STATUS "Building ${Yellow}parser${ColourReset} cxx files")
file(GLOB_RECURSE PARSE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/parse/*.cpp")
else ()
set(PARSE_FILES "")
endif ()
if (${BUILD_FORMAT})
message(STATUS "Building ${Yellow}format${ColourReset} cxx files")
file(GLOB_RECURSE FORMAT_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/format/*.cpp")
else ()
set(FORMAT_FILES ""
include/blt/std/iterator.h)
endif ()
if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
message("Found Parallel Hashmaps library, using ${Yellow}phmap${ColourReset} over ${Red}std::unordered_map${ColourReset}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
@ -84,17 +93,23 @@ endif ()
include_directories(include/)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/config/)
message("Standard Files ${STD_FILES}")
message("Profiler Files ${PROFILING_FILES}")
message("FS Files ${FS_FILES}")
message("Parser Files ${PARSE_FILES}")
add_library(${BLT_TARGET} ${STD_FILES} ${PROFILING_FILES} ${FS_FILES} ${PARSE_FILES} ${FORMAT_FILES})
string(REPLACE "+" "\\+" escaped_source ${CMAKE_CURRENT_SOURCE_DIR})
string(APPEND escaped_source "/src/blt/.*/")
list(TRANSFORM STD_FILES REPLACE ${escaped_source} "")
list(TRANSFORM PROFILING_FILES REPLACE ${escaped_source} "")
list(TRANSFORM FS_FILES REPLACE ${escaped_source} "")
list(TRANSFORM PARSE_FILES REPLACE ${escaped_source} "")
message("Standard Files ${Magenta}${STD_FILES}${ColourReset}")
message("Profiler Files ${Magenta}${PROFILING_FILES}${ColourReset}")
message("FS Files ${Magenta}${FS_FILES}${ColourReset}")
message("Parser Files ${Magenta}${PARSE_FILES}${ColourReset}")
message("Source: ${CMAKE_SOURCE_DIR}")
message("Current Source: ${CMAKE_CURRENT_SOURCE_DIR}")
message("Binary: ${CMAKE_BINARY_DIR}")
message("Current Binary: ${CMAKE_CURRENT_BINARY_DIR}")
add_library(${BLT_TARGET} ${STD_FILES} ${PROFILING_FILES} ${FS_FILES} ${PARSE_FILES})
if (${ZLIB_FOUND})
target_link_libraries(${BLT_TARGET} PUBLIC ZLIB::ZLIB)
endif ()
@ -124,30 +139,64 @@ install(FILES ${CMAKE_BINARY_DIR}/config/blt/config.h DESTINATION ${CMAKE_INSTAL
set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${BLT_VERSION})
set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR})
if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND)
target_compile_options(${BLT_TARGET} PUBLIC -fuse-ld=mold)
endif ()
install(TARGETS ${BLT_TARGET}
CONFIGURATIONS RelWithDebInfo
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
macro(blt_add_project name source type)
project(${name}-${type})
add_executable(${name}-${type} ${source})
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)
target_compile_definitions(${name}-${type} PRIVATE BLT_DEBUG_LEVEL=${DEBUG_LEVEL})
if (NOT ${MOLD} STREQUAL MOLD-NOTFOUND)
target_compile_options(${name}-${type} PUBLIC -fuse-ld=mold)
endif ()
if (${TRACK_ALLOCATIONS})
target_compile_definitions(${name}-${type} PRIVATE BLT_TRACK_ALLOCATIONS=1)
endif ()
if (${ENABLE_ADDRSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=address)
target_link_options(${name}-${type} PRIVATE -fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=undefined)
target_link_options(${name}-${type} PRIVATE -fsanitize=undefined)
endif ()
if (${ENABLE_TSAN} MATCHES ON)
target_compile_options(${name}-${type} PRIVATE -fsanitize=thread)
target_link_options(${name}-${type} PRIVATE -fsanitize=thread)
endif ()
add_test(NAME ${name} COMMAND ${name}-${type})
set(failRegex "\\[WARN\\]" "FAIL" "ERROR" "FATAL" "exception")
set_property(TEST ${name} PROPERTY FAIL_REGULAR_EXPRESSION "${failRegex}")
project(${BLT_TARGET})
endmacro()
if (${BUILD_TESTS})
message("Building test version ${BLT_TEST_VERSION}")
project(BLT_TESTS VERSION ${BLT_TEST_VERSION})
message("Building tests for version ${BLT_VERSION}")
include_directories(tests/include)
file(GLOB_RECURSE TEST_FILES "${CMAKE_CURRENT_SOURCE_DIR}/tests/src/*.cpp")
message("Using files ${TEST_FILES}")
add_executable(BLT_TESTS ${TEST_FILES})
target_link_libraries(BLT_TESTS PRIVATE BLT)
include(cmake/warnings.cmake)
include(cmake/sanitizers.cmake)
blt_add_project(blt-iterator tests/iterator_tests.cpp test)
message("Built tests")
endif ()
project(BLT)
project(BLT)

View File

@ -187,7 +187,7 @@ measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
the covered work, and you disclaim any intention to limit operation_t or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
@ -238,7 +238,7 @@ and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
beyond what the individual_t works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
@ -266,7 +266,7 @@ in one of these ways:
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
c) Convey individual_t copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
@ -331,7 +331,7 @@ requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
adversely affects the operation_t of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,

View File

@ -1,4 +1,4 @@
# **BLT v0.16**
# **BLT v0.20**
A C++17 common utilities library to make thing easy!
![Icon](icon_large.png)
@ -55,7 +55,7 @@ If you are using BLT as a CMake library (as you should!) this is done for you.
- Using CMake
- Several options are provided which disable various logging contexts, as such global logging can be disabled by passing `-DBLT_DISABLE_LOGGING:BOOL=ON`
- Options follow the pattern of `BLT_DISABLE_LEVEL` where level is one of `TRACE`,`DEBUG`,`INFO`,`WARN`,`ERROR`, or `FATAL`.
- This allows for individual logging levels to be disabled while leaving the others functional. These options can be combined.
- This allows for individual_t logging levels to be disabled while leaving the others functional. These options can be combined.
- See CMakeLists.txt for a complete list of options.
- Standalone
- The CMake options define global variables in a config file. If you are using logging standalone you will need to remove the config include.
@ -98,4 +98,4 @@ from the v1 profiler. It is encouraged to use the new blt::* profile functions o
- `std::chrono::duration_cast<std::chrono::nanoseconds>(std::chrono::high_resolution_clock::now().time_since_epoch()).count()` becomes `blt::system::nanoTime()`
- Formatted time string with year/month/date + current time
- ## Profiling
- Basic profiler with history and formatted output
- Basic profiler with history and formatted output

View File

@ -4,7 +4,7 @@
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="_DS3495almi1g_SXSTfi-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-1" target="_DS3495almi1g_SXSTfi-3">
<mxCell id="_DS3495almi1g_SXSTfi-13" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-1" target="_DS3495almi1g_SXSTfi-3">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="440" y="240" />
@ -12,7 +12,7 @@
</Array>
</mxGeometry>
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-1" target="_DS3495almi1g_SXSTfi-2">
<mxCell id="_DS3495almi1g_SXSTfi-14" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-1" target="_DS3495almi1g_SXSTfi-2">
<mxGeometry relative="1" as="geometry">
<Array as="points">
<mxPoint x="440" y="240" />
@ -23,25 +23,25 @@
<mxCell id="_DS3495almi1g_SXSTfi-1" value="&lt;div&gt;&lt;p style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;&lt;span style=&quot;background-color: rgb(255, 248, 247);&quot;&gt;arg_data_t&lt;/span&gt;&lt;/p&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="380" y="130" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-2" target="_DS3495almi1g_SXSTfi-5">
<mxCell id="_DS3495almi1g_SXSTfi-15" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-2" target="_DS3495almi1g_SXSTfi-5">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-2" value="&lt;div&gt;&lt;pre style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;&lt;font style=&quot;background-color: rgb(252, 245, 245);&quot; color=&quot;#030303&quot;&gt;arg_data_vec_t&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="560" y="280" width="150" height="60" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-6">
<mxCell id="_DS3495almi1g_SXSTfi-10" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-6">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-7">
<mxCell id="_DS3495almi1g_SXSTfi-11" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-7">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-9">
<mxCell id="_DS3495almi1g_SXSTfi-12" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-3" target="_DS3495almi1g_SXSTfi-9">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-3" value="&lt;div&gt;&lt;pre style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;&lt;font style=&quot;background-color: rgb(255, 248, 247);&quot; color=&quot;#030303&quot;&gt;arg_data_internal_t&lt;/font&gt;&lt;/pre&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="160" y="280" width="160" height="60" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-5" target="_DS3495almi1g_SXSTfi-19">
<mxCell id="_DS3495almi1g_SXSTfi-23" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-5" target="_DS3495almi1g_SXSTfi-19">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-5" value="&lt;pre style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;std::vector&amp;lt;arg_data_internal_t&amp;gt;&lt;/pre&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
@ -56,13 +56,13 @@
<mxCell id="_DS3495almi1g_SXSTfi-9" value="&lt;div style=&quot;background-color: rgb(30, 31, 34);&quot;&gt;&lt;pre style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;&lt;span style=&quot;background-color: rgb(255, 248, 247);&quot;&gt;int32_t&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
<mxGeometry x="320" y="440" width="120" height="60" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-20">
<mxCell id="_DS3495almi1g_SXSTfi-16" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-20">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-21">
<mxCell id="_DS3495almi1g_SXSTfi-17" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;entryX=0.5;entryY=0;entryDx=0;entryDy=0;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-21">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-22">
<mxCell id="_DS3495almi1g_SXSTfi-18" style="edgeStyle=orthogonalEdgeStyle;rounded=0;orthogonalLoop=1;jettySize=auto;html=1;" edge_t="1" parent="1" source="_DS3495almi1g_SXSTfi-19" target="_DS3495almi1g_SXSTfi-22">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="_DS3495almi1g_SXSTfi-19" value="&lt;div style=&quot;background-color: rgb(30, 31, 34);&quot;&gt;&lt;pre style=&quot;font-family:&#39;JetBrains Mono&#39;,monospace;font-size:9.8pt;&quot;&gt;&lt;span style=&quot;background-color: rgb(255, 248, 247);&quot;&gt;arg_data_internal_t&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">

View File

@ -1,19 +1,28 @@
include(cmake/color.cmake)
message("Enabling platform specific compile options for ${PROJECT_NAME}")
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(Blue "${Esc}[34m")
set(Green "${Esc}[32m")
endif ()
message("Enabling platform specific compile options for ${Blue}${PROJECT_NAME}${ColourReset}")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# using Clang
message("-- Clang Compile: ${Green}-Wall -Wextra -Wpedantic -Weverything -fdiagnostics-color=always${ColourReset}")
message("-- Clang Link: ${Green}-export_dynamic${ColourReset}")
message("-- Clang libs: ${Green}stdc++fs${ColourReset}")
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Wextra -Wpedantic -Weverything -fdiagnostics-color=always)
target_link_options(${PROJECT_NAME} PUBLIC -export_dynamic)
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
message(STATUS "Clang Compile: ${Green}-Wall -Wextra -Wpedantic -Weverything -fdiagnostics-color=always${ColourReset}")
message(STATUS "Clang Link: ${Green}-export_dynamic${ColourReset}")
message(STATUS "Clang 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 -export_dynamic -rdynamic)
if(NOT EMSCRIPTEN)
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
message("-- GCC Compile: ${Green}-Wall -Wextra -Wpedantic -fdiagnostics-color=always${ColourReset}")
message("-- GCC Link: ${Green}-rdynamic${ColourReset}")
message("-- GCC libs: ${Green}stdc++fs${ColourReset}")
target_compile_options(${PROJECT_NAME} PUBLIC -Wall -Wextra -Wpedantic -fdiagnostics-color=always)
message(STATUS "GCC Compile: ${Green}-Wall -Wextra -Wpedantic -fdiagnostics-color=always${ColourReset}")
message(STATUS "GCC Link: ${Green}-rdynamic${ColourReset}")
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)
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
include(GNUInstallDirs)
@ -21,8 +30,8 @@ elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# using Intel C++
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
message("-- MSVC Compile: ${Green}/Wall${ColourReset}")
message("-- MSVC Link: ${Green}${ColourReset}")
message("-- MSVC libs: ${Green}${ColourReset}")
message(STATUS "MSVC Compile: ${Green}/Wall${ColourReset}")
message(STATUS "MSVC Link: ${Green}${ColourReset}")
message(STATUS "MSVC libs: ${Green}${ColourReset}")
target_compile_options(${PROJECT_NAME} PUBLIC /Wall)
endif ()

264
commit.py
View File

@ -1,6 +1,13 @@
#!/usr/bin/python3
import subprocess
import argparse
import sys
import os
import itertools
import requests
import json
from pathlib import Path
#---------------------------------------
# CONFIG
@ -8,12 +15,110 @@ import subprocess
VERSION_BEGIN_STR = "set(BLT_VERSION "
VERSION_END_STR = ")"
PATCH_LIMIT = 1000
#---------------------------------------
# DO NOT TOUCH
#---------------------------------------
USER_HOME = Path.home()
ENVIRONMENT_DATA_LOCATION = USER_HOME / ".brett_scripts.env"
if sys.platform.startswith("win"):
CONFIG_FILE_DIRECTORY = Path(os.getenv('APPDATA') + "\blt")
CONFIG_FILE_LOCATION = Path(CONFIG_FILE_DIRECTORY + "\commit_config.json")
else:
XDG_CONFIG_HOME = os.environ.get('XDG_CONFIG_HOME')
if XDG_CONFIG_HOME is None:
XDG_CONFIG_HOME = USER_HOME / ".config"
else:
XDG_CONFIG_HOME = Path(XDG_CONFIG_HOME)
if len(str(XDG_CONFIG_HOME)) == 0:
XDG_CONFIG_HOME = USER_HOME
CONFIG_FILE_DIRECTORY = XDG_CONFIG_HOME / "blt"
CONFIG_FILE_LOCATION = CONFIG_FILE_DIRECTORY / "commit_config.json"
class Config:
def __init__(self):
# Inline with semantic versioning it doesn't make sense to branch / release on minor
self.branch_on_major = True
self.branch_on_minor = False
self.release_on_major = True
self.release_on_minor = True
self.main_branch = "main"
self.patch_limit = -1
def toJSON(self):
return json.dumps(self, default=lambda o: o.__dict__, sort_keys=True, indent=4)
def fromJSON(file):
with open(file, "r") as f:
j = json.load(f)
obj = Config()
[setattr(obj, key, val) for key, val in j.items() if hasattr(obj, key)]
if obj.branch_on_minor:
obj.branch_on_major = True
return obj
def from_file(file):
values = {}
if (not os.path.exists(file)):
return Config()
with open(file, "r") as f:
j = json.load(f)
obj = Config()
[setattr(obj, key, val) for key, val in j.items() if hasattr(obj, key)]
return obj
def save_to_file(self, file):
dir_index = str(file).rfind("/")
dir = str(file)[:dir_index]
if not os.path.exists(dir):
print(f"Creating config directory {dir}")
os.makedirs(dir)
with open(file, "w") as f:
json.dump(self, f, default=lambda o: o.__dict__, sort_keys=True, indent=4)
class EnvData:
def __init__(self, github_username = '', github_token = ''):
self.github_token = github_token
self.github_username = github_username
def get_env_from_file(file):
f = open(file, "rt")
values = {}
for line in f:
if line.startswith("export"):
content = line.split("=")
for idx, c in enumerate(content):
content[idx] = c.replace("export", "").strip()
values[content[0]] = content[1].replace("\"", "").replace("'", "")
try:
github_token = values["github_token"]
except Exception:
print("Failed to parse github token!")
try:
github_username = values["github_username"]
except:
print("Failed to parse github username! Assuming you are me!")
github_username = "Tri11Paragon"
return EnvData(github_username=github_username, github_token=github_token)
def open_process(command, print_out = True):
process = subprocess.Popen(command, stderr=subprocess.PIPE, stdout=subprocess.PIPE)
stdout, stderr = process.communicate()
exit_code = process.wait()
str_out = stdout.decode('utf8')
str_err = stderr.decode('utf8')
if print_out and len(str_out) > 0:
print(str_out, end='')
if print_out and len(str_err) > 0:
print(str_err, end='')
#print(stdout, stderr, exit_code)
return (stdout, stderr, exit_code)
def load_cmake():
cmake_file = open("CMakeLists.txt", 'r')
cmake_text = cmake_file.read()
@ -38,9 +143,8 @@ def split_version(cmake_text):
def recombine(cmake_text, version_parts, begin, end):
constructed_version = version_parts[0] + '.' + version_parts[1] + '.' + version_parts[2]
constructed_text_begin = cmake_text[0:begin]
constrcuted_text_end = cmake_text[end::]
return constructed_text_begin + constructed_version + constrcuted_text_end
constructed_text_end = cmake_text[end::]
return constructed_text_begin + constructed_version + constructed_text_end
def inc_major(cmake_text):
version_parts, begin, end = split_version(cmake_text)
@ -55,32 +159,158 @@ def inc_minor(cmake_text):
version_parts[2] = '0'
return recombine(cmake_text, version_parts, begin, end)
def inc_patch(cmake_text):
def inc_patch(config: Config, cmake_text):
version_parts, begin, end = split_version(cmake_text)
if int(version_parts[2]) + 1 >= PATCH_LIMIT:
if config.patch_limit > 0 and int(version_parts[2]) + 1 >= config.patch_limit:
return inc_minor(cmake_text)
version_parts[2] = str(int(version_parts[2]) + 1)
return recombine(cmake_text, version_parts, begin, end)
cmake_text = load_cmake()
cmake_version = get_version(cmake_text)[0]
print(f"Current Version: {cmake_version}")
def make_branch(config: Config, name):
print(f"Making new branch {name}")
subprocess.call(["git", "checkout", "-b", name])
subprocess.call(["git", "merge", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
def sync_branch(config: Config, version_parts, args):
if config.branch_on_major:
# Branch will be created.
if args.minor:
return;
try:
type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
def make_release(env: EnvData, name):
print(f"Making new release {name}")
repos_v = open_process(["git", "remote", "-v"])[0].splitlines()
urls = []
for line in repos_v:
origin = ''.join(itertools.takewhile(str.isalpha, line.decode('utf8')))
urls.append(open_process(["git", "remote", "get-url", origin], False)[0].decode('utf8').replace("\n", "").replace(".git", "").replace("https://github.com/", "https://api.github.com/repos/") + "/releases")
urls = set(urls)
data = {
'tag_name': name,
'name': name,
'body': "Automated Release '" + name + "'",
'draft': False,
'prerelease': False
}
headers = {
'Authorization': f'Bearer {env.github_token}',
'Accept': 'application/vnd.github+json',
'X-GitHub-Api-Version': '2022-11-28'
}
for url in urls:
response = requests.post(url, headers=headers, data=json.dumps(data))
if response.status_code == 201:
print('Release created successfully!')
release_data = response.json()
print(f"Release URL: {release_data['html_url']}")
else:
print(f"Failed to create release: {response.status_code}")
print(response.json())
if type.startswith('M'):
def main():
parser = argparse.ArgumentParser(
prog="Commit Helper",
description="Help you make pretty commits :3")
parser.add_argument("action", nargs='?', default=None)
parser.add_argument("-p", "--patch", action='store_true', default=False, required=False)
parser.add_argument("-m", "--minor", action='store_true', default=False, required=False)
parser.add_argument("-M", "--major", action='store_true', default=False, required=False)
parser.add_argument('-e', "--env", help="environment file", required=False, default=None)
parser.add_argument('-c', "--config", help="config file", required=False, default=None)
parser.add_argument("--create-default-config", action="store_true", default=False, required=False)
parser.add_argument("--no-release", action="store_true", default=False, required=False)
parser.add_argument("--no-branch", action="store_true", default=False, required=False)
args = parser.parse_args()
if args.create_default_config:
config = Config()
config.save_to_file(args.config if args.config is not None else CONFIG_FILE_LOCATION)
return
if args.env is not None:
env = EnvData.get_env_from_file(args.e)
else:
env = EnvData.get_env_from_file(ENVIRONMENT_DATA_LOCATION)
if args.config is not None:
config = Config.from_file(args.config)
else:
config = Config.from_file(CONFIG_FILE_LOCATION)
cmake_text = load_cmake()
cmake_version = get_version(cmake_text)[0]
print(f"Current Version: {cmake_version}")
if not (args.patch or args.minor or args.major):
try:
if args.action is not None:
type = args.action
else:
type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
if type.startswith('M'):
args.major = True
elif type.startswith('m'):
args.minor = True
elif type.startswith('p') or type.startswith('P') or len(type) == 0:
args.patch = True
except KeyboardInterrupt:
print("\nCancelling!")
return
if args.major:
print("Selected major")
write_cmake(inc_major(cmake_text))
elif type.startswith('m'):
elif args.minor:
print("Selected minor")
write_cmake(inc_minor(cmake_text))
elif type.startswith('p') or type.startswith('P') or len(type) == 0:
elif args.patch:
print("Selected patch")
write_cmake(inc_patch(cmake_text))
write_cmake(inc_patch(config, cmake_text))
subprocess.call(["git", "add", "*"])
subprocess.call(["git", "commit"])
cmake_text = load_cmake()
version_parts = split_version(cmake_text)[0]
if args.major:
if config.branch_on_major:
if not args.no_branch:
make_branch(config, "v" + str(version_parts[0]))
if args.minor:
if config.branch_on_minor:
if not args.no_branch:
make_branch(config, "v" + str(version_parts[0]) + "." + str(version_parts[1]))
elif config.branch_on_major:
subprocess.call(["git", "checkout", "v" + str(version_parts[0])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
if args.patch:
if config.branch_on_minor:
subprocess.call(["git", "checkout", "v" + str(version_parts[0]) + "." + str(version_parts[1])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
elif config.branch_on_major:
subprocess.call(["git", "checkout", "v" + str(version_parts[0])])
subprocess.call(["git", "rebase", config.main_branch])
subprocess.call(["git", "checkout", config.main_branch])
sync_branch(config=config, version_parts=version_parts, args=args)
subprocess.call(["sh", "-c", "git remote | xargs -L1 git push --all"])
except KeyboardInterrupt:
print("\nCancelling!")
if args.major:
if not args.no_release and config.release_on_major:
make_release(env, "v" + str(version_parts[0]))
if args.minor:
if not args.no_release and config.release_on_minor:
make_release(env, "v" + str(version_parts[0]) + "." + str(version_parts[1]))
if __name__ == "__main__":
main()

111
include/blt/format/boxing.h Normal file
View File

@ -0,0 +1,111 @@
#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_BOXING_H
#define BLT_BOXING_H
#include <blt/std/types.h>
#include <blt/std/logging.h>
#include <string>
namespace blt
{
namespace detail
{
class log_box_base_t
{
public:
explicit log_box_base_t(std::string_view title, blt::size_t padding = 0): padding(padding), title(title)
{}
template<typename Logger>
void make_padding(Logger& logger)
{
for (blt::size_t i = 0; i < padding; i++)
logger << '-';
}
template<typename Logger>
void make_full_width_line(Logger& logger)
{
for (blt::size_t i = 0; i < padding * 2 + 2 + title.size(); i++)
logger << '-';
}
template<typename Logger>
void make_full_title(Logger& logger)
{
make_padding(logger);
if (padding > 0)
logger << "{";
logger << title;
if (padding > 0)
logger << "}";
make_padding(logger);
}
protected:
blt::size_t padding;
std::string title;
};
}
template<typename Logger>
class log_box_t : detail::log_box_base_t
{
public:
log_box_t(Logger& logger, std::string_view title, blt::size_t padding = 0): detail::log_box_base_t(title, padding), logger(logger)
{
make_full_title(logger);
logger << '\n';
}
~log_box_t()
{
make_full_width_line(logger);
logger << '\n';
}
private:
Logger& logger;
};
template<>
class log_box_t<blt::logging::logger> : detail::log_box_base_t
{
public:
log_box_t(blt::logging::logger logger, std::string_view title, blt::size_t padding = 0): detail::log_box_base_t(title, padding), logger(logger)
{
make_full_title(logger);
logger << '\n';
}
~log_box_t()
{
make_full_width_line(logger);
logger << '\n';
}
private:
blt::logging::logger logger;
};
template<typename Logger>
log_box_t(Logger&& logger, std::string_view, blt::size_t) -> log_box_t<Logger>;
}
#endif //BLT_BOXING_H

View File

@ -11,25 +11,36 @@
#include <utility>
#include <vector>
#include <blt/math/math.h>
#include <blt/std/types.h>
#include <algorithm>
#include <string_view>
#include "memory.h"
#include "vector.h"
#include <blt/std/vector.h>
#include <variant>
namespace blt::string
{
template<typename T>
static inline std::string withGrouping(T t, size_t group = 3)
{
// TODO: all this + make it faster
static_assert(std::is_integral_v<T>, "Must be integer type! (Floats currently not supported!)");
static_assert(std::is_arithmetic_v<T> && "Must be arithmetic type!");
auto str = std::to_string(t);
std::string ret;
ret.reserve(str.size());
size_t count = 0;
for (int64_t i = str.size() - 1; i >= 0; i--)
blt::size_t count = 0;
auto start_pos = static_cast<blt::i64>(str.size() - 1);
for (auto i = start_pos; i >= 0; i--)
{
if (str[i] == '.')
{
start_pos = i - 1;
break;
}
}
for (auto i = static_cast<blt::i64>(str.size() - 1); i > start_pos; i--)
ret += str[i];
for (auto i = start_pos; i >= 0; i--)
{
ret += str[i];
if (count++ % (group) == group - 1 && i != 0)
@ -38,27 +49,118 @@ namespace blt::string
std::reverse(ret.begin(), ret.end());
return ret;
}
// negative decimal places will not round.
template<int decimal_places = -1>
static inline std::string fromBytes(unsigned long bytes)
}
namespace blt
{
class byte_convert_t
{
if (bytes > 1073741824)
{
// gigabyte
return std::to_string(round_up<decimal_places>((double) bytes / 1024.0 / 1024.0 / 1024.0)) += "gb";
} else if (bytes > 1048576)
{
// megabyte
return std::to_string(round_up<decimal_places>((double) bytes / 1024.0 / 1024.0)) += "mb";
} else if (bytes > 1024)
{
// kilobyte
return std::to_string(round_up<decimal_places>((double) bytes / 1024.0)) += "kb";
} else
{
return std::to_string(bytes) += "b";
}
public:
enum class byte_t : blt::u64
{
Bytes = 1,
Kilobyte = 1024,
Megabyte = 1024 * 1024,
Gigabyte = 1024 * 1024 * 1024,
};
explicit byte_convert_t(blt::u64 bytes): bytes(bytes)
{}
byte_convert_t(blt::u64 bytes, byte_t convert_type): bytes(bytes), type(convert_type)
{
converted = static_cast<double>(bytes) / static_cast<double>(static_cast<blt::u64>(type));
}
byte_convert_t& convert_to_nearest_type()
{
if (bytes > 1073741824)
{
// gigabyte
type = byte_t::Gigabyte;
} else if (bytes > 1048576)
{
// megabyte
type = byte_t::Megabyte;
} else if (bytes > 1024)
{
// kilobyte
type = byte_t::Kilobyte;
} else
{
type = byte_t::Bytes;
}
converted = static_cast<double>(bytes) / static_cast<double>(static_cast<blt::u64>(type));
return *this;
}
[[nodiscard]] std::string_view type_string() const
{
switch (type)
{
case byte_t::Bytes:
return "b";
case byte_t::Kilobyte:
return "KiB";
case byte_t::Megabyte:
return "MiB";
case byte_t::Gigabyte:
return "GiB";
}
return "NotPossible!";
}
[[nodiscard]] double getConverted() const
{
return converted;
}
template<blt::i64 decimal_places = -1, template<blt::i64> typename round_function = round_up_t>
[[nodiscard]] double getConvertedRound() const
{
round_function<decimal_places> convert{};
return convert(converted);
}
template<blt::i64 decimal_places = -1, template<blt::i64> typename round_function = round_up_t>
[[nodiscard]] std::string to_pretty_string() const
{
auto str = string::withGrouping(getConvertedRound<decimal_places, round_function>(), 3);
str += type_string();
return str;
}
[[nodiscard]] blt::u64 getBytes() const
{
return bytes;
}
[[nodiscard]] byte_t getType() const
{
return type;
}
private:
blt::u64 bytes = 0;
byte_t type = byte_t::Bytes;
double converted = 0;
};
}
namespace blt::string
{
// negative decimal places will not round.
template<blt::i64 decimal_places = -1>
static inline std::string fromBytes(blt::u64 bytes)
{
byte_convert_t convert(bytes);
convert.convert_to_nearest_type();
return std::to_string(convert.getConvertedRound<decimal_places>()) + convert.type_string();
}
static inline std::string bytes_to_pretty(blt::u64 bytes)
{
return byte_convert_t(bytes).convert_to_nearest_type().to_pretty_string();
}
// TODO: update table formatter to use these!
@ -260,6 +362,7 @@ namespace blt::string
private:
std::string m_tableName;
int m_columnPadding;
[[maybe_unused]]
int m_maxColumnWidth;
std::vector<TableColumn> columns;
std::vector<TableRow> rows;

View File

@ -13,7 +13,7 @@
#include <unordered_map>
#include <algorithm>
#include "blt/std/format.h"
#include "blt/format/format.h"
#include "blt/fs/filesystem.h"
#include "blt/std/logging.h"
#include "blt/std/memory.h"

View File

@ -0,0 +1,30 @@
#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_ITERATOR_ITER_COMMON
#define BLT_ITERATOR_ITER_COMMON
#include <type_traits>
#include <iterator>
namespace blt
{
}
#endif //BLT_ITERATOR_ITER_COMMON

View File

@ -0,0 +1,754 @@
#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_ITERATOR_H
#define BLT_ITERATOR_H
#include <blt/std/types.h>
#include <blt/std/logging.h>
#include <blt/iterator/iter_common.h>
#include <blt/iterator/zip.h>
#include <blt/meta/meta.h>
#include <blt/meta/iterator.h>
#include <type_traits>
#include <iterator>
#include <tuple>
namespace blt
{
// forward declare useful types
template<typename Iter, typename = std::void_t<>>
class enumerator;
template<typename Iter, typename = std::void_t<>>
class enumerator_rev;
template<typename Iter1, typename Iter2, typename = std::void_t<>>
class pair_iterator;
template<typename Iter, typename Iter2, typename = std::void_t<>>
class pair_iterator_rev;
template<typename... Iter>
class zip_iterator;
template<typename... Iter>
class zip_iterator_rev;
namespace iterator
{
template<typename Iter, typename = std::void_t<>>
class enumerate_wrapper;
template<typename Iter1, typename Iter2, typename = std::void_t<>>
class pair_wrapper;
/**
* struct which is returned by the enumerator.
* @tparam T type to store.
*/
template<typename T>
struct enumerate_item
{
blt::size_t index;
T value;
};
/**
* base class for iterators which operate on pairs of values. Handles comparison.
* @tparam Iter1 first iterator type. this will be used for comparison.
* @tparam Iter2 second iterator type. this value is not modified by this class.
*/
template<typename Iter1, typename Iter2>
class dual_iterator_base
{
public:
explicit dual_iterator_base(Iter1 iter1, Iter2 iter2): m_iter1(std::move(iter1)), m_iter2(std::move(iter2))
{}
friend bool operator==(const dual_iterator_base& a, const dual_iterator_base& b)
{
return a.m_iter1 == b.m_iter1;
}
friend bool operator!=(const dual_iterator_base& a, const dual_iterator_base& b)
{
return a.m_iter1 != b.m_iter1;
}
auto iter1() const
{
return m_iter1;
}
auto iter2() const
{
return m_iter2;
}
protected:
Iter1 m_iter1;
Iter2 m_iter2;
};
/**
* Base class for all enumerator iterators. Handles the deference (*) operator.
* @tparam Iter iterator type
*/
template<typename Iter>
class enumerate_iterator_base : public dual_iterator_base<Iter, blt::size_t>
{
public:
explicit enumerate_iterator_base(Iter iter, blt::size_t place = 0):
dual_iterator_base<Iter, blt::size_t>(std::move(iter), place)
{}
enumerate_item<blt::meta::deref_return_t<Iter>> operator*() const
{
return {this->m_iter2, *this->m_iter1};
}
};
template<typename Iter1, typename Iter2>
class pair_iterator_base : public dual_iterator_base<Iter1, Iter2>
{
public:
using dual_iterator_base<Iter1, Iter2>::dual_iterator_base;
std::pair<blt::meta::deref_return_t<Iter1>, blt::meta::deref_return_t<Iter2>> operator*() const
{
return {*this->m_iter1, *this->m_iter2};
}
};
/**
* Forward iterator base class. Contains the ++ operator.
* @tparam Base iterator base type.
*/
template<typename Base>
class forward_iterator_base : public Base
{
public:
using Base::Base;
forward_iterator_base& operator++()
{
++this->m_iter1;
++this->m_iter2;
return *this;
}
forward_iterator_base operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
};
/**
* Bidirectional iterator base class. Contains the -- operator.
* @tparam Base iterator base type.
*/
template<typename Base>
class bidirectional_iterator_base : public Base
{
public:
using Base::Base;
bidirectional_iterator_base& operator--()
{
--this->m_iter1;
--this->m_iter2;
return *this;
}
bidirectional_iterator_base operator--(int)
{
auto tmp = *this;
--*this;
return tmp;
}
};
template<typename Iter>
using enumerate_forward_iterator = forward_iterator_base<enumerate_iterator_base<Iter>>;
template<typename Iter>
using enumerate_bidirectional_iterator = bidirectional_iterator_base<enumerate_forward_iterator<Iter>>;
template<typename Iter1, typename Iter2>
using pair_forward_iterator = forward_iterator_base<pair_iterator_base<Iter1, Iter2>>;
template<typename Iter1, typename Iter2>
using pair_bidirectional_iterator = bidirectional_iterator_base<pair_forward_iterator<Iter1, Iter2>>;
/**
* Enumerator wrapper class specialization for forward iterators.
* @tparam Iter iterator type
*/
template<typename Iter>
class enumerate_wrapper<Iter, std::enable_if_t<blt::meta::is_forward_iterator_v<Iter>, std::void_t<std::forward_iterator_tag>>>
: public enumerate_forward_iterator<Iter>
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = enumerate_item<blt::meta::deref_return_t<Iter>>;
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using pointer = value_type;
using reference = value_type;
using enumerate_forward_iterator<Iter>::enumerate_forward_iterator;
};
/**
* Pair wrapper class specialization for forward iterators.
* @tparam Iter iterator type
*/
template<typename Iter1, typename Iter2>
class pair_wrapper<Iter1, Iter2, std::enable_if_t<
blt::meta::is_forward_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::forward_iterator_tag>>> : public pair_forward_iterator<Iter1, Iter2>
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = std::pair<blt::meta::deref_return_t<Iter1>, blt::meta::deref_return_t<Iter2>>;
using difference_type = std::common_type_t<typename std::iterator_traits<Iter1>::difference_type, typename std::iterator_traits<Iter2>::difference_type>;
using pointer = value_type;
using reference = value_type;
using pair_forward_iterator<Iter1, Iter2>::pair_forward_iterator;
};
/**
* Enumerator wrapper class for bidirectional iterators or random access iterators.
* @tparam Iter iterator type.
*/
template<typename Iter>
class enumerate_wrapper<Iter, std::enable_if_t<blt::meta::is_bidirectional_or_better_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public enumerate_bidirectional_iterator<Iter>
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = enumerate_item<blt::meta::deref_return_t<Iter>>;
using difference_type = typename std::iterator_traits<Iter>::difference_type;
using pointer = value_type;
using reference = value_type;
using enumerate_bidirectional_iterator<Iter>::enumerate_bidirectional_iterator;
};
/**
* Pair wrapper class for bidirectional iterators or random access iterators.
* @tparam Iter iterator type.
*/
template<typename Iter1, typename Iter2>
class pair_wrapper<Iter1, Iter2, std::enable_if_t<
blt::meta::is_bidirectional_or_better_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::bidirectional_iterator_tag>>> : public pair_bidirectional_iterator<Iter1, Iter2>
{
public:
using iterator_category = std::bidirectional_iterator_tag;
using value_type = std::pair<blt::meta::deref_return_t<Iter1>, blt::meta::deref_return_t<Iter2>>;
using difference_type = std::common_type_t<typename std::iterator_traits<Iter1>::difference_type, typename std::iterator_traits<Iter2>::difference_type>;
using pointer = value_type;
using reference = value_type;
using pair_bidirectional_iterator<Iter1, Iter2>::pair_bidirectional_iterator;
};
/**
* Base class for storing begin/end iterators.
* @tparam IterWrapper wrapper used to iterate
* @tparam CompleteClass completed class returned from skip/take methods
*/
template<typename IterWrapper, typename CompleteClass>
class iterator_storage_base
{
public:
explicit iterator_storage_base(IterWrapper begin, IterWrapper end): begin_(std::move(begin)), end_(std::move(end))
{}
auto begin()
{
return begin_;
}
auto end()
{
return end_;
}
/**
* Creates an enumerator that skips the first n elements.
* @param amount amount of values to skip.
*/
auto skip(blt::size_t amount)
{
auto begin = this->begin_;
for (blt::size_t i = 0; i < amount; i++)
++begin;
return CompleteClass{begin.iter1(),
this->end_.iter1(),
begin.iter2(),
this->end_.iter2()};
}
/**
* Creates an enumerator that yields the first n elements, or UB if the underlying iterator ends sooner.
* @param amount amount to take.
*/
auto take(blt::size_t amount)
{
auto end = this->begin();
for (blt::size_t i = 0; i < amount; i++)
++end;
return CompleteClass{this->begin_.iter1(),
end.iter1(),
this->begin_.iter2(),
end.iter2()};
}
protected:
IterWrapper begin_;
IterWrapper end_;
};
/**
* Reversible (bidirectional) base class storing the begin / end iterators.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate.
* @tparam CompleteClass completed class returned from skip/take methods
* @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
*/
template<typename IterWrapper, typename CompleteClass, typename CompleteClassRev>
class iterator_storage_reversible : public iterator_storage_base<IterWrapper, CompleteClass>
{
public:
explicit iterator_storage_reversible(IterWrapper begin, IterWrapper end):
iterator_storage_base<IterWrapper, CompleteClass>{std::move(begin), std::move(end)}
{}
/**
* Reverses the enumerators direction.
*/
auto rev() const
{
return CompleteClassRev{this->end_.iter1(),
this->begin_.iter1(),
this->end_.iter2(),
this->begin_.iter2()};
}
};
/**
* Random access base class storage for begin/end iterators.
* Has updated skip and take methods which make use of the random access nature of the iterator.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate.
* @tparam CompleteClass completed class returned from skip/take methods
* @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
*/
template<typename IterWrapper, typename CompleteClass, typename CompleteClassRev>
class iterator_storage_random_access : public iterator_storage_reversible<IterWrapper, CompleteClass, CompleteClassRev>
{
public:
using iterator_storage_reversible<IterWrapper, CompleteClass, CompleteClassRev>::iterator_storage_reversible;
auto skip(blt::size_t amount)
{
return CompleteClass{this->begin_.iter1() + amount,
this->end_.iter1(),
this->begin_.iter2() + amount,
this->end_.iter2()};
}
auto take(blt::size_t amount)
{
return CompleteClass{this->begin_.iter1(),
this->begin_.iter1() + amount,
this->begin_.iter2(),
this->begin_.iter2() + amount};
}
};
/**
* Reversible (bidirectional) base class for storing the begin/end iterators, operates in reverse for reverse iteration.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (std::reverse_iterator<enumerate_wrapper>).
* @tparam CompleteClass completed class returned from skip/take methods
* @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
*/
template<typename IterWrapper, typename CompleteClass, typename CompleteClassRev>
class iterator_storage_reversible_rev : public iterator_storage_reversible<IterWrapper, CompleteClass, CompleteClassRev>
{
public:
using iterator_storage_reversible<IterWrapper, CompleteClass, CompleteClassRev>::iterator_storage_reversible;
auto rev() const
{
return CompleteClass{this->end_.base().iter1(),
this->begin_.base().iter1(),
this->end_.base().iter2(),
this->begin_.base().iter2()};
}
auto skip(blt::size_t amount)
{
auto begin = this->begin_.base();
for (blt::size_t i = 0; i < amount; i++)
--begin;
return CompleteClassRev{begin.iter1(),
this->end_.base().iter1(),
begin.iter2(),
this->end_.base().iter2()};
}
auto take(blt::size_t amount)
{
auto end = this->begin_.base();
for (blt::size_t i = 0; i < amount; i++)
--end;
return CompleteClassRev{
this->begin_.base().iter1(),
end.iter1(),
this->begin_.base().iter2(),
end.iter2()};
}
};
/**
* Random access base class for storing the begin/end iterator.
* Has updated skip and take methods which make use of the random access nature of the iterator.
* Operates in reverse for reverse iteration.
* @tparam Iter iterator type.
* @tparam IterWrapper wrapper used to iterate (std::reverse_iterator<enumerate_wrapper>).
* @tparam CompleteClass completed class returned from skip/take methods
* @tparam CompleteClassRev reverse version of CompleteClass, returned from rev
*/
template<typename IterWrapper, typename CompleteClass, typename CompleteClassRev>
class iterator_storage_random_access_rev : public iterator_storage_reversible_rev<IterWrapper, CompleteClass, CompleteClassRev>
{
public:
using iterator_storage_reversible_rev<IterWrapper, CompleteClass, CompleteClassRev>::iterator_storage_reversible_rev;
auto skip(blt::size_t amount)
{
return CompleteClassRev{this->begin_.base().iter1() - amount,
this->end_.base().iter1(),
this->begin_.base().iter2() - amount,
this->end_.base().iter2()};
}
auto take(blt::size_t amount)
{
return CompleteClassRev{this->begin_.base().iter1(),
this->begin_.base().iter1() - amount,
this->begin_.base().iter2(),
this->begin_.base().iter2() - amount};
}
};
/**
* Base class for types which can be converted to an enumerator
*/
template<typename Derived, typename CompleteEnumerator>
class enumerator_convertible
{
public:
auto enumerate()
{
auto* b = static_cast<Derived*>(this);
return CompleteEnumerator{b->begin(), b->end(), static_cast<blt::size_t>(std::distance(b->begin(), b->end()))};
}
};
}
/**
* Enumerator specialization for forward iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_forward_iterator_v<Iter>, std::void_t<std::forward_iterator_tag>>>
: public iterator::iterator_storage_base<iterator::enumerate_wrapper<Iter>, enumerator<Iter>>
{
public:
explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
iterator::iterator_storage_base<iterator::enumerate_wrapper<Iter>, enumerator<Iter>>
{iterator::enumerate_wrapper<Iter>{std::move(begin), 0},
iterator::enumerate_wrapper<Iter>{std::move(end), container_size}}
{}
explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
iterator::iterator_storage_base<iterator::enumerate_wrapper<Iter>, enumerator<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(begin), begin_index},
iterator::enumerate_wrapper<Iter>{std::move(end), end_index}}
{}
};
/**
* Enumerator specialization for bidirectional iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_bidirectional_iterator_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::iterator_storage_reversible<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>
{
public:
explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
iterator::iterator_storage_reversible<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>
{iterator::enumerate_wrapper<Iter>{std::move(begin), 0},
iterator::enumerate_wrapper<Iter>{std::move(end), container_size}}
{}
explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
iterator::iterator_storage_reversible<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(begin), begin_index},
iterator::enumerate_wrapper<Iter>{std::move(end), end_index}}
{}
};
/**
* Enumerator specialization for random access iterators
*/
template<typename Iter>
class enumerator<Iter, std::enable_if_t<blt::meta::is_random_access_iterator_v<Iter>, std::void_t<std::random_access_iterator_tag>>>
: public iterator::iterator_storage_random_access<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>
{
public:
explicit enumerator(Iter begin, Iter end, blt::size_t container_size):
iterator::iterator_storage_random_access<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>
{iterator::enumerate_wrapper<Iter>{std::move(begin), 0},
iterator::enumerate_wrapper<Iter>{std::move(end), container_size}}
{}
explicit enumerator(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
iterator::iterator_storage_random_access<iterator::enumerate_wrapper<Iter>, enumerator<Iter>, enumerator_rev<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(begin), begin_index},
iterator::enumerate_wrapper<Iter>{std::move(end), end_index}}
{}
};
/**
* Reverse enumerator specialization for bidirectional iterators
*/
template<typename Iter>
class enumerator_rev<Iter, std::enable_if_t<blt::meta::is_bidirectional_iterator_v<Iter>, std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::iterator_storage_reversible_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>
{
public:
explicit enumerator_rev(Iter begin, Iter end, blt::size_t container_size):
iterator::iterator_storage_reversible_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>
{std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{iterator::enumerate_wrapper<Iter>{std::move(begin), 0}},
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(end), container_size}}}
{}
explicit enumerator_rev(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
iterator::iterator_storage_reversible_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>{
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(begin), begin_index}},
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{iterator::enumerate_wrapper<Iter>{std::move(end), end_index}}}
{}
};
/**
* Reverse enumerator specialization for random access iterators
*/
template<typename Iter>
class enumerator_rev<Iter, std::enable_if_t<blt::meta::is_random_access_iterator_v<Iter>, std::void_t<std::random_access_iterator_tag>>>
: public iterator::iterator_storage_random_access_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>
{
public:
explicit enumerator_rev(Iter begin, Iter end, blt::size_t container_size):
iterator::iterator_storage_random_access_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>
{std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{iterator::enumerate_wrapper<Iter>{std::move(begin), 0}},
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(end), container_size}}}
{}
explicit enumerator_rev(Iter begin, Iter end, blt::size_t begin_index, blt::size_t end_index):
iterator::iterator_storage_random_access_rev<std::reverse_iterator<iterator::enumerate_wrapper<Iter>>, enumerator<Iter>, enumerator_rev<Iter>>{
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{
iterator::enumerate_wrapper<Iter>{std::move(begin), begin_index}},
std::reverse_iterator<iterator::enumerate_wrapper<Iter>>{iterator::enumerate_wrapper<Iter>{std::move(end), end_index}}}
{}
};
// CTAD for enumerators
template<typename Iter>
enumerator(Iter, Iter) -> enumerator<Iter>;
template<typename Iter>
enumerator(Iter, Iter, blt::size_t) -> enumerator<Iter>;
template<typename Iter>
enumerator(Iter, Iter, blt::size_t, blt::size_t) -> enumerator<Iter>;
template<typename Iter1, typename Iter2>
class pair_iterator<Iter1, Iter2,
std::enable_if_t<
blt::meta::is_forward_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::forward_iterator_tag>>>
: public iterator::iterator_storage_base<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>>,
public iterator::enumerator_convertible<pair_iterator<Iter1, Iter2>, enumerator<iterator::pair_wrapper<Iter1, Iter2>>>
{
public:
explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
iterator::iterator_storage_base<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>>
{iterator::pair_wrapper<Iter1, Iter2>{std::move(begin1), std::move(begin2)},
iterator::pair_wrapper<Iter1, Iter2>{std::move(end1), std::move(end2)}}
{}
};
template<typename Iter1, typename Iter2>
class pair_iterator<Iter1, Iter2,
std::enable_if_t<
blt::meta::is_bidirectional_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::iterator_storage_reversible<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>,
public iterator::enumerator_convertible<pair_iterator<Iter1, Iter2>, enumerator<iterator::pair_wrapper<Iter1, Iter2>>>
{
public:
explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
iterator::iterator_storage_reversible<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>
{iterator::pair_wrapper<Iter1, Iter2>{std::move(begin1), std::move(begin2)},
iterator::pair_wrapper<Iter1, Iter2>{std::move(end1), std::move(end2)}}
{}
};
template<typename Iter1, typename Iter2>
class pair_iterator<Iter1, Iter2,
std::enable_if_t<
blt::meta::is_random_access_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::random_access_iterator_tag>>>
: public iterator::iterator_storage_random_access<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>,
public iterator::enumerator_convertible<pair_iterator<Iter1, Iter2>, enumerator<iterator::pair_wrapper<Iter1, Iter2>>>
{
public:
explicit pair_iterator(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
iterator::iterator_storage_random_access<iterator::pair_wrapper<Iter1, Iter2>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>
{iterator::pair_wrapper<Iter1, Iter2>{std::move(begin1), std::move(begin2)},
iterator::pair_wrapper<Iter1, Iter2>{std::move(end1), std::move(end2)}}
{}
};
template<typename Iter1, typename Iter2>
class pair_iterator_rev<Iter1, Iter2,
std::enable_if_t<
blt::meta::is_bidirectional_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::bidirectional_iterator_tag>>>
: public iterator::iterator_storage_reversible_rev<std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>,
public iterator::enumerator_convertible<pair_iterator<Iter1, Iter2>, enumerator<iterator::pair_wrapper<Iter1, Iter2>>>
{
public:
explicit pair_iterator_rev(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
iterator::iterator_storage_reversible_rev<std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>
{std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>{
iterator::pair_wrapper<Iter1, Iter2>{std::move(begin1), std::move(begin2)}},
std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>{
iterator::pair_wrapper<Iter1, Iter2>{std::move(end1), std::move(end2)}}}
{}
};
template<typename Iter1, typename Iter2>
class pair_iterator_rev<Iter1, Iter2,
std::enable_if_t<
blt::meta::is_random_access_iterator_category_v<blt::meta::lowest_iterator_category_t<Iter1, Iter2>>,
std::void_t<std::random_access_iterator_tag>>>
: public iterator::iterator_storage_random_access_rev<std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>,
public iterator::enumerator_convertible<pair_iterator<Iter1, Iter2>, enumerator<iterator::pair_wrapper<Iter1, Iter2>>>
{
public:
explicit pair_iterator_rev(Iter1 begin1, Iter1 end1, Iter2 begin2, Iter2 end2):
iterator::iterator_storage_random_access_rev<std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>, pair_iterator<Iter1, Iter2>, pair_iterator_rev<Iter1, Iter2>>
{std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>{
iterator::pair_wrapper<Iter1, Iter2>{std::move(begin1), std::move(begin2)}},
std::reverse_iterator<iterator::pair_wrapper<Iter1, Iter2>>{
iterator::pair_wrapper<Iter1, Iter2>{std::move(end1), std::move(end2)}}}
{}
};
// CTAD for pair iterators
template<typename Iter1, typename Iter2>
pair_iterator(Iter1, Iter1, Iter2, Iter2) -> pair_iterator<Iter1, Iter2>;
template<typename T, blt::size_t size>
static inline auto enumerate(const T(& container)[size])
{
return enumerator{&container[0], &container[size], size};
}
template<typename T, blt::size_t size>
static inline auto enumerate(T(& container)[size])
{
return enumerator{&container[0], &container[size], size};
}
template<typename T>
static inline auto enumerate(T& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
template<typename T>
static inline auto enumerate(T&& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
template<typename T>
static inline auto enumerate(const T& container)
{
return enumerator{container.begin(), container.end(), container.size()};
}
template<typename T, typename G>
static inline auto in_pairs(const T& container1, const G& container2)
{
return pair_iterator{container1.begin(), container1.end(), container2.begin(), container2.end()};
}
template<typename T, typename G>
static inline auto in_pairs(T& container1, G& container2)
{
return pair_iterator{container1.begin(), container1.end(), container2.begin(), container2.end()};
}
template<typename T, typename G, blt::size_t size>
static inline auto in_pairs(const T(& container1)[size], const G(& container2)[size])
{
return pair_iterator{&container1[0], &container1[size], &container2[0], &container2[size]};
}
template<typename T, typename G, blt::size_t size>
static inline auto in_pairs(T(& container1)[size], G(& container2)[size])
{
return pair_iterator{&container1[0], &container1[size], &container2[0], &container2[size]};
}
template<typename T, typename G>
static inline auto in_pairs(T&& container1, G&& container2)
{
return pair_iterator{container1.begin(), container1.end(), container2.begin(), container2.end()};
}
}
#endif //BLT_ITERATOR_H

380
include/blt/iterator/zip.h Normal file
View File

@ -0,0 +1,380 @@
#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_ITERATOR_ZIP
#define BLT_ITERATOR_ZIP
#include <blt/iterator/iter_common.h>
#include <tuple>
namespace blt
{
namespace iterator
{
template<typename Tag, typename... Iter>
class zip_wrapper;
template<typename Tag, typename... Iter>
class zip_iterator_storage;
template<typename Tag, typename... Iter>
class zip_iterator_storage_rev;
template<typename... Iter>
class zip_forward_iterator
{
public:
explicit zip_forward_iterator(Iter... iter): iter(std::make_tuple(iter...))
{}
std::tuple<blt::meta::deref_return_t<Iter>...> operator*() const
{
return std::apply([](auto& ... i) { return std::make_tuple(*i...); }, iter);
}
friend bool operator==(const zip_forward_iterator& a, const zip_forward_iterator& b)
{
return a.iter == b.iter;
}
friend bool operator!=(const zip_forward_iterator& a, const zip_forward_iterator& b)
{
return !(a.iter == b.iter);
}
zip_forward_iterator& operator++()
{
std::apply([](auto& ... i) { ((++i), ...); }, iter);
return *this;
}
zip_forward_iterator operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
auto base()
{
return iter;
}
protected:
std::tuple<Iter...> iter;
};
template<typename... Iter>
class zip_bidirectional_iterator : public zip_forward_iterator<Iter...>
{
public:
using zip_forward_iterator<Iter...>::zip_forward_iterator;
zip_bidirectional_iterator& operator--()
{
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
return *this;
}
zip_bidirectional_iterator operator--(int)
{
auto tmp = *this;
--*this;
return tmp;
}
};
template<typename... Iter>
class zip_random_access_iterator : public zip_bidirectional_iterator<Iter...>
{
private:
template<typename T, T... n>
static blt::ptrdiff_t sub(const zip_random_access_iterator& a, const zip_random_access_iterator& b,
std::integer_sequence<T, n...>)
{
auto min = std::min(std::get<n>(a.iter) - std::get<n>(b.iter)...);
return min;
}
public:
using zip_bidirectional_iterator<Iter...>::zip_bidirectional_iterator;
zip_random_access_iterator& operator+=(blt::ptrdiff_t n)
{
std::apply([n](auto& ... i) { ((i += n), ...); }, this->iter);
return *this;
}
zip_random_access_iterator& operator-=(blt::ptrdiff_t n)
{
std::apply([n](auto& ... i) { ((i -= n), ...); }, this->iter);
return *this;
}
friend zip_random_access_iterator operator+(const zip_random_access_iterator& a, blt::ptrdiff_t n)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i + n)...}; }, a.iter);
}
friend zip_random_access_iterator operator+(blt::ptrdiff_t n, const zip_random_access_iterator& a)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i + n)...}; }, a.iter);
}
friend zip_random_access_iterator operator-(const zip_random_access_iterator& a, blt::ptrdiff_t n)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i - n)...}; }, a.iter);
}
friend zip_random_access_iterator operator-(blt::ptrdiff_t n, const zip_random_access_iterator& a)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i - n)...}; }, a.iter);
}
friend blt::ptrdiff_t operator-(const zip_random_access_iterator& a, const zip_random_access_iterator& b)
{
return sub(a, b, std::index_sequence_for<Iter...>());
}
auto operator[](blt::ptrdiff_t n) const
{
return *(*this + n);
}
friend bool operator<(const zip_random_access_iterator& a, const zip_random_access_iterator& b)
{
return b - a > 0;
}
friend bool operator>(const zip_random_access_iterator& a, const zip_random_access_iterator& b)
{
return b < a;
}
friend bool operator>=(const zip_random_access_iterator& a, const zip_random_access_iterator& b)
{
return !(a < b); // NOLINT
}
friend bool operator<=(const zip_random_access_iterator& a, const zip_random_access_iterator& b)
{
return !(a > b); // NOLINT
}
};
template<typename... Iter>
class zip_wrapper<std::forward_iterator_tag, Iter...>
{
public:
using iterator_category = std::forward_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
explicit zip_wrapper(Iter... iter): iter(std::make_tuple(iter...))
{}
std::tuple<blt::meta::deref_return_t<Iter>...> operator*() const
{
return std::apply([](auto& ... i) { return std::make_tuple(*i...); }, iter);
}
friend bool operator==(const zip_wrapper& a, const zip_wrapper& b)
{
return a.iter == b.iter;
}
friend bool operator!=(const zip_wrapper& a, const zip_wrapper& b)
{
return !(a.iter == b.iter);
}
zip_wrapper& operator++()
{
std::apply([](auto& ... i) { ((++i), ...); }, iter);
return *this;
}
zip_wrapper operator++(int)
{
auto tmp = *this;
++*this;
return tmp;
}
auto base()
{
return iter;
}
protected:
std::tuple<Iter...> iter;
};
template<typename... Iter>
class zip_wrapper<std::bidirectional_iterator_tag, Iter...> : public zip_wrapper<std::forward_iterator_tag, Iter...>
{
public:
using zip_wrapper<std::forward_iterator_tag, Iter...>::zip_wrapper;
using iterator_category = std::bidirectional_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
zip_wrapper& operator--()
{
std::apply([](auto& ... i) { ((--i), ...); }, this->iter);
return *this;
}
zip_wrapper operator--(int)
{
auto tmp = *this;
--*this;
return tmp;
}
};
template<typename... Iter>
class zip_wrapper<std::random_access_iterator_tag, Iter...> : public zip_wrapper<std::bidirectional_iterator_tag, Iter...>
{
private:
template<typename T, T... n>
static blt::ptrdiff_t sub(const zip_wrapper& a, const zip_wrapper& b,
std::integer_sequence<T, n...>)
{
auto min = std::min(std::get<n>(a.iter) - std::get<n>(b.iter)...);
return min;
}
public:
using zip_wrapper<std::bidirectional_iterator_tag, Iter...>::zip_wrapper;
using iterator_category = std::random_access_iterator_tag;
using value_type = std::tuple<blt::meta::deref_return_t<Iter>...>;
using difference_type = blt::ptrdiff_t;
using pointer = value_type;
using reference = value_type;
using zip_bidirectional_iterator<Iter...>::zip_bidirectional_iterator;
zip_wrapper& operator+=(blt::ptrdiff_t n)
{
std::apply([n](auto& ... i) { ((i += n), ...); }, this->iter);
return *this;
}
zip_wrapper& operator-=(blt::ptrdiff_t n)
{
std::apply([n](auto& ... i) { ((i -= n), ...); }, this->iter);
return *this;
}
friend zip_wrapper operator+(const zip_wrapper& a, blt::ptrdiff_t n)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i + n)...}; }, a.iter);
}
friend zip_wrapper operator+(blt::ptrdiff_t n, const zip_wrapper& a)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i + n)...}; }, a.iter);
}
friend zip_wrapper operator-(const zip_wrapper& a, blt::ptrdiff_t n)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i - n)...}; }, a.iter);
}
friend zip_wrapper operator-(blt::ptrdiff_t n, const zip_wrapper& a)
{
return std::apply([n](auto& ... i) { return zip_random_access_iterator{(i - n)...}; }, a.iter);
}
friend blt::ptrdiff_t operator-(const zip_wrapper& a, const zip_wrapper& b)
{
return sub(a, b, std::index_sequence_for<Iter...>());
}
auto operator[](blt::ptrdiff_t n) const
{
return *(*this + n);
}
friend bool operator<(const zip_wrapper& a, const zip_wrapper& b)
{
return b - a > 0;
}
friend bool operator>(const zip_wrapper& a, const zip_wrapper& b)
{
return b < a;
}
friend bool operator>=(const zip_wrapper& a, const zip_wrapper& b)
{
return !(a < b); // NOLINT
}
friend bool operator<=(const zip_wrapper& a, const zip_wrapper& b)
{
return !(a > b); // NOLINT
}
};
template<typename... Iter>
class zip_iterator_storage<std::forward_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage<std::bidirectional_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage<std::random_access_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage_rev<std::forward_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage_rev<std::bidirectional_iterator_tag, Iter...>
{
};
template<typename... Iter>
class zip_iterator_storage_rev<std::random_access_iterator_tag, Iter...>
{
};
}
}
#endif //BLT_ITERATOR_ZIP

View File

@ -7,43 +7,61 @@
#ifndef BLT_TESTS_AVERAGES_H
#define BLT_TESTS_AVERAGES_H
namespace blt {
namespace blt
{
template<typename T, int Size>
class averagizer_o_matic {
class averagizer_o_matic
{
private:
T* data;
int index = 0;
int m_default = 0;
public:
averagizer_o_matic(): averagizer_o_matic(0) {}
explicit averagizer_o_matic(T default_value){
averagizer_o_matic(): averagizer_o_matic(0)
{}
explicit averagizer_o_matic(T default_value)
{
data = new T[Size];
for (int i = 0; i < Size; i++){
for (int i = 0; i < Size; i++)
{
data[i] = default_value;
}
m_default = default_value;
}
void insert(T t){
void insert(T t)
{
data[index++] = t;
if (index >= Size)
index = 0;
}
T average(){
T average()
{
T total = 0;
for (int i = 0; i < Size; i++){
for (int i = 0; i < Size; i++)
{
total += data[i];
}
return total / Size;
}
~averagizer_o_matic(){
~averagizer_o_matic()
{
delete[] data;
}
};
template<typename A, typename B>
double average(A a, B b)
{
if (b == 0)
return 0;
return static_cast<double>(a) / static_cast<double>(b);
}
}
#endif //BLT_TESTS_AVERAGES_H

View File

@ -0,0 +1,109 @@
#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_INTERPOLATION_H
#define BLT_INTERPOLATION_H
#include "vectors.h"
namespace blt
{
inline constexpr color4 linear_interpolate(const color4& in, const color4& desired, float factor)
{
auto diff = desired - in;
return in + (diff * factor);
}
class easing_function
{
public:
easing_function() = default;
virtual color4 apply(const color4& start, const color4& end) = 0;
void progress(float progress)
{
total_progress += progress;
}
void reset()
{
total_progress = 0;
}
protected:
float x()
{
return total_progress;
}
private:
float total_progress = 0;
};
class quad_easing : public easing_function
{
public:
color4 apply(const color4& start, const color4& end) final
{
if (x() >= 1)
return end;
auto diff = end - start;
return start + (diff * (x() * x()));
}
};
class cubic_easing : public easing_function
{
public:
color4 apply(const color4& start, const color4& end) final
{
if (x() >= 1)
return end;
auto diff = end - start;
return start + (diff * (x() * x() * x()));
}
};
class quart_easing : public easing_function
{
public:
color4 apply(const color4& start, const color4& end) final
{
if (x() >= 1)
return end;
auto diff = end - start;
return start + (diff * (x() * x() * x() * x()));
}
};
class quint_easing : public easing_function
{
public:
color4 apply(const color4& start, const color4& end) final
{
if (x() >= 1)
return end;
auto diff = end - start;
return start + (diff * (x() * x() * x() * x() * x()));
}
};
}
#endif //BLT_INTERPOLATION_H

View File

@ -16,8 +16,8 @@
namespace blt
{
template<typename Writer = blt::logging::logger, typename T, blt::u32 size>
static inline Writer& operator<<(Writer& log, const blt::vec<T, size>& vec)
template<typename T, blt::u32 size, typename CharT, typename Traits>
static inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& log, const blt::vec<T, size>& vec)
{
std::string type_string;
const auto tstr = blt::type_string<T>();
@ -27,8 +27,10 @@ namespace blt
type_string += tstr[0];
// for unsigned long / unsigned int
auto split = blt::string::split_sv(tstr, ' ');
if (tstr[0] == 'u'){
if (split.size() > 1){
if (tstr[0] == 'u')
{
if (split.size() > 1)
{
type_string += split[1][0];
} else
type_string += tstr[1];
@ -43,17 +45,32 @@ namespace blt
return log;
}
template<typename Writer = std::ostream>
inline Writer& operator<<(Writer& out, const mat4x4& v)
template<typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, const mat4x4& v)
{
out << "Mat4x4(\n";
out << "\t{" << v.m00() << ", " << v.m01() << ", " << v.m02() << ", " << v.m03() << "},\n";
out << "\t{" << v.m10() << ", " << v.m11() << ", " << v.m12() << ", " << v.m13() << "},\n";
out << "\t{" << v.m20() << ", " << v.m21() << ", " << v.m22() << ", " << v.m23() << "},\n";
out << "Mat4x4(";
out << "{" << v.m00() << ", " << v.m01() << ", " << v.m02() << ", " << v.m03() << "},";
out << "\t{" << v.m10() << ", " << v.m11() << ", " << v.m12() << ", " << v.m13() << "},";
out << "\t{" << v.m20() << ", " << v.m21() << ", " << v.m22() << ", " << v.m23() << "},";
out << "\t{" << v.m30() << ", " << v.m31() << ", " << v.m32() << ", " << v.m33() << "})";
return out;
}
template<typename T, blt::u32 rows, blt::u32 columns, typename CharT, typename Traits>
inline std::basic_ostream<CharT, Traits>& operator<<(std::basic_ostream<CharT, Traits>& out, const generalized_matrix<T, rows, columns>& mat)
{
out << "Mat" << rows << 'x' << columns << "(\n";
for (blt::u32 c = 0; c < columns; c++)
{
out << "\t{";
for (blt::u32 r = 0; r < rows; r++)
out << mat[c][r] << ((r < rows - 1) ? ", " : "");
out << '}' << ((c < columns - 1) ? "," : "") << "\n";
}
out << ")";
return out;
}
}
#endif //BLT_TESTS_LOG_UTIL_H

View File

@ -56,8 +56,8 @@ namespace blt
#ifdef __GNUC__
#pragma GCC diagnostic pop
#endif
template<typename B, typename P, typename R = decltype(B() * P())>
static inline constexpr R pow(B b, P p)
{
@ -67,22 +67,61 @@ namespace blt
return collection;
}
template<blt::i64 decimal_places>
struct round_up_t
{
constexpr inline double operator()(double value)
{
if constexpr (decimal_places < 0)
return value;
else
{
constexpr double multiplier = pow(10.0, decimal_places);
auto i_value = static_cast<blt::i64>(value * multiplier);
auto f_value = (value * multiplier) - static_cast<double>(i_value);
if (f_value > 0)
return ((static_cast<double>(i_value) + 1) / multiplier);
else
return static_cast<double>(i_value);
}
}
};
template<blt::i64 decimal_places>
struct round_down_t
{
constexpr inline double operator()(double value)
{
if constexpr (decimal_places < 0)
return value;
else
{
constexpr double multiplier = pow(10.0, decimal_places);
return (static_cast<blt::i64>(value * multiplier)) / multiplier;
}
}
};
/**
* This is a fast rounding function and is not guaranteed to be 100% correct
* @tparam decimal_places
* @param value
* @return
*/
template<int decimal_places>
template<blt::i64 decimal_places>
constexpr static inline double round_up(double value)
{
if constexpr (decimal_places < 0)
return value;
else
{
constexpr double multiplier = pow(10.0, decimal_places);
return ((int) (value * multiplier) + 1) / multiplier;
}
round_up_t<decimal_places> round_func;
return round_func(value);
}
template<blt::i64 decimal_places>
constexpr static inline double round_down(double value)
{
round_down_t<decimal_places> round_func;
return round_func(value);
}
/*inline std::ostream& operator<<(std::ostream& out, const mat4x4& v) {

File diff suppressed because it is too large Load Diff

View File

@ -20,7 +20,7 @@ namespace blt
#define MSVC_COMPILER (!defined(__GNUC__) && !defined(__clang__))
constexpr float EPSILON = 0.0001f;
constexpr float EPSILON = std::numeric_limits<float>::epsilon();
static inline constexpr bool f_equal(float v1, float v2)
{
@ -34,7 +34,7 @@ namespace blt
private:
std::array<T, size> elements;
public:
vec()
constexpr vec()
{
for (auto& v : elements)
v = static_cast<T>(0);
@ -46,7 +46,7 @@ namespace blt
* @param args list of args
*/
template<typename U, std::enable_if_t<std::is_same_v<T, U> || std::is_convertible_v<U, T>, bool> = true>
vec(U t, std::initializer_list<U> args)
constexpr vec(U t, std::initializer_list<U> args): elements()
{
auto b = args.begin();
for (auto& v : elements)
@ -66,59 +66,65 @@ namespace blt
* @param args
*/
template<typename U, std::enable_if_t<std::is_same_v<T, U> || std::is_convertible_v<U, T>, bool> = true>
vec(std::initializer_list<U> args): vec(U(), args)
constexpr vec(std::initializer_list<U> args): vec(U(), args)
{}
template<typename... Args>
explicit vec(Args... args): vec(std::array<T, size>{static_cast<T>(args)...})
template<typename... Args, std::enable_if_t<sizeof...(Args) == size, bool> = true>
constexpr explicit vec(Args... args): vec(std::array<T, size>{static_cast<T>(args)...})
{}
explicit vec(T t)
constexpr explicit vec(T t)
{
for (auto& v : elements)
v = t;
}
explicit vec(const T elem[size])
constexpr explicit vec(const T elem[size])
{
for (size_t i = 0; i < size; i++)
elements[i] = elem[i];
}
explicit vec(std::array<T, size> elem)
constexpr explicit vec(std::array<T, size> elem): elements(elem)
{}
template<typename G, size_t base_size, std::enable_if_t<std::is_convertible_v<G, T>, bool> = true>
constexpr explicit vec(std::array<G, base_size> el): elements()
{
auto b = elem.begin();
for (auto& v : elements)
auto b = el.begin();
auto m = elements.begin();
while (b != el.end() && m != elements.end())
{
v = *b;
*m = *b;
++m;
++b;
}
}
[[nodiscard]] inline T x() const
[[nodiscard]] constexpr inline T x() const
{
return elements[0];
}
[[nodiscard]] inline T y() const
[[nodiscard]] constexpr inline T y() const
{
static_assert(size > 1);
return elements[1];
}
[[nodiscard]] inline T z() const
[[nodiscard]] constexpr inline T z() const
{
static_assert(size > 2);
return elements[2];
}
[[nodiscard]] inline T w() const
[[nodiscard]] constexpr inline T w() const
{
static_assert(size > 3);
return elements[3];
}
[[nodiscard]] inline T magnitude() const
[[nodiscard]] constexpr inline T magnitude() const
{
T total = 0;
for (blt::u32 i = 0; i < size; i++)
@ -126,7 +132,7 @@ namespace blt
return std::sqrt(total);
}
[[nodiscard]] inline vec<T, size> normalize() const
[[nodiscard]] constexpr inline vec<T, size> normalize() const
{
T mag = this->magnitude();
if (mag == 0)
@ -134,24 +140,24 @@ namespace blt
return *this / mag;
}
inline T& operator[](int index)
constexpr inline T& operator[](blt::size_t index)
{
return elements[index];
}
inline T operator[](int index) const
constexpr inline T operator[](blt::size_t index) const
{
return elements[index];
}
inline vec<T, size>& operator=(T v)
constexpr inline vec<T, size>& operator=(T v)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] = v;
return *this;
}
inline vec<T, size> operator-()
constexpr inline vec<T, size> operator-()
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
@ -159,42 +165,42 @@ namespace blt
return vec<T, size>{initializer};
}
inline vec<T, size>& operator+=(const vec<T, size>& other)
constexpr inline vec<T, size>& operator+=(const vec<T, size>& other)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] += other[i];
return *this;
}
inline vec<T, size>& operator*=(const vec<T, size>& other)
constexpr inline vec<T, size>& operator*=(const vec<T, size>& other)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] *= other[i];
return *this;
}
inline vec<T, size>& operator+=(T f)
constexpr inline vec<T, size>& operator+=(T f)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] += f;
return *this;
}
inline vec<T, size>& operator*=(T f)
constexpr inline vec<T, size>& operator*=(T f)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] *= f;
return *this;
}
inline vec<T, size>& operator-=(const vec<T, size>& other)
constexpr inline vec<T, size>& operator-=(const vec<T, size>& other)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] -= other[i];
return *this;
}
inline vec<T, size>& operator-=(T f)
constexpr inline vec<T, size>& operator-=(T f)
{
for (blt::u32 i = 0; i < size; i++)
elements[i] -= f;
@ -204,7 +210,7 @@ namespace blt
/**
* performs the dot product of left * right
*/
static inline constexpr T dot(const vec<T, size>& left, const vec<T, size>& right)
constexpr static inline T dot(const vec<T, size>& left, const vec<T, size>& right)
{
T dot = 0;
for (blt::u32 i = 0; i < size; i++)
@ -212,7 +218,7 @@ namespace blt
return dot;
}
static inline constexpr vec<T, size> cross(
constexpr static inline vec<T, size> cross(
const vec<T, size>& left, const vec<T, size>& right
)
{
@ -223,7 +229,7 @@ namespace blt
left.x() * right.y() - left.y() * right.x()};
}
static inline constexpr vec<T, size> project(
constexpr static inline vec<T, size> project(
const vec<T, size>& u, const vec<T, size>& v
)
{
@ -232,32 +238,42 @@ namespace blt
return (du / dv) * v;
}
auto begin()
constexpr inline auto* data()
{
return elements.data();
}
[[nodiscard]] constexpr inline const auto* data() const
{
return elements.data();
}
constexpr auto begin()
{
return elements.begin();
}
auto end()
constexpr auto end()
{
return elements.end();
}
auto rbegin()
constexpr auto rbegin()
{
return elements.rbegin();
}
auto rend()
constexpr auto rend()
{
return elements.rend();
}
[[nodiscard]] auto cbegin() const
[[nodiscard]] constexpr auto cbegin() const
{
return elements.cbegin();
}
[[nodiscard]] auto cend() const
[[nodiscard]] constexpr auto cend() const
{
return elements.cend();
}
@ -281,39 +297,39 @@ namespace blt
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator+(const vec<T, size>& left, T f)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator+(const vec<T, size>& left, G right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = left[i] + f;
initializer[i] = left[i] + static_cast<T>(right);
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator-(const vec<T, size>& left, T f)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator-(const vec<T, size>& left, G right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = left[i] + f;
initializer[i] = left[i] + static_cast<T>(right);
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator+(T f, const vec<T, size>& right)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator+(G left, const vec<T, size>& right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = f + right[i];
initializer[i] = static_cast<T>(left) + right[i];
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator-(T f, const vec<T, size>& right)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator-(G left, const vec<T, size>& right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = f - right[i];
initializer[i] = static_cast<T>(left) - right[i];
return initializer;
}
@ -326,39 +342,52 @@ namespace blt
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator*(const vec<T, size>& left, T f)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator*(const vec<T, size>& left, G right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = left[i] * f;
initializer[i] = left[i] * static_cast<T>(right);
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator*(T f, const vec<T, size>& right)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator*(G left, const vec<T, size>& right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = f * right[i];
initializer[i] = static_cast<T>(left) * right[i];
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr vec<T, size> operator/(const vec<T, size>& left, T f)
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator/(const vec<T, size>& left, G right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = left[i] / f;
initializer[i] = left[i] / static_cast<T>(right);
return initializer;
}
template<typename T, typename G, blt::u32 size>
inline constexpr vec<T, size> operator/(G left, const vec<T, size>& right)
{
vec<T, size> initializer{};
for (blt::u32 i = 0; i < size; i++)
initializer[i] = static_cast<T>(left) / right[i];
return initializer;
}
template<typename T, blt::u32 size>
inline constexpr bool operator==(const vec<T, size>& left, const vec<T, size>& right)
{
constexpr double E = std::numeric_limits<T>::epsilon();
for (blt::u32 i = 0; i < size; i++)
if (left[i] != right[i])
{
auto diff = left[i] - right[i];
if (diff > E || diff < -E)
return false;
}
return true;
}
@ -405,6 +434,60 @@ namespace blt
using vec3 = vec3f;
using vec4 = vec4f;
using color4 = vec4;
using color3 = vec3;
inline constexpr color4 make_color(float r, float g, float b)
{
return color4{r, g, b, 1.0f};
}
template<typename ValueType, u32 size>
inline constexpr blt::vec<ValueType, 2> make_vec2(const blt::vec<ValueType, size>& t, size_t fill = 0)
{
if constexpr (size >= 2)
{
return blt::vec<ValueType, 2>(t.x(), t.y());
} else
{
return blt::vec<ValueType, 2>(t.x(), fill);
}
}
template<typename ValueType, u32 size>
inline constexpr blt::vec<ValueType, 3> make_vec3(const blt::vec<ValueType, size>& t, size_t fill = 0)
{
if constexpr (size >= 3)
{
return blt::vec<ValueType, 3>(t.x(), t.y(), t.z());
} else
{
blt::vec<ValueType, 3> ret;
for (size_t i = 0; i < size; i++)
ret[i] = t[i];
for (size_t i = size; i < 3; i++)
ret[i] = fill;
return ret;
}
}
template<typename ValueType, u32 size>
inline constexpr blt::vec<ValueType, 4> make_vec4(const blt::vec<ValueType, size>& t, size_t fill = 0)
{
if constexpr (size >= 4)
{
return blt::vec<ValueType, 4>(t.x(), t.y(), t.z(), t.w());
} else
{
blt::vec<ValueType, 4> ret;
for (size_t i = 0; i < size; i++)
ret[i] = t[i];
for (size_t i = size; i < 4; i++)
ret[i] = fill;
return ret;
}
}
namespace vec_algorithm
{
static inline void findOrthogonalBasis(const vec3& v, vec3& v1, vec3& v2, vec3& v3)

View File

@ -0,0 +1,55 @@
#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_CONFIG_GENERATOR_H
#define BLT_CONFIG_GENERATOR_H
#include <utility>
namespace blt
{
#define BLT_MAKE_GETTER(TYPE, NAME) \
TYPE& get_##NAME() { return NAME; } \
const TYPE& get_##NAME() const { return NAME; }
#define BLT_MAKE_SETTER(TYPE, NAME) \
auto& set_##NAME(const TYPE& new_##NAME) \
{ \
NAME = new_##NAME; \
return *this; \
} \
auto& set_##NAME(TYPE&& new_##NAME) \
{ \
NAME = std::move(new_##NAME); \
return *this; \
}
#define BLT_MAKE_GETTER_AND_SETTER(TYPE, NAME) \
BLT_MAKE_GETTER(TYPE, NAME) \
BLT_MAKE_SETTER(TYPE, NAME)
#define BLT_MAKE_FRIEND(FRIEND) friend FRIEND;
#define BLT_MAKE_CONFIG_TYPE(OBJECT, ...) \
class OBJECT { \
__VA_ARGS__ \
}; \
}
#endif //BLT_CONFIG_GENERATOR_H

119
include/blt/meta/iterator.h Normal file
View File

@ -0,0 +1,119 @@
#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_META_ITERATOR_H
#define BLT_META_ITERATOR_H
#include <type_traits>
#include <iterator>
namespace blt::meta
{
template<typename Category>
struct is_input_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::input_iterator_tag>;
};
template<typename Category>
struct is_forward_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::forward_iterator_tag>;
};
template<typename Category>
struct is_bidirectional_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::bidirectional_iterator_tag>;
};
template<typename Category>
struct is_random_access_iterator_category
{
constexpr static bool value = std::is_same_v<Category, std::random_access_iterator_tag>;
};
template<typename Iter>
inline constexpr bool is_input_iterator_category_v = is_input_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_forward_iterator_category_v = is_forward_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_iterator_category_v = is_bidirectional_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_random_access_iterator_category_v = is_random_access_iterator_category<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_or_better_category_v =
is_bidirectional_iterator_category_v<Iter> || is_random_access_iterator_category_v<Iter>;
// this is required! :/
template<typename Iter>
struct is_input_iterator
{
constexpr static bool value = is_input_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
};
template<typename Iter>
struct is_forward_iterator
{
constexpr static bool value = is_forward_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
};
template<typename Iter>
struct is_bidirectional_iterator
{
constexpr static bool value = is_bidirectional_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
};
template<typename Iter>
struct is_random_access_iterator
{
constexpr static bool value = is_random_access_iterator_category_v<typename std::iterator_traits<Iter>::iterator_category>;
};
template<typename Iter>
inline constexpr bool is_input_iterator_v = is_input_iterator<Iter>::value;
template<typename Iter>
inline constexpr bool is_forward_iterator_v = is_forward_iterator<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_iterator_v = is_bidirectional_iterator<Iter>::value;
template<typename Iter>
inline constexpr bool is_random_access_iterator_v = is_random_access_iterator<Iter>::value;
template<typename Iter>
inline constexpr bool is_bidirectional_or_better_v = is_bidirectional_iterator_v<Iter> || is_random_access_iterator_v<Iter>;
template<typename... Iter>
struct lowest_iterator_category
{
using type = std::common_type_t<typename std::iterator_traits<Iter>::iterator_category...>;
};
template<typename... Iter>
using lowest_iterator_category_t = typename lowest_iterator_category<Iter...>::type;
}
#endif //BLT_META_ITERATOR_H

248
include/blt/meta/meta.h Normal file
View File

@ -0,0 +1,248 @@
#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_META_H
#define BLT_META_H
#include <blt/std/types.h>
#include <utility>
#include <type_traits>
#include <ostream>
namespace blt::meta
{
template<typename IFirst = std::void_t<void>, typename... IArgs>
struct arg_helper
{
using First = IFirst;
using Next = arg_helper<IArgs...>;
};
template<typename IFirst>
struct arg_helper<IFirst>
{
using First = IFirst;
using Next = void;
};
template<>
struct arg_helper<>
{
using First = void;
using Next = void;
};
template<typename TheLambda, typename>
struct lambda_helper
{
using Lambda = TheLambda;
};
template<typename TheLambda, typename IReturn, typename IClass, typename... LArgs>
struct lambda_helper<TheLambda, IReturn (IClass::*)(LArgs...) const>
{
using Lambda = TheLambda;
using Return = IReturn;
using Class = IClass;
using Args = arg_helper<LArgs...>;
template<typename T>
explicit lambda_helper(T)
{}
lambda_helper() = default;
};
template<typename Lambda>
lambda_helper(Lambda) -> lambda_helper<Lambda, decltype(&Lambda::operator())>;
// https://stackoverflow.com/questions/66397071/is-it-possible-to-check-if-overloaded-operator-for-type-or-class-exists
template<typename T>
class is_streamable
{
private:
template<typename Subs>
static auto test(int) -> decltype(std::declval<std::ostream&>() << std::declval<Subs>(), std::true_type())
{
return std::declval<std::true_type>();
}
template<typename>
static auto test(...) -> std::false_type
{
return std::declval<std::false_type>();
}
public:
static constexpr bool value = decltype(test<T>(0))::value;
};
template<class T>
inline constexpr bool is_streamable_v = is_streamable<T>::value;
namespace detail
{
template<typename Or>
struct value_type_helper
{
template<typename Subs>
inline static constexpr auto get(int) -> typename Subs::value_type
{
return std::declval<Subs::value_type>();
}
template<typename>
inline static constexpr Or get(...)
{
return std::declval<Or>();
}
};
template<typename Or>
struct reference_type_helper
{
template<typename Subs>
inline static constexpr auto get(int) -> typename Subs::reference
{
return std::declval<typename Subs::reference>();
}
template<typename>
inline static constexpr Or get(...)
{
return std::declval<Or>();
}
};
template<typename Or>
struct const_reference_type_helper
{
template<typename Subs>
inline static constexpr auto get(int) -> typename Subs::const_reference
{
return std::declval<typename Subs::const_reference>();
}
template<typename>
inline static constexpr Or get(...)
{
return std::declval<Or>();
}
};
template<typename Or>
struct pointer_type_helper
{
template<typename Subs>
inline static constexpr auto get(int) -> typename Subs::pointer
{
return std::declval<typename Subs::pointer>();
}
template<typename>
inline static constexpr Or get(...)
{
return std::declval<Or>();
}
};
template<typename Or>
struct difference_type_helper
{
template<typename Subs>
inline static constexpr auto get(int) -> typename Subs::difference_type
{
return std::declval<typename Subs::difference_type>();
}
template<typename>
inline static constexpr Or get(...)
{
return std::declval<Or>();
}
};
}
template<typename T, typename Or>
using value_type_t = decltype(detail::value_type_helper<Or>::template get<T>(0));
template<typename T, typename Or>
using difference_t = decltype(detail::difference_type_helper<Or>::template get<T>(0));
template<typename T, typename Or>
using pointer_t = decltype(detail::pointer_type_helper<Or>::template get<T>(0));
template<typename T, typename Or>
using reference_t = decltype(detail::reference_type_helper<Or>::template get<T>(0));
template<typename T, typename Or>
using const_reference_t = decltype(detail::const_reference_type_helper<Or>::template get<T>(0));
template<typename T>
struct arrow_return
{
using type = typename std::result_of<decltype(&T::operator->)(T*)>::type;
};
template<typename T>
struct arrow_return<T*>
{
using type = T*;
};
// gets the return type for arrow operator
template<typename T>
using arrow_return_t = typename arrow_return<T>::type;
template<typename T>
struct deref_return
{
using type = typename std::result_of<decltype(&T::operator*)(T*)>::type;
};
template<typename T>
struct deref_return<T*>
{
using type = T&;
};
// gets the return type for the reference operator
template<typename T>
using deref_return_t = typename deref_return<T>::type;
#define BLT_META_MAKE_FUNCTION_CHECK(FUNC, ...)\
template<typename T, typename = void> \
class has_func_##FUNC : public std::false_type \
{}; \
template<typename T> \
class has_func_##FUNC<T, std::void_t<decltype(std::declval<T>().FUNC(,##__VA_ARGS__))>> : public std::true_type \
{}; \
template<typename T> \
inline constexpr bool has_func_##FUNC##_v = has_func_##FUNC<T>::value;
#define BLT_META_MAKE_MEMBER_CHECK(MEMBER)\
template<typename T, typename = void> \
class has_member_##MEMBER : public std::false_type \
{}; \
template<typename T> \
class has_member_##MEMBER<T, std::void_t<decltype(T::MEMBER)>> : public std::true_type \
{}; \
template<typename T> \
inline constexpr bool has_member_##MEMBER##_v = has_member_##MEMBER<T>::value;
}
#endif //BLT_GP_META_H

View File

@ -0,0 +1,344 @@
#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_TEMPLATING_H
#define BLT_TEMPLATING_H
#include <string>
#include <string_view>
#include <utility>
#include <vector>
#include <utility>
#include <blt/std/hashmap.h>
#include <blt/std/types.h>
#include <blt/std/expected.h>
#include <blt/std/logging.h>
#include <variant>
namespace blt
{
class template_engine_t;
template<typename Storage, typename Consumable>
class template_consumer_base_t
{
public:
explicit template_consumer_base_t(Storage storage): storage(std::move(storage))
{}
[[nodiscard]] Consumable next(size_t offset = 0) const
{
return storage[current_index + offset];
}
void advance(size_t offset = 1)
{
current_index += offset;
}
[[nodiscard]] bool hasNext(size_t offset = 1) const
{
return (current_index + (offset - 1)) < storage.size();
}
[[nodiscard]] Consumable consume()
{
Consumable c = next();
advance();
return c;
}
[[nodiscard]] size_t getCurrentIndex() const
{
return current_index;
}
[[nodiscard]] size_t getPreviousIndex() const
{
return current_index - 1;
}
protected:
size_t current_index = 0;
Storage storage;
};
enum class template_token_t
{
//STRING, // A string of characters not $ { or }
IDENT, // $
ADD, // +
CURLY_OPEN, // {
CURLY_CLOSE, // }
IF, // IF
ELSE, // ELSE
PAR_OPEN, // (
PAR_CLOSE, // )
OR, // ||
AND, // &&
XOR, // ^
NOT, // !
QUOTE, // "
SEMI, // ;
COMMA, // ,
PERIOD, // .
FUNCTION, // ~
STRING // variable name
};
namespace detail
{
inline const blt::hashmap_t<std::string_view, template_token_t> identifiers = {
{"IF", template_token_t::IF},
{"ELSE", template_token_t::ELSE}
};
}
inline std::string template_token_to_string(template_token_t token)
{
switch (token)
{
case template_token_t::IDENT:
return "[Template Identifier]";
case template_token_t::CURLY_OPEN:
return "[Curly Open]";
case template_token_t::CURLY_CLOSE:
return "[Curly Close]";
case template_token_t::IF:
return "[IF]";
case template_token_t::ELSE:
return "[ELSE]";
case template_token_t::PAR_OPEN:
return "[Par Open]";
case template_token_t::PAR_CLOSE:
return "[Par Close]";
case template_token_t::OR:
return "[OR]";
case template_token_t::AND:
return "[AND]";
case template_token_t::XOR:
return "[XOR]";
case template_token_t::NOT:
return "[NOT]";
case template_token_t::QUOTE:
return "[QUOTE]";
case template_token_t::FUNCTION:
return "[FUNC]";
case template_token_t::STRING:
return "[STR]";
case template_token_t::SEMI:
return "[SEMI]";
case template_token_t::COMMA:
return "[COMMA]";
case template_token_t::PERIOD:
return "[PERIOD]";
case template_token_t::ADD:
return "[ADD]";
}
}
enum class template_tokenizer_failure_t
{
MISMATCHED_CURLY,
MISMATCHED_PAREN,
MISMATCHED_QUOTE,
};
enum class template_parser_failure_t
{
SUBSTITUTION_NOT_FOUND,
TOKENIZER_FAILURE,
NO_MATCHING_CURLY,
MISSING_IDENT_BRACES,
FUNCTION_EXPECTED_STRING,
FUNCTION_NOT_FOUND,
FUNCTION_DISCARD,
STRING_EXPECTED_CONCAT,
IF_EXPECTED_PAREN,
IF_EXPECTED_CURLY,
BOOL_EXPECTED_PAREN,
BOOL_TYPE_NOT_FOUND,
UNKNOWN_STATEMENT_ERROR,
UNKNOWN_ERROR
};
struct template_token_data_t
{
template_token_t type;
size_t level;
std::string_view token;
size_t paren_level = 0;
template_token_data_t(template_token_t type, size_t level, const std::string_view& token): type(type), level(level), token(token)
{}
template_token_data_t(template_token_t type, size_t level, const std::string_view& token, size_t parenLevel):
type(type), level(level), token(token), paren_level(parenLevel)
{}
};
class template_char_consumer_t : public template_consumer_base_t<std::string_view, char>
{
public:
explicit template_char_consumer_t(std::string_view statement): template_consumer_base_t(statement)
{}
[[nodiscard]] std::string_view from(size_t begin, size_t end)
{
return std::string_view{&storage[begin], end - begin};
}
};
class template_token_consumer_t : public template_consumer_base_t<std::vector<template_token_data_t>, template_token_data_t>
{
public:
explicit template_token_consumer_t(const std::vector<template_token_data_t>& statement, std::string_view raw_string):
template_consumer_base_t(statement), raw_string(raw_string)
{}
void set_marker()
{
// when setting the marker, we need to go from the last closing brace
auto index = storage.begin() + getCurrentIndex();
while (index->type != template_token_t::CURLY_CLOSE)
index--;
last_read_index = ((&index->token.front() + index->token.size()) - &raw_string[last_read_index]);
}
std::string_view from_last()
{
if (!hasNext())
return std::string_view(&raw_string[last_read_index], raw_string.size() - last_read_index);
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);
return str;
}
void back()
{
current_index--;
}
auto prev()
{
if (current_index == 0)
throw std::runtime_error("Current Index cannot be zero!");
return storage[current_index - 1];
}
private:
std::string_view raw_string;
size_t last_read_index = 0;
};
class template_engine_t
{
public:
inline std::string& operator[](const std::string& key)
{
return substitutions[key];
}
inline std::string& operator[](std::string_view key)
{
return substitutions[key];
}
inline template_engine_t& set(std::string_view key, std::string_view replacement)
{
substitutions[key] = replacement;
return *this;
}
inline bool contains(std::string_view token)
{
return substitutions.contains(token);
}
inline auto get(std::string_view token)
{
return internal_evaluate(substitutions[token], true);
}
static blt::expected<std::vector<template_token_data_t>, template_tokenizer_failure_t> process_string(std::string_view str);
blt::expected<std::string, template_parser_failure_t> evaluate(std::string_view str)
{
auto eval = internal_evaluate(str, false);
if (eval.has_value())
return eval;
else
if (eval.error() == template_parser_failure_t::FUNCTION_DISCARD)
return "";
else
return eval;
}
private:
blt::expected<std::string, template_parser_failure_t> internal_evaluate(std::string_view str, bool discard);
blt::hashmap_t<std::string, std::string> substitutions;
};
class template_parser_t
{
public:
using estring = blt::expected<std::string, template_parser_failure_t>;
using ebool = blt::expected<bool, template_parser_failure_t>;
template_parser_t(template_engine_t& engine, template_token_consumer_t& consumer):
engine(engine), consumer(consumer)
{}
estring parse()
{
auto next = consumer.consume();
if (next.type == template_token_t::IDENT && consumer.next().type == template_token_t::CURLY_OPEN)
{
consumer.advance();
auto str = statement();
consumer.advance();
return str;
}
return blt::unexpected(template_parser_failure_t::MISSING_IDENT_BRACES);
}
private:
estring statement();
estring function();
estring if_func();
estring string();
ebool bool_statement();
ebool bool_value();
ebool bool_expression();
template_engine_t& engine;
template_token_consumer_t& consumer;
};
}
#endif //BLT_TEMPLATING_H

View File

@ -16,7 +16,7 @@
namespace blt
{
// use the historical values (average) instead of the latest values
static inline constexpr std::uint32_t PRINT_HISTORY = 0x1;
static inline constexpr std::uint32_t AVERAGE_HISTORY = 0x1;
// print out the cycles
static inline constexpr std::uint32_t PRINT_CYCLES = 0x2;
// print out the wall time
@ -96,7 +96,7 @@ namespace blt
void endInterval(interval_t* interval);
void printProfile(profile_t& profiler, std::uint32_t flags = PRINT_HISTORY | PRINT_CYCLES | PRINT_THREAD | PRINT_WALL,
void printProfile(profile_t& profiler, std::uint32_t flags = AVERAGE_HISTORY | PRINT_CYCLES | PRINT_THREAD | PRINT_WALL,
sort_by sort = sort_by::CYCLES, blt::logging::log_level log_level = blt::logging::log_level::NONE);
void writeProfile(std::ifstream& stream, const profile_t& profiler);
@ -109,7 +109,7 @@ namespace blt
void endInterval(const std::string& profile_name, const std::string& interval_name);
void printProfile(const std::string& profile_name, std::uint32_t flags = PRINT_HISTORY | PRINT_CYCLES | PRINT_THREAD | PRINT_WALL,
void printProfile(const std::string& profile_name, std::uint32_t flags = AVERAGE_HISTORY | PRINT_CYCLES | PRINT_THREAD | PRINT_WALL,
sort_by sort = sort_by::CYCLES, blt::logging::log_level log_level = blt::logging::log_level::NONE);
void writeProfile(std::ifstream& stream, const std::string& profile_name);

View File

@ -22,20 +22,21 @@
#include <limits>
#include <vector>
#include <blt/std/ranges.h>
#include <blt/iterator/iterator.h>
#include <blt/std/utility.h>
#include <blt/std/types.h>
// TODO: remove
//#include <blt/std/hashmap.h>
#include <blt/std/assert.h>
#include <blt/std/mmap.h>
#include <blt/compatibility.h>
#include <stdexcept>
#include "logging.h"
#include <cstdlib>
#ifdef __unix__
#ifdef __unix__
#include <sys/mman.h>
#endif
#include <sys/mman.h>
#endif
namespace blt
{
@ -158,10 +159,10 @@ namespace blt
*/
inline std::optional<block_view> search_for_block(block_storage* blk, size_t n)
{
for (auto kv : blt::enumerate(blk->unallocated_blocks))
for (auto [index, item] : blt::enumerate(blk->unallocated_blocks))
{
if (kv.second.n >= n)
return block_view{blk, kv.first, kv.second.n - n};
if (item.n >= n)
return block_view{blk, index, item.n - n};
}
return {};
}
@ -542,8 +543,42 @@ namespace blt
}
};
// size of 2mb in bytes
inline constexpr blt::size_t BLT_2MB_SIZE = 4096 * 512;
template<typename T, bool WARN_ON_FAIL = false>
static inline T* allocate_huge_page(blt::size_t BLOCK_SIZE, blt::size_t HUGE_PAGE_SIZE = BLT_2MB_SIZE)
{
BLT_ASSERT((BLOCK_SIZE & (HUGE_PAGE_SIZE - 1)) == 0 && "Must be multiple of the huge page size!");
T* buffer = static_cast<T*>(mmap(nullptr, BLOCK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0));
// if we fail to allocate a huge page we can try to allocate normally
if (buffer == MAP_FAILED)
{
if constexpr (WARN_ON_FAIL)
{
BLT_WARN_STREAM << "We failed to allocate huge pages\n";
BLT_WARN_STREAM << handle_mmap_error();
BLT_WARN_STREAM << "\033[1;31mYou should attempt to enable "
"huge pages as this will allocate normal pages and double the memory usage!\033[22m\n";
}
blt::size_t bytes = BLOCK_SIZE * 2;
buffer = static_cast<T*>(mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
if (buffer == MAP_FAILED)
{
BLT_ERROR_STREAM << "Failed to allocate normal pages\n";
throw bad_alloc_t(handle_mmap_error());
}
if constexpr (WARN_ON_FAIL)
{
if (((size_t) buffer & (HUGE_PAGE_SIZE - 1)) != 0)
BLT_ERROR("Pointer is not aligned! %p", buffer);
}
auto* ptr = static_cast<void*>(buffer);
auto ptr_size = reinterpret_cast<blt::size_t>(ptr);
buffer = static_cast<T*>(std::align(BLOCK_SIZE, BLOCK_SIZE, ptr, bytes));
if constexpr (WARN_ON_FAIL)
BLT_ERROR("Offset by %ld pages, resulting: %p", (reinterpret_cast<blt::size_t>(buffer) - ptr_size) / 4096, buffer);
}
return buffer;
}
/**
* blt::bump_allocator. Allocates blocks of BLOCK_SIZE with zero reuse. When all objects from a block are fully deallocated the block will be freed
@ -627,68 +662,6 @@ namespace blt
stats_t stats;
//blt::hashset_t<void*> deletes;
/**
* Logging function used for handling mmap errors. call after a failed mmap call.
* @param LOG_FUNC function to log with, must be a BLT_*_STREAM
*/
template<typename LOG_FUNC>
static void handle_mmap_error(LOG_FUNC func = BLT_ERROR_STREAM)
{
#define BLT_WRITE(arg) func << arg << '\n';
switch (errno)
{
case EACCES:
BLT_WRITE("fd not set to open!");
break;
case EAGAIN:
BLT_WRITE("The file has been locked, or too much memory has been locked");
break;
case EBADF:
BLT_WRITE("fd is not a valid file descriptor");
break;
case EEXIST:
BLT_WRITE("MAP_FIXED_NOREPLACE was specified in flags, and the range covered "
"by addr and length clashes with an existing mapping.");
break;
case EINVAL:
BLT_WRITE("We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).");
BLT_WRITE("Or length was 0");
BLT_WRITE("Or flags contained none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE.");
break;
case ENFILE:
BLT_WRITE("The system-wide limit on the total number of open files has been reached.");
break;
case ENODEV:
BLT_WRITE("The underlying filesystem of the specified file does not support memory mapping.");
break;
case ENOMEM:
BLT_WRITE("No memory is available.");
BLT_WRITE("Or The process's maximum number of mappings would have been exceeded. "
"This error can also occur for munmap(), when unmapping a region in the middle of an existing mapping, "
"since this results in two smaller mappings on either side of the region being unmapped.");
BLT_WRITE("Or The process's RLIMIT_DATA limit, described in getrlimit(2), would have been exceeded.");
BLT_WRITE("Or We don't like addr, because it exceeds the virtual address space of the CPU.");
break;
case EOVERFLOW:
BLT_WRITE("On 32-bit architecture together with the large file extension (i.e., using 64-bit off_t): "
"the number of pages used for length plus number of "
"pages used for offset would overflow unsigned long (32 bits).");
break;
case EPERM:
BLT_WRITE("The prot argument asks for PROT_EXEC but the mapped area "
"belongs to a file on a filesystem that was mounted no-exec.");
BLT_WRITE("Or The operation was prevented by a file seal");
BLT_WRITE("Or The MAP_HUGETLB flag was specified, but the caller "
"was not privileged (did not have the CAP_IPC_LOCK capability) "
"and is not a member of the sysctl_hugetlb_shm_group group; "
"see the description of /proc/sys/vm/sysctl_hugetlb_shm_group");
break;
case ETXTBSY:
BLT_WRITE("MAP_DENYWRITE was set but the object specified by fd is open for writing.");
break;
}
}
struct block
{
struct block_metadata_t
@ -724,38 +697,7 @@ namespace blt
#ifdef __unix__
if constexpr (USE_HUGE)
{
static_assert((BLOCK_SIZE & (HUGE_PAGE_SIZE - 1)) == 0 && "Must be multiple of the huge page size!");
buffer = static_cast<block*>(mmap(nullptr, BLOCK_SIZE, PROT_READ | PROT_WRITE,
MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | MAP_POPULATE, -1, 0));
// if we fail to allocate a huge page we can try to allocate normally
if (buffer == MAP_FAILED)
{
if constexpr (WARN_ON_FAIL)
{
BLT_WARN_STREAM << "We failed to allocate huge pages\n";
handle_mmap_error(BLT_WARN_STREAM);
BLT_WARN_STREAM << "\033[1;31mYou should attempt to enable "
"huge pages as this will allocate normal pages and double the memory usage!\033[22m\n";
}
blt::size_t bytes = BLOCK_SIZE * 2;
buffer = static_cast<block*>(mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_POPULATE, -1, 0));
if (buffer == MAP_FAILED)
{
BLT_ERROR_STREAM << "Failed to allocate normal pages\n";
handle_mmap_error(BLT_ERROR_STREAM);
throw std::bad_alloc();
}
if constexpr (WARN_ON_FAIL)
{
if (((size_t) buffer & (HUGE_PAGE_SIZE - 1)) != 0)
BLT_ERROR("Pointer is not aligned! %p", buffer);
}
auto* ptr = static_cast<void*>(buffer);
auto ptr_size = reinterpret_cast<blt::size_t>(ptr);
buffer = static_cast<block*>(std::align(BLOCK_SIZE, BLOCK_SIZE, ptr, bytes));
if constexpr (WARN_ON_FAIL)
BLT_ERROR("Offset by %ld pages, resulting: %p", (reinterpret_cast<blt::size_t>(buffer) - ptr_size) / 4096, buffer);
}
buffer = allocate_huge_page<block, WARN_ON_FAIL>(BLOCK_SIZE, HUGE_PAGE_SIZE);
} else
buffer = reinterpret_cast<block*>(std::aligned_alloc(BLOCK_SIZE, BLOCK_SIZE));
#else
@ -794,7 +736,7 @@ namespace blt
{
if (head == nullptr)
return nullptr;
blt::size_t remaining_bytes = BLOCK_REMAINDER - static_cast<blt::size_t>(head->metadata.offset - head->buffer);
blt::size_t remaining_bytes = BLOCK_REMAINDER - static_cast<blt::ptrdiff_t>(head->metadata.offset - head->buffer);
auto pointer = static_cast<void*>(head->metadata.offset);
return std::align(alignment, bytes, pointer, remaining_bytes);
}
@ -832,7 +774,7 @@ namespace blt
if (munmap(p, BLOCK_SIZE))
{
BLT_ERROR_STREAM << "FAILED TO DEALLOCATE BLOCK\n";
handle_mmap_error(BLT_ERROR_STREAM);
throw bad_alloc_t(handle_mmap_error());
}
} else
free(p);

View File

@ -16,12 +16,14 @@ namespace blt
void b_assert_failed(const char* expression, const char* msg, const char* path, int line);
void b_throw(const char* what, const char* path, int line);
void b_abort(const char* what, const char* path, int line);
}
/**
* Prints error with stack trace if assertion fails. Does not stop execution.
*/
#define blt_assert(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, nullptr, __FILE__, __LINE__) } while (0)
#define blt_assert(expr) do {static_cast<bool>(expr) ? void(0) : blt::b_assert_failed(#expr, nullptr, __FILE__, __LINE__); } while (0)
/**
* Prints error with stack trace if assertion fails. Will print fail_message after
* the assertion expression but before the stack trace. Does not stop execution.
@ -33,7 +35,7 @@ namespace blt
#define BLT_ASSERT(expr) do { \
if (!static_cast<bool>(expr)) { \
blt::b_assert_failed(#expr, nullptr, __FILE__, __LINE__); \
std::exit(EXIT_FAILURE); \
std::abort(); \
} \
} while (0)
@ -44,7 +46,7 @@ namespace blt
#define BLT_ASSERT_MSG(expr, fail_message) do { \
if (!static_cast<bool>(expr)) { \
blt::b_assert_failed(#expr, fail_message, __FILE__, __LINE__); \
std::exit(EXIT_FAILURE); \
std::abort(); \
} \
} while (0)
@ -54,4 +56,6 @@ namespace blt
#define BLT_THROW(throwable) do {blt::b_throw(throwable.what(), __FILE__, __LINE__); throw throwable;} while(0)
#define BLT_ABORT(message) do {blt::b_abort(message, __FILE__, __LINE__); std::abort(); } while (0)
#endif //BLT_ASSERT_H

View File

@ -0,0 +1,127 @@
#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_ATOMIC_ALLOCATOR_H
#define BLT_ATOMIC_ALLOCATOR_H
#include <optional>
#include <limits>
#include <vector>
#include <blt/std/ranges.h>
#include <blt/std/utility.h>
#include <blt/std/types.h>
#include <blt/std/assert.h>
#include <blt/std/mmap.h>
#include <blt/compatibility.h>
#include <stdexcept>
#include "logging.h"
#include <cstdlib>
#include <atomic>
namespace blt
{
// template<typename Alloc = blt::aligned_huge_allocator>
// class atomic_bump_allocator
// {
// private:
// struct block
// {
// struct block_metadata_t
// {
// const blt::size_t size = 0;
// std::atomic<blt::size_t> allocated_objects = 0;
// std::atomic<block*> next = nullptr;
// std::atomic<block*> prev = nullptr;
// std::atomic<blt::u8*> offset = nullptr;
// } metadata;
// blt::u8 buffer[8]{};
//
// explicit block(blt::size_t size)
// {
// metadata.size = size;
// metadata.offset = buffer;
// }
//
// [[nodiscard]] blt::ptrdiff_t storage_size() const noexcept
// {
// return static_cast<blt::ptrdiff_t>(metadata.size - sizeof(typename block::block_metadata_t));
// }
//
// [[nodiscard]] blt::ptrdiff_t used_bytes_in_block() const noexcept
// {
// return static_cast<blt::ptrdiff_t>(metadata.offset - buffer);
// }
//
// [[nodiscard]] blt::ptrdiff_t remaining_bytes_in_block() const noexcept
// {
// return storage_size() - used_bytes_in_block();
// }
// };
//
// public:
// void* allocate(blt::size_t bytes)
// {
// auto head_ptr = head.load(std::memory_order_relaxed);
// auto new_head = head_ptr;
// do
// {
// if (head_ptr->remaining_bytes_in_block() < bytes)
// {
//
// }
// } while (!head.compare_exchange_weak(head_ptr, new_head, std::memory_order_release, std::memory_order_acquire));
// }
//
// void deallocate(void* ptr)
// {
// auto blk = to_block(ptr);
// --blk.metadata.allocated_objects;
// if (blk.metadata.allocated_objects == 0)
// {
// if (blk->metadata.prev != nullptr)
// blk->metadata.prev->metadata.next = blk->metadata.next;
// if (blk->metadata.next != nullptr)
// blk->metadata.next->metadata.prev = blk->metadata.prev;
// alloc.deallocate(blk, blk.metadata.size);
// }
// }
//
// private:
// static inline block* to_block(void* p)
// {
// return reinterpret_cast<block*>(reinterpret_cast<std::uintptr_t>(p) & static_cast<std::uintptr_t>(~(BLT_2MB_SIZE - 1)));
// }
//
// inline block* allocate_block(blt::size_t bytes)
// {
// auto size = align_size_to(bytes, BLT_2MB_SIZE);
// auto ptr = static_cast<block*>(alloc.allocate(size));
// new(ptr) block{size};
// return ptr;
// }
//
// std::atomic<block*> head = nullptr;
// Alloc alloc;
// };
}
#endif //BLT_ATOMIC_ALLOCATOR_H

View File

@ -75,7 +75,7 @@ namespace blt
}
template<typename E2>
inline friend constexpr bool operator==(const unexpected& x, const unexpected <E2>& y)
inline friend constexpr bool operator==(const unexpected& x, const unexpected<E2>& y)
{
return x.error() == y.error();
}
@ -122,31 +122,48 @@ namespace blt
template<typename U, typename G>
inline static constexpr bool eight_insanity_v =
std::is_constructible_v<T, expected<U, G>&> || std::is_constructible_v<T, expected<U, G>> ||
std::is_constructible_v<T, const expected<U, G>&> || std::is_constructible_v<T, const expected<U, G>> ||
std::is_convertible_v<expected<U, G>&, T> || std::is_convertible_v<expected<U, G>, T> ||
std::is_convertible_v<const expected<U, G>&, T> || std::is_convertible_v<const expected<U, G>, T>;
std::is_constructible_v<T, const expected<U, G>&> || std::is_constructible_v<T, const expected<U, G>> ||
std::is_convertible_v<expected<U, G>&, T> || std::is_convertible_v<expected<U, G>, T> ||
std::is_convertible_v<const expected<U, G>&, T> || std::is_convertible_v<const expected<U, G>, T>;
template<typename U, typename G>
inline static constexpr bool four_insanity_v =
std::is_constructible_v<unexpected<E>, expected<U, G>&> || std::is_constructible_v<unexpected<E>, expected<U, G>> ||
std::is_constructible_v<unexpected<E>, const expected<U, G>&> || std::is_constructible_v<unexpected<E>, const expected<U, G>>;
std::is_constructible_v<unexpected<E>, const expected<U, G>&> || std::is_constructible_v<unexpected<E>, const expected<U, G>>;
public:
template<typename std::enable_if_t<std::is_default_constructible_v<T>, bool> = true>
constexpr expected() noexcept: v(T())
template<typename G, std::enable_if_t<std::is_default_constructible_v<G> && std::is_convertible_v<G, T>, bool> = true>
constexpr expected(): v(G{})
{}
constexpr expected(const expected& copy) = delete;
constexpr expected(expected&& move) noexcept: v(move ? std::move(*move) : std::move(move.error()))
// template<typename H, std::enable_if_t<!std::is_default_constructible_v<T> && std::is_default_constructible_v<E> && std::is_convertible_v<H, E>, bool> = true>
// constexpr expected(): v(H{})
// {}
// constexpr expected(const expected& copy) = delete;
constexpr expected(const expected<T, E, true>& copy): expected<T, E, true>::v(copy.v) // NOLINT
{}
expected& operator=(const expected& copy)
{
v = copy.v;
return *this;
}
constexpr expected(expected&& move) noexcept: v(std::move(move.v))
{}
expected& operator=(expected&& move)
{
std::swap(v, move.v);
return *this;
}
/*
* (4)...(5)
*/
template<class U, class G, class UF = std::add_lvalue_reference_t<const U>, class GF = const G&, std::enable_if_t<
(!std::is_convertible_v<UF, T> || !std::is_convertible_v<GF, E>) && (std::is_constructible_v<T, UF> || std::is_void_v<U>) &&
std::is_constructible_v<E, GF> && !eight_insanity_v < U, G>&& !four_insanity_v<U, G>, bool> = true>
std::is_constructible_v<E, GF> && !eight_insanity_v<U, G> && !four_insanity_v<U, G>, bool> = true>
constexpr explicit expected(const expected<U, G>& other):
v(other.has_value() ? std::forward<UF>(*other) : std::forward<GF>(other.error()))
@ -154,7 +171,7 @@ namespace blt
template<class U, class G, class UF = U, class GF = G, std::enable_if_t<
(!std::is_convertible_v<UF, T> || !std::is_convertible_v<GF, E>) && (std::is_constructible_v<T, UF> || std::is_void_v<U>) &&
std::is_constructible_v<E, GF> && !eight_insanity_v < U, G>&& !four_insanity_v<U, G>, bool> = true>
std::is_constructible_v<E, GF> && !eight_insanity_v<U, G> && !four_insanity_v<U, G>, bool> = true>
constexpr explicit expected(expected<U, G>&& other):
v(other.has_value() ? std::forward<UF>(*other) : std::forward<GF>(other.error()))
@ -162,17 +179,17 @@ namespace blt
template<class U, class G, class UF = std::add_lvalue_reference_t<const U>, class GF = const G&, std::enable_if_t<
(std::is_convertible_v<UF, T> && std::is_convertible_v<GF, E>) && (std::is_constructible_v<T, UF> || std::is_void_v<U>) &&
std::is_constructible_v<E, GF> && !eight_insanity_v < U, G>&& !four_insanity_v<U, G>, bool> = true>
std::is_constructible_v<E, GF> && !eight_insanity_v<U, G> && !four_insanity_v<U, G>, bool> = true>
constexpr expected(const expected<U, G>& other):
constexpr expected(const expected<U, G>& other): // NOLINT
v(other.has_value() ? std::forward<UF>(*other) : std::forward<GF>(other.error()))
{}
template<class U, class G, class UF = U, class GF = G, std::enable_if_t<
(std::is_convertible_v<UF, T> && std::is_convertible_v<GF, E>) && (std::is_constructible_v<T, UF> || std::is_void_v<U>) &&
std::is_constructible_v<E, GF> && !eight_insanity_v < U, G>&& !four_insanity_v<U, G>, bool> = true>
std::is_constructible_v<E, GF> && !eight_insanity_v<U, G> && !four_insanity_v<U, G>, bool> = true>
constexpr expected(expected<U, G>&& other):
constexpr expected(expected<U, G>&& other): // NOLINT
v(other.has_value() ? std::forward<UF>(*other) : std::forward<GF>(other.error()))
{}
@ -182,23 +199,23 @@ namespace blt
*/
template<class U = T, std::enable_if_t<!std::is_convertible_v<U, T> &&
!std::is_same_v<remove_cvref_t<T>, void> &&
!std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
!std::is_same_v<expected, remove_cvref_t<U>> &&
std::is_constructible_v<T, U> &&
!std::is_same_v<remove_cvref_t<U>, unexpected<U>> &&
!std::is_same_v<remove_cvref_t<U>, expected<T, E>>, bool> = true>
!std::is_same_v<remove_cvref_t<T>, void> &&
!std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
!std::is_same_v<expected, remove_cvref_t<U>> &&
std::is_constructible_v<T, U> &&
!std::is_same_v<remove_cvref_t<U>, unexpected<U>> &&
!std::is_same_v<remove_cvref_t<U>, expected<T, E>>, bool> = true>
constexpr explicit expected(U&& v): v(T(std::forward<U>(v)))
{}
template<class U = T, std::enable_if_t<std::is_convertible_v<U, T> &&
!std::is_same_v<remove_cvref_t<T>, void> &&
!std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
!std::is_same_v<expected, remove_cvref_t<U>> &&
std::is_constructible_v<T, U> &&
!std::is_same_v<remove_cvref_t<U>, unexpected<U>> &&
!std::is_same_v<remove_cvref_t<U>, expected<T, E>>, bool> = true>
constexpr expected(U&& v): v(T(std::forward<U>(v)))
!std::is_same_v<remove_cvref_t<T>, void> &&
!std::is_same_v<remove_cvref_t<U>, std::in_place_t> &&
!std::is_same_v<expected, remove_cvref_t<U>> &&
std::is_constructible_v<T, U> &&
!std::is_same_v<remove_cvref_t<U>, unexpected<U>> &&
!std::is_same_v<remove_cvref_t<U>, expected<T, E>>, bool> = true>
constexpr expected(U&& v): v(T(std::forward<U>(v))) // NOLINT
{}
/*
@ -212,7 +229,7 @@ namespace blt
template<class G, class GF = std::add_const_t<std::add_lvalue_reference_t<G>>, std::enable_if_t<
std::is_convertible_v<const G&, E> && std::is_constructible_v<E, GF>, bool> = true>
constexpr expected(const unexpected<G>& e): v(std::forward<GF>(e.error()))
constexpr expected(const unexpected<G>& e): v(std::forward<GF>(e.error())) // NOLINT
{}
/*
@ -226,7 +243,7 @@ namespace blt
template<class G, class GF = std::add_const_t<std::add_lvalue_reference_t<G>>, std::enable_if_t<
std::is_convertible_v<G, E> && std::is_constructible_v<E, GF>, bool> = true>
constexpr expected(unexpected<G>&& e): v(std::forward<GF>(e.error()))
constexpr expected(unexpected<G>&& e): v(std::forward<GF>(e.error())) // NOLINT
{}
/*
@ -252,10 +269,6 @@ namespace blt
constexpr explicit expected(unexpect_t, std::initializer_list<U> il, Args&& ... args): v(E(il, std::forward<Args>(args)...))
{}
expected& operator=(const expected& copy) = delete;
expected& operator=(expected&& move) = default;
[[nodiscard]] constexpr explicit operator bool() const noexcept
{
return std::holds_alternative<T>(v);
@ -362,15 +375,14 @@ namespace blt
};
template<typename T, typename E>
class expected<T, E, true> : expected<T, E, false>
class expected<T, E, false>
{
public:
using expected<T, E, false>::expected;
using expected<T, E, true>::expected;
constexpr expected(const expected& copy): expected<T, E, false>::v(copy ? *copy : copy.error())
{}
constexpr expected(const expected<T, E, false>& copy) = delete;
expected& operator=(const expected& copy) = default;
expected& operator=(const expected& copy) = delete;
};
}

View File

@ -172,6 +172,8 @@ namespace blt::logging
void flush();
void newline();
void setThreadName(const std::string& name);
void setLogFormat(const log_format& format);
@ -630,8 +632,9 @@ namespace blt::logging {
void log_stream_internal(const std::string& str, const logger& logger) {
auto& s = loggingStreamLines[std::this_thread::get_id()][logger.level];
s += str;
// s += str;
for (char c : str){
s += c;
if (c == '\n'){
log(s, logger.level, logger.file, logger.line);
s = "";
@ -676,6 +679,11 @@ namespace blt::logging {
std::cout.flush();
}
void newline()
{
std::cout << std::endl;
}
}
#endif
@ -705,6 +713,7 @@ namespace blt::logging {
#define BLT_ERROR(format, ...)
#define BLT_FATAL(format, ...)
#else
#define BLT_NEWLINE() blt::logging::newline()
#define BLT_LOG(format, level, ...) blt::logging::log(format, level, __FILE__, __LINE__, ##__VA_ARGS__)
#define BLT_LOG_STREAM(level) blt::logging::logger{level, __FILE__, __LINE__}
#ifdef BLT_DISABLE_TRACE

View File

@ -224,7 +224,7 @@ namespace blt
constexpr inline const_iterator crbegin() const noexcept
{
return const_reverse_iterator {cend()};
return const_reverse_iterator{cend()};
}
constexpr inline reverse_iterator crend() const noexcept
@ -248,6 +248,276 @@ namespace blt
scoped_buffer operator=(scoped_buffer& copyAssignment) = delete;
};
// TODO: might already have a version of this somewhere!
template<typename T, bool = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>>
class expanding_buffer;
template<typename T>
class expanding_buffer<T, true>
{
public:
using element_type = T;
using value_type = std::remove_cv_t<T>;
using pointer = T*;
using const_pointer = const T*;
using reference = T&;
using const_reference = const T&;
using iterator = ptr_iterator<T>;
using const_iterator = ptr_iterator<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
T* buffer_ = nullptr;
size_t size_ = 0;
public:
constexpr expanding_buffer(): buffer_(nullptr), size_(0)
{}
constexpr explicit expanding_buffer(size_t size): size_(size)
{
if (size > 0)
buffer_ = new T[size];
else
buffer_ = nullptr;
}
constexpr expanding_buffer(const expanding_buffer& copy)
{
if (copy.size() == 0)
{
buffer_ = nullptr;
size_ = 0;
return;
}
buffer_ = new T[copy.size()];
size_ = copy.size_;
if constexpr (std::is_trivially_copyable_v<T>)
{
std::memcpy(buffer_, copy.buffer_, copy.size() * sizeof(T));
} else
{
if constexpr (std::is_copy_constructible_v<T> && !std::is_copy_assignable_v<T>)
{
for (size_t i = 0; i < this->size_; i++)
buffer_[i] = T(copy[i]);
} else
for (size_t i = 0; i < this->size_; i++)
buffer_[i] = copy[i];
}
}
constexpr expanding_buffer& operator=(const expanding_buffer& copy)
{
if (&copy == this)
return *this;
if (copy.size() == 0)
{
buffer_ = nullptr;
size_ = 0;
return *this;
}
delete_this(buffer_, size());
buffer_ = new T[copy.size()];
size_ = copy.size_;
if constexpr (std::is_trivially_copyable_v<T>)
{
std::memcpy(buffer_, copy.buffer_, copy.size() * sizeof(T));
} else
{
if constexpr (std::is_copy_constructible_v<T> && !std::is_copy_assignable_v<T>)
{
for (size_t i = 0; i < this->size_; i++)
buffer_[i] = T(copy[i]);
} else
for (size_t i = 0; i < this->size_; i++)
buffer_[i] = copy[i];
}
return *this;
}
constexpr expanding_buffer(expanding_buffer&& move) noexcept
{
delete_this(buffer_, size());
buffer_ = move.buffer_;
size_ = move.size();
move.buffer_ = nullptr;
}
constexpr expanding_buffer& operator=(expanding_buffer&& moveAssignment) noexcept
{
delete_this(buffer_, size());
buffer_ = moveAssignment.buffer_;
size_ = moveAssignment.size();
moveAssignment.buffer_ = nullptr;
return *this;
}
/**
* Resize the internal buffer. Nothing will occur if the sizes are equal.
* This function WILL NOT COPY ANY DATA. It is meant for use when creating a scoped buffer without size.
*/
constexpr void resize(size_t size)
{
if (size == 0)
return;
if (size == size_)
return;
delete_this(buffer_, this->size());
buffer_ = new T[size];
size_ = size;
}
constexpr inline T& operator[](size_t index)
{
if (index >= size())
allocate_for(index);
return buffer_[index];
}
constexpr inline const T& operator[](size_t index) const
{
if (index >= size())
BLT_ABORT("Index out of bounds");
return buffer_[index];
}
constexpr inline T* operator*()
{
return buffer_;
}
[[nodiscard]] constexpr inline size_t size() const
{
return size_;
}
constexpr inline T*& ptr()
{
return buffer_;
}
constexpr inline const T* const& ptr() const
{
return buffer_;
}
constexpr inline const T* const& data() const
{
return buffer_;
}
constexpr inline T*& data()
{
return buffer_;
}
constexpr iterator begin() noexcept
{
return iterator{data()};
}
constexpr iterator end() noexcept
{
return iterator{data() + size()};
}
constexpr const_iterator cbegin() const noexcept
{
return const_iterator{data()};
}
constexpr const_iterator cend() const noexcept
{
return const_iterator{data() + size()};
}
constexpr inline reverse_iterator rbegin() noexcept
{
return reverse_iterator{end()};
}
constexpr inline reverse_iterator rend() noexcept
{
return reverse_iterator{begin()};
}
constexpr inline const_iterator crbegin() const noexcept
{
return const_reverse_iterator{cend()};
}
constexpr inline reverse_iterator crend() const noexcept
{
return reverse_iterator{cbegin()};
}
~expanding_buffer()
{
delete_this(buffer_, size());
}
void expand(blt::size_t new_size)
{
T* new_buffer = new T[new_size];
if (buffer_ != nullptr)
{
if constexpr (std::is_trivially_copyable_v<T>)
{
std::memcpy(new_buffer, buffer_, size_ * sizeof(T));
} else
{
if constexpr (std::is_copy_constructible_v<T> && !std::is_move_constructible_v<T>)
{
for (size_t i = 0; i < size_; i++)
new_buffer[i] = T(buffer_[i]);
} else
for (size_t i = 0; i < size_; i++)
new_buffer[i] = std::move(buffer_[i]);
}
delete[] buffer_;
}
buffer_ = new_buffer;
size_ = new_size;
}
private:
void allocate_for(blt::size_t accessing_index)
{
accessing_index = std::max(size_, accessing_index);
accessing_index = blt::mem::next_byte_allocation(accessing_index);
expand(accessing_index);
}
inline void delete_this(T* buffer, blt::size_t)
{
// if constexpr (std::is_trivially_destructible_v<T>)
// return;
// if (buffer == nullptr)
// return;
// for (blt::size_t i = 0; i < size; i++)
// buffer[i]->~T();
// free(buffer);
delete[] buffer;
}
};
template<typename T>
class expanding_buffer<T, false> : expanding_buffer<T, true>
{
using expanding_buffer<T, true>::expanding_buffer;
public:
expanding_buffer(const expanding_buffer& copy) = delete;
expanding_buffer operator=(expanding_buffer& copyAssignment) = delete;
};
template<typename T>
struct nullptr_initializer
{

View File

@ -19,6 +19,7 @@
#ifndef BLT_MEMORY_UTIL_H
#define BLT_MEMORY_UTIL_H
#include <blt/std/types.h>
#include <type_traits>
#include <array>
#include <cstring>
@ -113,8 +114,10 @@ namespace blt::mem
return fromBytes(in, *out);
}
inline static size_t next_byte_allocation(size_t prev_size, size_t default_allocation_block = 8192)
inline static size_t next_byte_allocation(size_t prev_size, size_t default_allocation_block = 8192, size_t default_size = 16)
{
if (prev_size < default_size)
return default_size;
if (prev_size < default_allocation_block)
return prev_size * 2;
return prev_size + default_allocation_block;
@ -138,19 +141,24 @@ namespace blt
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using difference_type = blt::ptrdiff_t;
using value_type = V;
using pointer = value_type*;
using reference = value_type&;
using iter_reference = ptr_iterator&;
explicit ptr_iterator(V* v): _v(v)
{}
reference operator*() const
{ return *_v; }
{
return *_v;
}
pointer operator->()
{ return _v; }
{
return _v;
}
ptr_iterator& operator++()
{
@ -178,6 +186,63 @@ namespace blt
return tmp;
}
iter_reference operator+=(difference_type amount)
{
_v += amount;
return *this;
}
iter_reference operator-=(difference_type amount)
{
_v -= amount;
return *this;
}
reference operator[](difference_type index)
{
return *(_v + index);
}
reference operator[](blt::size_t index)
{
return *(_v + index);
}
friend bool operator<(const ptr_iterator& a, const ptr_iterator& b)
{
return b._v - a._v > 0;
}
friend bool operator>(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v - b._v > 0;
}
friend bool operator<=(const ptr_iterator& a, const ptr_iterator& b)
{
return b._v - a._v >= 0;
}
friend bool operator>=(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v - b._v >= 0;
}
friend difference_type operator-(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v - b._v;
}
friend ptr_iterator operator+(const ptr_iterator& a, difference_type n)
{
return ptr_iterator(a._v + n);
}
friend ptr_iterator operator+(difference_type n, const ptr_iterator& a)
{
return ptr_iterator(a._v + n);
}
friend bool operator==(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v == b._v;

109
include/blt/std/mmap.h Normal file
View File

@ -0,0 +1,109 @@
#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_MMAP_H
#define BLT_MMAP_H
#include <blt/std/logging.h>
#include <blt/std/types.h>
#include <cstdlib>
// size of 2mb in bytes
inline constexpr blt::size_t BLT_2MB_SIZE = 2048 * 1024;
inline constexpr blt::size_t BLT_1GB_SIZE = 1048576 * 1024;
namespace blt
{
enum class huge_page_t : blt::u64
{
BLT_2MB_PAGE,
BLT_1GB_PAGE
};
class bad_alloc_t : public std::exception
{
public:
bad_alloc_t() = default;
explicit bad_alloc_t(std::string_view str): str(str)
{}
explicit bad_alloc_t(std::string str): str(std::move(str))
{}
[[nodiscard]] const char* what() const noexcept override
{
return str.c_str();
}
private:
std::string str;
};
/**
* Logging function used for handling mmap errors. call after a failed mmap call.
*/
std::string handle_mmap_error();
inline static constexpr blt::size_t align_size_to(blt::size_t size, blt::size_t align)
{
const blt::size_t MASK = ~(align - 1);
return (size & MASK) + align;
}
void* allocate_huge_pages(huge_page_t page_type, blt::size_t bytes);
void mmap_free(void* ptr, blt::size_t bytes);
class mmap_huge_allocator
{
public:
explicit mmap_huge_allocator(huge_page_t page_type): page_type(page_type)
{}
void* allocate(blt::size_t bytes) // NOLINT
{
return allocate_huge_pages(page_type, bytes);
}
void deallocate(void* ptr, blt::size_t bytes) // NOLINT
{
mmap_free(ptr, bytes);
}
private:
huge_page_t page_type;
};
class aligned_huge_allocator
{
public:
void* allocate(blt::size_t bytes) // NOLINT
{
return std::aligned_alloc(BLT_2MB_SIZE, bytes);
}
void deallocate(void* ptr, blt::size_t) // NOLINT
{
std::free(ptr);
}
};
}
#endif //BLT_MMAP_H

View File

@ -7,86 +7,218 @@
#ifndef BLT_RANDOM_H
#define BLT_RANDOM_H
#include <blt/std/types.h>
#include <random>
namespace blt::random {
namespace blt::random
{
// https://github.com/avaneev/komihash/tree/main
static inline uint32_t PCG_Hash(uint32_t input) {
uint32_t state = input * 747796405u + 2891336453u;
uint32_t word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^
word;
constexpr static inline blt::u32 pcg_hash32(blt::u32 input)
{
blt::u32 state = input * 747796405u + 2891336453u;
blt::u32 word = ((state >> ((state >> 28u) + 4u)) ^ state) * 277803737u;
return (word >> 22u) ^ word;
}
static inline float randomFloat(uint32_t& seed){
seed = PCG_Hash(seed);
return (float)seed / (float)std::numeric_limits<uint32_t>::max();
//https://lemire.me/blog/2018/08/15/fast-strongly-universal-64-bit-hashing-everywhere/
constexpr static inline blt::u64 murmur64(blt::u64 h)
{
h ^= h >> 33;
h *= 0xff51afd7ed558ccdL;
h ^= h >> 33;
h *= 0xc4ceb9fe1a85ec53L;
h ^= h >> 33;
return h;
}
constexpr static inline double pcg_double32(blt::u32& seed)
{
seed = pcg_hash32(seed);
return static_cast<double>(seed) / static_cast<double>(std::numeric_limits<blt::u32>::max());
}
constexpr static inline float pcg_float32(blt::u32& seed)
{
return static_cast<float>(pcg_double32(seed));
}
/**
* @return random float without changing seed
*/
static inline float randomFloat_c(uint32_t seed){
return randomFloat(seed);
constexpr static inline float pcg_float32c(blt::u32 seed)
{
return pcg_float32(seed);
}
constexpr static inline double pcg_double32c(blt::u32 seed)
{
return pcg_double32(seed);
}
/**
* @param seed seed for random
* @param min inclusive min
* @param max exclusive max
* @return random int between min (inclusive) and max (exclusive)
*/
static inline int randomInt(uint32_t& seed, int min = 0, int max = 1){
return (int)((randomFloat(seed) * (float)(max - min)) + (float)min);
template<typename T = blt::i32>
constexpr static inline T pcg_random32(blt::u32& seed, T min = 0, T max = 2)
{
return static_cast<T>((pcg_double32(seed) * static_cast<double>(max - min)) + static_cast<double>(min));
}
static inline int randomInt_c(uint32_t seed, int min = 0, int max = 1){
return randomInt(seed, min, max);
}
/**
* Creates a container class for generating random number distributions
* @tparam T numeric type
* @tparam dist std::uniform_real_distribution or std::uniform_int_distribution
*/
template<typename T, template<typename = T> typename dist = std::uniform_real_distribution>
class random {
private:
std::random_device rd; // obtain a random number from hardware
std::mt19937 gen;
dist<T>* distribution = nullptr;
public:
/**
* Construct the random number generator.
* @param min min value possible to generate. (default: 0)
* @param max max value possible to generate. (default: 1)
* @param seed seed to use in generating random values. (default: 0)
*/
explicit random(T min = (T) 0, T max = (T) 1, long seed = 0): gen(std::mt19937(seed)) {
distribution = new dist(min, max);
}
/**
* Note the min/max are inclusive and defaults to a **uniform** distribution.
* @return random number between the defined min/max or the default of [0,1].
*/
T get() {
return (*distribution)(gen);
}
~random() {
delete distribution;
}
};
template<typename T>
class simplex_noise {
private:
template<typename T = blt::i32>
constexpr static inline T pcg_random32c(blt::u32 seed, T min = 0, T max = 2)
{
return pcg_random32(seed, min, max);
}
constexpr static inline double murmur_double64(blt::u64& seed)
{
seed = murmur64(seed);
return static_cast<double>(seed) / static_cast<double>(std::numeric_limits<blt::u64>::max());
}
constexpr static inline float murmur_float64(blt::u64& seed)
{
return static_cast<float>(murmur_double64(seed));
}
constexpr static inline float murmur_float64c(blt::u64 seed)
{
return murmur_float64(seed);
}
constexpr static inline double murmur_double64c(blt::u64 seed)
{
return murmur_double64(seed);
}
template<typename T = blt::i32>
constexpr static inline T murmur_random64(blt::u64& seed, T min = 0, T max = 2)
{
return static_cast<T>((murmur_double64(seed) * static_cast<double>(max - min)) + static_cast<double>(min));
}
template<typename T = blt::i32>
constexpr static inline T murmur_random64c(blt::u64 seed, T min = 0, T max = 2)
{
return murmur_random64(seed, min, max);
}
#define BLT_RANDOM_FUNCTION blt::random::murmur_random64
#define BLT_RANDOM_FLOAT blt::random::murmur_float64
#define BLT_RANDOM_DOUBLE blt::random::murmur_double64
class random_t
{
public:
simplex_noise() {
using result_type = blt::u64;
constexpr static result_type MIN = std::numeric_limits<result_type>::min();
constexpr static result_type MAX = std::numeric_limits<result_type>::max() - 1;
explicit constexpr random_t(blt::u64 seed): seed(seed)
{}
constexpr void set_seed(blt::u64 s)
{
seed = s;
}
constexpr float get_float()
{
return BLT_RANDOM_FLOAT(seed);
}
constexpr double get_double()
{
return BLT_RANDOM_DOUBLE(seed);
}
// [min, max)
constexpr double get_double(double min, double max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
// [min, max)
constexpr float get_float(float min, float max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr i32 get_i32(i32 min, i32 max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr u32 get_u32(u32 min, u32 max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr i64 get_i64(i64 min, i64 max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr u64 get_u64(u64 min, u64 max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr blt::size_t get_size_t(blt::size_t min, blt::size_t max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
template<typename T>
constexpr T get(T min, T max)
{
return BLT_RANDOM_FUNCTION(seed, min, max);
}
constexpr bool choice()
{
return BLT_RANDOM_DOUBLE(seed) < 0.5;
}
constexpr bool choice(double cutoff)
{
return BLT_RANDOM_DOUBLE(seed) <= cutoff;
}
template<typename Container>
constexpr auto& select(Container& container)
{
return container[get_u64(0, container.size())];
}
template<typename Container>
constexpr const auto& select(const Container& container)
{
return container[get_u64(0, container.size())];
}
constexpr static result_type min()
{
return MIN;
}
constexpr static result_type max()
{
return MAX;
}
constexpr result_type operator()()
{
return get_u64(min(), max() + 1);
}
private:
blt::u64 seed;
};
}

View File

@ -9,6 +9,8 @@
#define BLT_RANGES_H
#include <blt/std/types.h>
#include <blt/meta/meta.h>
#include <blt/meta/iterator.h>
#include <type_traits>
#include <iterator>
#include <memory>
@ -19,139 +21,148 @@ namespace blt
{
namespace itr
{
template<typename TYPE_ITR, bool is_ptr = std::is_pointer_v<TYPE_ITR>>
class iterator;
template<typename TYPE_ITR>
class iterator<TYPE_ITR, false>
template<typename Begin, typename End>
class itr_container
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = typename TYPE_ITR::value_type;
using difference_type = typename TYPE_ITR::difference_type;
using pointer = typename TYPE_ITR::pointer;
using reference = typename TYPE_ITR::reference;
using const_reference = const typename TYPE_ITR::reference;
private:
blt::size_t index = 0;
TYPE_ITR current;
public:
explicit iterator(TYPE_ITR current): current(std::move(current))
itr_container(Begin&& begin, End&& end): begin_(std::forward<Begin>(begin)), end_(std::forward<End>(end))
{}
iterator& operator++()
Begin begin()
{
++index;
++current;
return *this;
return begin_;
}
bool operator==(iterator other) const
End end()
{
return current == other.current;
return end_;
}
bool operator!=(iterator other) const
{
return current != other.current;
}
std::pair<blt::size_t, const_reference> operator*() const
{
return {index, *current};
};
std::pair<blt::size_t, reference> operator*()
{
return {index, *current};
};
private:
Begin begin_;
End end_;
};
template<typename TYPE_ITR>
class iterator<TYPE_ITR, true>
// TODO: cleanup! all of this! add support for reversing
template<typename C1_TYPE, typename C2_TYPE>
class pair_iterator
{
public:
using iterator_category = std::input_iterator_tag;
using value_type = std::remove_pointer_t<TYPE_ITR>;
using difference_type = std::ptrdiff_t;
using pointer = TYPE_ITR;
using reference = std::remove_pointer_t<TYPE_ITR>&;
using const_reference = const std::remove_pointer_t<TYPE_ITR>&;
private:
blt::size_t index = 0;
TYPE_ITR current;
public:
explicit iterator(TYPE_ITR current): current(std::move(current))
using c1_ref = blt::meta::deref_return_t<C1_TYPE>;
using c2_ref = blt::meta::deref_return_t<C2_TYPE>;
using iterator_category = std::forward_iterator_tag;
using value_type = std::pair<c1_ref, c2_ref>;
using difference_type = blt::ptrdiff_t;
using pointer = void*;
using reference = value_type&;
using const_reference = const value_type&;
explicit pair_iterator(C1_TYPE c1, C2_TYPE c2): current_c1_iter(c1), current_c2_iter(c2)
{}
iterator& operator++()
pair_iterator& operator++()
{
++index;
++current;
++current_c1_iter;
++current_c2_iter;
return *this;
}
bool operator==(iterator other) const
bool operator==(pair_iterator other) const
{
return current == other.current;
return current_c1_iter == other.current_c1_iter && current_c2_iter == other.current_c2_iter;
}
bool operator!=(iterator other) const
bool operator!=(pair_iterator other) const
{
return current != other.current;
return current_c1_iter != other.current_c1_iter || current_c2_iter != other.current_c2_iter;
}
std::pair<blt::size_t, const_reference> operator*() const
value_type operator*() const
{
return {index, *current};
return {*current_c1_iter, *current_c2_iter};
};
std::pair<blt::size_t, reference> operator*()
value_type operator*()
{
return {index, *current};
return {*current_c1_iter, *current_c2_iter};
};
private:
C1_TYPE current_c1_iter;
C2_TYPE current_c2_iter;
};
}
template<typename TYPE_ITR>
class enumerator
template<typename Begin, typename End>
static inline auto iterate(Begin&& begin, End&& end)
{
return itr::itr_container<Begin, End>{std::forward<Begin>(begin), std::forward<End>(end)};
}
template<typename Begin, typename End>
static inline auto reverse_iterate(Begin&& begin, End&& end)
{
return itr::itr_container{std::reverse_iterator(std::forward<Begin>(end)), std::reverse_iterator(std::forward<End>(begin))};
}
template<typename C1_ITER, typename C2_ITER, template<typename, typename> typename iterator = itr::pair_iterator>
class pair_enumerator
{
public:
explicit enumerator(TYPE_ITR begin, TYPE_ITR end): begin_(std::move(begin)), end_(std::move(end))
{}
explicit pair_enumerator(C1_ITER c1_begin, C1_ITER c1_end, C2_ITER c2_begin, C2_ITER c2_end):
begin_(std::move(c1_begin), std::move(c2_begin)), end_(std::move(c1_end), std::move(c2_end))
{
auto size_c1 = c1_end - c1_begin;
auto size_c2 = c2_end - c2_begin;
if (size_c1 != size_c2)
throw std::runtime_error("Iterator sizes don't match!");
}
itr::iterator<TYPE_ITR> begin()
iterator<C1_ITER, C2_ITER> begin()
{
return begin_;
}
itr::iterator<TYPE_ITR> end()
iterator<C1_ITER, C2_ITER> end()
{
return end_;
}
private:
itr::iterator<TYPE_ITR> begin_;
itr::iterator<TYPE_ITR> end_;
iterator<C1_ITER, C2_ITER> begin_;
iterator<C1_ITER, C2_ITER> end_;
};
template<typename T>
static inline auto enumerate(const T& container)
{
return enumerator{container.begin(), container.end()};
}
template<typename T>
static inline auto enumerate(T& container)
{
return enumerator{container.begin(), container.end()};
}
template<typename T>
static inline auto enumerate(T&& container)
{
return enumerator{container.begin(), container.end()};
}
// template<typename T, typename G>
// static inline auto in_pairs(const T& container1, const G& container2)
// {
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
// }
//
// template<typename T, typename G>
// static inline auto in_pairs(T& container1, G& container2)
// {
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
// }
//
// template<typename T, typename G, blt::size_t size>
// static inline auto in_pairs(const T(& container1)[size], const G(& container2)[size])
// {
// return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
// }
//
// template<typename T, typename G, blt::size_t size>
// static inline auto in_pairs(T(& container1)[size], G(& container2)[size])
// {
// return pair_enumerator{&container1[0], &container1[size], &container2[0], &container2[size]};
// }
//
// template<typename T, typename G>
// static inline auto in_pairs(T&& container1, G&& container2)
// {
// return pair_enumerator{container1.begin(), container1.end(), container2.begin(), container2.end()};
// }
template<typename T>
struct range
@ -366,19 +377,19 @@ namespace blt
template<std::size_t N, typename std::enable_if_t<(N == dynamic_extent || N == extent) &&
(std::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true>
constexpr span(element_type (& arr)[N]) noexcept: size_{N}, data_{arr}
constexpr span(element_type (& arr)[N]) noexcept: size_{N}, data_{arr} // NOLINT
{}
template<class U, std::size_t N, typename std::enable_if_t<(N == dynamic_extent || N == extent) &&
(std::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true>
constexpr span(std::array<U, N>& arr) noexcept: size_(N), data_{arr.data()}
constexpr span(std::array<U, N>& arr) noexcept: size_(N), data_{arr.data()} // NOLINT
{}
template<class U, std::size_t N, typename std::enable_if_t<(N == dynamic_extent || N == extent) &&
(std::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true>
constexpr span(const std::array<U, N>& arr) noexcept: size_(N), data_{arr.data()}
constexpr span(const std::array<U, N>& arr) noexcept: size_(N), data_{arr.data()} // NOLINT
{}
template<class R, class RCV = std::remove_cv_t<std::remove_reference_t<R>>, typename std::enable_if_t<
@ -390,17 +401,17 @@ namespace blt
template<class R, class RCV = std::remove_cv_t<std::remove_reference_t<R>>, typename std::enable_if_t<
extent == dynamic_extent && span_detail::is_cont_v<RCV> &&
std::is_convertible_v<std::remove_pointer_t<decltype(std::data(std::declval<R>()))>(*)[], T(*)[]>, bool> = true>
constexpr span(R&& range): size_(std::size(range)), data_(std::data(range))
constexpr span(R&& range): size_(std::size(range)), data_(std::data(range)) // NOLINT
{}
template<size_type SIZE, typename std::enable_if_t<
extent != dynamic_extent && SIZE == extent && std::is_const_v<element_type>, bool> = true>
explicit constexpr span(std::initializer_list<value_type> il) noexcept: size_(il.size()), data_(&il.begin())
explicit constexpr span(std::initializer_list<value_type> il) noexcept: size_(il.size()), data_(&il.begin()) // NOLINT
{}
template<size_type SIZE, typename std::enable_if_t<
extent == dynamic_extent && SIZE == extent && std::is_const_v<element_type>, bool> = true>
explicit span(std::initializer_list<value_type> il) noexcept: size_(il.size()), data_(&il.begin())
explicit span(std::initializer_list<value_type> il) noexcept: size_(il.size()), data_(&il.begin()) // NOLINT
{}
template<class U, std::size_t N, typename std::enable_if_t<
@ -410,9 +421,16 @@ namespace blt
template<class U, std::size_t N, typename std::enable_if_t<
!(extent != dynamic_extent && N == dynamic_extent) && std::is_convertible_v<U(*)[], T(*)[]>, bool> = true>
constexpr span(const span<U, N>& source) noexcept: size_{source.size()}, data_{source.data()}
constexpr span(const span<U, N>& source) noexcept: size_{source.size()}, data_{source.data()} // NOLINT
{}
constexpr span& operator=(const span& copy)
{
size_ = copy.size();
data_ = copy.data();
return *this;
}
constexpr span(const span& other) noexcept = default;
constexpr iterator begin() const noexcept

View File

@ -22,13 +22,12 @@
#if defined(__AVX__) || defined(__AVX2__)
#include <immintrin.h>
#include <xmmintrin.h>
#else
//#warning AVX is not available.
#endif
#include <xmmintrin.h>
namespace blt
{
class simd

View File

@ -91,7 +91,16 @@ namespace blt::string
#endif
}
BLT_CPP20_CONSTEXPR bool ends_with(std::string_view string, std::string_view search);
inline BLT_CPP20_CONSTEXPR bool ends_with(std::string_view string, std::string_view search)
{
#ifdef BLT_USE_CPP20
return string.ends_with(search);
#else
if (string.empty())
return false;
return string.substr(string.size() - search.size()) == search;
#endif
}
static inline BLT_CPP20_CONSTEXPR bool ends_with(std::string_view string, char search)
{

View File

@ -17,6 +17,7 @@
#endif
#else
#include <chrono>
using suseconds_t = int;
#endif
#include <cstdint>

View File

@ -19,20 +19,91 @@
#ifndef BLT_THREAD_H
#define BLT_THREAD_H
#include <blt/std/types.h>
#include <thread>
#include <functional>
#include <string>
#include <vector>
#include <queue>
#include <utility>
#include <variant>
#include <atomic>
#include <mutex>
#include <chrono>
#include <optional>
#include <blt/std/logging.h>
#include <condition_variable>
namespace blt
{
class barrier
{
public:
explicit barrier(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(barrier&& move) = delete;
barrier& operator=(const barrier& copy) = delete;
barrier& operator=(barrier&& move) = delete;
~barrier() = default;
void wait()
{
// (unique_lock acquires lock)
std::unique_lock lock(count_mutex);
std::size_t current_uses = use_count;
if (++threads_waiting == thread_count)
{
threads_waiting = 0;
use_count++;
cv.notify_all();
} else
{
if constexpr (BUSY_LOOP_WAIT > 0) // NOLINT
{
lock.unlock();
for (blt::size_t i = 0; i < BUSY_LOOP_WAIT; i++)
{
if (use_count != current_uses || (exit_cond && exit_cond->get()))
return;
}
lock.lock();
}
cv.wait(lock, [this, &current_uses]() {
return (use_count != current_uses || (exit_cond && exit_cond->get()));
});
}
}
void notify_all()
{
cv.notify_all();
}
private:
blt::size_t thread_count;
blt::size_t threads_waiting;
std::atomic_uint64_t use_count;
std::optional<std::reference_wrapper<std::atomic_bool>> exit_cond;
std::mutex count_mutex;
std::condition_variable cv;
// 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;
};
/**
* @tparam queue should we use a queue or execute the same function over and over?
*/

View File

@ -37,10 +37,52 @@ namespace blt
using u64 = std::uint64_t;
using size_t = std::size_t;
using ptrdiff_t = std::ptrdiff_t;
using f32 = float;
using f64 = double;
#ifndef NO_BLT_NAMESPACE_ON_TYPES
}
#endif
namespace blt
{
template<typename T>
struct integer_type
{
using value_type = T;
T id;
integer_type() = default;
integer_type(T id): id(id) // NOLINT
{}
inline operator T() const // NOLINT
{
return id;
}
friend bool operator==(const integer_type<T>& a, const integer_type<T>& b)
{
return a.id == b.id;
}
friend bool operator!=(const integer_type<T>& a, const integer_type<T>& b)
{
return a.id != b.id;
}
friend bool operator<(const integer_type<T>& a, const integer_type<T>& b)
{
return a.id < b.id;
}
friend bool operator>(const integer_type<T>& a, const integer_type<T>& b)
{
return a.id > b.id;
}
};
}
#endif //BLT_TYPES_H

View File

@ -31,6 +31,9 @@
namespace blt
{
template<typename RefType>
using ref = std::reference_wrapper<RefType>;
static inline std::string demangle(const std::string& str)
{
int status;
@ -60,6 +63,12 @@ namespace blt
{
return demangle(typeid(T).name());
}
template<typename T>
static BLT_CPP20_CONSTEXPR inline std::string type_string_raw()
{
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; }
@ -87,13 +96,37 @@ namespace blt
#if defined(__GNUC__) || defined(__llvm__)
#define BLT_UNREACHABLE __builtin_unreachable()
#define BLT_ATTRIB_NO_INLINE __attribute__ ((noinline))
/**
* means that the return value is solely a function of the arguments,
* and if any of the arguments are pointers, then the pointers must not be dereferenced.
* Calls to functions whose return value is not affected by changes to the observable state of the program
* and that have no observable effects on such state other than
* to return a value may lend themselves to optimizations such as common subexpression elimination.
*/
#define BLT_ATTRIB_NO_SIDE_EFFECTS __attribute__((const))
/**
* the function has no side effects and the value returned depends on the arguments and the state of global variables.
* Therefore it is safe for the optimizer to elide some calls to it, if the arguments are the same,
* and the caller did not do anything to change the state of the globals in between the calls.
*/
#define BLT_ATTRIB_GLOBAL_READ_ONLY __attribute__((pure))
#else
#if defined(_MSC_VER) && !defined(__INTEL_COMPILER)
#define BLT_ATTRIB_NO_INLINE __declspec(noinline)
#define BLT_UNREACHABLE __assume(false)
#else
#define BLT_ATTRIB_NO_INLINE
#define BLT_UNREACHABLE
#endif
#define BLT_ATTRIB_CONST
#define BLT_ATTRIB_PURE
#endif
#if __cplusplus > 202002L
#undef BLT_UNREACHABLE
#define BLT_UNREACHABLE std::unreachable()
#endif
template<typename T>

View File

@ -25,6 +25,7 @@
#include <blt/compatibility.h>
#include "ranges.h"
#include <stdexcept>
#include <array>
namespace blt
{
@ -33,9 +34,14 @@ namespace blt
class static_vector
{
private:
T buffer_[MAX_SIZE];
std::array<T, MAX_SIZE> buffer_;
size_t size_ = 0;
using value_type = T;
using reference = T&;
using pointer = T*;
using const_reference = const T&;
using const_pointer = const T*;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
@ -59,21 +65,19 @@ namespace blt
return true;
}
constexpr inline T& at(size_t index)
//TODO: replace with placement new / byte data
template<typename... Args>
constexpr inline bool emplace_back(Args&& ... args)
{
if (index >= MAX_SIZE)
throw std::runtime_error("Array index " + std::to_string(index) + " out of bounds! (Max size: " + std::to_string(MAX_SIZE) + ')');
return buffer_[index];
if (size_ >= MAX_SIZE)
return false;
buffer_[size_++] = T{std::forward<Args>(args)...};
return true;
}
constexpr inline T& operator[](size_t index)
constexpr inline void pop_back()
{
return buffer_[index];
}
constexpr inline const T& operator[](size_t index) const
{
return buffer_[index];
size_--;
}
constexpr inline void reserve(size_t size)
@ -83,6 +87,18 @@ namespace blt
size_ = size;
}
[[nodiscard]] constexpr inline bool empty() const
{
return size() == 0;
}
constexpr inline void clear()
{
for (auto& v : *this)
v = {};
size_ = 0;
}
[[nodiscard]] constexpr inline size_t size() const
{
return size_;
@ -93,19 +109,66 @@ namespace blt
return MAX_SIZE;
}
constexpr inline T* data()
[[nodiscard]] constexpr inline blt::size_t max_size() const
{
return buffer_;
return MAX_SIZE;
}
constexpr inline T* operator*()
constexpr inline reference at(size_t index)
{
return buffer_;
if (index >= MAX_SIZE)
throw std::runtime_error("Array index " + std::to_string(index) + " out of bounds! (Max size: " + std::to_string(MAX_SIZE) + ')');
return buffer_[index];
}
constexpr inline const T* data() const
constexpr inline reference operator[](size_t index)
{
return buffer_;
return buffer_[index];
}
constexpr inline const_reference operator[](size_t index) const
{
return buffer_[index];
}
constexpr inline reference operator*()
{
return *buffer_.data();
}
constexpr inline const_reference operator*() const
{
return *buffer_.data();
}
constexpr inline pointer data()
{
return buffer_.data();
}
constexpr inline const_pointer data() const
{
return buffer_.data();
}
constexpr inline reference front()
{
return data()[0];
}
constexpr inline const_reference front() const
{
return data()[0];
}
constexpr inline reference back()
{
return data()[size() - 1];
}
constexpr inline const_reference back() const
{
return data()[size() - 1];
}
constexpr inline iterator begin() noexcept
@ -147,6 +210,67 @@ namespace blt
{
return reverse_iterator{cbegin()};
}
template<typename G, std::enable_if_t<std::is_convertible_v<G, T>, bool> = true>
constexpr iterator insert(const_iterator pos, G&& ref)
{
blt::ptrdiff_t loc = pos - buffer_;
if (size_ + 1 >= capacity())
{
BLT_ABORT("Inserting exceeds size of internal buffer!");
}
for (auto insert = end() - 1; (insert - buffer_) != loc - 1; insert--)
{
auto new_pos = insert + 1;
*new_pos = *insert;
}
buffer_[loc] = ref;
size_++;
return buffer_ + loc;
}
constexpr iterator erase(const_iterator pos)
{
blt::ptrdiff_t loc = pos - buffer_;
for (auto fetch = begin() + loc + 1; fetch != end(); fetch++)
{
auto insert = fetch - 1;
*insert = *fetch;
}
size_--;
return buffer_ + loc + 1;
}
constexpr iterator erase(const_iterator first, const_iterator last)
{
blt::ptrdiff_t first_pos = first - buffer_;
blt::ptrdiff_t last_pos = last - buffer_;
blt::ptrdiff_t remove_amount = last_pos - first_pos;
for (auto fetch = begin() + last_pos, insert = begin() + first_pos; fetch != end(); fetch++, insert++)
{
*insert = *fetch;
}
size_ -= remove_amount;
return buffer_ + first_pos + 1;
}
template<typename T1, blt::size_t size1, typename T2, blt::size_t size2, std::enable_if_t<std::is_convertible_v<T1, T2>, bool> = true>
constexpr friend bool operator==(const static_vector<T1, size1>& v1, const static_vector<T2, size2>& v2)
{
if (v1.size() != v2.size())
return false;
for (blt::size_t i = 0; i < v1.size(); i++)
{
if (v1[i] != v2[i])
return false;
}
return true;
}
};
template<typename T, typename ALLOC = std::allocator<T>>
@ -411,6 +535,78 @@ namespace blt
}
};
template<typename T, blt::size_t BUFFER_SIZE = 8 / sizeof(T), typename ALLOC = std::allocator<T>>
class svo_vector
{
public:
constexpr svo_vector() = default;
template<typename G, std::enable_if_t<std::is_convertible_v<G, T>, bool> = true>
constexpr svo_vector(std::initializer_list<G> list)
{
if (list.size() > BUFFER_SIZE)
{
// TODO: how to avoid copy here?
data.buffer_pointer = alloc.allocate(list.size());
for (const auto& v : blt::enumerate(list))
new (&data.buffer_pointer[v.first]) T(v.second);
capacity = list.size();
used = list.size();
} else
{
for (const auto& v : blt::enumerate(list))
new (&data.buffer[v.first]) T(v.second);
used = list.size();
}
}
template<typename G, std::enable_if_t<std::is_same_v<blt::vector<T>, G> || std::is_same_v<std::vector<T>, G>, bool> = true>
constexpr explicit svo_vector(G&& universal)
{
if (universal.size() > BUFFER_SIZE)
{
} else
{
}
}
[[nodiscard]] constexpr blt::size_t size() const
{
return used;
}
[[nodiscard]] constexpr bool is_heap() const
{
return used > BUFFER_SIZE;
}
BLT_CPP20_CONSTEXPR ~svo_vector()
{
if (is_heap())
{
for (blt::size_t i = 0; i < used; i++)
data.buffer_pointer[i].~T();
alloc.deallocate(data.buffer_pointer, capacity);
} else
{
for (blt::size_t i = 0; i < used; i++)
data.buffer[i].~T();
}
}
private:
union buffer_data
{
T* buffer_pointer;
T buffer[BUFFER_SIZE];
} data;
ALLOC alloc;
blt::size_t used = 0;
blt::size_t capacity = BUFFER_SIZE;
};
}
#endif //BLT_VECTOR_H

View File

@ -3,7 +3,7 @@
* Licensed under GNU General Public License V3.0
* See LICENSE file for license detail
*/
#include <blt/std/format.h>
#include <blt/format/format.h>
#include <blt/std/string.h>
#include <cmath>
#include "blt/std/logging.h"

View File

@ -6,6 +6,7 @@
#include <blt/parse/argparse.h>
#include <iostream>
#include <blt/std/string.h>
#include <blt/iterator/iterator.h>
#include <algorithm>
#include "blt/std/utility.h"
@ -122,10 +123,10 @@ namespace blt
{
std::string result = "[";
for (const auto& value : blt::enumerate(vec))
for (const auto& [index, value] : blt::enumerate(vec))
{
result += to_string(value.second);
if (value.first != vec.size() - 1)
result += to_string(value);
if (index != vec.size() - 1)
result += ", ";
}
result += "]";

View File

@ -21,6 +21,7 @@
#include <blt/parse/obj_loader.h>
#include <blt/fs/loader.h>
#include <blt/std/string.h>
#include <blt/iterator/iterator.h>
#include <cctype>
#include <charconv>
#include "blt/std/assert.h"
@ -141,10 +142,9 @@ namespace blt::parse
obj_model_t obj_loader::parseFile(std::string_view file)
{
auto lines = blt::fs::getLinesFromFile(std::string(file));
for (auto line_e : blt::enumerate(lines))
for (const auto& [index, line] : blt::enumerate(lines))
{
auto& line = line_e.second;
current_line = line_e.first;
current_line = index;
char_tokenizer token(line);
if (!token.has_next() || token.read_fully().empty())
continue;
@ -220,9 +220,9 @@ namespace blt::parse
void obj_loader::handle_face_vertex(const std::vector<std::string>& face_list, int32_t* arr)
{
for (const auto& pair : blt::enumerate(face_list))
for (const auto& [e_index, value] : blt::enumerate(face_list))
{
auto indices = blt::string::split(pair.second, '/');
auto indices = blt::string::split(value, '/');
BLT_ASSERT(indices.size() == 3 && "Must have vertex, uv, and normal indices!!");
auto vi = get<std::int32_t>(indices[0]) - 1;
@ -242,14 +242,14 @@ namespace blt::parse
BLT_DEBUG("Vertex: (%f, %f, %f), UV: (%f, %f), Normal: (%f, %f, %f)", vertices[vi].x(), vertices[vi].y(), vertices[vi].z(),
uvs[ui].x(), uvs[ui].y(), normals[ni].x(), normals[ni].y(), normals[ni].z());
vertex_map.insert({face, index});
arr[pair.first] = index;
arr[e_index] = index;
} else
{
BLT_TRACE("Using cached data; %d; map size: %d", loc->second, vertex_data.size());
//const auto& d = vertex_data[loc->second];
BLT_TRACE("Vertex: (%f, %f, %f), UV: (%f, %f), Normal: (%f, %f, %f)", d.vertex.x(), d.vertex.y(), d.vertex.z(),
d.uv.x(), d.uv.y(), d.normal.x(), d.normal.y(), d.normal.z());
arr[pair.first] = loc->second;
arr[e_index] = loc->second;
}
}
}

View File

@ -0,0 +1,467 @@
/*
* <Short Description>
* 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/>.
*/
#include <blt/parse/templating.h>
#include <blt/std/string.h>
#include <cctype>
#include "blt/std/logging.h"
namespace blt
{
bool isNonStringNext(char c)
{
switch (c)
{
case '$':
case '{':
case '}':
case '(':
case ')':
case '"':
case '^':
case '!':
case '&':
case ';':
case ',':
case '.':
case '|':
case '+':
return true;
default:
return false;
}
}
blt::expected<std::vector<template_token_data_t>, template_tokenizer_failure_t> template_engine_t::process_string(std::string_view str)
{
std::vector<template_token_data_t> tokens;
template_char_consumer_t consumer(str);
i64 start = -1;
size_t paren_level = 0;
size_t level = 0;
bool open = false;
while (consumer.hasNext())
{
i64 current_start = static_cast<i64>(consumer.getCurrentIndex());
char c = consumer.consume();
switch (c)
{
case '$':
tokens.emplace_back(template_token_t::IDENT, level, consumer.from(current_start, current_start + 1));
if (consumer.next() == '{')
{
paren_level = 0;
open = true;
}
continue;
case '{':
tokens.emplace_back(template_token_t::CURLY_OPEN, level, consumer.from(current_start, current_start + 1));
if (open)
level++;
continue;
case '}':
tokens.emplace_back(template_token_t::CURLY_CLOSE, level, consumer.from(current_start, current_start + 1));
if (open)
level--;
if (level == 0)
{
open = false;
if (paren_level != 0)
return blt::unexpected(template_tokenizer_failure_t::MISMATCHED_PAREN);
}
continue;
case '(':
tokens.emplace_back(template_token_t::PAR_OPEN, level, consumer.from(current_start, current_start + 1), paren_level);
paren_level++;
break;
case ')':
tokens.emplace_back(template_token_t::PAR_CLOSE, level, consumer.from(current_start, current_start + 1), paren_level);
paren_level--;
break;
case '"':
tokens.emplace_back(template_token_t::QUOTE, level, consumer.from(current_start, current_start + 1));
// if we just encountered a quote, we need to consume characters until we find its matching quote
// only if we are currently inside a template though...
if (open)
{
current_start = static_cast<i64>(consumer.getCurrentIndex());
while (consumer.hasNext() && consumer.next() != '"')
consumer.advance();
if (!consumer.hasNext())
return blt::unexpected(template_tokenizer_failure_t::MISMATCHED_QUOTE);
tokens.emplace_back(template_token_t::STRING, level, consumer.from(current_start, consumer.getCurrentIndex()));
consumer.advance();
current_start = static_cast<i64>(consumer.getCurrentIndex());
tokens.emplace_back(template_token_t::QUOTE, level, consumer.from(current_start, current_start + 1));
}
break;
case '^':
tokens.emplace_back(template_token_t::XOR, level, consumer.from(current_start, current_start + 1));
break;
case '!':
tokens.emplace_back(template_token_t::NOT, level, consumer.from(current_start, current_start + 1));
break;
case ';':
tokens.emplace_back(template_token_t::SEMI, level, consumer.from(current_start, current_start + 1));
break;
case ',':
tokens.emplace_back(template_token_t::COMMA, level, consumer.from(current_start, current_start + 1));
break;
case '+':
tokens.emplace_back(template_token_t::ADD, level, consumer.from(current_start, current_start + 1));
break;
case '.':
tokens.emplace_back(template_token_t::PERIOD, level, consumer.from(current_start, current_start + 1));
break;
case '~':
tokens.emplace_back(template_token_t::FUNCTION, level, consumer.from(current_start, current_start + 1));
break;
case '|':
if (consumer.hasNext() && consumer.next() == '|')
{
consumer.advance();
tokens.emplace_back(template_token_t::OR, level, consumer.from(current_start, current_start + 2));
continue;
}
start = current_start;
break;
case '&':
if (consumer.hasNext() && consumer.next() == '&')
{
consumer.advance();
tokens.emplace_back(template_token_t::AND, level, consumer.from(current_start, current_start + 2));
continue;
}
start = current_start;
break;
default:
// do not add whitespace to anything
if (std::isspace(c))
{
break;
}
if (start == -1)
start = current_start;
if (consumer.hasNext() && (isNonStringNext(consumer.next()) || std::isspace(consumer.next())))
{
tokens.emplace_back(template_token_t::STRING, level, consumer.from(start, consumer.getCurrentIndex()));
start = -1;
}
break;
}
}
if (start != -1)
tokens.emplace_back(template_token_t::STRING, level, consumer.from(start, consumer.getCurrentIndex()));
for (auto& token : tokens)
{
if (token.type == template_token_t::STRING && detail::identifiers.contains(token.token))
token.type = detail::identifiers.at(token.token);
}
if (level != 0)
return unexpected(template_tokenizer_failure_t::MISMATCHED_CURLY);
return tokens;
}
blt::expected<std::string, template_parser_failure_t> template_engine_t::internal_evaluate(std::string_view str, bool discard)
{
auto tokens = process_string(str);
if (!tokens)
{
switch (tokens.error())
{
case template_tokenizer_failure_t::MISMATCHED_CURLY:
BLT_ERROR("Mismatched curly braces");
break;
case template_tokenizer_failure_t::MISMATCHED_PAREN:
BLT_ERROR("Mismatched parentheses");
break;
case template_tokenizer_failure_t::MISMATCHED_QUOTE:
BLT_ERROR("Mismatched quotes");
break;
}
return blt::unexpected(template_parser_failure_t::TOKENIZER_FAILURE);
}
std::string return_str;
//return_str.reserve(str.size());
template_token_consumer_t consumer{tokens.value(), str};
template_parser_t parser(*this, consumer);
while (consumer.hasNext())
{
while (consumer.hasNext(2))
{
if (consumer.next().type == template_token_t::IDENT && consumer.next(1).type == template_token_t::CURLY_OPEN)
{
return_str += consumer.from_last();
break;
}
consumer.advance();
}
if (!consumer.hasNext(2))
break;
if (auto result = parser.parse())
return_str += result.value();
else
{
if (result.error() == template_parser_failure_t::FUNCTION_DISCARD)
{
if (discard)
return blt::unexpected(template_parser_failure_t::FUNCTION_DISCARD);
} else
return result;
}
consumer.set_marker();
}
while (consumer.hasNext())
consumer.advance();
return_str += consumer.from_last();
return return_str;
}
template_parser_t::ebool template_parser_t::bool_expression()
{
// this whole thing is just bad. please redo. TODO
std::vector<int> values;
while (consumer.next().type != template_token_t::CURLY_OPEN)
{
auto next = consumer.next();
auto bv = bool_value();
if (!bv)
return bv;
values.push_back(bv.value());
if (values.size() == 2)
{
auto b1 = values[0];
auto b2 = values[1];
values.pop_back();
values.pop_back();
switch (next.type)
{
case template_token_t::AND:
values.push_back(b1 && b2);
break;
case template_token_t::OR:
values.push_back(b1 || b2);
break;
case template_token_t::XOR:
values.push_back(b1 ^ b2);
break;
default:
BLT_WARN("Unexpected token '%s'", std::string(next.token).c_str());
return blt::unexpected(template_parser_failure_t::BOOL_TYPE_NOT_FOUND);
}
}
next = consumer.next();
if (next.type == template_token_t::CURLY_OPEN)
break;
consumer.advance();
}
if (values.empty())
BLT_WARN("This is not possible!");
return values[0];
}
template_parser_t::ebool template_parser_t::bool_value()
{
bool b1;
auto next = consumer.next();
bool invert = false;
// prefixes
if (next.type == template_token_t::NOT)
{
invert = true;
consumer.advance();
next = consumer.next();
}
if (next.type == template_token_t::PAR_OPEN)
{
auto b = bool_statement();
if (!b)
return b;
b1 = b.value();
} else
{
if (consumer.next().type == template_token_t::PAR_OPEN)
{
auto b = bool_statement();
if (!b)
return b;
b1 = b.value();
} else
{
auto b = statement();
if (!b)
return blt::unexpected(b.error());
b1 = !b.value().empty();
}
}
if (invert)
b1 = !b1;
return b1;
}
template_parser_t::ebool template_parser_t::bool_statement()
{
auto next = consumer.next();
if (next.type == template_token_t::PAR_OPEN)
{
consumer.advance();
auto b = bool_statement();
if (consumer.consume().type != template_token_t::PAR_CLOSE)
return blt::unexpected(template_parser_failure_t::BOOL_EXPECTED_PAREN);
consumer.advance();
return b;
}
return bool_expression();
}
template_parser_t::estring template_parser_t::string()
{
auto next = consumer.consume();
if (next.type == template_token_t::STRING)
{
//
// return blt::unexpected(template_parser_failure_t::SUBSTITUTION_NOT_FOUND);
if (consumer.next().type == template_token_t::SEMI || consumer.next().type == template_token_t::ELSE ||
consumer.next().type == template_token_t::CURLY_CLOSE || consumer.next().type == template_token_t::PAR_CLOSE)
{
if (consumer.next().type == template_token_t::SEMI)
consumer.advance();
if (!engine.contains(next.token))
return "";
return engine.get(next.token);
}
if (consumer.next().type != template_token_t::ADD)
return blt::unexpected(template_parser_failure_t::STRING_EXPECTED_CONCAT);
consumer.advance();
auto str = string();
if (!str)
return str;
auto sub = engine.get(next.token);
if (!sub)
return sub;
return sub.value() + str.value();
} else
{
if (consumer.next().type == template_token_t::SEMI)
{
consumer.advance();
return std::string(next.token);
}
auto str = string();
if (str)
return std::string(next.token) + str.value();
else
return str;
}
}
template_parser_t::estring template_parser_t::if_func()
{
// IF(
if (consumer.consume().type != template_token_t::PAR_OPEN)
return blt::unexpected(template_parser_failure_t::IF_EXPECTED_PAREN);
// (statement)
auto bool_eval = bool_statement();
if (!bool_eval)
return blt::unexpected(bool_eval.error());
if (consumer.consume().type != template_token_t::CURLY_OPEN)
return blt::unexpected(template_parser_failure_t::IF_EXPECTED_CURLY);
auto true_statement = statement();
if (consumer.consume().type != template_token_t::CURLY_CLOSE)
return blt::unexpected(template_parser_failure_t::IF_EXPECTED_CURLY);
estring false_statement = blt::unexpected(template_parser_failure_t::UNKNOWN_ERROR);
bool has_false = false;
if (consumer.next().type == template_token_t::ELSE)
{
consumer.advance();
if (consumer.consume().type != template_token_t::CURLY_OPEN)
return blt::unexpected(template_parser_failure_t::IF_EXPECTED_CURLY);
false_statement = statement();
if (consumer.consume().type != template_token_t::CURLY_CLOSE)
return blt::unexpected(template_parser_failure_t::IF_EXPECTED_CURLY);
has_false = true;
}
if (bool_eval.value())
return true_statement;
else
{
if (has_false)
return false_statement;
return "";
}
}
template_parser_t::estring template_parser_t::function()
{
auto str = consumer.consume();
if (consumer.next().type == template_token_t::SEMI)
consumer.advance();
if (str.type != template_token_t::STRING)
return blt::unexpected(template_parser_failure_t::FUNCTION_EXPECTED_STRING);
if (str.token == "DISCARD")
return blt::unexpected(template_parser_failure_t::FUNCTION_DISCARD);
return blt::unexpected(template_parser_failure_t::FUNCTION_NOT_FOUND);
}
template_parser_t::estring template_parser_t::statement()
{
auto next = consumer.consume();
if (next.type == template_token_t::STRING || next.type == template_token_t::QUOTE)
{
consumer.back();
auto str = string();
return str;
} else if (next.type == template_token_t::FUNCTION)
{
return function();
} else if (next.type == template_token_t::IDENT && consumer.hasNext() && consumer.next().type == template_token_t::CURLY_OPEN)
{
consumer.advance();
auto stmt = statement();
// should never occur
if (consumer.hasNext() && consumer.next().type != template_token_t::CURLY_CLOSE)
return blt::unexpected(template_parser_failure_t::NO_MATCHING_CURLY);
consumer.advance();
return stmt;
} else if (next.type == template_token_t::IF)
{
return if_func();
}
return blt::unexpected(template_parser_failure_t::UNKNOWN_STATEMENT_ERROR);
}
}

View File

@ -10,7 +10,7 @@
#include <blt/std/logging.h>
#include <iostream>
#include <algorithm>
#include <blt/std/format.h>
#include <blt/format/format.h>
#define TIME_FUNCTION blt::system::getCPUThreadTime()

View File

@ -6,7 +6,7 @@
#include <blt/profiling/profiler_v2.h>
#include <blt/std/time.h>
#include <blt/std/system.h>
#include <blt/std/format.h>
#include <blt/format/format.h>
#include <functional>
#include <blt/std/hashmap.h>
#include <blt/compatibility.h>
@ -19,29 +19,23 @@ namespace blt
* --------------------------
*/
#define SORT_INTERVALS_FUNC_MACRO(use_history, TYPE_END, TYPE_START, TYPE_TOTAL) \
[&use_history](const interval_t* a, const interval_t* b) -> bool { \
if (!use_history){ \
auto a_diff = a->TYPE_END - a->TYPE_START; \
auto b_diff = b->TYPE_END - b->TYPE_START; \
return a_diff > b_diff; \
} else { \
#define SORT_INTERVALS_FUNC_MACRO(TYPE_END, TYPE_START, TYPE_TOTAL) \
[](const interval_t* a, const interval_t* b) -> bool { \
return a->TYPE_TOTAL < b->TYPE_TOTAL; \
} \
}
#define INTERVAL_DIFFERENCE_MACRO(printHistory, interval) \
auto wall = printHistory \
? (static_cast<double>(interval->wall_total) / static_cast<double>(interval->count)) \
: static_cast<double>(interval->wall_end - interval->wall_start); \
: static_cast<double>(interval->wall_total); \
\
auto thread = printHistory \
? (static_cast<double>(interval->thread_total) / static_cast<double>(interval->count)) \
: static_cast<double>(interval->thread_end - interval->thread_start); \
: (static_cast<double>(interval->thread_total)); \
\
auto cycles = printHistory \
? ((interval->cycles_total) / (interval->count)) \
: (interval->cycles_end - interval->cycles_start);
: (interval->cycles_total);
enum class unit
{
@ -100,19 +94,19 @@ namespace blt
BLT_WARN("Write profile for V2 is currently a TODO");
}
void sort_intervals(std::vector<interval_t*>& intervals, sort_by sort, bool use_history)
void sort_intervals(std::vector<interval_t*>& intervals, sort_by sort, bool)
{
std::function<bool(const interval_t* a, const interval_t* b)> sort_func;
switch (sort)
{
case sort_by::CYCLES:
sort_func = SORT_INTERVALS_FUNC_MACRO(use_history, cycles_start, cycles_end, cycles_total);
sort_func = SORT_INTERVALS_FUNC_MACRO(cycles_start, cycles_end, cycles_total);
break;
case sort_by::WALL:
sort_func = SORT_INTERVALS_FUNC_MACRO(use_history, wall_start, wall_end, wall_total);
sort_func = SORT_INTERVALS_FUNC_MACRO(wall_start, wall_end, wall_total);
break;
case sort_by::THREAD:
sort_func = SORT_INTERVALS_FUNC_MACRO(use_history, thread_start, thread_end, thread_total);
sort_func = SORT_INTERVALS_FUNC_MACRO(thread_start, thread_end, thread_total);
break;
}
std::sort(intervals.begin(), intervals.end(), sort_func);
@ -150,7 +144,7 @@ namespace blt
void printProfile(profile_t& profiler, std::uint32_t flags, sort_by sort, blt::logging::log_level log_level)
{
bool printHistory = flags & PRINT_HISTORY;
bool printHistory = flags & AVERAGE_HISTORY;
bool printCycles = flags & PRINT_CYCLES;
bool printThread = flags & PRINT_THREAD;
bool printWall = flags & PRINT_WALL;
@ -227,11 +221,15 @@ namespace blt
void _internal::endInterval(const std::string& profile_name, const std::string& interval_name)
{
if (profiles[profile_name].empty() || profiles[profile_name].find(interval_name) == profiles[profile_name].end())
return;
blt::endInterval(profiles[profile_name].at(interval_name));
}
void _internal::writeProfile(std::ifstream& stream, const std::string& profile_name)
{
if (profiles.find(profile_name) == profiles.end())
return;
auto& pref = profiles[profile_name];
profile_t profile{profile_name};
for (const auto& i : pref)
@ -242,6 +240,8 @@ namespace blt
void _internal::printProfile(const std::string& profile_name, std::uint32_t flags, sort_by sort, blt::logging::log_level log_level)
{
if (profiles.find(profile_name) == profiles.end())
return;
auto& pref = profiles[profile_name];
profile_t profile{profile_name};
for (const auto& i : pref)

View File

@ -10,11 +10,43 @@
#include <iostream>
#include <iomanip>
#include <sstream>
#include <exception>
#include <cstring>
struct abort_exception : public std::exception
{
public:
explicit abort_exception(const char* what)
{
auto len = std::strlen(what) + 1;
error = static_cast<char*>(std::malloc(len));
std::memcpy(static_cast<char*>(error), what, len);
}
abort_exception(const abort_exception& copy) = delete;
abort_exception& operator=(const abort_exception& copy) = delete;
[[nodiscard]] const char* what() const noexcept override
{
if (error == nullptr)
return "Abort called";
return error;
}
~abort_exception() override
{
std::free(static_cast<void*>(error));
}
private:
char* error{nullptr};
};
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
#include <execinfo.h>
#include <cstdlib>
#endif
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
@ -29,16 +61,20 @@
#define BLT_FREE_STACK_TRACE() void();
#endif
namespace blt {
namespace blt
{
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
static inline std::string _macro_filename(const std::string& path){
static inline std::string _macro_filename(const std::string& path)
{
auto paths = blt::string::split(path, "/");
auto final = paths[paths.size()-1];
auto final = paths[paths.size() - 1];
if (final == "/")
return paths[paths.size()-2];
return paths[paths.size() - 2];
return final;
}
#endif
void b_throw(const char* what, const char* path, int line)
@ -71,11 +107,15 @@ namespace blt {
printStacktrace(messages, size, path, line);
BLT_FREE_STACK_TRACE();
#endif
#else
(void) expression;
(void) msg;
(void) path;
(void) line;
#endif
if (msg != nullptr)
throw abort_exception(msg);
throw abort_exception(expression);
}
void printStacktrace(char** messages, int size, const char* path, int line)
@ -83,7 +123,8 @@ namespace blt {
if (messages == nullptr)
return;
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
for (int i = 1; i < size; i++){
for (int i = 1; i < size; i++)
{
int tabs = i - 1;
std::string buffer;
for (int j = 0; j < tabs; j++)
@ -113,7 +154,7 @@ namespace blt {
buffer += " in ";
buffer += loc;
BLT_ERROR(buffer);
}
#else
@ -124,5 +165,21 @@ namespace blt {
}
void b_abort(const char* what, const char* path, int line)
{
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
BLT_STACK_TRACE(50);
#endif
BLT_FATAL("----{BLT ABORT}----");
BLT_FATAL("\tWhat: %s", what);
BLT_FATAL("\tcalled from %s:%d", path, line);
#if defined(__GNUC__) && !defined(__EMSCRIPTEN__)
printStacktrace(messages, size, path, line);
BLT_FREE_STACK_TRACE();
#endif
throw abort_exception(what);
}
}

View File

@ -36,7 +36,7 @@ namespace blt::error
BLT_WARN("Address already in use");
break;
case EADDRNOTAVAIL:
BLT_WARN("Cannot assign requested address");
BLT_WARN("Cannot copy_fast requested address");
break;
case EAFNOSUPPORT:
BLT_WARN("Address family not supported by protocol");
@ -69,7 +69,7 @@ namespace blt::error
BLT_WARN("Network is unreachable");
break;
case ENOTSOCK:
BLT_WARN("Socket operation on non-socket");
BLT_WARN("Socket operation_t on non-socket");
break;
case EPROTOTYPE:
BLT_WARN("Protocol wrong type for socket");

114
src/blt/std/mmap.cpp Normal file
View File

@ -0,0 +1,114 @@
/*
* <Short Description>
* 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/>.
*/
#include <blt/std/mmap.h>
#ifdef __unix__
#include <sys/mman.h>
#endif
namespace blt
{
std::string handle_mmap_error()
{
std::string str;
#define BLT_WRITE(arg) str += arg; str += '\n';
switch (errno)
{
case EACCES:
BLT_WRITE("fd not set to open!");
break;
case EAGAIN:
BLT_WRITE("The file has been locked, or too much memory has been locked");
break;
case EBADF:
BLT_WRITE("fd is not a valid file descriptor");
break;
case EEXIST:
BLT_WRITE("MAP_FIXED_NOREPLACE was specified in flags, and the range covered "
"by addr and length clashes with an existing mapping.");
break;
case EINVAL:
BLT_WRITE("We don't like addr, length, or offset (e.g., they are too large, or not aligned on a page boundary).");
BLT_WRITE("Or length was 0");
BLT_WRITE("Or flags contained none of MAP_PRIVATE, MAP_SHARED, or MAP_SHARED_VALIDATE.");
break;
case ENFILE:
BLT_WRITE("The system-wide limit on the total number of open files has been reached.");
break;
case ENODEV:
BLT_WRITE("The underlying filesystem of the specified file does not support memory mapping.");
break;
case ENOMEM:
BLT_WRITE("No memory is available.");
BLT_WRITE("Or The process's maximum number of mappings would have been exceeded. "
"This error can also occur for munmap(), when unmapping a region in the middle of an existing mapping, "
"since this results in two smaller mappings on either side of the region being unmapped.");
BLT_WRITE("Or The process's RLIMIT_DATA limit, described in getrlimit(2), would have been exceeded.");
BLT_WRITE("Or We don't like addr, because it exceeds the virtual address space of the CPU.");
break;
case EOVERFLOW:
BLT_WRITE("On 32-bit architecture together with the large file extension (i.e., using 64-bit off_t): "
"the number of pages used for length plus number of "
"pages used for offset would overflow unsigned long (32 bits).");
break;
case EPERM:
BLT_WRITE("The prot argument asks for PROT_EXEC but the mapped area "
"belongs to a file on a filesystem that was mounted no-exec.");
BLT_WRITE("Or The operation_t was prevented by a file seal");
BLT_WRITE("Or The MAP_HUGETLB flag was specified, but the caller "
"was not privileged (did not have the CAP_IPC_LOCK capability) "
"and is not a member of the sysctl_hugetlb_shm_group group; "
"see the description of /proc/sys/vm/sysctl_hugetlb_shm_group");
break;
case ETXTBSY:
BLT_WRITE("MAP_DENYWRITE was set but the object specified by fd is open for writing.");
break;
}
return str;
}
void* allocate_huge_pages(huge_page_t page_type, blt::size_t bytes)
{
#ifdef __unix__
auto type = (21 << MAP_HUGE_SHIFT);
if (page_type == huge_page_t::BLT_1GB_PAGE)
type = (30 << MAP_HUGE_SHIFT);
auto buffer = mmap(nullptr, bytes, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS | MAP_HUGETLB | type | MAP_POPULATE, -1, 0);
if (buffer == MAP_FAILED)
{
throw bad_alloc_t(handle_mmap_error());
}
return buffer;
#else
BLT_ABORT("Platform not supported for huge page allocation!");
#endif
}
void mmap_free(void* ptr, blt::size_t bytes)
{
if (munmap(ptr, bytes))
{
BLT_ERROR_STREAM << "Failed to deallocate\n";
throw bad_alloc_t(handle_mmap_error());
}
}
}

View File

@ -23,6 +23,7 @@
#include <blt/parse/argparse.h>
#include <utility_test.h>
#include <blt/std/utility.h>
#include <templating_test.h>
namespace blt::test
{

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_TEMPLATING_TEST_H
#define BLT_TEMPLATING_TEST_H
namespace blt::test
{
void template_test();
}
#endif //BLT_TEMPLATING_TEST_H

123
tests/iterator_tests.cpp Normal file
View File

@ -0,0 +1,123 @@
/*
* <Short Description>
* 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/>.
*/
#include <blt/std/logging.h>
#include <blt/std/types.h>
#include <blt/std/assert.h>
#include <blt/math/vectors.h>
#include <blt/math/log_util.h>
#include <blt/iterator/zip.h>
#include <blt/iterator/iterator.h>
#include <blt/format/boxing.h>
#include <array>
constexpr auto increasing_reverse_pairs = [](blt::size_t i, blt::size_t index, blt::size_t size) { return i == 0 ? index : (size - 1) - index; };
constexpr auto increasing_pairs = [](blt::size_t, blt::size_t index, blt::size_t) { return index; };
constexpr auto decreasing_pairs = [](blt::size_t, blt::size_t index, blt::size_t size) { return size - index; };
template<blt::size_t n, typename Func>
std::array<blt::vec2, n> make_array(Func&& func)
{
std::array<blt::vec2, n> array;
for (auto&& [index, value] : blt::enumerate(array))
value = blt::vec2(func(0, index, n), func(1, index, n));
return array;
}
constexpr blt::size_t array_size = 10;
auto array_1 = make_array<array_size>(increasing_reverse_pairs);
auto array_2 = make_array<array_size>(increasing_pairs);
auto array_3 = make_array<array_size>(decreasing_pairs);
void test_enumerate()
{
blt::log_box_t box(std::cout, "Enumerate Tests", 25);
for (const auto& [index, item] : blt::enumerate(array_1))
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).rev())
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).take(3))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index < 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).take(3).rev())
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index < 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).rev())
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).take(5))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 3 && index < (array_1.size() - 5) + 3);
}
BLT_TRACE("");
for (const auto& [index, item] : blt::enumerate(array_1).skip(3).rev().take(5))
{
BLT_TRACE_STREAM << index << " : " << item << "\n";
BLT_ASSERT(index >= 5);
}
}
void test_pairs()
{
blt::log_box_t box(std::cout, "Pairs Tests", 25);
}
void test_zip()
{
blt::log_box_t box(std::cout, "Zip Tests", 25);
}
int main()
{
test_enumerate();
std::cout << std::endl;
test_pairs();
std::cout << std::endl;
test_zip();
}

View File

@ -28,8 +28,8 @@ namespace blt::test
void print(const T& ref)
{
BLT_TRACE_STREAM << "(" << ref.size() << ") [";
for (auto v : blt::enumerate(ref))
BLT_TRACE_STREAM << v.second << ((v.first != ref.size()-1) ? ", " : "]\n");
for (auto [index, item] : blt::enumerate(ref))
BLT_TRACE_STREAM << item << ((index != ref.size()-1) ? ", " : "]\n");
}
void vector_run()

View File

@ -24,7 +24,7 @@ void run_logging() {
// blt::logging::trace << "Seeee\n Super\n";
std::string hello = "superSexyMax";
std::cout << "String starts with: " << blt::string::contains(hello, "superSexyMaxE") << "\n";
std::cout << "String starts with: " << blt::string::contains(main_graph, "superSexyMaxE") << "\n";
}
#endif //BLT_TESTS_LOGGING_H

View File

@ -7,7 +7,7 @@
#include <blt/fs/nbt.h>
#include <blt/profiling/profiler.h>
#include <blt/std/logging.h>
#include <blt/std/format.h>
#include <blt/format/format.h>
#include <blt/fs/filesystem.h>
#include <filesystem>

View File

@ -15,7 +15,7 @@ namespace blt::tests {
template<typename T>
T* generateRandomData(T* arr, size_t size, uint32_t seed = 0) {
for (size_t i = 0; i < size; i++)
arr[i] = blt::random::randomInt_c(i * size + seed, std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
arr[i] = blt::random::random_t(i * size + seed).get(std::numeric_limits<T>::min(), std::numeric_limits<T>::max());
return arr;
}

View File

@ -10,7 +10,7 @@
#include "blt/profiling/profiler_v2.h"
#include "blt/std/logging.h"
#include "blt/std/time.h"
#include "blt/std/format.h"
#include "blt/format/format.h"
void print(const std::vector<std::string>& vtr) {
for (const auto& line : vtr)

View File

@ -19,6 +19,7 @@
#include <blt/std/utility.h>
#include <blt/std/string.h>
#include <blt/std/logging.h>
#include <blt/iterator/iterator.h>
namespace blt::test
{
@ -32,27 +33,27 @@ namespace blt::test
auto sv_splits_c = blt::string::split_sv(str, ' ');
auto sv_splits_s = blt::string::split_sv(str, "LOT");
for (auto v : blt::enumerate(s_splits_c))
for (auto [index, item] : blt::enumerate(s_splits_c))
{
if (v.second != sv_splits_c[v.first])
if (item != sv_splits_c[index])
{
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", v.second.c_str(), std::string(sv_splits_c[v.first]).c_str());
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", item.c_str(), std::string(sv_splits_c[index]).c_str());
} else
{
BLT_DEBUG(v.second);
BLT_DEBUG(item);
}
}
BLT_INFO("");
for (auto v : blt::enumerate(s_splits_s))
for (auto [index, item] : blt::enumerate(s_splits_s))
{
if (v.second != sv_splits_s[v.first])
if (item != sv_splits_s[index])
{
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", v.second.c_str(), std::string(sv_splits_s[v.first]).c_str());
BLT_WARN("THEY DO NOT MATCH!!! '%s' vs '%s'", item.c_str(), std::string(sv_splits_s[index]).c_str());
} else
{
BLT_DEBUG(v.second);
BLT_DEBUG(item);
}
}
}

View File

@ -0,0 +1,89 @@
/*
* <Short Description>
* 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/>.
*/
#include <templating_test.h>
#include <string>
#include <blt/std/logging.h>
#include <blt/parse/templating.h>
const std::string shader_test_string = R"("
#version 300 es
precision mediump float;
${LAYOUT_STRING} out vec4 FragColor;
in vec2 uv;
in vec2 pos;
uniform sampler2D tex;
vec4 linear_iter(vec4 i, vec4 p, float factor){
return (i + p) * factor;
}
void main() {
FragColor = texture(tex, uv);
}
")";
void process_string(const std::string& str)
{
BLT_DEBUG(str);
auto results = blt::template_engine_t::process_string(str);
if (results)
{
auto val = results.value();
for (auto& v : val)
{
BLT_TRACE_STREAM << (blt::template_token_to_string(v.type));
}
BLT_TRACE_STREAM << "\n";
for (auto& v : val)
{
BLT_TRACE("{%s: %s}", blt::template_token_to_string(v.type).c_str(), std::string(v.token).c_str());
}
} else
{
auto error = results.error();
switch (error)
{
case blt::template_tokenizer_failure_t::MISMATCHED_CURLY:
BLT_ERROR("Tokenizer Failure: Mismatched curly");
break;
case blt::template_tokenizer_failure_t::MISMATCHED_PAREN:
BLT_ERROR("Tokenizer Failure: Mismatched parenthesis");
break;
case blt::template_tokenizer_failure_t::MISMATCHED_QUOTE:
BLT_ERROR("Tokenizer Failure: Mismatched Quotes");
break;
}
}
BLT_DEBUG("--------------------------");
}
namespace blt::test
{
void template_test()
{
process_string(shader_test_string);
process_string("~hello");
process_string("hello");
process_string("hello ${WORLD}");
process_string("layout (location = ${IF(LAYOUT_LOCATION) LAYOUT_LOCATION ELSE ~DISCARD})");
}
}

View File

@ -16,7 +16,7 @@
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#include <blt/std/utility.h>
#include <blt/std/format.h>
#include <blt/format/format.h>
#include <blt/std/logging.h>
#include <blt/profiling/profiler_v2.h>
#include <utility_test.h>