Compare commits

..

98 Commits

Author SHA1 Message Date
Brett cbb747634a fp working now 2024-04-04 09:20:11 -04:00
Brett 2bab551319 fixed pointer numbers time! 2024-04-04 09:00:48 -04:00
Brett 496a1d6db7 argparse? 2024-04-02 12:08:33 -04:00
Brett 1e6bc67850 vector const fix for gcc12 2024-04-01 08:31:20 -04:00
Brett 93812fd138 namespace change 2024-03-31 13:57:42 -04:00
Brett 2280046f14 socket error handler 2024-03-31 13:56:56 -04:00
Brett 822d926651 argparse bug fix 2024-03-31 01:42:38 -04:00
Brett 31bc3f3bf7 add doubles, floats and longs to argparse 2024-03-30 17:23:23 -04:00
Brett f100e95a30 fix some issue with the allocator 2024-03-24 17:31:11 -04:00
Brett 9950fd3c94 patch 2024-03-23 19:52:29 -04:00
Brett 26e606afb1 based 2024-03-23 02:48:13 -04:00
Brett 1256ec201c any_t const 2024-03-22 19:32:59 -04:00
Brett 2dd44ca6e7 allow any_t buffered (threads!!) 2024-03-22 18:56:44 -04:00
Brett 16641a27cb more thread pool changes, added counting of tasks. im sure parker will hate this :3 2024-03-22 11:40:01 -04:00
Brett 6a5b7a6865 minior thread pool change 2024-03-22 11:30:58 -04:00
Brett 9bba525b1f add any type 2024-03-11 17:08:11 -04:00
Brett 1abd3214be make not round by default 2024-03-11 12:07:00 -04:00
Brett 7e405a27ee changes to how formatter works 2024-03-11 12:05:37 -04:00
Brett b564b3e57b restrict member access 2024-03-11 11:56:15 -04:00
Brett 6400b1521b allocator stats 2024-03-11 11:51:13 -04:00
Brett 263bbc88cf fix not calling the destructor 2024-03-10 22:57:40 -04:00
Brett 62a973246d ranges 2024-03-10 15:49:52 -04:00
Brett 1dc08ca723 add null check 2024-03-09 12:57:58 -05:00
Brett 24cc37f220 docs for the allocator, minor cleanup 2024-03-08 22:34:50 -05:00
Brett 7e7e542f51 forgot to make free 2024-03-08 16:56:50 -05:00
Brett 7177b03a43 fix allocator issue
misaligned size
2024-03-08 16:37:51 -05:00
Brett 55bae67407 having some issues with the allocator 2024-03-08 12:27:07 -05:00
Brett b4be72795d make sure stored type is trivally_copyable 2024-03-07 13:01:58 -05:00
Brett e29faf7f3a move the extra data to the start 2024-03-07 12:55:12 -05:00
Brett b937df3ca6 allow storage of extra data inside metadata 2024-03-07 12:46:00 -05:00
Brett 19857f3b2b increase patch limit 2024-03-07 12:00:52 -05:00
Brett a18ea4b1a5 test patch limit 2024-03-07 11:59:38 -05:00
Brett f477f8d9f2 catch KeyboardInterrupt 2024-03-07 11:56:05 -05:00
Brett 7ed84ab0bf finished commit script? 2024-03-07 11:54:09 -05:00
Brett 0e8445e7ef maybe it works now? 2024-03-07 11:50:23 -05:00
Brett 479b28b2f8 python file working? 2024-03-07 11:50:04 -05:00
Brett 50dd245ecb python file now works 2024-03-07 11:49:29 -05:00
Brett a71df8b7de python script is now all you need@ 2024-03-07 11:48:49 -05:00
Brett 2eb4af7797 git commiting 2024-03-07 11:47:57 -05:00
Brett 3f06d0e619 array now accounts for alignment 2024-03-07 11:38:09 -05:00
Brett 56b569e0fd automatic commiting 2024-03-07 09:52:02 -05:00
Brett b55c00bcb5 version bumb 2024-03-07 09:00:36 -05:00
Brett eaad38e588 array 2024-03-07 09:00:19 -05:00
Brett 7444103897 version bump 2024-03-07 08:25:53 -05:00
Brett ec6ac4e5c2 cleanup 2024-03-07 08:25:30 -05:00
Brett d3166acbbb 2mb size 2024-03-07 08:12:31 -05:00
Brett 3652d987d0 merge 2024-03-07 08:07:46 -05:00
Brett 8e3fc713e4 allocator alignment 2024-03-07 08:06:42 -05:00
Brett 0b1e566217 no default huge 2024-03-06 23:53:03 -05:00
Brett bfb7b04ce5 no more annoying warnings, just enable THB 2024-03-06 23:52:43 -05:00
Brett 06892a3418 more alignment in the allocator 2024-03-06 21:48:17 -05:00
Brett bb695ab703 page aligned allocators, if you are not using huge pages please disable, it'll provide slight performance improvement 2024-03-06 20:35:54 -05:00
Brett a71adc328e more allocator nonsense 2024-03-06 16:42:13 -05:00
Brett be4a61cc80 allocator fix 2024-03-05 13:20:17 -05:00
Brett fe9cd9a6ef remove debug message 2024-03-04 11:33:04 -05:00
Brett e2364280b0 destory alloc fix 2024-03-04 11:21:43 -05:00
Brett c6c92bbd30 alloc 2024-03-04 11:15:25 -05:00
Brett b7d69bdcbb allocator 2024-03-04 10:58:37 -05:00
Brett 0ff9513070 alloc fixes 2024-03-04 10:39:19 -05:00
Brett 148768d690 allocators 2024-02-29 15:07:56 -05:00
Brett 20ceffd64a allocators 2024-02-29 15:07:35 -05:00
Brett ffa20e0e51 lovely 2024-02-29 10:27:02 -05:00
Brett 1732f39a42 vec 2024-02-29 10:14:03 -05:00
Brett fd58930c1d delusion's of parker's rust boner 2024-02-29 09:54:11 -05:00
Brett 490c52c803 Fix issue with initalizer order 2024-02-29 09:10:29 -05:00
Brett 47354e1d8a std:: hashmap variant fix 2024-02-29 08:20:23 -05:00
Brett b40c40efdc profering 2024-02-29 08:11:40 -05:00
Brett 9ad652195b fix private 2024-02-26 11:02:16 -05:00
Brett 9b4d0cc9a8 push version 0.12.0. Breaking changes to the hashmap typename, Now blt::hashmap_t and blt::hashset_t
This was done to be more consistent
2024-02-25 14:39:56 -05:00
Brett 61d46de573 time update 2024-02-24 14:31:59 -05:00
Brett b4dbb6377e unicode, cmakes 2024-02-24 03:30:31 -05:00
Brett 384529333c GNUC define fix 2024-02-22 15:54:52 -05:00
Brett e9a11a9a7e time on linx fix 2024-02-22 15:52:01 -05:00
Laptop Windows 89bde7c6e8 warnings 2024-02-21 20:36:22 -05:00
Laptop Windows 43cf8c0ba1 windows 2024-02-21 20:24:00 -05:00
Laptop Windows 2b4b7bcdf9 ignore 2024-02-21 19:33:31 -05:00
Laptop Windows 9b53d82f1c working msvc 2024-02-21 19:32:40 -05:00
Brett 392c32751d vector 3 2024-02-21 15:31:22 -05:00
Brett 8571a8034b vector 2 2024-02-21 13:55:56 -05:00
Brett e320355d62 vector 2024-02-21 13:18:05 -05:00
Brett 6bea6f87f5 unused var fix 2024-02-20 15:22:15 -05:00
Brett 0b6b6aed9b untested vector changes 2024-02-20 15:18:05 -05:00
Brett 1fdf6f6e89 allocator cleanup 2024-02-19 14:47:09 -05:00
Brett 83fff1652d he's a beautuful lad though -michael 2024-02-17 20:46:29 -05:00
Brett 8af1db43c3 uwu 2024-02-16 20:06:06 -05:00
Brett 3395a56bd3 more allocators 2024-02-16 18:38:12 -05:00
Brett 8a32d6b675 allocators 2024-02-16 18:21:13 -05:00
Brett 68f6a0af44 whoops 2024-02-16 00:23:11 -05:00
Brett 558ed1e0fd GET FUCKED 2024-02-16 00:16:58 -05:00
Brett fcf2a19ca1 ignore 2024-02-14 16:21:28 -05:00
Brett 6ec0b1f886 changes? 2024-02-14 16:19:48 -05:00
Brett 8e5b3ed284 make template specialization more clear 2024-02-14 15:25:18 -05:00
Brett ea31d8f26c add resize to scoped buffer to allow better usage in the GP assignment 2024-02-14 15:21:59 -05:00
Brett 3473247e6c what changed? 2024-02-13 23:49:18 -05:00
Brett e1530de338 constexpr funny man 2024-02-13 17:26:05 -05:00
Brett c7beb41042 more tricks to the buffer 2024-02-13 17:06:33 -05:00
Brett cef8eb26b9 pointer fix 2024-02-13 15:11:02 -05:00
Brett 6f2b1c9041 maybe fix span 2024-02-13 15:09:08 -05:00
97 changed files with 8701 additions and 431 deletions

3
.gitignore vendored Executable file → Normal file
View File

@ -1,4 +1,5 @@
/cmake-build-*/ /cmake-build-*/
tests/cmake-build-*/ tests/cmake-build-*/
.vs/ .vs/
out/ out/
.idea/

8
.idea/.gitignore vendored Normal file
View File

@ -0,0 +1,8 @@
# Default ignored files
/shelf/
/workspace.xml
# Editor-based HTTP Client requests
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

1
.idea/.name Normal file
View File

@ -0,0 +1 @@
BLT

2
.idea/Code.iml Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="UTF-8"?>
<module classpath="CMake" type="CPP_MODULE" version="4" />

14
.idea/deployment.xml Normal file
View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="PublishConfigData" remoteFilesAllowedToDisappearOnAutoupload="false">
<serverData>
<paths name="Lafoge GCC (4972adc7-5214-4799-a7ab-d5d141cf07f2)">
<serverdata>
<mappings>
<mapping local="$PROJECT_DIR$" web="/" />
</mappings>
</serverdata>
</paths>
</serverData>
</component>
</project>

4
.idea/misc.xml Normal file
View File

@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CMakeWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
</project>

9
.idea/modules.xml Normal file
View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/BLT.iml" filepath="$PROJECT_DIR$/.idea/BLT.iml" />
<module fileurl="file://$PROJECT_DIR$/.idea/Code.iml" filepath="$PROJECT_DIR$/.idea/Code.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$/libraries/parallel-hashmap" vcs="Git" />
</component>
</project>

119
CMakeLists.txt Executable file → Normal file
View File

