Compare commits
144 Commits
9db3f12048
...
7580fa544a
Author | SHA1 | Date |
---|---|---|
Brett | 7580fa544a | |
Brett | fb3ed3aa5e | |
Brett | 709401e4da | |
Brett | aabb9d801d | |
Brett | 88e8e8fc5b | |
Brett | 0ecee088f6 | |
Brett | 0d13e9738f | |
Brett | a0a2052479 | |
Brett | 369ab664b6 | |
Brett | 4a80161f33 | |
Brett | 329eeb174b | |
Brett | a27651b21d | |
Brett | c83f089e9c | |
Brett | cacc082ce9 | |
Tri11Paragon | bbd5641073 | |
Tri11Paragon | 854e613a9b | |
Tri11Paragon | 43be54097e | |
Brett | 88506e5cce | |
Brett | a7412fccec | |
Brett | 373cf5e0a2 | |
Brett | ce09a70241 | |
Brett | 7935e34ad4 | |
Brett | b944b936f4 | |
Brett | c5b8830ff0 | |
Brett | 0aa686a87a | |
Brett | 209b97079c | |
Brett | 96b071e337 | |
Brett | 7300f895bb | |
Brett | b5ea7a1e15 | |
Brett | 39fd5a73d6 | |
Brett | 1ceb71aac9 | |
Brett | 6646db8249 | |
Brett | a60380c898 | |
Brett | e19a88c454 | |
Brett | ba10bd633e | |
Brett | d1aaf4db94 | |
Brett | 5375231ce5 | |
Brett | e3c925ed11 | |
Brett | 494125214f | |
Brett | 0869509c6a | |
Brett | cd9ec507d6 | |
Brett | 56a3c2f836 | |
Brett | 7410dfe0ff | |
Brett | 7198a8b0c3 | |
Brett | 82cc1aff96 | |
Brett | a7645d9dde | |
Brett | ab482f1a1c | |
Brett | 79e080cfd3 | |
Brett | b6354bed78 | |
Brett | 6632d04528 | |
Brett | 1b09483af0 | |
Brett | 675c4234bc | |
Brett | 9ce6c89ce0 | |
Brett | 78710a12cc | |
Brett | 72211e3d7b | |
Brett | daa9757375 | |
Brett | a0a855463d | |
Brett | 97990401e2 | |
Brett | 941aa6809c | |
Brett | 627f8022f2 | |
Brett | 6f06647a21 | |
Brett | c7e3accb9d | |
Brett | 644f426843 | |
Brett | 92300bc6a2 | |
Brett | 4327b34c84 | |
Brett | 99e735b760 | |
Brett | 941aedb510 | |
Brett | 42fa378200 | |
Brett | 785565f03e | |
Brett | 3e8b616bf9 | |
Brett | f9938691ec | |
Brett | 8535480ad5 | |
Brett | 79ad108fab | |
Brett | befd5e0ca1 | |
Brett | e979447de0 | |
Brett | 6acbc24245 | |
Brett | fb17ff16c0 | |
Brett | c3fdfbade6 | |
Brett | d579ddf1cc | |
Brett | 7a551435a0 | |
Brett | f99e6b3db9 | |
Brett | 5ab01e43df | |
Brett | 394dff9cc4 | |
Brett | 4114de74db | |
Brett | 27d1b94493 | |
Brett | cd5c98d748 | |
Brett | 7c49a8a854 | |
Brett | 60f77961fb | |
Brett | 9a437ec75a | |
Brett | c5f3d9ba3b | |
Brett | 456eeb12ac | |
Brett | 4de3aeb87c | |
Brett | b6048ed39c | |
Brett | 42dcfe069f | |
Brett | c88f1c3e38 | |
Brett | 5e65416684 | |
Brett | 4776546e35 | |
Brett | 57ddcfca1e | |
Brett | 1caae86e43 | |
Brett | bccd2f4ba3 | |
Brett | f3451b57ab | |
Brett | 7778efce5c | |
Brett | 114a04500a | |
Brett | 1328095603 | |
Brett | cdb91d8007 | |
Brett | 2a34be2e7b | |
Brett | ac163a34b9 | |
Brett | cc788e98f4 | |
Brett | 1ca46b9d7b | |
Brett | 9ad96191ff | |
Brett | 2266d64f04 | |
Brett | 8d3bfbcdc3 | |
Brett | 00f368eb23 | |
Brett | bc68e6dd4a | |
Brett | a8b2bc2d01 | |
Brett | a3e187bd01 | |
Brett | 9bd19ed372 | |
Brett | 12169a7001 | |
Brett | 9c0fc81969 | |
Brett | f228cfbbe3 | |
Brett | fa5083b637 | |
Brett | 7cd736cf6c | |
Brett | c3cd00cf04 | |
Brett | 83329f6736 | |
Brett | ce7c1357e0 | |
Brett | 4ef3fe7573 | |
Brett | da82a40699 | |
Brett | fa979a2fd4 | |
Brett | b857bc96ef | |
Brett | 943fb84211 | |
Brett | 9b86278a29 | |
Brett | 3f0ea887cd | |
Brett | 37da0bd76d | |
Brett | 8a5794cfee | |
Brett | e6b4c4a330 | |
Brett | 0a04408e70 | |
Brett | 133728b641 | |
Brett | 86fd4a2a9a | |
Brett | 69e6a505d6 | |
Brett | c8ce910fe1 | |
Brett | 1772e9a6d7 | |
Brett | c6a54f5106 | |
Brett | 325508e807 | |
Brett | 898760e938 |
105
CMakeLists.txt
105
CMakeLists.txt
|
@ -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)
|
||||
|
|
8
LICENSE
8
LICENSE
|
@ -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,
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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="<div><p style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="background-color: rgb(255, 248, 247);">arg_data_t</span></p></div>" 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="<div><pre style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><font style="background-color: rgb(252, 245, 245);" color="#030303">arg_data_vec_t</font></pre></div>" 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="<div><pre style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><font style="background-color: rgb(255, 248, 247);" color="#030303">arg_data_internal_t</font></pre></div>" 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="<pre style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;">std::vector&lt;arg_data_internal_t&gt;</pre>" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
|
@ -56,13 +56,13 @@
|
|||
<mxCell id="_DS3495almi1g_SXSTfi-9" value="<div style="background-color: rgb(30, 31, 34);"><pre style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="background-color: rgb(255, 248, 247);">int32_t</span></pre></div>" 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="<div style="background-color: rgb(30, 31, 34);"><pre style="font-family:'JetBrains Mono',monospace;font-size:9.8pt;"><span style="background-color: rgb(255, 248, 247);">arg_data_internal_t</span></pre></div>" style="rounded=0;whiteSpace=wrap;html=1;" vertex="1" parent="1">
|
||||
|
|
|
@ -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
264
commit.py
|
@ -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()
|
||||
|
|
|
@ -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
|
|
@ -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;
|
|
@ -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"
|
||||
|
|
|
@ -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
|
|
@ -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 enumerator’s 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
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
|
|
@ -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
|
@ -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)
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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);
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 (© == 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
|
||||
{
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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
|
|
@ -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;
|
||||
};
|
||||
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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)
|
||||
{
|
||||
|
|
|
@ -17,6 +17,7 @@
|
|||
#endif
|
||||
#else
|
||||
#include <chrono>
|
||||
using suseconds_t = int;
|
||||
#endif
|
||||
|
||||
#include <cstdint>
|
||||
|
|
|
@ -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, ¤t_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?
|
||||
*/
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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"
|
|
@ -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 += "]";
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -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");
|
||||
|
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
{
|
||||
|
|
|
@ -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
|
|
@ -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();
|
||||
}
|
|
@ -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()
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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>
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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})");
|
||||
}
|
||||
}
|
|
@ -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>
|
||||
|
|
Loading…
Reference in New Issue