@ -1,6 +1,7 @@
cmake_minimum_required(VERSION 3.5) cmake_minimum_required(VERSION 3.5)
include(cmake/color.cmake)
set(BLT_VERSION 0.11.3) set(BLT_VERSION 0.16.1)
set(BLT_TEST_VERSION 0.0.1) set(BLT_TEST_VERSION 0.0.1)
set(BLT_TARGET BLT) set(BLT_TARGET BLT)
@ -20,6 +21,7 @@ option(BUILD_PARSE "Build the BLT parsers" ON)
option(BUILD_TESTS "Build the BLT test set" OFF) option(BUILD_TESTS "Build the BLT test set" OFF)
option(BLT_DISABLE_STATS "Disable tracking stats in certain objects. Enabling this will cause stat functions to return 0" OFF)
option(BLT_DISABLE_LOGGING "Disable blt::logging (all macros and will safely disable logging function!)" OFF) option(BLT_DISABLE_LOGGING "Disable blt::logging (all macros and will safely disable logging function!)" OFF)
option(BLT_DISABLE_TRACE "Disable blt::logging BLT_TRACE macro" OFF) option(BLT_DISABLE_TRACE "Disable blt::logging BLT_TRACE macro" OFF)
option(BLT_DISABLE_DEBUG "Disable blt::logging BLT_DEBUG macro" OFF) option(BLT_DISABLE_DEBUG "Disable blt::logging BLT_DEBUG macro" OFF)
@ -28,50 +30,56 @@ option(BLT_DISABLE_WARN "Disable blt::logging BLT_WARN macro" OFF)
option(BLT_DISABLE_ERROR "Disable blt::logging BLT_ERROR macro" OFF) option(BLT_DISABLE_ERROR "Disable blt::logging BLT_ERROR macro" OFF)
option(BLT_DISABLE_FATAL "Disable blt::logging BLT_FATAL macro" OFF) option(BLT_DISABLE_FATAL "Disable blt::logging BLT_FATAL macro" OFF)
if(${BLT_DISABLE_STATS})
add_compile_definitions(BLT_DISABLE_STATS)
endif ()
configure_file(include/blt/config.h.in config/blt/config.h @ONLY) configure_file(include/blt/config.h.in config/blt/config.h @ONLY)
if(${BUILD_STD} OR ${BUILD_PROFILING}) message("Enabling library compilation")
message("Building STD") if (${BUILD_STD} OR ${BUILD_PROFILING})
message("-- Building ${Yellow}standard${ColourReset} cxx files")
file(GLOB_RECURSE STD_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/std/*.cpp") file(GLOB_RECURSE STD_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/std/*.cpp")
else() else ()
set(STD_FILES "") set(STD_FILES "")
endif() endif ()
if(${BUILD_PROFILING}) if (${BUILD_PROFILING})
message("Building Profiling") message("-- Building ${Yellow}profiling${ColourReset} cxx files")
file(GLOB_RECURSE PROFILING_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/profiling/*.cpp") file(GLOB_RECURSE PROFILING_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/profiling/*.cpp")
else() else ()
message("We are not building profiling")
set(PROFILING_FILES "") set(PROFILING_FILES "")
endif() endif ()
if(${BUILD_FS}) if (${BUILD_FS})
message("Building FS") message("-- Building ${Yellow}filesystem${ColourReset} cxx files")
file(GLOB_RECURSE FS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/fs/*.cpp") file(GLOB_RECURSE FS_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/fs/*.cpp")
else() else ()
set(FS_FILES "") set(FS_FILES "")
endif() endif ()
if(${BUILD_PARSE}) if (${BUILD_PARSE})
message("Building Parsers") message("-- Building ${Yellow}parser${ColourReset} cxx files")
file(GLOB_RECURSE PARSE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/parse/*.cpp") file(GLOB_RECURSE PARSE_FILES "${CMAKE_CURRENT_SOURCE_DIR}/src/blt/parse/*.cpp")
else() else ()
set(PARSE_FILES "") set(PARSE_FILES "")
endif() endif ()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
message("Found Parallel Hashmaps") message("Found Parallel Hashmaps library, using ${Yellow}phmap${ColourReset} over ${Red}std::unordered_map${ColourReset}")
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) include_directories(${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
endif() else()
message("Parallel Hashmaps library not found! using ${Yellow}std::unordered_map${ColourReset}")
endif ()
#include zlib if the user has it. #include zlib if the user has it.
find_package(ZLIB QUIET) find_package(ZLIB QUIET)
if (${ZLIB_FOUND}) if (${ZLIB_FOUND})
include_directories(${ZLIB_INCLUDE_DIRS}) include_directories(${ZLIB_INCLUDE_DIRS})
else() else ()
message("ZLIB was not found, this is fine however if you wish you use gzip with NBT it is required.") message("ZLIB was not found, this is fine however if you wish you use gzip with NBT it is required.")
endif() endif ()
include_directories(include/) include_directories(include/)
include_directories(${CMAKE_CURRENT_BINARY_DIR}/config/) include_directories(${CMAKE_CURRENT_BINARY_DIR}/config/)
@ -82,37 +90,30 @@ message("FS Files ${FS_FILES}")
message("Parser Files ${PARSE_FILES}") message("Parser Files ${PARSE_FILES}")
message("Source: ${CMAKE_SOURCE_DIR}") message("Source: ${CMAKE_SOURCE_DIR}")
message("Current Source: ${CMAKE_CURRENT_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}) add_library(${BLT_TARGET} ${STD_FILES} ${PROFILING_FILES} ${FS_FILES} ${PARSE_FILES})
if (${ZLIB_FOUND})
target_link_libraries(${BLT_TARGET} PUBLIC ZLIB::ZLIB)
endif ()
include(cmake/warnings.cmake)
target_include_directories(${BLT_TARGET} PUBLIC include/) target_include_directories(${BLT_TARGET} PUBLIC include/)
target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config/) target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_BINARY_DIR}/config/)
if(${ZLIB_FOUND}) if (EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
target_link_libraries(${BLT_TARGET} PUBLIC ZLIB::ZLIB) message("Including Parallel Hashmap directory")
endif()
if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
message("Including phmap")
target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap) target_include_directories(${BLT_TARGET} PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/libraries/parallel-hashmap)
endif() endif ()
if(MSVC) message("BLT ${Yellow}${BLT_VERSION}${ColourReset} Successfully included!")
#target_compile_options(${BLT_TARGET} PRIVATE /W4)
else()
# perhaps we should warn on unused variables, but BLT will have lots of them.
target_compile_options(${BLT_TARGET} PRIVATE -Wall -Wextra -Wpedantic)
target_link_options(${BLT_TARGET} PUBLIC -rdynamic)
endif()
message("BLT ${CMAKE_PROJECT_VERSION} Successfully included!")
if ("${CMAKE_CXX_COMPILER_ID}" STREQUAL "GNU")
include(GNUInstallDirs)
endif()
message("Installing to ${CMAKE_INSTALL_LIBDIR} with headers at ${CMAKE_INSTALL_INCLUDEDIR}") message("Installing to ${CMAKE_INSTALL_LIBDIR} with headers at ${CMAKE_INSTALL_INCLUDEDIR}")
file(GLOB_RECURSE BLT_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h") file(GLOB_RECURSE BLT_HEADER_FILES "${CMAKE_CURRENT_SOURCE_DIR}/include/*.h")
foreach(S ${BLT_HEADER_FILES}) foreach (S ${BLT_HEADER_FILES})
string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/include/" "" SO ${S}) string(REPLACE "${CMAKE_CURRENT_SOURCE_DIR}/include/" "" SO ${S})
string(REGEX REPLACE "\/[A-Z|a-z|0-9|_|-]*\\.h" "/" SA ${SO}) string(REGEX REPLACE "\/[A-Z|a-z|0-9|_|-]*\\.h" "/" SA ${SO})
list(APPEND BLT_F_HEADERS ${SA}) list(APPEND BLT_F_HEADERS ${SA})
@ -121,7 +122,7 @@ endforeach ()
install(FILES ${CMAKE_BINARY_DIR}/config/blt/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/blt/) install(FILES ${CMAKE_BINARY_DIR}/config/blt/config.h DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/blt/)
set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${PROJECT_VERSION}) set_target_properties(${BLT_TARGET} PROPERTIES VERSION ${BLT_VERSION})
set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR}) set_target_properties(${BLT_TARGET} PROPERTIES SOVERSION ${PROJECT_VERSION_MAJOR})
install(TARGETS ${BLT_TARGET} install(TARGETS ${BLT_TARGET}
@ -129,8 +130,8 @@ install(TARGETS ${BLT_TARGET}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}) PUBLIC_HEADER DESTINATION ${CMAKE_INSTALL_INCLUDEDIR})
if(${BUILD_TESTS}) if (${BUILD_TESTS})
message("Building test") message("Building test version ${BLT_TEST_VERSION}")
project(BLT_TESTS VERSION ${BLT_TEST_VERSION}) project(BLT_TESTS VERSION ${BLT_TEST_VERSION})
include_directories(tests/include) include_directories(tests/include)
@ -141,30 +142,12 @@ if(${BUILD_TESTS})
add_executable(BLT_TESTS ${TEST_FILES}) add_executable(BLT_TESTS ${TEST_FILES})
target_link_libraries(BLT_TESTS BLT) target_link_libraries(BLT_TESTS PRIVATE BLT)
if(MSVC) include(cmake/warnings.cmake)
include(cmake/sanitizers.cmake)
else()
target_compile_options(BLT_TESTS PRIVATE -Wall -Werror -Wpedantic -Wno-comment)
target_link_options(BLT_TESTS PRIVATE -Wall -Werror -Wpedantic -Wno-comment)
endif()
if (${ENABLE_ADDRSAN} MATCHES ON)
target_compile_options(BLT_TESTS PRIVATE -fsanitize=address)
target_link_options(BLT_TESTS PRIVATE -fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
target_compile_options(BLT_TESTS PRIVATE -fsanitize=undefined)
target_link_options(BLT_TESTS PRIVATE -fsanitize=undefined)
endif ()
if (${ENABLE_TSAN} MATCHES ON)
target_compile_options(BLT_TESTS PRIVATE -fsanitize=thread)
target_link_options(BLT_TESTS PRIVATE -fsanitize=thread)
endif ()
message("Built tests") message("Built tests")
endif() endif ()
project(BLT) project(BLT)

0
CMakeSettings.json Executable file → Normal file
View File

0
LICENSE Executable file → Normal file
View File

0
README.md Executable file → Normal file
View File

0
build_and_run_debug.sh Executable file → Normal file
View File

1
cloc.sh Executable file
View File

@ -0,0 +1 @@
cloc --exclude-list-file=exclude.txt include src

19
cmake/color.cmake Normal file
View File

@ -0,0 +1,19 @@
if(NOT WIN32)
string(ASCII 27 Esc)
set(ColourReset "${Esc}[m")
set(ColourBold "${Esc}[1m")
set(Red "${Esc}[31m")
set(Green "${Esc}[32m")
set(Yellow "${Esc}[33m")
set(Blue "${Esc}[34m")
set(Magenta "${Esc}[35m")
set(Cyan "${Esc}[36m")
set(White "${Esc}[37m")
set(BoldRed "${Esc}[1;31m")
set(BoldGreen "${Esc}[1;32m")
set(BoldYellow "${Esc}[1;33m")
set(BoldBlue "${Esc}[1;34m")
set(BoldMagenta "${Esc}[1;35m")
set(BoldCyan "${Esc}[1;36m")
set(BoldWhite "${Esc}[1;37m")
endif()

58
cmake/sanitizers.cmake Normal file
View File

@ -0,0 +1,58 @@
include(cmake/color.cmake)
message("Enabling requested sanitizers for ${PROJECT_NAME}")
if (CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
# using Clang
if (${ENABLE_ADDRSAN} MATCHES ON)
message("-- Using Clang address sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
message("-- Using Clang undefined behaviour sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=undefined)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=undefined)
endif ()
if (${ENABLE_TSAN} MATCHES ON)
message("-- Using Clang thread sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=thread)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=thread)
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
# using GCC
if (${ENABLE_ADDRSAN} MATCHES ON)
message("-- Using GCC address sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
message("-- Using GCC undefined behaviour sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=undefined)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=undefined)
endif ()
if (${ENABLE_TSAN} MATCHES ON)
message("-- Using GCC thread sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE -fsanitize=thread)
target_link_options(${PROJECT_NAME} PRIVATE -fsanitize=thread)
endif ()
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "Intel")
# using Intel C++
elseif (CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
# using Visual Studio C++
if (${ENABLE_ADDRSAN} MATCHES ON)
message("-- Using GCC address sanitizer")
target_compile_options(${PROJECT_NAME} PRIVATE /fsanitize=address)
target_link_options(${PROJECT_NAME} PRIVATE /fsanitize=address)
endif ()
if (${ENABLE_UBSAN} MATCHES ON)
message("-- ${Red}Undefined behaviour sanitizer not supported on this platform${ColourReset}")
endif ()
if (${ENABLE_TSAN} MATCHES ON)
message("-- ${Red}Thread sanitizer not supported on this platform${ColourReset}")
endif ()
endif ()

28
cmake/warnings.cmake Normal file
View File

@ -0,0 +1,28 @@
include(cmake/color.cmake)
message("Enabling platform specific compile options for ${PROJECT_NAME}")
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)
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)
target_link_options(${PROJECT_NAME} PUBLIC -rdynamic)
target_link_libraries(${PROJECT_NAME} PUBLIC stdc++fs)
include(GNUInstallDirs)
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}")
target_compile_options(${PROJECT_NAME} PUBLIC /Wall)
endif ()

86
commit.py Executable file
View File

@ -0,0 +1,86 @@
#!/usr/bin/python3
import subprocess
#---------------------------------------
# CONFIG
#---------------------------------------
VERSION_BEGIN_STR = "set(BLT_VERSION "
VERSION_END_STR = ")"
PATCH_LIMIT = 1000
#---------------------------------------
# DO NOT TOUCH
#---------------------------------------
def load_cmake():
cmake_file = open("CMakeLists.txt", 'r')
cmake_text = cmake_file.read()
cmake_file.close()
return cmake_text
def write_cmake(cmake_text):
cmake_file = open("CMakeLists.txt", 'w')
cmake_file.write(cmake_text)
cmake_file.close()
def get_version(cmake_text):
begin = cmake_text.find(VERSION_BEGIN_STR) + len(VERSION_BEGIN_STR)
end = cmake_text.find(VERSION_END_STR, begin)
return (cmake_text[begin:end], begin, end)
def split_version(cmake_text):
version, begin, end = get_version(cmake_text)
version_parts = version.split('.')
return (version_parts, begin, end)
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
def inc_major(cmake_text):
version_parts, begin, end = split_version(cmake_text)
version_parts[0] = str(int(version_parts[0]) + 1)
version_parts[1] = '0'
version_parts[2] = '0'
return recombine(cmake_text, version_parts, begin, end)
def inc_minor(cmake_text):
version_parts, begin, end = split_version(cmake_text)
version_parts[1] = str(int(version_parts[1]) + 1)
version_parts[2] = '0'
return recombine(cmake_text, version_parts, begin, end)
def inc_patch(cmake_text):
version_parts, begin, end = split_version(cmake_text)
if int(version_parts[2]) + 1 >= 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}")
try:
type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
if type.startswith('M'):
print("Selected major")
write_cmake(inc_major(cmake_text))
elif type.startswith('m'):
print("Selected minor")
write_cmake(inc_minor(cmake_text))
elif type.startswith('p') or type.startswith('P') or len(type) == 0:
print("Selected patch")
write_cmake(inc_patch(cmake_text))
subprocess.call(["git", "add", "*"])
subprocess.call(["git", "commit"])
subprocess.call(["sh", "-c", "git remote | xargs -L1 git push --all"])
except KeyboardInterrupt:
print("\nCancelling!")

74
commit.py.save Executable file
View File

@ -0,0 +1,74 @@
#!/usr/bin/python3
import subprocess
#---------------------------------------
# CONFIG
#---------------------------------------
VERSION_BEGIN_STR = "set(BLT_VERSION "
VERSION_END_STR = ")"
#---------------------------------------
# DO NOT TOUCH
#---------------------------------------
type = input("What kind of commit is this ((M)ajor, (m)inor, (p)atch)? ")
def load_cmake():
cmake_file = open("CMakeLists.txt", 'r')
cmake_text = cmake_file.read()
cmake_file.close()
return cmake_text
def write_cmake(cmake_text):
cmake_file = open("CMakeLists.txt", 'w')
cmake_file.write(cmake_text)
cmake_file.close()
def get_version(cmake_text):
begin = cmake_text.find(VERSION_BEGIN_STR) + len(find_text)
end = cmake_text.find(VERSION_END_STR, begin)
return (cmake_text[begin:end], begin, end)
def split_version(cmake_text):
version, begin, end = get_version(cmake_text)
version_parts = version.split('.')
return (version_parts, begin, end)
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
def inc_major(cmake_text):
version_parts, begin, end = split_version(cmake_text)
version_parts[0] = str(int(version_parts[0]) + 1)
return recombine(cmake_text, version_parts, begin, end)
def inc_minor(cmake_text):
version_parts, begin, end = split_version(cmake_text)
version_parts[1] = str(int(version_parts[1]) + 1)
return recombine(cmake_text, version_parts, begin, end)
def inc_patch(cmake_text):
version_parts, begin, end = split_version(cmake_text)
version_parts[2] = str(int(version_parts[2]) + 1)
return recombine(cmake_text, version_parts, begin, end)
if type.startswith('M'):
print("Selected major")
write_cmake(inc_major(load_cmake()))
elif type.startswith('m'):
print("Selected minor")
write_cmake(inc_minor(load_cmake()))
elif type.startswith('p') or type.startswith('P') or len(type) == 0:
print("Selected patch")
write_cmake(inc_patch(load_cmake()))
#subprocess.call("./py_commit_helper.sh")
subprocess.call("git", "add", "*")
subprocess.call("git", "commit")
subprocess.call("sh -e 'git remote | xargs -L1 git push --all'")

0
commit.sh Executable file → Normal file
View File

0
design.txt Executable file → Normal file
View File

1
exclude.txt Normal file
View File

@ -0,0 +1 @@
include/blt/unicode_emoji.h

0
icon.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 39 KiB

After

Width:  |  Height:  |  Size: 39 KiB

0
icon_large.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 118 KiB

After

Width:  |  Height:  |  Size: 118 KiB

0
icon_small.png Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

0
include/blt/config.h.in Executable file → Normal file
View File

0
include/blt/fs/filesystem.h Executable file → Normal file
View File

0
include/blt/fs/loader.h Executable file → Normal file
View File

8
include/blt/fs/nbt.h Executable file → Normal file
View File

@ -250,8 +250,8 @@ namespace blt::nbt {
BLT_WARN("Tag Type not found!"); BLT_WARN("Tag Type not found!");
return nullptr; return nullptr;
} }
static HASHMAP<std::string, tag_t*> toHashmap(const std::vector<tag_t*>& v){ static hashmap_t<std::string, tag_t*> toHashmap(const std::vector<tag_t*>& v){
HASHMAP<std::string, tag_t*> tags; hashmap_t<std::string, tag_t*> tags;
for (const auto& t : v) for (const auto& t : v)
tags[t->getName()] = t; tags[t->getName()] = t;
return tags; return tags;
@ -321,12 +321,12 @@ namespace blt::nbt {
} }
}; };
class tag_compound : public tag<HASHMAP<std::string, tag_t*>> { class tag_compound : public tag<hashmap_t<std::string, tag_t*>> {
public: public:
tag_compound(): tag(nbt_tag::COMPOUND) {} tag_compound(): tag(nbt_tag::COMPOUND) {}
tag_compound(const std::string& name, const std::vector<tag_t*>& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {} tag_compound(const std::string& name, const std::vector<tag_t*>& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {}
tag_compound(const std::string& name, const std::initializer_list<tag_t*>& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {} tag_compound(const std::string& name, const std::initializer_list<tag_t*>& v): tag(nbt_tag::COMPOUND, name, _internal_::toHashmap(v)) {}
tag_compound(const std::string& name, const HASHMAP<std::string, tag_t*>& v): tag(nbt_tag::COMPOUND, name, v) {} tag_compound(const std::string& name, const hashmap_t<std::string, tag_t*>& v): tag(nbt_tag::COMPOUND, name, v) {}
inline void put(tag_t* tag) { inline void put(tag_t* tag) {
t[tag->getName()] = tag; t[tag->getName()] = tag;

0
include/blt/fs/nbt_block.h Executable file → Normal file
View File

0
include/blt/math/averages.h Executable file → Normal file
View File

View File

@ -0,0 +1,89 @@
/*
* <Short Description>
* Copyright (C) 2024 Brett Terpstra
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <https://www.gnu.org/licenses/>.
*/
#ifndef BLT_FIXED_POINT_H
#define BLT_FIXED_POINT_H
#include <blt/std/types.h>
#include <blt/std/utility.h>
namespace blt
{
struct fp64
{
private:
u64 v = 0;
fp64() = default;
explicit fp64(u64 v): v(v)
{}
public:
static fp64 from_u64(u64 ui)
{
fp64 fp;
fp.v = ui << 32;
return fp;
}
static fp64 from_i64(i64 si)
{
u64 ui = static_cast<u64>(si);
fp64 fp;
fp.v = ui << 32;
return fp;
}
BLT_ATTRIB_NO_INLINE friend fp64 operator+(fp64 left, fp64 right)
{
return fp64(left.v + right.v);
}
BLT_ATTRIB_NO_INLINE friend fp64 operator-(fp64 left, fp64 right)
{
return fp64(left.v - right.v);
}
BLT_ATTRIB_NO_INLINE friend fp64 operator*(fp64 left, fp64 right)
{
auto lhs = static_cast<__int128>(left.v);
auto rhs = static_cast<__int128>(right.v);
return fp64(static_cast<u64>((lhs * rhs) >> 32));
}
BLT_ATTRIB_NO_INLINE friend fp64 operator/(fp64 left, fp64 right)
{
auto lhs = static_cast<__int128>(left.v);
auto rhs = static_cast<__int128>(right.v);
return fp64(static_cast<u64>((lhs / rhs) << 32));
}
[[nodiscard]] u64 as_u64() const
{
return v >> 32;
}
[[nodiscard]] i64 as_i64() const
{
return static_cast<i64>(v >> 32);
}
};
}
#endif //BLT_FIXED_POINT_H

0
include/blt/math/log_util.h Executable file → Normal file
View File

17
include/blt/math/math.h Executable file → Normal file
View File

@ -31,8 +31,10 @@ namespace blt
return ((seed * (seed * seed * 15731 + 789221) + 1376312589) & 0x7fffffff); return ((seed * (seed * seed * 15731 + 789221) + 1376312589) & 0x7fffffff);
} }
#ifdef __GNUC__
#pragma GCC diagnostic push #pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wstrict-aliasing" #pragma GCC diagnostic ignored "-Wstrict-aliasing"
#endif
/** /**
* fast inverse sqrt * fast inverse sqrt
@ -51,8 +53,10 @@ namespace blt
return y; return y;
} }
#ifdef __GNUC__
#pragma GCC diagnostic pop #pragma GCC diagnostic pop
#endif
static inline constexpr double pow(int b, int p) static inline constexpr double pow(int b, int p)
{ {
@ -69,10 +73,15 @@ namespace blt
* @return * @return
*/ */
template<int decimal_places> template<int decimal_places>
static inline double round_up(double value) constexpr static inline double round_up(double value)
{ {
constexpr double multiplier = pow(10, decimal_places); if constexpr (decimal_places < 0)
return ((int) (value * multiplier) + 1) / multiplier; return value;
else
{
constexpr double multiplier = pow(10, decimal_places);
return ((int) (value * multiplier) + 1) / multiplier;
}
} }
/*inline std::ostream& operator<<(std::ostream& out, const mat4x4& v) { /*inline std::ostream& operator<<(std::ostream& out, const mat4x4& v) {

0
include/blt/math/matrix.h Executable file → Normal file
View File

0
include/blt/math/vectors.h Executable file → Normal file
View File

42
include/blt/parse/argparse.h Executable file → Normal file
View File

@ -17,6 +17,7 @@
#include <variant> #include <variant>
#include <algorithm> #include <algorithm>
#include <type_traits> #include <type_traits>
#include "blt/std/utility.h"
namespace blt namespace blt
{ {
@ -307,8 +308,13 @@ namespace blt
template<typename T> template<typename T>
static inline T get_cast(arg_data_t& v) static inline T get_cast(arg_data_t& v)
{ {
if constexpr (std::is_same_v<T, arg_data_vec_t>) if (std::holds_alternative<arg_data_vec_t>(v))
return std::get<arg_data_vec_t>(v); {
if constexpr (std::is_same_v<T, arg_data_vec_t>)
return std::get<arg_data_vec_t>(v);
else
throw std::runtime_error("Cannot request singular data from stored vector type");
}
auto t = std::get<arg_data_internal_t>(v); auto t = std::get<arg_data_internal_t>(v);
// user is requesting an int, but holds a string, we are going to make the assumption the data can be converted // user is requesting an int, but holds a string, we are going to make the assumption the data can be converted
// it is up to the user to deal with the variant if they do not want this behaviour! // it is up to the user to deal with the variant if they do not want this behaviour!
@ -319,12 +325,20 @@ namespace blt
return static_cast<T>(std::get<int32_t>(t)); return static_cast<T>(std::get<int32_t>(t));
if (std::holds_alternative<bool>(t)) if (std::holds_alternative<bool>(t))
return static_cast<T>(std::get<bool>(t)); return static_cast<T>(std::get<bool>(t));
auto s = std::get<std::string>(t); auto s = std::get<std::string>(t);
if (s.empty())
throw std::runtime_error("Key does not have value!");
if constexpr (std::is_floating_point_v<T>) if constexpr (std::is_floating_point_v<T>)
return static_cast<T>(std::stod(s)); return static_cast<T>(std::stod(s));
if constexpr (std::is_signed_v<T>) else if constexpr (std::is_signed_v<T>)
return static_cast<T>(std::stoll(s)); return static_cast<T>(std::stoll(s));
return static_cast<T>(std::stoull(s)); else if constexpr (std::is_unsigned_v<T>)
return static_cast<T>(std::stoull(s));
else
return static_cast<T>(s);
} }
struct arg_results struct arg_results
@ -332,11 +346,11 @@ namespace blt
friend arg_parse; friend arg_parse;
private: private:
// stores dest value not the flag/name! // stores dest value not the flag/name!
HASHSET<std::string> found_args; hashset_t<std::string> found_args;
std::vector<std::string> unrecognized_args; std::vector<std::string> unrecognized_args;
public: public:
std::string program_name; std::string program_name;
HASHMAP<std::string, arg_data_t> data; hashmap_t<std::string, arg_data_t> data;
inline arg_data_t& operator[](const std::string& key) inline arg_data_t& operator[](const std::string& key)
{ {
@ -346,10 +360,17 @@ namespace blt
template<typename T> template<typename T>
inline T get(const std::string& key) inline T get(const std::string& key)
{ {
if constexpr (std::is_same_v<T, std::string>) hashmap_t<std::string, arg_data_t>::iterator val;
return blt::arg_parse::get<T>(data[key]); if (blt::string::starts_with(key, "--"))
val = data.find(key.substr(2));
else if (blt::string::starts_with(key, '-'))
val = data.find(key.substr(1));
else else
return blt::arg_parse::get_cast<T>(data[key]); val = data.find(key);
if constexpr (std::is_same_v<T, std::string>)
return blt::arg_parse::get<T>(val->second);
else
return blt::arg_parse::get_cast<T>(val->second);
} }
inline auto begin() inline auto begin()
@ -371,6 +392,7 @@ namespace blt
return data.find(key) != data.end(); return data.find(key) != data.end();
} }
}; };
private: private:
struct struct
{ {
@ -384,7 +406,7 @@ namespace blt
std::string postfix; std::string postfix;
public: public:
std::vector<arg_properties_t*> name_associations; std::vector<arg_properties_t*> name_associations;
HASHMAP<std::string, arg_properties_t*> flag_associations; hashmap_t<std::string, arg_properties_t*> flag_associations;
} user_args; } user_args;
arg_results loaded_args; arg_results loaded_args;

0
include/blt/parse/mustache.h Executable file → Normal file
View File

View File

@ -116,9 +116,9 @@ namespace blt::parse
private: private:
std::vector<constructed_vertex_t> vertex_data_; std::vector<constructed_vertex_t> vertex_data_;
std::vector<object_data> objects_; std::vector<object_data> objects_;
HASHMAP<std::string, material_t> materials_; hashmap_t<std::string, material_t> materials_;
public: public:
obj_model_t(std::vector<constructed_vertex_t>&& vertex_data, std::vector<object_data>&& objects, HASHMAP<std::string, material_t>&& mats): obj_model_t(std::vector<constructed_vertex_t>&& vertex_data, std::vector<object_data>&& objects, hashmap_t<std::string, material_t>&& mats):
vertex_data_(vertex_data), objects_(objects), materials_(mats) vertex_data_(vertex_data), objects_(objects), materials_(mats)
{} {}
@ -148,11 +148,11 @@ namespace blt::parse
std::vector<normal_t> normals; std::vector<normal_t> normals;
// maps between face (constructed vertex) -> vertex indices // maps between face (constructed vertex) -> vertex indices
HASHMAP<face_t, std::int32_t, face_hash, face_eq> vertex_map; hashmap_t<face_t, std::int32_t, face_hash, face_eq> vertex_map;
std::vector<constructed_vertex_t> vertex_data; std::vector<constructed_vertex_t> vertex_data;
object_data current_object; object_data current_object;
std::vector<object_data> data; std::vector<object_data> data;
HASHMAP<std::string, material_t> materials; hashmap_t<std::string, material_t> materials;
size_t current_line = 0; size_t current_line = 0;
private: private:

0
include/blt/profiling/profiler.h Executable file → Normal file
View File

View File

@ -17,17 +17,64 @@
*/ */
#ifndef BLT_ALLOCATOR_H #ifndef BLT_ALLOCATOR_H
#include <optional> #include <optional>
#include <limits> #include <limits>
#include <vector> #include <vector>
#include <blt/std/utility.h> #include <blt/std/ranges.h>
#include <stdexcept> #include <blt/std/utility.h>
#include <blt/std/types.h>
// TODO: remove
//#include <blt/std/hashmap.h>
#include <blt/compatibility.h>
#include <stdexcept>
#include "logging.h"
#include <cstdlib>
#ifdef __unix__
#include <sys/mman.h>
#endif
namespace blt namespace blt
{ {
template<typename value_type, typename pointer, typename const_pointer>
class allocator_base
{
public:
template<class U, class... Args>
inline void construct(U* p, Args&& ... args)
{
::new((void*) p) U(std::forward<Args>(args)...);
}
template<class U>
inline void destroy(U* p)
{
if (p != nullptr)
p->~U();
}
[[nodiscard]] inline size_t max_size() const
{
return std::numeric_limits<size_t>::max();
}
inline const_pointer address(const value_type& val)
{
return std::addressof(val);
}
inline pointer address(value_type& val)
{
return std::addressof(val);
}
};
template<typename T, size_t BLOCK_SIZE = 8192> template<typename T, size_t BLOCK_SIZE = 8192>
class area_allocator class area_allocator : public allocator_base<T, T*, const T*>
{ {
public: public:
using value = T; using value = T;
@ -47,6 +94,7 @@ namespace blt
{ {
typedef blt::area_allocator<U, BLOCK_SIZE> other; typedef blt::area_allocator<U, BLOCK_SIZE> other;
}; };
using allocator_base<value_type, pointer, const_pointer>::allocator_base;
private: private:
/** /**
* Stores a view to a region of memory that has been deallocated * Stores a view to a region of memory that has been deallocated
@ -225,6 +273,140 @@ namespace blt
} }
} }
~area_allocator()
{
for (auto*& blk : blocks)
{
free(blk->data);
delete blk;
}
}
private:
std::vector<block_storage*> blocks;
};
// template<typename T>
// class bump_allocator : public allocator_base<T, T*, const T*>
// {
// public:
// using value = T;
// using type = T;
// using value_type = type;
// using pointer = type*;
// using const_pointer = const type*;
// using void_pointer = void*;
// using const_void_pointer = const void*;
// using reference = value_type&;
// using const_reference = const value_type&;
// using size_type = size_t;
// using difference_type = size_t;
// using propagate_on_container_move_assignment = std::false_type;
// template<class U>
// struct rebind
// {
// typedef blt::bump_allocator<U> other;
// };
// using allocator_base<value_type, pointer, const_pointer>::allocator_base;
// private:
// pointer buffer_;
// blt::size_t offset_;
// blt::size_t size_;
// public:
// explicit bump_allocator(blt::size_t size): buffer_(static_cast<pointer>(malloc(size * sizeof(T)))), offset_(0), size_(size)
// {}
//
// template<typename... Args>
// explicit bump_allocator(blt::size_t size, Args&& ... defaults):
// buffer_(static_cast<pointer>(malloc(size * sizeof(type)))), offset_(0), size_(size)
// {
// for (blt::size_t i = 0; i < size_; i++)
// ::new(&buffer_[i]) T(std::forward<Args>(defaults)...);
// }
//
// bump_allocator(pointer buffer, blt::size_t size): buffer_(buffer), offset_(0), size_(size)
// {}
//
// bump_allocator(const bump_allocator& copy) = delete;
//
// bump_allocator(bump_allocator&& move) noexcept
// {
// buffer_ = move.buffer_;
// size_ = move.size_;
// offset_ = move.offset_;
// }
//
// bump_allocator& operator=(const bump_allocator& copy) = delete;
//
// bump_allocator& operator=(bump_allocator&& move) noexcept
// {
// std::swap(move.buffer_, buffer_);
// std::swap(move.size_, size_);
// std::swap(move.offset_, offset_);
// }
//
// pointer allocate(blt::size_t n)
// {
// auto nv = offset_ + n;
// if (nv > size_)
// throw std::bad_alloc();
// pointer b = &buffer_[offset_];
// offset_ = nv;
// return b;
// }
//
// void deallocate(pointer, blt::size_t)
// {}
//
// ~bump_allocator()
// {
// free(buffer_);
// }
// };
/**
* The bump allocator is meant to be a faster area allocator which will only allocate forward through either a supplied buffer or size
* or will create a linked list type data structure of buffered blocks.
* @tparam ALLOC allocator to use for any allocations. In the case of the non-linked variant, this will be used if a size is supplied. The supplied buffer must be allocated with this allocator!
* @tparam linked use a linked list to allocate with the allocator or just use the supplied buffer and throw an exception of we cannot allocate
*/
template<bool linked, template<typename> typename ALLOC = std::allocator>
class bump_allocator_old;
template<template<typename> typename ALLOC>
class bump_allocator_old<false, ALLOC>
{
private:
ALLOC<blt::u8> allocator;
blt::u8* buffer_;
blt::u8* offset_;
blt::size_t size_;
public:
explicit bump_allocator_old(blt::size_t size): buffer_(static_cast<blt::u8*>(allocator.allocate(size))), offset_(buffer_), size_(size)
{}
explicit bump_allocator_old(blt::u8* buffer, blt::size_t size): buffer_(buffer), offset_(buffer), size_(size)
{}
template<typename T>
[[nodiscard]] T* allocate()
{
size_t remaining_num_bytes = size_ - static_cast<size_t>(buffer_ - offset_);
auto pointer = static_cast<void*>(offset_);
const auto aligned_address = std::align(alignof(T), sizeof(T), pointer, remaining_num_bytes);
if (aligned_address == nullptr)
throw std::bad_alloc{};
offset_ = static_cast<blt::u8*>(aligned_address) + sizeof(T);
return static_cast<T*>(aligned_address);
}
template<typename T, typename... Args>
[[nodiscard]] T* emplace(Args&& ... args)
{
const auto allocated_memory = allocate<T>();
return new(allocated_memory) T{std::forward<Args>(args)...};
}
template<class U, class... Args> template<class U, class... Args>
inline void construct(U* p, Args&& ... args) inline void construct(U* p, Args&& ... args)
{ {
@ -238,32 +420,595 @@ namespace blt
p->~U(); p->~U();
} }
[[nodiscard]] inline size_t max_size() const ~bump_allocator_old()
{ {
return std::numeric_limits<size_t>::max(); allocator.deallocate(buffer_, size_);
}
};
template<template<typename> typename ALLOC>
class bump_allocator_old<true, ALLOC>
{
private:
struct block
{
blt::size_t allocated_objects = 0;
blt::u8* buffer = nullptr;
blt::u8* offset = nullptr;
explicit block(blt::u8* buffer): buffer(buffer), offset(buffer)
{}
};
ALLOC<blt::u8> allocator;
std::vector<block, ALLOC<block>> blocks;
blt::size_t size_;
blt::size_t allocations = 0;
blt::size_t deallocations = 0;
void expand()
{
auto ptr = static_cast<blt::u8*>(allocator.allocate(size_));
blocks.push_back(block{ptr});
allocations++;
} }
inline const_pointer address(const value_type& val) template<typename T>
T* allocate_back()
{ {
return std::addressof(val); auto& back = blocks.back();
} size_t remaining_bytes = size_ - static_cast<size_t>(back.offset - back.buffer);
auto pointer = static_cast<void*>(back.offset);
inline pointer address(value_type& val) const auto aligned_address = std::align(alignof(T), sizeof(T), pointer, remaining_bytes);
{ if (aligned_address != nullptr)
return std::addressof(val);
}
~area_allocator()
{
for (auto*& blk : blocks)
{ {
free(blk->data); back.offset = static_cast<blt::u8*>(aligned_address) + sizeof(T);
delete blk; back.allocated_objects++;
} }
return static_cast<T*>(aligned_address);
} }
public:
/**
* @param size of the list blocks
*/
explicit bump_allocator_old(blt::size_t size): size_(size)
{
expand();
}
template<typename T>
[[nodiscard]] T* allocate()
{
if (auto ptr = allocate_back<T>(); ptr == nullptr)
expand();
else
return ptr;
if (auto ptr = allocate_back<T>(); ptr == nullptr)
throw std::bad_alloc();
else
return ptr;
}
template<typename T>
void deallocate(T* p)
{
auto* ptr = reinterpret_cast<blt::u8*>(p);
for (auto e : blt::enumerate(blocks))
{
auto& block = e.second;
if (ptr >= block.buffer && ptr <= block.offset)
{
block.allocated_objects--;
if (block.allocated_objects == 0)
{
std::iter_swap(blocks.begin() + e.first, blocks.end() - 1);
allocator.deallocate(blocks.back().buffer, size_);
blocks.pop_back();
deallocations++;
}
return;
}
}
}
template<typename T, typename... Args>
[[nodiscard]] T* emplace(Args&& ... args)
{
const auto allocated_memory = allocate<T>();
return new(allocated_memory) T{std::forward<Args>(args)...};
}
template<class U, class... Args>
inline void construct(U* p, Args&& ... args)
{
::new((void*) p) U(std::forward<Args>(args)...);
}
template<class U>
inline void destroy(U* p)
{
if (p != nullptr)
p->~U();
}
~bump_allocator_old()
{
if (allocations != deallocations)
BLT_WARN("Allocator has blocks which have not been deallocated! Destructors might not have been called!");
for (auto& v : blocks)
allocator.deallocate(v.buffer, size_);
}
};
// size of 2mb in bytes
inline constexpr blt::size_t BLT_2MB_SIZE = 4096 * 512;
/**
* 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
* @tparam BLOCK_SIZE size of block to use. recommended to be multiple of page size or huge page size.
* @tparam USE_HUGE allocate using mmap and huge pages. If this fails it will use mmap to allocate normally. defaults to off because linux has parent huge pages.
* @tparam HUGE_PAGE_SIZE size the system allows huge pages to be. defaults to 2mb
* @tparam WARN_ON_FAIL print warning messages if allocating huge pages fail
*/
template<blt::size_t BLOCK_SIZE = BLT_2MB_SIZE, bool USE_HUGE = false, blt::size_t HUGE_PAGE_SIZE = BLT_2MB_SIZE, bool WARN_ON_FAIL = false>
class bump_allocator
{
// ensure power of two
static_assert(((BLOCK_SIZE & (BLOCK_SIZE - 1)) == 0) && "Must be a power of two!");
public:
/**
* convert any pointer back into a pointer its block
*/
template<typename T>
static inline auto to_block(T* p)
{
return reinterpret_cast<block*>(reinterpret_cast<std::uintptr_t>(p) & static_cast<std::uintptr_t>(~(BLOCK_SIZE - 1)));
}
class stats_t
{
friend bump_allocator;
private:
blt::size_t allocated_blocks = 0;
blt::size_t allocated_bytes = 0;
blt::size_t peak_blocks = 0;
blt::size_t peak_bytes = 0;
protected:
inline void incrementBlocks()
{
allocated_blocks++;
if (allocated_blocks > peak_blocks)
peak_blocks = allocated_blocks;
}
inline void decrementBlocks()
{
allocated_blocks--;
}
inline void incrementBytes(blt::size_t bytes)
{
allocated_bytes += bytes;
if (allocated_bytes > peak_bytes)
peak_bytes = allocated_bytes;
}
inline void decrementBytes(blt::size_t bytes)
{
allocated_bytes -= bytes;
}
public:
inline auto getAllocatedBlocks() const
{
return allocated_blocks;
}
inline auto getAllocatedBytes() const
{
return allocated_bytes;
}
inline auto getPeakBlocks() const
{
return peak_blocks;
}
inline auto getPeakBytes() const
{
return peak_bytes;
}
};
private: private:
std::vector<block_storage*> blocks; 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
{
blt::size_t allocated_objects = 0;
block* next = nullptr;
block* prev = nullptr;
blt::u8* offset = nullptr;
} metadata;
blt::u8 buffer[BLOCK_SIZE - sizeof(block_metadata_t)]{};
block()
{
metadata.offset = buffer;
}
};
// remaining space inside the block after accounting for the metadata
static constexpr blt::size_t BLOCK_REMAINDER = BLOCK_SIZE - sizeof(typename block::block_metadata_t);
block* base = nullptr;
block* head = nullptr;
/**
* Handles the allocation of the bytes for the block.
* This function will either use mmap to allocate huge pages if requested
* or use std::align_alloc to create an aligned allocation
* @return pointer to a constructed block
*/
block* allocate_block()
{
block* buffer;
#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);
}
} else
buffer = reinterpret_cast<block*>(std::aligned_alloc(BLOCK_SIZE, BLOCK_SIZE));
#else
buffer = reinterpret_cast<block*>(std::aligned_alloc(BLOCK_SIZE, BLOCK_SIZE));
#endif
construct(buffer);
#ifndef BLT_DISABLE_STATS
stats.incrementBlocks();
#endif
return buffer;
}
/**
* Allocates a new block and pushes it to the front of the linked listed
*/
void allocate_forward()
{
auto* block = allocate_block();
if (head == nullptr)
{
base = head = block;
return;
}
block->metadata.prev = head;
head->metadata.next = block;
head = block;
}
/**
* handles the actual allocation and alignment of memory
* @param bytes number of bytes to allocate
* @param alignment alignment required
* @return aligned pointer
*/
void* allocate_bytes(blt::size_t bytes, blt::size_t alignment)
{
if (head == nullptr)
return nullptr;
blt::size_t remaining_bytes = BLOCK_REMAINDER - static_cast<blt::size_t>(head->metadata.offset - head->buffer);
auto pointer = static_cast<void*>(head->metadata.offset);
return std::align(alignment, bytes, pointer, remaining_bytes);
}
/**
* allocate an object starting from the next available address
* @tparam T type to allocate for
* @param count number of elements to allocate
* @return nullptr if the object could not be allocated, pointer to the object if it could, pointer to the start if count != 1
*/
template<typename T>
T* allocate_object(blt::size_t count)
{
blt::size_t bytes = sizeof(T) * count;
const auto aligned_address = allocate_bytes(bytes, alignof(T));
if (aligned_address != nullptr)
{
head->metadata.allocated_objects++;
head->metadata.offset = static_cast<blt::u8*>(aligned_address) + bytes;
}
return static_cast<T*>(aligned_address);
}
/**
* Frees a block
* @param p pointer to the block to free
*/
inline void delete_block(block* p)
{
#ifndef BLT_DISABLE_STATS
stats.decrementBlocks();
#endif
if constexpr (USE_HUGE)
{
if (munmap(p, BLOCK_SIZE))
{
BLT_ERROR_STREAM << "FAILED TO DEALLOCATE BLOCK\n";
handle_mmap_error(BLT_ERROR_STREAM);
}
} else
free(p);
}
public:
bump_allocator() = default;
/**
* Takes an unused size parameter. Purely used for compatibility with the old bump_allocator
*/
explicit bump_allocator(blt::size_t)
{}
/**
* Allocate bytes for a type
* @tparam T type to allocate
* @param count number of elements to allocate for
* @throws std::bad_alloc
* @return aligned pointer to the beginning of the allocated memory
*/
template<typename T>
[[nodiscard]] T* allocate(blt::size_t count = 1)
{
if constexpr (sizeof(T) > BLOCK_REMAINDER)
throw std::bad_alloc();
#ifndef BLT_DISABLE_STATS
stats.incrementBytes(sizeof(T) * count);
#endif
T* ptr = allocate_object<T>(count);
if (ptr != nullptr)
return ptr;
allocate_forward();
ptr = allocate_object<T>(count);
if (ptr == nullptr)
throw std::bad_alloc();
return ptr;
}
/**
* Deallocate a pointer, does not call the destructor
* @tparam T type of pointer
* @param p pointer to deallocate
*/
template<typename T>
void deallocate(T* p, blt::size_t count = 1)
{
if (p == nullptr)
return;
#ifndef BLT_DISABLE_STATS
stats.decrementBytes(sizeof(T) * count);
#endif
// if (deletes.contains(p))
// {
// BLT_FATAL("pointer %p has already been freed", p);
// throw std::bad_alloc();
// }else
// deletes.insert(static_cast<void*>(p));
auto blk = to_block(p);
blk->metadata.allocated_objects--;
if (blk->metadata.allocated_objects == 0)
{
//BLT_INFO("Deallocating block from %p in (1) %p current head %p, based: %p", p, blk, head, base);
if (blk == base)
{
base = base->metadata.next;
// if they were equal (single allocated block) we also need to move the head forward
if (blk == head)
head = base;
} else if (blk == head) // else, need to make sure the head ptr gets moved back, otherwise we will use a head that has been freed
head = blk->metadata.prev;
else if (blk->metadata.prev != nullptr) // finally if it wasn't the head we need to bridge the gap in the list
blk->metadata.prev->metadata.next = blk->metadata.next;
//BLT_INFO("Deallocating block from %p in (2) %p current head %p, based: %p", p, blk, head, base);
delete_block(blk);
}
}
/**
* allocate a type then call its constructor with arguments
* @tparam T type to construct
* @tparam Args type of args to construct with
* @param args args to construct with
* @return aligned pointer to the constructed type
*/
template<typename T, typename... Args>
[[nodiscard]] T* emplace(Args&& ... args)
{
const auto allocated_memory = allocate<T>();
return new(allocated_memory) T{std::forward<Args>(args)...};
}
/**
* allocate an array of count T with argument(s) args and call T's constructor
* @tparam T class to construct
* @tparam Args argument types to supply to construction
* @param count size of the array to allocate in number of elements. Note calling this with count = 0 is equivalent to calling emplace
* @param args the args to supply to construction
* @return aligned pointer to the beginning of the array of T
*/
template<typename T, typename... Args>
[[nodiscard]] T* emplace_many(blt::size_t count, Args&& ... args)
{
if (count == 0)
return nullptr;
const auto allocated_memory = allocate<T>(count);
for (blt::size_t i = 0; i < count; i++)
new(allocated_memory + i) T{std::forward<Args>(args)...};
return allocated_memory;
}
/**
* Used to construct a class U with parameters Args
* @tparam U class to construct
* @tparam Args args to use
* @param p pointer to non-constructed memory
* @param args list of arguments to build the class with
*/
template<class U, class... Args>
inline void construct(U* p, Args&& ... args)
{
::new((void*) p) U(std::forward<Args>(args)...);
}
/**
* Call the destructor for class U with pointer p
* @tparam U class to call destructor on, this will not do anything if the type is std::trivially_destructible
* @param p
*/
template<class U>
inline void destroy(U* p)
{
if constexpr (!std::is_trivially_destructible_v<U>)
{
if (p != nullptr)
p->~U();
}
}
/**
* Calls destroy on pointer p
* Then calls deallocate on p
* @tparam U class to destroy
* @param p pointer to deallocate
*/
template<class U>
inline void destruct(U* p)
{
destroy(p);
deallocate(p);
}
inline void resetStats()
{
stats = {};
}
inline const auto& getStats() const
{
return stats;
}
~bump_allocator()
{
block* next = base;
while (next != nullptr)
{
auto* after = next->metadata.next;
delete_block(next);
next = after;
}
}
}; };
} }

226
include/blt/std/any.h Normal file
View File

@ -0,0 +1,226 @@
#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/>.
*/
#include <cstring>
#ifndef BLT_ANY_H
#define BLT_ANY_H
#include <any>
#include <blt/std/types.h>
namespace blt::unsafe
{
class any_t_union
{
private:
static constexpr auto SIZE = sizeof(std::any);
union variant_t
{
constexpr variant_t()
{}
blt::u8 data[SIZE]{};
std::any any;
~variant_t()
{}
};
variant_t variant;
bool has_any = false;
public:
any_t_union() = default;
any_t_union(const any_t_union& copy)
{
if (copy.has_any)
{
variant.any = copy.variant.any;
has_any = true;
} else
{
std::memcpy(variant.data, copy.variant.data, SIZE);
}
}
any_t_union(any_t_union&& move) noexcept
{
if (move.has_any)
{
variant.any = std::move(move.variant.any);
has_any = true;
} else
{
std::memcpy(variant.data, move.variant.data, SIZE);
}
}
~any_t_union()
{
if (has_any)
variant.any.~any();
}
template<typename T>
any_t_union(T t)
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v<T>)
{
std::memcpy(variant.data, &t, sizeof(t));
} else
{
variant.any = t;
has_any = true;
}
}
any_t_union& operator=(const any_t_union& copy)
{
if (has_any)
variant.any.~any();
if (copy.has_any)
{
std::memset(variant.data, 0, SIZE);
variant.any = copy.variant.any;
has_any = true;
} else
{
std::memcpy(variant.data, copy.variant.data, SIZE);
has_any = false;
}
return *this;
}
any_t_union& operator=(any_t_union&& move) noexcept
{
if (has_any)
variant.any.~any();
if (move.has_any)
{
std::memset(variant.data, 0, SIZE);
variant.any = std::move(move.variant.any);
has_any = true;
} else
{
std::memcpy(variant.data, move.variant.data, SIZE);
has_any = false;
}
return *this;
}
template<typename T>
any_t_union& operator=(T t)
{
if (has_any)
variant.any.~any();
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v<T>)
{
std::memcpy(variant.data, &t, sizeof(t));
has_any = false;
} else
{
std::memset(variant.data, 0, SIZE);
variant.any = std::move(t);
has_any = true;
}
return *this;
}
template<typename T>
T any_cast()
{
if constexpr (sizeof(T) <= SIZE && std::is_trivially_copyable_v<T>)
{
if (!has_any)
{
T t;
std::memcpy(&t, variant.data, sizeof(T));
return t;
}
}
return std::any_cast<T>(variant.any);
}
};
class buffer_any_t
{
private:
blt::u8* _data;
public:
explicit buffer_any_t(blt::u8* data): _data(data)
{}
template<typename T>
void set(const T& t) const
{
static_assert(std::is_trivially_copyable_v<T> && "Type must be trivially copyable");
std::memcpy(_data, &t, sizeof(t));
}
template<typename T>
T any_cast() const
{
static_assert(std::is_trivially_copyable_v<T> && "Type must be trivially copyable");
T t;
std::memcpy(&t, _data, sizeof(T));
return t;
}
};
template<blt::size_t SIZE>
class any_t_base
{
private:
blt::u8 data[SIZE]{};
public:
any_t_base() = default;
template<typename T>
any_t_base(T t)
{
static_assert(std::is_trivially_copyable_v<T> && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
std::memcpy(data, &t, sizeof(t));
}
template<typename T>
any_t_base& operator=(T t)
{
static_assert(std::is_trivially_copyable_v<T> && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
std::memcpy(data, &t, sizeof(t));
return *this;
}
template<typename T>
T any_cast()
{
static_assert(std::is_trivially_copyable_v<T> && "Type must be byte copyable");
static_assert(sizeof(T) <= SIZE && "Size must be less than or equal to internal buffer");
T t;
std::memcpy(&t, data, sizeof(T));
return t;
}
};
using any_t = any_t_base<8>;
}
#endif //BLT_ANY_H

226
include/blt/std/array.h Normal file
View File

@ -0,0 +1,226 @@
/*
* <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/>.
*/
#ifndef BLT_ARRAY_H
#define BLT_ARRAY_H
#include <type_traits>
#include <blt/std/types.h>
#include <blt/std/memory_util.h>
#include <stdexcept>
#include <iterator>
#include <memory>
#include "logging.h"
namespace blt
{
template<typename MetaExtra>
struct metadata_template_t;
template<>
struct metadata_template_t<void>
{
// size in number of elements!
blt::size_t size;
explicit metadata_template_t(blt::size_t size): size(size)
{}
};
template<typename Extra>
struct metadata_template_t
{
static_assert(std::is_trivially_copyable_v<Extra> && "Must be raw type!");
Extra extra;
// size in number of elements!
blt::size_t size;
explicit metadata_template_t(blt::size_t size): size(size)
{}
};
/**
* @tparam T type to store inside
* @tparam Extra any extra data to store. void will result in zero size increase.
*/
template<typename T = void, typename Extra = void>
class array
{
public:
using iterator = blt::ptr_iterator<T>;
using const_iterator = blt::ptr_iterator<const T>;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private:
using metadata_t = metadata_template_t<Extra>;
metadata_t metadata;
static constexpr blt::size_t ALIGNMENT = std::max(sizeof(metadata_t), alignof(T));
inline T* _data()
{
return reinterpret_cast<T*>(reinterpret_cast<blt::u8*>(this) + ALIGNMENT);
}
/**
* constructs an array out of a block of memory of size bytes
* @param size number of bytes available in the memory allocated to this array.
*/
explicit array(blt::size_t size): metadata((size - sizeof(metadata)) / sizeof(T))
{}
public:
inline static array* construct(void* ptr, blt::size_t size)
{
auto aligned_ptr = std::align(alignof(array), sizeof(array), ptr, size);
return new(aligned_ptr) array<T>{size};
}
array(const array&) = delete;
array(array&&) = delete;
array& operator=(const array&) = delete;
array& operator=(array&&) = delete;
inline T& operator[](blt::size_t index)
{
return _data()[index];
}
inline const T& operator[](blt::size_t index) const
{
return _data()[index];
}
[[nodiscard]] inline T& at(blt::size_t index)
{
if (index > size())
throw std::runtime_error("Index " + std::to_string(index) += " is outside the bounds of this array!");
return _data()[index];
}
[[nodiscard]] inline const T& at(blt::size_t index) const
{
if (index > size())
throw std::runtime_error("Index " + std::to_string(index) += " is outside the bounds of this array!");
return _data()[index];
}
[[nodiscard]] inline T* data()
{
return _data();
}
[[nodiscard]] inline T* data() const
{
return _data();
}
[[nodiscard]] inline blt::size_t size() const
{
return metadata.size;
}
[[nodiscard]] inline blt::size_t size_bytes() const
{
return (metadata.size * sizeof(T)) + sizeof(metadata);
}
constexpr inline T* operator*()
{
return data();
}
constexpr inline T& front()
{
return *_data();
}
constexpr inline const T& front() const
{
return *data();
}
constexpr inline T& back()
{
return data()[size() - 1];
}
constexpr inline const T& back() const
{
return data()[size() - 1];
}
constexpr inline iterator begin() const noexcept
{
return data();
}
constexpr inline iterator end() const noexcept
{
return data() + size();
}
constexpr inline const_iterator cbegin() const noexcept
{
return data();
}
constexpr inline const_iterator cend() const noexcept
{
return data() + size();
}
constexpr inline reverse_iterator rbegin() const noexcept
{
return reverse_iterator{end()};
}
constexpr inline reverse_iterator rend() const 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()};
}
constexpr inline metadata_t& get_metadata()
{
return metadata;
}
constexpr inline const metadata_t& get_metadata() const
{
return metadata;
}
~array() = default;
};
}
#endif //BLT_ARRAY_H

0
include/blt/std/binary_tree.h Executable file → Normal file
View File

29
include/blt/std/error.h Normal file
View File

@ -0,0 +1,29 @@
#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_ERROR_H
#define BLT_ERROR_H
namespace blt::error
{
void print_socket_error();
}
#endif //BLT_ERROR_H

9
include/blt/std/format.h Executable file → Normal file
View File

@ -14,6 +14,7 @@
#include <algorithm> #include <algorithm>
#include <string_view> #include <string_view>
#include "memory.h" #include "memory.h"
#include "vector.h"
#include <variant> #include <variant>
namespace blt::string namespace blt::string
@ -38,20 +39,22 @@ namespace blt::string
return ret; return ret;
} }
// negative decimal places will not round.
template<int decimal_places = -1>
static inline std::string fromBytes(unsigned long bytes) static inline std::string fromBytes(unsigned long bytes)
{ {
if (bytes > 1073741824) if (bytes > 1073741824)
{ {
// gigabyte // gigabyte
return std::to_string(round_up<3>((double) bytes / 1024.0 / 1024.0 / 1024.0)) += "gb"; return std::to_string(round_up<decimal_places>((double) bytes / 1024.0 / 1024.0 / 1024.0)) += "gb";
} else if (bytes > 1048576) } else if (bytes > 1048576)
{ {
// megabyte // megabyte
return std::to_string(round_up<3>((double) bytes / 1024.0 / 1024.0)) += "mb"; return std::to_string(round_up<decimal_places>((double) bytes / 1024.0 / 1024.0)) += "mb";
} else if (bytes > 1024) } else if (bytes > 1024)
{ {
// kilobyte // kilobyte
return std::to_string(round_up<3>((double) bytes / 1024.0)) += "kb"; return std::to_string(round_up<decimal_places>((double) bytes / 1024.0)) += "kb";
} else } else
{ {
return std::to_string(bytes) += "b"; return std::to_string(bytes) += "b";

40
include/blt/std/hashmap.h Executable file → Normal file
View File

@ -9,7 +9,7 @@
namespace blt namespace blt
{ {
// template<typename K, typename V, typename Hash = std::hash<K>, typename Eq = std::equal_to<K>> // template<typename K, typename V, typename Hash = std::hash<K>, typename Eq = std::equal_to<K>>
// class hashmap // class hashmap
// { // {
@ -18,7 +18,7 @@ namespace blt
// public: // public:
// //
// }; // };
} }
#ifndef HASHMAP #ifndef HASHMAP
@ -27,32 +27,36 @@ namespace blt
#include <parallel_hashmap/phmap.h> #include <parallel_hashmap/phmap.h>
#include <parallel_hashmap/phmap_fwd_decl.h> #include <parallel_hashmap/phmap_fwd_decl.h>
template<class K, class V, namespace blt
class Hash = phmap::priv::hash_default_hash<K>, {
class Eq = phmap::priv::hash_default_eq<K>, template<class K, class V,
class Alloc = phmap::priv::Allocator<phmap::priv::Pair<const K, V>>> class Hash = phmap::priv::hash_default_hash <K>,
using HASHMAP = phmap::flat_hash_map<K, V, Hash, Eq, Alloc>; class Eq = phmap::priv::hash_default_eq <K>,
template<class T, class Alloc = phmap::priv::Allocator <phmap::priv::Pair<const K, V>>>
class Hash = phmap::priv::hash_default_hash<T>, using hashmap_t = phmap::flat_hash_map<K, V, Hash, Eq, Alloc>;
class Eq = phmap::priv::hash_default_eq<T>, template<class T,
class Alloc = phmap::priv::Allocator<T>> class Hash = phmap::priv::hash_default_hash <T>,
using HASHSET = phmap::flat_hash_set<T, Hash, Eq, Alloc>; class Eq = phmap::priv::hash_default_eq <T>,
class Alloc = phmap::priv::Allocator <T>>
using hashset_t = phmap::flat_hash_set<T, Hash, Eq, Alloc>;
}
#else #else
#include <unordered_map> #include <unordered_map>
#include <unordered_set> #include <unordered_set>
namespace blt {
template<typename K, typename V, template<typename K, typename V,
typename Hash = std::hash<K>, typename Hash = std::hash<K>,
typename Eq = std::equal_to<K>, typename Eq = std::equal_to<K>,
typename Alloc = std::allocator<std::pair<const K, V>>> typename Alloc = std::allocator<std::pair<const K, V>>>
using HASHMAP = std::unordered_map<K, V, Hash, Eq, Alloc>; using hashmap_t = std::unordered_map<K, V, Hash, Eq, Alloc>;
template<typename K, template<typename K,
typename Hash = std::hash<K>, typename Hash = std::hash<K>,
typename Eq = std::equal_to<K>, typename Eq = std::equal_to<K>,
typename Alloc = std::allocator<K>> typename Alloc = std::allocator<K>>
using HASHSET = std::unordered_set<K, Hash, Eq, Alloc>; using hashset_t = std::unordered_set<K, Hash, Eq, Alloc>;
}
#endif #endif
#endif #endif

43
include/blt/std/logging.h Executable file → Normal file
View File

@ -318,18 +318,24 @@ namespace blt::logging {
delete(output); delete(output);
} }
}; };
#define BLT_NOW() auto t = std::time(nullptr); auto now = std::localtime(&t) #ifdef WIN32
#define BLT_ISO_YEAR(S) auto S = std::to_string(now->tm_year + 1900); \ #define BLT_NOW() auto t = std::time(nullptr); tm now{}; localtime_s(&now, &t)
#else
#define BLT_NOW() auto t = std::time(nullptr); auto now_ptr = std::localtime(&t); auto& now = *now_ptr
#endif
//#define BLT_NOW() auto t = std::time(nullptr); tm now; localtime_s(&now, &t); //auto now = std::localtime(&t)
#define BLT_ISO_YEAR(S) auto S = std::to_string(now.tm_year + 1900); \
S += '-'; \ S += '-'; \
S += ensureHasDigits(now->tm_mon+1, 2); \ S += ensureHasDigits(now.tm_mon+1, 2); \
S += '-'; \ S += '-'; \
S += ensureHasDigits(now->tm_mday, 2); S += ensureHasDigits(now.tm_mday, 2);
#define BLT_CUR_TIME(S) auto S = ensureHasDigits(now->tm_hour, 2); \ #define BLT_CUR_TIME(S) auto S = ensureHasDigits(now.tm_hour, 2); \
S += ':'; \ S += ':'; \
S += ensureHasDigits(now->tm_min, 2); \ S += ensureHasDigits(now.tm_min, 2); \
S += ':'; \ S += ':'; \
S += ensureHasDigits(now->tm_sec, 2); S += ensureHasDigits(now.tm_sec, 2);
static inline std::string ensureHasDigits(int current, int digits) { static inline std::string ensureHasDigits(int current, int digits) {
std::string asString = std::to_string(current); std::string asString = std::to_string(current);
@ -352,27 +358,27 @@ namespace blt::logging {
const std::unique_ptr<tag_map> tagMap = std::make_unique<tag_map>(tag_map{ const std::unique_ptr<tag_map> tagMap = std::make_unique<tag_map>(tag_map{
{"YEAR", [](const tag_func_param&) -> std::string { {"YEAR", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return std::to_string(now->tm_year); return std::to_string(now.tm_year);
}}, }},
{"MONTH", [](const tag_func_param&) -> std::string { {"MONTH", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return ensureHasDigits(now->tm_mon+1, 2); return ensureHasDigits(now.tm_mon+1, 2);
}}, }},
{"DAY", [](const tag_func_param&) -> std::string { {"DAY", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return ensureHasDigits(now->tm_mday, 2); return ensureHasDigits(now.tm_mday, 2);
}}, }},
{"HOUR", [](const tag_func_param&) -> std::string { {"HOUR", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return ensureHasDigits(now->tm_hour, 2); return ensureHasDigits(now.tm_hour, 2);
}}, }},
{"MINUTE", [](const tag_func_param&) -> std::string { {"MINUTE", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return ensureHasDigits(now->tm_min, 2); return ensureHasDigits(now.tm_min, 2);
}}, }},
{"SECOND", [](const tag_func_param&) -> std::string { {"SECOND", [](const tag_func_param&) -> std::string {
BLT_NOW(); BLT_NOW();
return ensureHasDigits(now->tm_sec, 2); return ensureHasDigits(now.tm_sec, 2);
}}, }},
{"MS", [](const tag_func_param&) -> std::string { {"MS", [](const tag_func_param&) -> std::string {
return std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>( return std::to_string(std::chrono::duration_cast<std::chrono::milliseconds>(
@ -674,6 +680,11 @@ namespace blt::logging {
#endif #endif
#if defined(__clang__) || defined(__llvm__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wgnu-zero-variadic-macro-arguments"
#endif
#ifdef BLT_DISABLE_LOGGING #ifdef BLT_DISABLE_LOGGING
#define BLT_LOG(format, level, ...) #define BLT_LOG(format, level, ...)
#define BLT_LOG_STREAM(level) #define BLT_LOG_STREAM(level)
@ -753,4 +764,8 @@ namespace blt::logging {
#endif #endif
#endif #endif
#if defined(__clang__) || defined(__llvm__)
#pragma clang diagnostic pop
#endif
#endif //BLT_TESTS_LOGGING2_H #endif //BLT_TESTS_LOGGING2_H

240
include/blt/std/memory.h Executable file → Normal file
View File

@ -22,64 +22,8 @@
namespace blt namespace blt
{ {
template<typename V> template<typename T, bool = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>>
struct ptr_iterator class scoped_buffer;
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = V;
using pointer = value_type*;
using reference = value_type&;
explicit ptr_iterator(V* v): _v(v)
{}
reference operator*() const
{ return *_v; }
pointer operator->()
{ return _v; }
ptr_iterator& operator++()
{
_v++;
return *this;
}
ptr_iterator& operator--()
{
_v--;
return *this;
}
ptr_iterator operator++(int)
{
auto tmp = *this;
++(*this);
return tmp;
}
ptr_iterator operator--(int)
{
auto tmp = *this;
--(*this);
return tmp;
}
friend bool operator==(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v == b._v;
}
friend bool operator!=(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v != b._v;
}
private:
V* _v;
};
/** /**
* Creates an encapsulation of a T array which will be automatically deleted when this object goes out of scope. * Creates an encapsulation of a T array which will be automatically deleted when this object goes out of scope.
@ -88,17 +32,28 @@ namespace blt
* The operator * has been overloaded to return the internal buffer. * The operator * has been overloaded to return the internal buffer.
* @tparam T type that is stored in buffer eg char * @tparam T type that is stored in buffer eg char
*/ */
template<typename T, bool = std::is_copy_constructible_v<T> || std::is_copy_assignable_v<T>> template<typename T>
class scoped_buffer class scoped_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: private:
T* buffer_ = nullptr; T* buffer_ = nullptr;
size_t size_; size_t size_;
public: public:
scoped_buffer(): buffer_(nullptr), size_(0) constexpr scoped_buffer(): buffer_(nullptr), size_(0)
{} {}
explicit scoped_buffer(size_t size): size_(size) constexpr explicit scoped_buffer(size_t size): size_(size)
{ {
if (size > 0) if (size > 0)
buffer_ = new T[size]; buffer_ = new T[size];
@ -106,7 +61,7 @@ namespace blt
buffer_ = nullptr; buffer_ = nullptr;
} }
scoped_buffer(const scoped_buffer& copy) constexpr scoped_buffer(const scoped_buffer& copy)
{ {
if (copy.size() == 0) if (copy.size() == 0)
{ {
@ -132,7 +87,7 @@ namespace blt
} }
} }
scoped_buffer& operator=(const scoped_buffer& copy) constexpr scoped_buffer& operator=(const scoped_buffer& copy)
{ {
if (&copy == this) if (&copy == this)
return *this; return *this;
@ -164,7 +119,7 @@ namespace blt
return *this; return *this;
} }
scoped_buffer(scoped_buffer&& move) noexcept constexpr scoped_buffer(scoped_buffer&& move) noexcept
{ {
delete[] buffer_; delete[] buffer_;
buffer_ = move.buffer_; buffer_ = move.buffer_;
@ -172,7 +127,7 @@ namespace blt
move.buffer_ = nullptr; move.buffer_ = nullptr;
} }
scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept constexpr scoped_buffer& operator=(scoped_buffer&& moveAssignment) noexcept
{ {
delete[] buffer_; delete[] buffer_;
buffer_ = moveAssignment.buffer_; buffer_ = moveAssignment.buffer_;
@ -182,54 +137,99 @@ namespace blt
return *this; return *this;
} }
inline T& operator[](size_t index) /**
* 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[] buffer_;
buffer_ = new T[size];
size_ = size;
}
constexpr inline T& operator[](size_t index)
{ {
return buffer_[index]; return buffer_[index];
} }
inline const T& operator[](size_t index) const constexpr inline const T& operator[](size_t index) const
{ {
return buffer_[index]; return buffer_[index];
} }
inline T* operator*() constexpr inline T* operator*()
{ {
return buffer_; return buffer_;
} }
[[nodiscard]] inline size_t size() const [[nodiscard]] constexpr inline size_t size() const
{ {
return size_; return size_;
} }
inline T*& ptr() constexpr inline T*& ptr()
{ {
return buffer_; return buffer_;
} }
inline const T* const& ptr() const constexpr inline const T* const& ptr() const
{ {
return buffer_; return buffer_;
} }
inline const T* const& data() const constexpr inline const T* const& data() const
{ {
return buffer_; return buffer_;
} }
inline T*& data() constexpr inline T*& data()
{ {
return buffer_; return buffer_;
} }
inline ptr_iterator<T> begin() constexpr iterator begin() noexcept
{ {
return ptr_iterator{buffer_}; return iterator{data()};
} }
inline ptr_iterator<T> end() constexpr iterator end() noexcept
{ {
return ptr_iterator{&buffer_[size_]}; 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()};
} }
~scoped_buffer() ~scoped_buffer()
@ -238,90 +238,6 @@ namespace blt
} }
}; };
template<typename T, size_t MAX_SIZE>
class static_vector
{
private:
T buffer_[MAX_SIZE];
size_t size_ = 0;
public:
static_vector() = default;
inline bool push_back(const T& copy)
{
if (size_ >= MAX_SIZE)
return false;
buffer_[size_++] = copy;
return true;
}
inline bool push_back(T&& move)
{
if (size_ >= MAX_SIZE)
return false;
buffer_[size_++] = std::move(move);
return true;
}
inline T& at(size_t index)
{
if (index >= MAX_SIZE)
throw std::runtime_error("Array index " + std::to_string(index) + " out of bounds! (Max size: " + std::to_string(MAX_SIZE) + ')');
}
inline T& operator[](size_t index)
{
return buffer_[index];
}
inline const T& operator[](size_t index) const
{
return buffer_[index];
}
inline void reserve(size_t size)
{
if (size > MAX_SIZE)
size = MAX_SIZE;
size_ = size;
}
[[nodiscard]] inline size_t size() const
{
return size_;
}
[[nodiscard]] inline size_t capacity() const
{
return MAX_SIZE;
}
inline T* data()
{
return buffer_;
}
inline T* operator*()
{
return buffer_;
}
inline T* data() const
{
return buffer_;
}
inline T* begin()
{
return buffer_;
}
inline T* end()
{
return &buffer_[size_];
}
};
template<typename T> template<typename T>
class scoped_buffer<T, false> : scoped_buffer<T, true> class scoped_buffer<T, false> : scoped_buffer<T, true>
{ {

View File

@ -27,11 +27,20 @@
#if defined(__clang__) || defined(__llvm__) || defined(__GNUC__) || defined(__GNUG__) #if defined(__clang__) || defined(__llvm__) || defined(__GNUC__) || defined(__GNUG__)
#include <byteswap.h> #if defined(__GNUC__) || defined(__GNUG__)
#include <byteswap.h>
#define SWAP16(val) bswap_16(val)
#define SWAP32(val) bswap_32(val)
#define SWAP64(val) bswap_64(val)
#else
#define SWAP16(val) __builtin_bswap16(val)
#define SWAP32(val) __builtin_bswap32(val)
#define SWAP64(val) __builtin_bswap64(val)
#endif
#define SWAP16(val) bswap_16(val)
#define SWAP32(val) bswap_32(val)
#define SWAP64(val) bswap_64(val)
#if __cplusplus >= 202002L #if __cplusplus >= 202002L
#include <bit> #include <bit>
@ -119,6 +128,69 @@ namespace blt::mem
std::memcpy(&r, &type, sizeof(type)); std::memcpy(&r, &type, sizeof(type));
return r; return r;
} }
}
namespace blt
{
template<typename V>
struct ptr_iterator
{
public:
using iterator_category = std::random_access_iterator_tag;
using difference_type = std::ptrdiff_t;
using value_type = V;
using pointer = value_type*;
using reference = value_type&;
explicit ptr_iterator(V* v): _v(v)
{}
reference operator*() const
{ return *_v; }
pointer operator->()
{ return _v; }
ptr_iterator& operator++()
{
_v++;
return *this;
}
ptr_iterator& operator--()
{
_v--;
return *this;
}
ptr_iterator operator++(int)
{
auto tmp = *this;
++(*this);
return tmp;
}
ptr_iterator operator--(int)
{
auto tmp = *this;
--(*this);
return tmp;
}
friend bool operator==(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v == b._v;
}
friend bool operator!=(const ptr_iterator& a, const ptr_iterator& b)
{
return a._v != b._v;
}
private:
V* _v;
};
} }
#endif //BLT_MEMORY_UTIL_H #endif //BLT_MEMORY_UTIL_H

0
include/blt/std/queue.h Executable file → Normal file
View File

0
include/blt/std/random.h Executable file → Normal file
View File

View File

@ -17,69 +17,122 @@
namespace blt 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>
{
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))
{}
iterator& operator++()
{
++index;
++current;
return *this;
}
bool operator==(iterator other) const
{
return current == other.current;
}
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};
};
};
template<typename TYPE_ITR>
class iterator<TYPE_ITR, true>
{
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))
{}
iterator& operator++()
{
++index;
++current;
return *this;
}
bool operator==(iterator other) const
{
return current == other.current;
}
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};
};
};
}
template<typename TYPE_ITR> template<typename TYPE_ITR>
class enumerator class enumerator
{ {
public: public:
class iterator
{
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;
private:
blt::size_t index = 0;
TYPE_ITR current;
public:
explicit iterator(TYPE_ITR current): current(std::move(current))
{}
iterator& operator++()
{
++index;
++current;
return *this;
}
bool operator==(iterator other) const
{
return current == other.current;
}
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};
};
};
explicit enumerator(TYPE_ITR begin, TYPE_ITR end): begin_(std::move(begin)), end_(std::move(end)) explicit enumerator(TYPE_ITR begin, TYPE_ITR end): begin_(std::move(begin)), end_(std::move(end))
{} {}
iterator begin() itr::iterator<TYPE_ITR> begin()
{ {
return begin_; return begin_;
} }
iterator end() itr::iterator<TYPE_ITR> end()
{ {
return end_; return end_;
} }
private: private:
iterator begin_; itr::iterator<TYPE_ITR> begin_;
iterator end_; itr::iterator<TYPE_ITR> end_;
}; };
template<typename T> template<typename T>
@ -286,71 +339,76 @@ namespace blt
using const_reverse_iterator = std::reverse_iterator<const_iterator>; using const_reverse_iterator = std::reverse_iterator<const_iterator>;
private: private:
size_type size_; size_type size_;
pointer* data_; pointer data_;
public: public:
constexpr span() noexcept: size_(0), data_(nullptr) constexpr span() noexcept: size_(0), data_(nullptr)
{} {}
template<class It, std::enable_if_t<extent != dynamic_extent, bool> = true> constexpr span(T* data, size_type count): size_(count), data_(data)
{}
template<class It, std::size_t SIZE, typename std::enable_if_t<extent != dynamic_extent && SIZE == extent, bool> = true>
constexpr explicit span(It first, size_type count): size_(count), data_(&*first) constexpr explicit span(It first, size_type count): size_(count), data_(&*first)
{} {}
template<class It, std::enable_if_t<extent == dynamic_extent, bool> = true> template<class It, std::size_t SIZE, typename std::enable_if_t<extent == dynamic_extent && SIZE == extent, bool> = true>
constexpr span(It first, size_type count): size_(count), data_(&*first) constexpr span(It first, size_type count): size_(count), data_(&*first)
{} {}
template<class It, class End, std::enable_if_t<extent != dynamic_extent, bool> = true> template<class It, class End, std::size_t SIZE, typename std::enable_if_t<extent != dynamic_extent && SIZE == extent, bool> = true>
constexpr explicit span(It first, End last): size_(&*last - &*first), data_(&*first) constexpr explicit span(It first, End last): size_(&*last - &*first), data_(&*first)
{} {}
template<class It, class End, std::enable_if_t<extent == dynamic_extent, bool> = true> template<class It, class End, std::size_t SIZE, typename std::enable_if_t<extent == dynamic_extent && SIZE == extent, bool> = true>
constexpr span(It first, End last): size_(&*last - &*first), data_(&*first) constexpr span(It first, End last): size_(&*last - &*first), data_(&*first)
{} {}
template<std::size_t N, std::enable_if_t<(N == dynamic_extent || N == extent) && 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::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true> 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}
{} {}
template<class U, std::size_t N, std::enable_if_t<(N == dynamic_extent || N == extent) && 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::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true> 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()}
{} {}
template<class U, std::size_t N, std::enable_if_t<(N == dynamic_extent || N == extent) && 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::is_convertible_v<std::remove_pointer_t<decltype(
std::data(std::declval<T(&)[N]>()))>(*)[], T(*)[]>), bool> = true> 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()}
{} {}
template<class R, class RCV = std::remove_cv_t<std::remove_reference_t<R>>, std::enable_if_t< 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> && 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> std::is_convertible_v<std::remove_pointer_t<decltype(std::data(std::declval<R>()))>(*)[], T(*)[]>, bool> = true>
explicit constexpr span(R&& range): size_(std::size(range)), data_(std::data(range)) explicit constexpr span(R&& range): size_(std::size(range)), data_(std::data(range))
{} {}
template<class R, class RCV = std::remove_cv_t<std::remove_reference_t<R>>, std::enable_if_t< 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> && 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> 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))
{} {}
template<std::enable_if_t<extent != dynamic_extent && std::is_const_v<element_type>, bool> = true> 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())
{} {}
template<std::enable_if_t<extent == dynamic_extent && std::is_const_v<element_type>, bool> = true> 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())
{} {}
template<class U, std::size_t N, std::enable_if_t< 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> extent != dynamic_extent && N == dynamic_extent && std::is_convertible_v<U(*)[], T(*)[]>, bool> = true>
explicit constexpr span(const span<U, N>& source) noexcept: size_{source.size()}, data_{source.data()} explicit constexpr span(const span<U, N>& source) noexcept: size_{source.size()}, data_{source.data()}
{} {}
template<class U, std::size_t N, std::enable_if_t< 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> !(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()}
{} {}

50
include/blt/std/simd.h Normal file
View File

@ -0,0 +1,50 @@
/*
* <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/>.
*/
#ifndef BLT_SIMD_H
#define BLT_SIMD_H
#if defined(__AVX__) || defined(__AVX2__)
#include <immintrin.h>
#else
//#warning AVX is not available.
#endif
#include <xmmintrin.h>
namespace blt
{
class simd
{
public:
private:
#if defined(__AVX__) || defined(__AVX2__)
__m256d data;
#else
#endif
public:
};
}
#endif // BLT_SIMD_H

0
include/blt/std/string.h Executable file → Normal file
View File

4
include/blt/std/system.h Executable file → Normal file
View File

@ -144,6 +144,10 @@ namespace blt::system
// number of dirty pages (0) // number of dirty pages (0)
std::uint64_t dt; std::uint64_t dt;
}; };
#ifdef _MSC_VER
using suseconds_t = std::size_t;
#endif
struct timeval { struct timeval {
time_t tv_sec; /* Seconds */ time_t tv_sec; /* Seconds */

View File

@ -36,23 +36,24 @@ namespace blt
/** /**
* @tparam queue should we use a queue or execute the same function over and over? * @tparam queue should we use a queue or execute the same function over and over?
*/ */
template<bool queue = false> template<bool queue = false, typename... Args>
class thread_pool class thread_pool
{ {
private: private:
typedef std::function<void()> thread_function; using thread_function = std::function<void(Args...)>;
volatile std::atomic_bool should_stop = false; volatile std::atomic_bool should_stop = false;
volatile std::atomic_uint64_t stopped = 0; volatile std::atomic_uint64_t stopped = 0;
std::uint64_t number_of_threads = 0; std::uint64_t number_of_threads = 0;
std::vector<std::thread*> threads; std::vector<std::thread*> threads;
std::variant<std::queue<thread_function>, thread_function> func_queue; std::variant<std::queue<thread_function>, thread_function> func_queue;
std::mutex queue_mutex; std::mutex queue_mutex;
public: // only used when a queue
explicit thread_pool(std::uint64_t number_of_threads = 8, std::optional<thread_function> default_function = {}) volatile std::atomic_uint64_t tasks = 0;
volatile std::atomic_uint64_t completed_tasks = 0;
bool func_loaded = false;
void init()
{ {
if (default_function.has_value())
func_queue = default_function.value();
this->number_of_threads = number_of_threads;
for (std::uint64_t i = 0; i < number_of_threads; i++) for (std::uint64_t i = 0; i < number_of_threads; i++)
{ {
threads.push_back(new std::thread([this]() { threads.push_back(new std::thread([this]() {
@ -74,16 +75,19 @@ namespace blt
func_q.pop(); func_q.pop();
lock.unlock(); lock.unlock();
func(); func();
completed_tasks++;
} else } else
{ {
if (!func_loaded)
{ {
std::scoped_lock lock(queue_mutex); std::scoped_lock lock(queue_mutex);
if (std::holds_alternative<std::queue<thread_function>>(func_queue)) if (std::holds_alternative<std::queue<thread_function>>(func_queue))
{ {
std::this_thread::sleep_for(std::chrono::milliseconds(16)); std::this_thread::sleep_for(std::chrono::milliseconds(16));
BLT_WARN("Running non queue variant with a queue inside!"); //BLT_WARN("Running non queue variant with a queue inside!");
break; continue;
} }
func_loaded = true;
} }
auto& func = std::get<thread_function>(func_queue); auto& func = std::get<thread_function>(func_queue);
func(); func();
@ -94,6 +98,25 @@ namespace blt
} }
} }
void cleanup()
{
for (auto* t : threads)
{
if (t->joinable())
t->join();
delete t;
}
}
public:
explicit thread_pool(std::uint64_t number_of_threads = 8, std::optional<thread_function> default_function = {})
{
if (default_function.has_value())
func_queue = default_function.value();
this->number_of_threads = number_of_threads;
init();
}
inline void execute(const thread_function& func) inline void execute(const thread_function& func)
{ {
std::scoped_lock lock(queue_mutex); std::scoped_lock lock(queue_mutex);
@ -101,13 +124,20 @@ namespace blt
{ {
auto& v = std::get<std::queue<thread_function>>(func_queue); auto& v = std::get<std::queue<thread_function>>(func_queue);
v.push(func); v.push(func);
tasks++;
} else } else
{ {
func_queue = func; func_queue = func;
} }
} }
[[nodiscard]] inline bool complete() const { [[nodiscard]] inline bool tasks_complete() const
{
return completed_tasks == tasks;
}
[[nodiscard]] inline bool complete() const
{
return stopped == number_of_threads; return stopped == number_of_threads;
} }
@ -116,15 +146,24 @@ namespace blt
should_stop = true; should_stop = true;
} }
inline void reset_tasks()
{
tasks = 0;
completed_tasks = 0;
}
inline void reset()
{
stop();
cleanup();
stopped = 0;
init();
}
~thread_pool() ~thread_pool()
{ {
should_stop = true; should_stop = true;
for (auto* t : threads) cleanup();
{
if (t->joinable())
t->join();
delete t;
}
} }
}; };
} }

44
include/blt/std/time.h Executable file → Normal file
View File

@ -13,6 +13,11 @@
namespace blt::system namespace blt::system
{ {
#ifdef WIN32
#define BLT_TIME_FUNC(name) auto t = std::time(nullptr); tm name{}; localtime_s(&name, &t)
#else
#define BLT_TIME_FUNC(name) auto t = std::time(nullptr); auto ptr_##name = std::localtime(&t); auto& name = *ptr_##name
#endif
static inline std::string ensureHasDigits(int current, int digits) static inline std::string ensureHasDigits(int current, int digits)
{ {
@ -85,20 +90,19 @@ namespace blt::system
*/ */
static inline std::string getTimeString() static inline std::string getTimeString()
{ {
auto t = std::time(nullptr); BLT_TIME_FUNC(now);
auto now = std::localtime(&t);
std::stringstream timeString; std::stringstream timeString;
timeString << (1900 + now->tm_year); timeString << (1900 + now.tm_year);
timeString << "-"; timeString << "-";
timeString << (1 + now->tm_mon); timeString << (1 + now.tm_mon);
timeString << "-"; timeString << "-";
timeString << now->tm_mday; timeString << now.tm_mday;
timeString << " "; timeString << " ";
timeString << now->tm_hour; timeString << now.tm_hour;
timeString << ":"; timeString << ":";
timeString << now->tm_min; timeString << now.tm_min;
timeString << ":"; timeString << ":";
timeString << now->tm_sec; timeString << now.tm_sec;
return timeString.str(); return timeString.str();
} }
@ -109,14 +113,13 @@ namespace blt::system
*/ */
static inline std::string getTimeStringLog() static inline std::string getTimeStringLog()
{ {
auto t = std::time(nullptr); BLT_TIME_FUNC(now);
auto now = std::localtime(&t);
std::string timeString = "["; std::string timeString = "[";
timeString += ensureHasDigits(now->tm_hour, 2); timeString += ensureHasDigits(now.tm_hour, 2);
timeString += ":"; timeString += ":";
timeString += ensureHasDigits(now->tm_min, 2); timeString += ensureHasDigits(now.tm_min, 2);
timeString += ":"; timeString += ":";
timeString += ensureHasDigits(now->tm_sec, 2); timeString += ensureHasDigits(now.tm_sec, 2);
timeString += "] "; timeString += "] ";
return timeString; return timeString;
} }
@ -126,20 +129,19 @@ namespace blt::system
*/ */
static inline std::string getTimeStringFS() static inline std::string getTimeStringFS()
{ {
auto t = std::time(nullptr); BLT_TIME_FUNC(now);
auto now = std::localtime(&t);
std::stringstream timeString; std::stringstream timeString;
timeString << (1900 + now->tm_year); timeString << (1900 + now.tm_year);
timeString << "-"; timeString << "-";
timeString << (1 + now->tm_mon); timeString << (1 + now.tm_mon);
timeString << "-"; timeString << "-";
timeString << now->tm_mday; timeString << now.tm_mday;
timeString << "_"; timeString << "_";
timeString << now->tm_hour; timeString << now.tm_hour;
timeString << "-"; timeString << "-";
timeString << now->tm_min; timeString << now.tm_min;
timeString << "-"; timeString << "-";
timeString << now->tm_sec; timeString << now.tm_sec;
return timeString.str(); return timeString.str();
} }
} }

View File

@ -20,6 +20,7 @@
#define BLT_TYPES_H #define BLT_TYPES_H
#include <cstdint> #include <cstdint>
#include <cstddef>
#ifndef NO_BLT_NAMESPACE_ON_TYPES #ifndef NO_BLT_NAMESPACE_ON_TYPES
namespace blt namespace blt

0
include/blt/std/uuid.h Executable file → Normal file
View File

416
include/blt/std/vector.h Normal file
View File

@ -0,0 +1,416 @@
/*
* <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/>.
*/
#ifndef BLT_VECTOR_H
#define BLT_VECTOR_H
#include <iterator>
#include <blt/std/memory_util.h>
#include <blt/std/allocator.h>
#include <blt/compatibility.h>
#include "ranges.h"
#include <stdexcept>
namespace blt
{
template<typename T, size_t MAX_SIZE>
class static_vector
{
private:
T buffer_[MAX_SIZE];
size_t size_ = 0;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
public:
constexpr static_vector() = default;
constexpr inline bool push_back(const T& copy)
{
if (size_ >= MAX_SIZE)
return false;
buffer_[size_++] = copy;
return true;
}
constexpr inline bool push_back(T&& move)
{
if (size_ >= MAX_SIZE)
return false;
buffer_[size_++] = std::move(move);
return true;
}
constexpr inline T& at(size_t index)
{
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 T& operator[](size_t index)
{
return buffer_[index];
}
constexpr inline const T& operator[](size_t index) const
{
return buffer_[index];
}
constexpr inline void reserve(size_t size)
{
if (size > MAX_SIZE)
size = MAX_SIZE;
size_ = size;
}
[[nodiscard]] constexpr inline size_t size() const
{
return size_;
}
[[nodiscard]] constexpr inline size_t capacity() const
{
return MAX_SIZE;
}
constexpr inline T* data()
{
return buffer_;
}
constexpr inline T* operator*()
{
return buffer_;
}
constexpr inline const T* data() const
{
return buffer_;
}
constexpr inline iterator begin() noexcept
{
return data();
}
constexpr inline iterator end() noexcept
{
return data() + size();
}
constexpr inline const_iterator cbegin() const noexcept
{
return data();
}
constexpr inline const_iterator cend() const noexcept
{
return data() + size();
}
constexpr inline reverse_iterator rbegin() const noexcept
{
return reverse_iterator{end()};
}
constexpr inline reverse_iterator rend() const 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()};
}
};
template<typename T, typename ALLOC = std::allocator<T>>
class vector
{
private:
ALLOC allocator;
T* buffer_;
size_t capacity_ = 0;
size_t size_ = 0;
using value_type = T;
using allocator_type = ALLOC;
using size_type = size_t;
using difference_type = std::ptrdiff_t;
using reference = value_type&;
using const_reference = const value_type&;
using pointer = value_type*;
using const_pointer = const pointer;
using iterator = T*;
using const_iterator = const T*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
constexpr inline void expand(size_t new_size = 0)
{
if (new_size == 0)
new_size = blt::mem::next_byte_allocation(capacity_);
auto new_buffer = allocator.allocate(new_size);
for (size_t i = 0; i < size_; i++)
new_buffer[i] = buffer_[i];
allocator.deallocate(buffer_, capacity_);
buffer_ = new_buffer;
capacity_ = new_size;
}
public:
constexpr vector(): capacity_(16)
{
buffer_ = allocator.allocate(capacity_);
}
constexpr explicit vector(size_t capacity): capacity_(capacity)
{
buffer_ = allocator.allocate(capacity_);
}
template<typename G, std::enable_if_t<std::is_convertible_v<G, T>, bool> = true>
constexpr vector(std::initializer_list<G>&& list): capacity_(list.size()), size_(list.size())
{
buffer_ = allocator.allocate(capacity_);
for (auto e : blt::enumerate(list))
buffer_[e.first] = e.second;
}
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 vector(const G& copy): size_(copy.size()), capacity_(copy.capacity())
{
buffer_ = allocator.allocate(capacity_);
for (auto e : blt::enumerate(copy))
buffer_[e.first] = e.second;
}
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 vector(G&& move): buffer_(move.buffer_), capacity_(move.capacity()), size_(move.size())
{
move.buffer_ = nullptr;
}
BLT_CPP20_CONSTEXPR ~vector()
{
allocator.deallocate(buffer_, capacity_);
}
constexpr inline void push_back(const T& copy)
{
if (size_ >= capacity_)
expand();
buffer_[size_++] = copy;
}
constexpr inline void push_back(T&& move)
{
if (size_ >= capacity_)
expand();
buffer_[size_++] = std::move(move);
}
template<typename... Args>
constexpr inline void emplace_back(Args&& ... args)
{
if (size_ >= capacity_)
expand();
new(&buffer_[size_++]) T(std::forward<Args>(args)...);
}
constexpr inline T& at(size_t index)
{
if (index >= capacity_)
throw std::runtime_error(
"Array index " + std::to_string(index) + " out of bounds! (Max size: " + std::to_string(capacity_) + ')');
return buffer_[index];
}
constexpr inline const T& at(size_t index) const
{
if (index >= capacity_)
throw std::runtime_error(
"Array index " + std::to_string(index) + " out of bounds! (Max size: " + std::to_string(capacity_) + ')');
return buffer_[index];
}
constexpr inline T& operator[](size_t index)
{
return buffer_[index];
}
constexpr inline const T& operator[](size_t index) const
{
return buffer_[index];
}
constexpr inline void reserve(size_t size)
{
expand(size);
}
[[nodiscard]] constexpr inline size_t size() const
{
return size_;
}
[[nodiscard]] constexpr inline size_t capacity() const
{
return capacity_;
}
constexpr inline reference front()
{
return *buffer_;
}
constexpr inline const_reference front() const
{
return *buffer_;
}
constexpr inline reference back()
{
return buffer_[size_ - 1];
}
constexpr inline const_reference back() const
{
return buffer_[size_ - 1];
}
constexpr inline T* data()
{
return buffer_;
}
constexpr inline T* operator*()
{
return buffer_;
}
constexpr inline T* data() const
{
return buffer_;
}
[[nodiscard]] constexpr inline bool empty() const
{
return size_ == 0;
}
template<typename G, std::enable_if_t<std::is_convertible_v<G, T>, bool> = true>
constexpr iterator insert(const_iterator pos, G&& ref)
{
difference_type loc = pos - buffer_;
if (size_ + 1 >= capacity_)
expand();
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)
{
difference_type 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)
{
difference_type first_pos = first - buffer_;
difference_type last_pos = last - buffer_;
difference_type 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;
}
constexpr inline iterator begin() const noexcept
{
return data();
}
constexpr inline iterator end() const noexcept
{
return data() + size();
}
constexpr inline const_iterator cbegin() const noexcept
{
return data();
}
constexpr inline const_iterator cend() const noexcept
{
return data() + size();
}
constexpr inline reverse_iterator rbegin() const noexcept
{
return reverse_iterator{end()};
}
constexpr inline reverse_iterator rend() const 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()};
}
};
}
#endif //BLT_VECTOR_H

5736
include/blt/unicode_emoji.h Normal file

File diff suppressed because it is too large Load Diff

0
include/blt/window/window.h Executable file → Normal file
View File

@ -1 +1 @@
Subproject commit 65775fa09fecaa65d0b0022ab6bf091c0e509445 Subproject commit 7ef2e733416953b222851f9a360d7fc72d068ee5

6
py_commit_helper.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
git add *
git commit
git remote | xargs -L1 git push --all
#git push -u github main
#git push -u tpgc main

0
src/blt/fs/filesystem.cpp Executable file → Normal file
View File

0
src/blt/fs/loader.cpp Executable file → Normal file
View File

0
src/blt/fs/nbt.cpp Executable file → Normal file
View File

0
src/blt/fs/nbt_block.cpp Executable file → Normal file
View File

18
src/blt/math/math.cpp Normal file
View File

@ -0,0 +1,18 @@
/*
* <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/math/fixed_point.h>

8
src/blt/parse/argparse.cpp Executable file → Normal file
View File

@ -106,15 +106,15 @@ namespace blt
std::string to_string(const arg_data_internal_t& v) std::string to_string(const arg_data_internal_t& v)
{ {
return std::visit(blt::lambda_visitor{ return std::visit(blt::lambda_visitor{
[&](const std::string& str) { [](const std::string& str) {
return str; return str;
}, },
[&](bool b) { [](bool b) {
return std::string(b ? "True" : "False"); return std::string(b ? "True" : "False");
}, },
[&](int32_t i) { [](int32_t i) {
return std::to_string(i); return std::to_string(i);
} },
}, v); }, v);
} }

View File

@ -246,7 +246,7 @@ namespace blt::parse
} else } else
{ {
BLT_TRACE("Using cached data; %d; map size: %d", loc->second, vertex_data.size()); BLT_TRACE("Using cached data; %d; map size: %d", loc->second, vertex_data.size());
const auto& d = vertex_data[loc->second]; //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(), 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()); d.uv.x(), d.uv.y(), d.normal.x(), d.normal.y(), d.normal.z());
arr[pair.first] = loc->second; arr[pair.first] = loc->second;

0
src/blt/profiling/profiler.cpp Executable file → Normal file
View File

View File

@ -210,8 +210,8 @@ namespace blt
* profiler V1 partial backwards compat * profiler V1 partial backwards compat
* ---------------------------- * ----------------------------
*/ */
HASHMAP<std::string, HASHMAP<std::string, interval_t*>> profiles; hashmap_t<std::string, hashmap_t<std::string, interval_t*>> profiles;
void _internal::startInterval(const std::string& profile_name, const std::string& interval_name) void _internal::startInterval(const std::string& profile_name, const std::string& interval_name)
{ {

View File

@ -30,7 +30,8 @@
#endif #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 paths = blt::string::split(path, "/");
auto final = paths[paths.size()-1]; auto final = paths[paths.size()-1];
@ -38,6 +39,7 @@ namespace blt {
return paths[paths.size()-2]; return paths[paths.size()-2];
return final; return final;
} }
#endif
void b_throw(const char* what, const char* path, int line) void b_throw(const char* what, const char* path, int line)
{ {
@ -49,6 +51,10 @@ namespace blt {
printStacktrace(messages, size, path, line); printStacktrace(messages, size, path, line);
BLT_FREE_STACK_TRACE(); BLT_FREE_STACK_TRACE();
#else
(void) what;
(void) path;
(void) line;
#endif #endif
} }
@ -66,6 +72,10 @@ namespace blt {
BLT_FREE_STACK_TRACE(); BLT_FREE_STACK_TRACE();
#endif #endif
(void) expression;
(void) msg;
(void) path;
(void) line;
} }
void printStacktrace(char** messages, int size, const char* path, int line) void printStacktrace(char** messages, int size, const char* path, int line)
@ -106,7 +116,12 @@ namespace blt {
BLT_ERROR(buffer); BLT_ERROR(buffer);
} }
#else
(void) size;
(void) path;
(void) line;
#endif #endif
} }

82
src/blt/std/error.cpp Normal file
View File

@ -0,0 +1,82 @@
/*
* 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/error.h>
#include <blt/std/logging.h>
namespace blt::error
{
void print_socket_error()
{
switch (errno)
{
case EINVAL:
BLT_WARN("Invalid argument");
break;
case EACCES:
BLT_WARN("Permission denied");
break;
case EPERM:
BLT_WARN("Operation not permitted");
break;
case EADDRINUSE:
BLT_WARN("Address already in use");
break;
case EADDRNOTAVAIL:
BLT_WARN("Cannot assign requested address");
break;
case EAFNOSUPPORT:
BLT_WARN("Address family not supported by protocol");
break;
case EAGAIN:
BLT_WARN("Try again");
break;
case EALREADY:
BLT_WARN("Operation already in progress");
break;
case EBADF:
BLT_WARN("Bad file number");
break;
case ECONNREFUSED:
BLT_WARN("Connection refused");
break;
case EFAULT:
BLT_WARN("Bad address");
break;
case EINPROGRESS:
BLT_WARN("Operation now in progress");
break;
case EINTR:
BLT_WARN("Interrupted system call");
break;
case EISCONN:
BLT_WARN("Transport endpoint is already connected");
break;
case ENETUNREACH:
BLT_WARN("Network is unreachable");
break;
case ENOTSOCK:
BLT_WARN("Socket operation on non-socket");
break;
case EPROTOTYPE:
BLT_WARN("Protocol wrong type for socket");
break;
case ETIMEDOUT:
BLT_WARN("Connection timed out");
break;
}
}
}

0
src/blt/std/format.cpp Executable file → Normal file
View File

0
src/blt/std/logging.cpp Executable file → Normal file
View File

26
src/blt/std/simd.cpp Normal file
View File

@ -0,0 +1,26 @@
/*
* <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/simd.h>
#include <blt/std/logging.h>
namespace blt
{
}

0
src/blt/std/string.cpp Executable file → Normal file
View File

9
src/blt/std/system.cpp Executable file → Normal file
View File

@ -6,10 +6,15 @@
#include <blt/std/system.h> #include <blt/std/system.h>
#include <blt/std/logging.h> #include <blt/std/logging.h>
#ifndef _MSC_VER
#include <sys/time.h> /* for struct timeval */ #include <sys/time.h> /* for struct timeval */
#include <climits> /* for CLK_TCK */
#include <sys/resource.h> #include <sys/resource.h>
#else
#include <windows.h>
#define RUSAGE_SELF 1
#endif
#include <climits> /* for CLK_TCK */
#include <cstring> #include <cstring>
#ifndef WIN32 #ifndef WIN32

0
src/blt/window/window.cpp Executable file → Normal file
View File

0
tests/clean.sh Executable file → Normal file
View File

View File

@ -35,6 +35,10 @@ namespace blt::test
{ {
} }
void vector_run();
void allocator();
void fixed_point();
} }
#endif //BLT_BLT_TESTS_H #endif //BLT_BLT_TESTS_H

View File

@ -0,0 +1,26 @@
/*
* <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_tests.h>
namespace blt::test
{
void allocator()
{
}
}

0
tests/src/binary_trees.h Executable file → Normal file
View File

View File

@ -0,0 +1,79 @@
/*
* <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_tests.h>
#include <blt/std/vector.h>
#include <blt/std/logging.h>
#include "blt/std/assert.h"
namespace blt::test
{
template<typename T>
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");
}
void vector_run()
{
blt::vector<int> vec;
vec.push_back(10);
vec.push_back(20);
vec.push_back(30);
vec.push_back(40);
vec.push_back(50);
vec.push_back(60);
vec.push_back(70);
vec.push_back(80);
vec.push_back(90);
print(vec);
BLT_ASSERT(vec.size() == 9 && "Failed at push_back");
vec.insert(vec.cbegin() + 2, 25);
BLT_ASSERT(vec.size() == 10 && "Failed at insert single");
print(vec);
for (int i = 0; i < 128; i++)
vec.insert(vec.begin() + 2, i);
BLT_ASSERT(vec.size() == 138 && "Failed at insert 128");
print(vec);
vec.erase(vec.begin() + 3, vec.begin() + 8);
BLT_ASSERT(vec.size() == 133 && "Failed at erase range (non end)");
print(vec);
vec.erase(vec.begin() + 5);
print(vec);
BLT_ASSERT(vec.size() == 132 && "Failed at erase single");
vec.erase(vec.begin() + 10, vec.end());
print(vec);
BLT_ASSERT(vec.size() == 10 && "Failed at erase range (end)");
}
}

0
tests/src/hashmap_tests.h Executable file → Normal file
View File

0
tests/src/logging.h Executable file → Normal file
View File

12
tests/src/main.cpp Executable file → Normal file
View File

@ -84,6 +84,9 @@ int main(int argc, const char** argv)
.setNArgs('?').build()); .setNArgs('?').build());
parser.addArgument(blt::arg_builder("--utility").setHelp("Run tests on utility functions").setAction(blt::arg_action_t::STORE_TRUE).build()); parser.addArgument(blt::arg_builder("--utility").setHelp("Run tests on utility functions").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder("--data").setHelp("Run tests on data functions").setAction(blt::arg_action_t::STORE_TRUE).build()); parser.addArgument(blt::arg_builder("--data").setHelp("Run tests on data functions").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder("--vector").setHelp("Run tests for the vectors").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder("--fixed_point").setHelp("Run tests for the vectors").setAction(blt::arg_action_t::STORE_TRUE).build());
parser.addArgument(blt::arg_builder("--allocator").setHelp("Run tests for the vectors").setAction(blt::arg_action_t::STORE_TRUE).build());
auto args = parser.parse_args(argc, argv); auto args = parser.parse_args(argc, argv);
@ -103,6 +106,15 @@ int main(int argc, const char** argv)
if (args.contains("--data")) if (args.contains("--data"))
blt::test::data::run(); blt::test::data::run();
if (args.contains("--vector"))
blt::test::vector_run();
if (args.contains("--fixed_point"))
blt::test::fixed_point();
if (args.contains("--allocator"))
blt::test::allocator();
if (args.contains("--nbt")) if (args.contains("--nbt"))
{ {
auto v = blt::arg_parse::get<std::string>(args["nbt"]); auto v = blt::arg_parse::get<std::string>(args["nbt"]);

38
tests/src/math_tests.cpp Normal file
View File

@ -0,0 +1,38 @@
/*
* <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/math/fixed_point.h>
#include <blt/std/logging.h>
#include <iostream>
#include <blt_tests.h>
namespace blt::test
{
void fixed_point()
{
fp64 uv = fp64::from_u64(32);
fp64 iv = fp64::from_i64(16);
std::cout << uv.as_i64() << " : " << uv.as_u64() << std::endl;
std::cout << iv.as_i64() << " : " << iv.as_u64() << std::endl;
std::cout << (uv * iv).as_i64() << std::endl;
std::cout << (uv * iv).as_u64() << std::endl;
std::cout << (uv / iv).as_i64() << std::endl;
std::cout << (uv / iv).as_u64() << std::endl;
}
}

View File

@ -23,6 +23,7 @@
#include <blt/std/random.h> #include <blt/std/random.h>
#include <type_traits> #include <type_traits>
#include "blt/std/utility.h" #include "blt/std/utility.h"
#include "blt/std/vector.h"
#include <unordered_set> #include <unordered_set>
#include <blt/compatibility.h> #include <blt/compatibility.h>

0
tests/src/nbt_tests.cpp Executable file → Normal file
View File

0
tests/src/nbt_tests.h Executable file → Normal file
View File

0
tests/src/profiling_tests.h Executable file → Normal file
View File

0
tests/src/queue_tests.h Executable file → Normal file
View File

0
tests/test.sh Executable file → Normal file
View File