├── .gitignore ├── CHANGELOG.md ├── CONTRIBUTING.md ├── LICENSE ├── LICENSE-KHASH ├── README.md ├── base.mk ├── buntils.mk ├── buntils.sln ├── buntils ├── ConvertUTF.c ├── HighPrecisionTimer.cpp ├── INIParser.c ├── INIentry.cpp ├── INIsection.cpp ├── INIstorage.cpp ├── Logger.cpp ├── UBJSON.cpp ├── XML.cpp ├── buntils.cpp ├── buntils.rc ├── buntils.vcxproj ├── buntils.vcxproj.filters ├── buntils_c.c ├── fontconfig │ └── fontconfig.h └── profiler.cpp ├── include └── buntils │ ├── AATree.h │ ├── AVLTree.h │ ├── AliasTable.h │ ├── Alloc.h │ ├── Animation.h │ ├── Array.h │ ├── ArrayCircular.h │ ├── ArraySort.h │ ├── BinaryHeap.h │ ├── BitField.h │ ├── BitStream.h │ ├── BlockAlloc.h │ ├── BlockAllocMT.h │ ├── CacheAlloc.h │ ├── Collision.h │ ├── CompactArray.h │ ├── Delegate.h │ ├── DisjointSet.h │ ├── Dual.h │ ├── DynArray.h │ ├── FixedPt.h │ ├── Geometry.h │ ├── Graph.h │ ├── GreedyAlloc.h │ ├── GreedyBlockAlloc.h │ ├── Hash.h │ ├── HighPrecisionTimer.h │ ├── INIentry.h │ ├── INIparse.h │ ├── INIsection.h │ ├── INIstorage.h │ ├── JSON.h │ ├── KDTree.h │ ├── LLBase.h │ ├── LinkedArray.h │ ├── LinkedList.h │ ├── LocklessQueue.h │ ├── Logger.h │ ├── Map.h │ ├── PriorityQueue.h │ ├── Profiler.h │ ├── Queue.h │ ├── RWLock.h │ ├── RandomQueue.h │ ├── Rational.h │ ├── RefCounter.h │ ├── RingAlloc.h │ ├── Scheduler.h │ ├── Serializer.h │ ├── Singleton.h │ ├── Stack.h │ ├── Str.h │ ├── StringTable.h │ ├── TOML.h │ ├── TRBtree.h │ ├── Thread.h │ ├── ThreadPool.h │ ├── Trie.h │ ├── UBJSON.h │ ├── Variant.h │ ├── XML.h │ ├── XorshiftEngine.h │ ├── algo.h │ ├── buntils.h │ ├── buntils_c.h │ ├── compare.h │ ├── compiler.h │ ├── defines.h │ ├── khash.h │ ├── literals.h │ ├── lockless.h │ ├── os.h │ ├── sseVec.h │ ├── stream.h │ ├── utf_conv.h │ ├── vector.h │ └── win32_includes.h ├── makefile ├── pack.bat ├── test.mk └── test ├── buntils.ico ├── test.cpp ├── test.h ├── test.rc ├── test.vcxproj ├── test_aatree.cpp ├── test_algo.cpp ├── test_aliastable.cpp ├── test_alloc.h ├── test_alloc_block.cpp ├── test_alloc_block_mt.cpp ├── test_alloc_cache.cpp ├── test_alloc_greedy.cpp ├── test_alloc_greedy_block.cpp ├── test_animation.cpp ├── test_array.cpp ├── test_arraycircular.cpp ├── test_arraysort.cpp ├── test_avltree.cpp ├── test_binaryheap.cpp ├── test_bitfield.cpp ├── test_bitstream.cpp ├── test_buntils.cpp ├── test_buntils_c.cpp ├── test_c.c ├── test_collision.cpp ├── test_compactarray.cpp ├── test_defines.cpp ├── test_delegate.cpp ├── test_disjointset.cpp ├── test_dual.cpp ├── test_dynarray.cpp ├── test_fixedpt.cpp ├── test_geometry.cpp ├── test_graph.cpp ├── test_hash.cpp ├── test_highprecisiontimer.cpp ├── test_inistorage.cpp ├── test_json.cpp ├── test_kdtree.cpp ├── test_linkedarray.cpp ├── test_linkedlist.cpp ├── test_literals.cpp ├── test_lockless.cpp ├── test_locklessqueue.cpp ├── test_logger.cpp ├── test_map.cpp ├── test_os.cpp ├── test_priorityqueue.cpp ├── test_profile.cpp ├── test_queue.cpp ├── test_randomqueue.cpp ├── test_rational.cpp ├── test_refcounter.cpp ├── test_rwlock.cpp ├── test_scheduler.cpp ├── test_serializer.cpp ├── test_singleton.cpp ├── test_sse.cpp ├── test_stack.cpp ├── test_str.cpp ├── test_stream.cpp ├── test_strtable.cpp ├── test_thread.cpp ├── test_threadpool.cpp ├── test_toml.cpp ├── test_trbtree.cpp ├── test_trie.cpp ├── test_ubjson.cpp ├── test_variant.cpp ├── test_vector.cpp ├── test_xml.cpp └── util.cpp /.gitignore: -------------------------------------------------------------------------------- 1 | *.sdf 2 | *.suo 3 | *.opensdf 4 | *.bak 5 | *.aps 6 | *.VC.db 7 | *.VC.opendb 8 | *.log 9 | *.h.gch 10 | *.pch 11 | *.vcxproj.user 12 | /bin/ 13 | /bin32/ 14 | /buntils/x64/ 15 | /buntils/Win32/ 16 | /test/x64/ 17 | /test/Win32/ 18 | /ATOMIC.H 19 | /buntils.VC.opendb 20 | /_hugo/ 21 | /.vs/ -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contribution Guidelines 2 | 3 | buntils requires at least Visual Studio 2017 15.3, or GCC 7+, due to it's use of C++17 features. Make sure your compiler is up to date before filing an issue. -------------------------------------------------------------------------------- /LICENSE-KHASH: -------------------------------------------------------------------------------- 1 | The MIT License 2 | 3 | Copyright (c) 2008, 2009 by attractor 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining 6 | a copy of this software and associated documentation files (the 7 | "Software"), to deal in the Software without restriction, including 8 | without limitation the rights to use, copy, modify, merge, publish, 9 | distribute, sublicense, and/or sell copies of the Software, and to 10 | permit persons to whom the Software is furnished to do so, subject to 11 | the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be 14 | included in all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 17 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 18 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 19 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS 20 | BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN 21 | ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 22 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bunny Utility Library 2 | 3 | This is a collection of miscellaneous utility code used to simplify common tasks in C/C++ programs. 4 | 5 | * Type safe variant object for algebriac types. 6 | * Allocators with a state 7 | * Logging 8 | * Reference counting 9 | * Generalized linked list manipulation 10 | * Array-based linked list 11 | * Threaded red-black tree implementation 12 | * AVL tree implementation 13 | * DLL-friendly simplified dynamic array implementation 14 | * Array-based stack implementation 15 | * Array-based queue implementation 16 | * cStr, an extension of the standard std::string object that supports UTF8 conversions and other operations. 17 | * A single-producer, single-consumer lockless queue 18 | * A multi-producer, multi-consumer microlock queue 19 | * Templatized implementations of cmpxchg,xchg,xadd, and other lockless primitives. 20 | * A template-based hash implementation based on khash 21 | * Command line parsing 22 | * Block, ring, and greedy allocation schemes 23 | * Fixed-size bit-based flag manipulation 24 | * High precision timer 25 | * Binary heap implementation 26 | * Priority queue based on binary heap 27 | * Priority heap based on Priority Queue that tracks entries to allow implementing Dijkstra's Algorithm 28 | * #defines to help deal with stupid windows.h conflicts and VC++ deprecated functions 29 | * Sorted array using a bisection algorithm 30 | * Map based on sorted array 31 | * Frighteningly efficient delegate implementation 32 | * Automatic differentiation with dual numbers 33 | * Fixed-point arithmetic. 34 | * Template-based SSE2 objects for automatic SSE optimizations. 35 | * Alias table for random number generation 36 | * Generic animation system 37 | * Circular array implementation 38 | * Disjoint Set Data Structure that implements Kruskal's minimum spanning tree algorithm. 39 | * Cross-platform extension to std::thread that allows signaling threads. 40 | * Stream splitting object using standard buffer implementation. 41 | * Integral rational data structure for precise fractions. 42 | * String table for localization. 43 | * High performance profiler with multiple output options. 44 | * Multi-consumer multi-producer lockless block allocator. 45 | * Generalized KD-tree implementation for querying how many rectangles are inside a given rectangle. 46 | * Implementation of Robert Bridson's Fast Poisson Disk Sampling algorithm. 47 | * An in-place compressed Trie data structure implementation. 48 | * Arbitrary scheduler class for delaying actions. 49 | * Thread pool implementation 50 | * Implementation of a graph representation that implements the push-relabel algorithm, along with reductions from circulation and lower-bound circulation graph problems. 51 | * Implements efficient breadth-first traversal of a tree or graph 52 | * Includes an ID hash system that can be rebased at any time, including a reversal extension. 53 | * Implements mathematically correct integer and float modulo 54 | * Includes an n-dimensional vector and matrix math library, with optimized 4x4, 3x3 and 2x2 operations. 55 | * Implementes the xorshift random number generation algorithm as a standards-compliant engine. 56 | * AA tree implementation 57 | * Universal object serializer 58 | * XML parser and serializer 59 | * JSON parser and serializer 60 | * UBJSON parser and serializer 61 | * INI parser and serializer 62 | -------------------------------------------------------------------------------- /base.mk: -------------------------------------------------------------------------------- 1 | C_OBJS := ${C_SRCS:.c=.o} 2 | CXX_OBJS := ${CXX_SRCS:.cpp=.o} 3 | OBJS := $(addprefix $(OBJDIR)/c/,$(C_OBJS)) $(addprefix $(OBJDIR)/cxx/,$(CXX_OBJS)) 4 | CPPFLAGS += $(foreach includedir,$(INCLUDE_DIRS),-I$(includedir)) -msse2 -mcx16 -Wl,-rpath -Wl,. 5 | LDFLAGS += $(foreach librarydir,$(LIBRARY_DIRS),-L$(librarydir)) -msse2 -mcx16 6 | LDLIBS := $(foreach library,$(LIBRARIES),-l$(library)) 7 | 8 | .PHONY: all clean distclean 9 | 10 | all: $(BUILDDIR)/$(TARGET) 11 | 12 | $(OBJDIR)/c/%.o : %.c 13 | +@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR) 14 | +@[ -d $(OBJDIR)/c ] || mkdir -p $(OBJDIR)/c 15 | +@[ -d $(OBJDIR)/c/$(SRCDIR) ] || mkdir -p $(OBJDIR)/c/$(SRCDIR) 16 | $(COMPILE.c) $< -o $@ 17 | 18 | $(OBJDIR)/cxx/%.o : %.cpp 19 | +@[ -d $(OBJDIR) ] || mkdir -p $(OBJDIR) 20 | +@[ -d $(OBJDIR)/cxx ] || mkdir -p $(OBJDIR)/cxx 21 | +@[ -d $(OBJDIR)/cxx/$(SRCDIR) ] || mkdir -p $(OBJDIR)/cxx/$(SRCDIR) 22 | $(COMPILE.cpp) $< -o $@ 23 | 24 | $(BUILDDIR)/$(TARGET): $(OBJS) 25 | +@[ -d $(BUILDDIR) ] || mkdir -p $(BUILDDIR) 26 | $(LINK.cc) $(OBJS) -o $@ $(LDLIBS) 27 | 28 | clean: distclean 29 | @- $(RM) $(BUILDDIR)/$(TARGET) 30 | 31 | debug: CPPFLAGS += -ggdb -fvar-tracking-assignments 32 | debug: all 33 | -------------------------------------------------------------------------------- /buntils.mk: -------------------------------------------------------------------------------- 1 | TARGET := libbuntils.so 2 | SRCDIR := buntils 3 | BUILDDIR := bin 4 | OBJDIR := bin/obj 5 | C_SRCS := $(wildcard $(SRCDIR)/*.c) 6 | CXX_SRCS := $(wildcard $(SRCDIR)/*.cpp) 7 | INCLUDE_DIRS := include 8 | LIBRARY_DIRS := 9 | LIBRARIES := rt 10 | 11 | CPPFLAGS += -fPIC -D BSS_UTIL_EXPORTS -std=c++20 -DLIBICONV_PLUG -Wall -Wshadow -Wno-attributes -Wno-unknown-pragmas -Wno-reorder -Wno-missing-braces -Wno-unused-function -Wno-char-subscripts -fsanitize=signed-integer-overflow -fuse-ld=gold -Wno-class-memaccess 12 | LDFLAGS += -shared 13 | 14 | include base.mk 15 | 16 | distclean: 17 | @- $(RM) $(OBJS) 18 | @- $(RM) -r $(OBJDIR) 19 | 20 | PREFIX = /usr 21 | 22 | .PHONY: install 23 | install: 24 | test -d $(PREFIX) || mkdir $(PREFIX) 25 | test -d $(PREFIX)/lib || mkdir $(PREFIX)/lib 26 | test -d $(PREFIX)/include || mkdir $(PREFIX)/include 27 | test -d $(PREFIX)/include/$(SRCDIR) || mkdir $(PREFIX)/include/$(SRCDIR) 28 | cp $(BUILDDIR)/$(TARGET) $(PREFIX)/lib/$(TARGET) 29 | cp include/$(SRCDIR)/*.h $(PREFIX)/include/$(SRCDIR)/ 30 | 31 | .PHONY: uninstall 32 | uninstall: 33 | rm -f $(PREFIX)/lib/$(TARGET) 34 | rm -f -r $(PREFIX)/include/$(SRCDIR) -------------------------------------------------------------------------------- /buntils.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.13 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test", "test\test.vcxproj", "{07854893-CF69-4467-AFCE-28D35B115D41}" 7 | ProjectSection(ProjectDependencies) = postProject 8 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68} = {4F702B9E-ADE1-41D3-AC1C-4059B557BE68} 9 | EndProjectSection 10 | EndProject 11 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "buntils", "buntils\buntils.vcxproj", "{4F702B9E-ADE1-41D3-AC1C-4059B557BE68}" 12 | EndProject 13 | Global 14 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 15 | Debug|Win32 = Debug|Win32 16 | Debug|x64 = Debug|x64 17 | Debug-Static|Win32 = Debug-Static|Win32 18 | Debug-Static|x64 = Debug-Static|x64 19 | Release|Win32 = Release|Win32 20 | Release|x64 = Release|x64 21 | Release-Clang|Win32 = Release-Clang|Win32 22 | Release-Clang|x64 = Release-Clang|x64 23 | Release-Static|Win32 = Release-Static|Win32 24 | Release-Static|x64 = Release-Static|x64 25 | Release-STD|Win32 = Release-STD|Win32 26 | Release-STD|x64 = Release-STD|x64 27 | EndGlobalSection 28 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 29 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug|Win32.ActiveCfg = Debug|Win32 30 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug|Win32.Build.0 = Debug|Win32 31 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug|x64.ActiveCfg = Debug|x64 32 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug|x64.Build.0 = Debug|x64 33 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 34 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 35 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 36 | {07854893-CF69-4467-AFCE-28D35B115D41}.Debug-Static|x64.Build.0 = Debug-Static|x64 37 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release|Win32.ActiveCfg = Release|Win32 38 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release|Win32.Build.0 = Release|Win32 39 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release|x64.ActiveCfg = Release|x64 40 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release|x64.Build.0 = Release|x64 41 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Clang|Win32.ActiveCfg = Release-Clang|Win32 42 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Clang|Win32.Build.0 = Release-Clang|Win32 43 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Clang|x64.ActiveCfg = Release-Clang|x64 44 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Clang|x64.Build.0 = Release-Clang|x64 45 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 46 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Static|Win32.Build.0 = Release-Static|Win32 47 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Static|x64.ActiveCfg = Release-Static|x64 48 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-Static|x64.Build.0 = Release-Static|x64 49 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-STD|Win32.ActiveCfg = Release-STD|Win32 50 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-STD|Win32.Build.0 = Release-STD|Win32 51 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-STD|x64.ActiveCfg = Release-STD|x64 52 | {07854893-CF69-4467-AFCE-28D35B115D41}.Release-STD|x64.Build.0 = Release-STD|x64 53 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug|Win32.ActiveCfg = Debug|Win32 54 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug|Win32.Build.0 = Debug|Win32 55 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug|x64.ActiveCfg = Debug|x64 56 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug|x64.Build.0 = Debug|x64 57 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug-Static|Win32.ActiveCfg = Debug-Static|Win32 58 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug-Static|Win32.Build.0 = Debug-Static|Win32 59 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug-Static|x64.ActiveCfg = Debug-Static|x64 60 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Debug-Static|x64.Build.0 = Debug-Static|x64 61 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release|Win32.ActiveCfg = Release|Win32 62 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release|Win32.Build.0 = Release|Win32 63 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release|x64.ActiveCfg = Release|x64 64 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release|x64.Build.0 = Release|x64 65 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Clang|Win32.ActiveCfg = Release-Clang|Win32 66 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Clang|Win32.Build.0 = Release-Clang|Win32 67 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Clang|x64.ActiveCfg = Release-Clang|x64 68 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Clang|x64.Build.0 = Release-Clang|x64 69 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Static|Win32.ActiveCfg = Release-Static|Win32 70 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Static|Win32.Build.0 = Release-Static|Win32 71 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Static|x64.ActiveCfg = Release-Static|x64 72 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-Static|x64.Build.0 = Release-Static|x64 73 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-STD|Win32.ActiveCfg = Release-STD|Win32 74 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-STD|Win32.Build.0 = Release-STD|Win32 75 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-STD|x64.ActiveCfg = Release-STD|x64 76 | {4F702B9E-ADE1-41D3-AC1C-4059B557BE68}.Release-STD|x64.Build.0 = Release-STD|x64 77 | EndGlobalSection 78 | GlobalSection(SolutionProperties) = preSolution 79 | HideSolutionNode = FALSE 80 | EndGlobalSection 81 | EndGlobal 82 | -------------------------------------------------------------------------------- /buntils/HighPrecisionTimer.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #include "buntils/HighPrecisionTimer.h" 5 | #ifdef BUN_PLATFORM_WIN32 6 | #include "buntils/win32_includes.h" 7 | #endif 8 | 9 | using namespace bun; 10 | 11 | #ifdef BUN_PLATFORM_WIN32 12 | uint64_t hpt_freq; // The CPU frequency can't change during program execution, so we just get it here and retrieve it later. 13 | BOOL hpt_throwaway = QueryPerformanceFrequency((LARGE_INTEGER*)&hpt_freq); 14 | #endif 15 | 16 | HighPrecisionTimer::HighPrecisionTimer() : _time(0), _nsTime(0) 17 | { 18 | ResetDelta(); 19 | } 20 | 21 | double HighPrecisionTimer::Update() 22 | { 23 | uint64_t newTime; 24 | _queryTime(&newTime); 25 | if(newTime < _curTime) newTime = _curTime; // Do not allow time to run backwards 26 | #ifdef BUN_PLATFORM_WIN32 27 | _delta = double((newTime - _curTime) * 1000) / (double)hpt_freq; //We multiply by 1000 BEFORE dividing into a double to maintain precision (since its unlikely the difference between newtime and oldtime is going to be bigger then 9223372036854775 28 | _nsDelta = ((newTime - _curTime) * 1000000000) / hpt_freq; 29 | #else 30 | _delta = (newTime - _curTime) / ((double)1000000); 31 | _nsDelta = newTime - _curTime; 32 | #endif 33 | _curTime = newTime; 34 | _nsTime += _nsDelta; 35 | _time = _nsTime / 1000000.0; // not dividing by 1 billion because this is in milliseconds, not seconds 36 | return _delta; 37 | } 38 | 39 | double HighPrecisionTimer::Update(double timewarp) 40 | { 41 | if(timewarp == 1.0) return Update(); 42 | uint64_t newTime; 43 | _queryTime(&newTime); 44 | if(newTime < _curTime) newTime = _curTime; // Do not allow time to run backwards 45 | #ifdef BUN_PLATFORM_WIN32 46 | uint64_t warpfreq = (uint64_t)(hpt_freq*timewarp); 47 | _delta = double((newTime - _curTime) * 1000) / (hpt_freq*timewarp); 48 | _nsDelta = ((newTime - _curTime) * 1000000000) / warpfreq; 49 | #else 50 | _delta = (newTime - _curTime) / (1000000 * timewarp); 51 | _nsDelta = (uint64_t)((newTime - _curTime)*timewarp); 52 | #endif 53 | _curTime = newTime; 54 | _nsTime += _nsDelta; 55 | _time = _nsTime / 1000000.0; 56 | return _delta; 57 | } 58 | void HighPrecisionTimer::Override(uint64_t nsdelta) 59 | { 60 | _queryTime(&_curTime); 61 | _nsDelta = nsdelta; 62 | _delta = nsdelta / 1000000.0; 63 | _nsTime += _nsDelta; 64 | _time = _nsTime / 1000000.0; 65 | } 66 | void HighPrecisionTimer::Override(double delta) 67 | { 68 | _queryTime(&_curTime); 69 | _nsDelta = (uint64_t)(delta * 1000000.0); 70 | _delta = delta; 71 | _nsTime += _nsDelta; 72 | _time = _nsTime / 1000000.0; 73 | } 74 | 75 | #ifdef BUN_PLATFORM_WIN32 76 | void HighPrecisionTimer::_queryTime(uint64_t* _pval) 77 | { // The multicore timing glitch that used to happen with QPC calls no longer affects modern windows. See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn553408(v=vs.85).aspx 78 | //DWORD procmask=_getaffinity(); 79 | //HANDLE curthread = GetCurrentThread(); 80 | //SetThreadAffinityMask(curthread, 1); 81 | 82 | QueryPerformanceCounter((LARGE_INTEGER*)_pval); 83 | 84 | //SetThreadAffinityMask(curthread, procmask); 85 | } 86 | #else 87 | void HighPrecisionTimer::_queryTime(uint64_t* _pval, clockid_t clock) 88 | { 89 | timespec tspec; 90 | clock_gettime(clock, &tspec); 91 | *_pval = (((uint64_t)tspec.tv_sec) * 1000000000) + (uint64_t)tspec.tv_nsec; 92 | } 93 | #endif 94 | 95 | #ifdef BUN_PLATFORM_WIN32 96 | uint64_t HighPrecisionTimer::_getFrequency() { return hpt_freq; } 97 | #endif -------------------------------------------------------------------------------- /buntils/INIentry.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #include "buntils/buntils.h" 5 | #include "buntils/INIentry.h" 6 | #include 7 | #include 8 | #include 9 | 10 | using namespace bun; 11 | 12 | INIentry::INIentry() : _ivalue(0), _dvalue(0.0) 13 | {} 14 | INIentry::INIentry(const char *key, const char *svalue, int64_t ivalue, double dvalue) : _key(key), _svalue(svalue), 15 | _ivalue(ivalue), _dvalue(dvalue) 16 | {} 17 | INIentry::INIentry(const char* key, const char* data) : _key(key) { Set(data); } 18 | 19 | INIentry::~INIentry() 20 | {} 21 | 22 | bool INIentry::operator ==(INIentry &other) const { return STRICMP(_key, other._key) == 0 && STRICMP(_svalue, other._svalue) == 0 && _ivalue == other._ivalue && _dvalue == other._dvalue; } 23 | 24 | //bool INIentry::operator ==(INIentry &other) const { return WCSICMP(_key,other._key)==0 && WCSICMP(_svalue,other._svalue)==0; } 25 | //bool INIentry::operator !=(INIentry &other) const { return WCSICMP(_key,other._key)!=0 || WCSICMP(_svalue,other._svalue)!=0; } 26 | 27 | void INIentry::Set(const char* data) 28 | { 29 | if(!data) return; 30 | _svalue = data; 31 | 32 | if(_svalue[0] == '0' && (_svalue[1] == 'x' || _svalue[1] == 'X')) //If this is true its a hex number 33 | { 34 | uint64_t v = STRTOULL(_svalue, 0, 16); //We store the unsigned here so it gets properly stored in the double even if it overflows on the signed int64_t 35 | _ivalue = (int64_t)v; 36 | _dvalue = (double)v; 37 | } 38 | else if(!strchr(_svalue, '.')) //If there isn't a period in the sequence, its either a string (in which case we don't care) or an integer, so round _dvalue to the integer. 39 | { 40 | _ivalue = ATOLL(_svalue); 41 | _dvalue = (double)_ivalue; 42 | } 43 | else //Ok its got a . in there so its either a double or a string, so we just round _ivalue 44 | { 45 | _dvalue = atof(_svalue); 46 | _ivalue = (int64_t)_dvalue; 47 | } 48 | } 49 | void INIentry::SetInt(int64_t i) 50 | { 51 | _ivalue = i; 52 | _dvalue = (double)i; 53 | _svalue = std::to_string(i); 54 | } 55 | void INIentry::SetFloat(double d) 56 | { 57 | _ivalue = (int64_t)d; 58 | _dvalue = d; 59 | _svalue = std::to_string(d); 60 | } 61 | -------------------------------------------------------------------------------- /buntils/INIsection.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #include "buntils/buntils.h" 5 | #include "buntils/INIstorage.h" 6 | #include 7 | 8 | using namespace bun; 9 | 10 | INIentry INIsection::_entrysentinel; 11 | LocklessBlockPolicy INIsection::_alloc; 12 | 13 | INIsection::INIsection(const INIsection& copy) : _name(copy._name),_index(copy._index), _parent(copy._parent), _root(0),_last(0) 14 | { 15 | _copy(copy); 16 | } 17 | INIsection::INIsection(INIsection&& mov) : _name(std::move(mov._name)),_index(mov._index), _parent(mov._parent), 18 | _entries(std::move(mov._entries)),_root(mov._root),_last(mov._last) 19 | { 20 | mov._root=0; 21 | mov._last=0; 22 | } 23 | INIsection::INIsection() : _index((size_t)~0), _parent(0), _root(0), _last(0) 24 | { 25 | } 26 | INIsection::INIsection(const char* name, INIstorage* parent, size_t index) : _name(name), _index(index), _parent(parent), _root(0),_last(0) 27 | { 28 | } 29 | INIsection::~INIsection() 30 | { 31 | _destroy(); 32 | } 33 | void INIsection::_destroy() 34 | { 35 | _NODE* t; 36 | while(_root) 37 | { 38 | t=_root->next; 39 | _root->~_NODE(); 40 | _alloc.deallocate(_root, 1); 41 | _root=t; 42 | } 43 | _last=0; 44 | } 45 | void INIsection::_copy(const INIsection& copy) 46 | { 47 | assert(!_root && !_last); 48 | _NODE* t=copy._root; 49 | _NODE* last=0; 50 | size_t c=0; 51 | while(t) 52 | { 53 | _NODE* p=_alloc.allocate(1); 54 | bun_Fill(*p, 0); 55 | new (&p->val) INIentry(t->val); 56 | if(!_root) 57 | _root=_last=p; 58 | else 59 | _last=LLAddAfter(p,_last); 60 | 61 | if(t->instances.Capacity()!=0) { 62 | _entries.Insert(p->val.GetKey(),p); 63 | p->instances.SetCapacity(c=t->instances.Capacity()); 64 | last=t; 65 | --c; 66 | } else if(c>0) { 67 | assert(last!=0); 68 | last->instances[last->instances.Capacity()-(c--)-1]=p; //This never goes negative because c>0 and is therefore at least 1 69 | } else 70 | _entries.Insert(p->val.GetKey(),p); 71 | 72 | t=t->next; 73 | } 74 | } 75 | 76 | void INIsection::_addEntry(const char* key, const char* data) 77 | { 78 | _NODE* p=_alloc.allocate(1); 79 | bun_Fill(*p, 0); 80 | new (&p->val) INIentry(key,data); 81 | khiter_t iter=_entries.Iterator(key); 82 | 83 | if(iter==_entries.Back()) 84 | { 85 | _entries.Insert(p->val.GetKey(),p); 86 | if(!_root) 87 | _root=_last=p; 88 | else 89 | _last=LLAddAfter(p,_last); 90 | } else { 91 | assert(_last!=0 && _root!=0); 92 | _NODE* r=_entries.Value(iter); 93 | _NODE* t=!r->instances.Capacity()?r:r->instances.Back(); 94 | LLInsertAfter(p,t,_last); 95 | r->instances.Insert(p,r->instances.Capacity()); 96 | } 97 | } 98 | 99 | INIsection& INIsection::operator=(const INIsection& right) 100 | { 101 | if(&right == this) return *this; 102 | _name=right._name; 103 | _index=right._index; 104 | _parent=right._parent; 105 | _destroy(); 106 | _entries.Clear(); 107 | _copy(right); 108 | return *this; 109 | } 110 | 111 | INIsection& INIsection::operator=(INIsection&& mov) 112 | { 113 | if(&mov == this) return *this; 114 | _name=std::move(mov._name); 115 | _index=mov._index; 116 | _parent=mov._parent; 117 | _entries=std::move(mov._entries); 118 | _root=mov._root; 119 | _last=mov._last; 120 | mov._root=0; 121 | mov._last=0; 122 | return *this; 123 | } 124 | 125 | INIsection::_NODE* INIsection::GetEntryNode(const char* key, size_t instance) const 126 | { 127 | _NODE* n = _entries[key]; 128 | if(!n) return 0; 129 | if(!instance) return n; 130 | return (instance>n->instances.Capacity())?0:(n->instances[instance-1]); 131 | } 132 | 133 | INIentry* INIsection::GetEntryPtr(const char* key, size_t instance) const 134 | { 135 | _NODE* entry=GetEntryNode(key,instance); 136 | return !entry?0:&entry->val; 137 | } 138 | 139 | size_t INIsection::GetNumEntries(const char* key) const 140 | { 141 | _NODE* n = _entries[key]; 142 | if(!n) return 0; 143 | return n->instances.Capacity()+1; 144 | } 145 | 146 | INIentry& INIsection::GetEntry(const char* key, size_t instance) const 147 | { 148 | _NODE* entry=GetEntryNode(key,instance); 149 | return !entry?_entrysentinel:entry->val; 150 | } 151 | 152 | char INIsection::EditEntry(const char* key, const char* data, size_t instance) 153 | { // We put this down here because the compiler never actually inlines it, so there's no point in going through hoops to keep it inline. 154 | return !_parent?-1:_parent->EditEntry(_name,key,data,instance,_index); 155 | } 156 | -------------------------------------------------------------------------------- /buntils/buntils.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/buntils/buntils.rc -------------------------------------------------------------------------------- /include/buntils/AliasTable.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __ALIAS_TABLE_H__BUN__ 5 | #define __ALIAS_TABLE_H__BUN__ 6 | 7 | #include "algo.h" 8 | 9 | namespace bun { 10 | // Implementation of the Alias method, based off Keith Schwarz's code, found here: http://www.keithschwarz.com/darts-dice-coins/ 11 | template 12 | class AliasTable 13 | { 14 | public: 15 | AliasTable(const AliasTable& copy) : _alias(new UINT[copy._count]), _prob(new F[copy._count]), _count(copy._count), 16 | _dist(copy._dist), _fdist(copy._fdist) 17 | { 18 | memcpy(_alias, copy._alias, sizeof(UINT)*copy._count); 19 | memcpy(_prob, copy._prob, sizeof(UINT)*copy._count); 20 | } 21 | AliasTable(AliasTable&& mov) : _prob(std::move(mov._prob)), _alias(std::move(mov._alias)), 22 | _dist(std::move(mov._dist)), _fdist(std::move(mov._fdist)), _count(mov._count) 23 | {} 24 | AliasTable() : _alias(0), _prob(0), _count(0), _fdist(0, (F)1) {} 25 | // Constructs a new table from a list of probabilities of type F (defaults to double) 26 | AliasTable(const F* problist, UINT count) : _alias(0), _prob(0), _count(0), _fdist(0, (F)1) 27 | { 28 | if(!problist || !count) 29 | return; 30 | _count = count; //this is done here so a failure results in _count=0 31 | _prob.reset(new F[_count]); 32 | _alias.reset(new UINT[_count]); 33 | F average = ((F)1.0) / _count; 34 | 35 | std::unique_ptr _probcopy(new F[_count]); //Temporary copy of probabilities (seperate from our stored ones) 36 | memcpy(_probcopy.get(), problist, sizeof(F)*count); 37 | 38 | #ifdef BUN_DEBUG 39 | bun_FillN(_alias.get(), _count, -1); 40 | #endif 41 | std::unique_ptr small(new UINT[_count]); //Small and large stacks as simple arrays 42 | UINT n_small = 0; 43 | std::unique_ptr large(new UINT[_count]); 44 | UINT n_large = 0; 45 | 46 | for(UINT i = 0; i < count; ++i) 47 | { 48 | if(_probcopy[i] >= average) 49 | large[n_large++] = i; 50 | else 51 | small[n_small++] = i; 52 | } 53 | 54 | UINT l; 55 | UINT g; 56 | while(n_small != 0 && n_large != 0) //In a perfect world, small always empties before large, but our world isn't, so we check both 57 | { 58 | l = small[--n_small]; 59 | g = large[--n_large]; 60 | 61 | _prob[l] = _probcopy[l] * _count; //scale probabilities so 1/n is given weight 1.0 62 | _alias[l] = g; 63 | _probcopy.get()[g] = (_probcopy[g] + _probcopy[l]) - average; //Set new probability 64 | 65 | if(_probcopy[g] >= average) //Move new probability to correct list 66 | large[n_large++] = g; 67 | else 68 | small[n_small++] = g; 69 | } 70 | 71 | //Set everything to 1.0 (both lists are set due to numerical uncertainty) 72 | while(n_large != 0) 73 | _prob[large[--n_large]] = 1.0; 74 | while(n_small != 0) 75 | _prob[small[--n_small]] = 1.0; 76 | 77 | #ifdef BUN_DEBUG 78 | for(UINT i = 0; i < _count; ++i) 79 | assert(_alias[i] < _count || (_prob[i] == 1.0)); 80 | for(UINT i = 0; i < _count; ++i) 81 | assert(_prob[i] <= 1.0); 82 | #endif 83 | 84 | _dist = std::uniform_int_distribution(0, _count - 1); 85 | } 86 | template 87 | explicit AliasTable(const F(&problist)[I]) : AliasTable(problist, I) {} 88 | template 89 | explicit AliasTable(const std::array& problist) : AliasTable(problist.data(), I) {} 90 | ~AliasTable() {} 91 | // Gets a new random integer using ENGINE (defaults to xorshift) over a uniform integer distribution 92 | template 93 | BUN_FORCEINLINE UINT Get(ENGINE& e) const 94 | { 95 | UINT c = _dist(e); 96 | UINT r = (_fdist(e) <= _prob[c]) ? c : _alias[c]; // must be <= to ensure it's ALWAYS true if _prob[c]==1.0 97 | assert(r < _count); 98 | return r; 99 | } 100 | BUN_FORCEINLINE UINT Get() const { return Get(bun_getdefaultengine()); } 101 | template 102 | BUN_FORCEINLINE UINT operator()(ENGINE& e) const { return Get(e); } 103 | BUN_FORCEINLINE UINT operator()(void) const { return Get(); } 104 | inline F* GetProbabilities() const { return _prob; } 105 | inline UINT* GetAliases() const { return _alias; } 106 | inline UINT GetCount() const { return _count; } 107 | 108 | inline AliasTable& operator=(const AliasTable& copy) 109 | { 110 | _count = copy._count; 111 | _dist = copy._dist; 112 | _fdist = copy._fdist; 113 | _alias.reset(new UINT[copy._count]); 114 | _prob.reset(new F[copy._count]); 115 | memcpy(_alias.get(), copy._alias.get(), sizeof(UINT)*copy._count); 116 | memcpy(_prob.get(), copy._prob.get(), sizeof(UINT)*copy._count); 117 | return *this; 118 | } 119 | inline AliasTable& operator=(AliasTable&& mov) 120 | { 121 | _count = mov._count; 122 | _dist = std::move(mov._dist); 123 | _fdist = std::move(mov._fdist); 124 | _alias = std::move(mov._alias); 125 | _prob = std::move(mov._prob); 126 | return *this; 127 | } 128 | 129 | protected: 130 | std::unique_ptr _alias; 131 | std::unique_ptr _prob; 132 | UINT _count; 133 | mutable std::uniform_int_distribution _dist; 134 | mutable std::uniform_real_distribution _fdist; 135 | }; 136 | } 137 | 138 | #endif 139 | -------------------------------------------------------------------------------- /include/buntils/BitStream.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BITSTREAM_H__BUN__ 5 | #define __BITSTREAM_H__BUN__ 6 | 7 | #include "buntils.h" 8 | #include "Str.h" 9 | #include 10 | 11 | namespace bun { 12 | // This wraps around an existing stream and flushes to it. Capable of writing and reading with single-bit precision. 13 | template 14 | class BUN_COMPILER_DLLEXPORT BitStream 15 | { 16 | public: 17 | BitStream(const BitStream& copy) : _base(copy._base), _roffset(copy._roffset), _woffset(copy._woffset), _buf(copy._buf) {} 18 | BitStream(BitStream&& mov) : _base(mov._base), _roffset(mov._roffset), _woffset(mov._woffset), _buf(mov._buf) { mov._base = 0; } 19 | explicit BitStream(STREAM& base) : _base(&base), _roffset(0), _woffset(0), _buf(0) {} 20 | ~BitStream() { if(_base) Flush(); } 21 | void Write(const void* source, int bits) 22 | { 23 | const uint8_t* d = (const uint8_t*)source; 24 | int k = 0; 25 | int i; 26 | 27 | for(i = bits; i >= 8; i -= 8) 28 | { 29 | _buf |= (d[k] << _woffset); 30 | _base->put(_buf); 31 | _buf = (d[k++] >> (8 - _woffset)); 32 | } 33 | 34 | if(!i) 35 | return; 36 | 37 | _buf |= (d[k] << _woffset); 38 | 39 | if((_woffset + i) >= 8) // We ran over our current character 40 | { 41 | _base->put(_buf); 42 | _buf = (d[k] >> (8 - _woffset)); 43 | } 44 | 45 | _woffset = ((_woffset + i) & 7); 46 | _buf = (_buf&((1 << _woffset) - 1)); // This zeros out all bits we didn't assign in _buf 47 | } 48 | template 49 | void Write(const T& source) { Write(&source, std::conditional::value, std::integral_constant, std::integral_constant>::type::value); } 50 | void Read(void* dest, int bits) 51 | { 52 | uint8_t* d = (uint8_t*)dest; 53 | uint8_t b; 54 | int k = 0; 55 | int i; 56 | 57 | for(i = bits; i >= 8; i -= 8) 58 | { 59 | d[k] = (_base->peek() >> _roffset); 60 | _base->get(*((char*)&b)); 61 | d[k++] |= (_base->peek() << (8 - _roffset)); 62 | } 63 | 64 | if(!i) 65 | return; 66 | 67 | d[k] |= (_base->peek() >> _roffset); 68 | 69 | if((_roffset + i) >= 8) // We ran over our current character 70 | { 71 | _base->get(*((char*)&b)); 72 | if((_roffset + i) > 8) // We do this so we don't accidentally peek into an invalid character 73 | d[k] |= (_base->peek() << (8 - _roffset)); 74 | } 75 | 76 | _roffset = ((_roffset + i) & 7); 77 | d[k] = (d[k] & ((1 << i) - 1)); // This zeros out all bits we didn't assign 78 | } 79 | template 80 | void Read(T& dest) { Read(&dest, std::conditional::value, std::integral_constant, std::integral_constant>::type::value); } 81 | void Flush() { if(_woffset) _flush(_base, _buf); } 82 | 83 | BitStream& operator=(const BitStream& copy) { _base = copy._base; return *this; } 84 | BitStream& operator=(BitStream&& mov) { _base = mov._base; mov._base = 0; return *this; } 85 | template 86 | BitStream& operator<<(const T& v) { Write(v); return *this; } 87 | template 88 | BitStream& operator>>(T& v) { Read(v); return *this; } 89 | 90 | protected: 91 | template::value> 92 | BUN_FORCEINLINE static typename std::enable_if::type _flush(STREAM* s, uint8_t buf) { s->write((char*)&buf, 1); } 93 | template::value> 94 | BUN_FORCEINLINE static typename std::enable_if::type _flush(STREAM* s, uint8_t buf) { } 95 | 96 | STREAM* _base; 97 | uint8_t _buf; 98 | uint8_t _roffset; // Offset from current reading position in bits 99 | uint8_t _woffset; // Offset from current writing position in bits 100 | }; 101 | 102 | // This is a function that takes a basic type and serializes it, converting it to little-endian format if necessary 103 | void bun_Serialize(auto d, std::ostream& s) 104 | { 105 | #ifdef BUN_ENDIAN_BIG 106 | FlipEndian(&d); 107 | #endif 108 | s.write((const char*)&d, sizeof(decltype(d))); 109 | } 110 | template<> 111 | void bun_Serialize(const char* d, std::ostream& s) 112 | { 113 | size_t len = strlen(d); 114 | bun_Serialize(len, s); 115 | s.write(d, len); 116 | } 117 | 118 | template 119 | void bun_Deserialize(T& d, std::istream& s) 120 | { 121 | s.read((char*)&d, sizeof(T)); 122 | #ifdef BUN_ENDIAN_BIG 123 | FlipEndian(&d); 124 | #endif 125 | } 126 | template<> 127 | void bun_Deserialize(std::string& d, std::istream& s) 128 | { 129 | size_t len; 130 | bun_Deserialize(len, s); 131 | d.resize(len); 132 | s.read(d.data(), len); 133 | } 134 | template<> 135 | void bun_Deserialize(Str& d, std::istream& s) { bun_Deserialize(d, s); } 136 | } 137 | 138 | #endif -------------------------------------------------------------------------------- /include/buntils/Collision.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/include/buntils/Collision.h -------------------------------------------------------------------------------- /include/buntils/Delegate.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __DELEGATE_H__BUN__ 5 | #define __DELEGATE_H__BUN__ 6 | 7 | #include "buntils.h" 8 | #include 9 | 10 | namespace bun { 11 | // Delegate class using variadic templates 12 | template 13 | class BUN_COMPILER_DLLEXPORT Delegate 14 | { 15 | inline Delegate(std::function&& src) = delete; // Don't do Delegate([&](){ return; }) or it'll go out of scope. 16 | using RTYPE = R; 17 | typedef R(*FUNCTYPE)(void*, Args...); 18 | typedef RTYPE(*COREFUNC)(Args...); 19 | public: 20 | inline Delegate(const Delegate& copy) noexcept : _src(copy._src), _stub(copy._stub) {} 21 | inline Delegate(void* src, R(*stub)(void*, Args...)) noexcept : _src(src), _stub(stub) {} 22 | inline Delegate(std::function& src) noexcept : _src(&src), _stub(&StubLambda) {} 23 | inline Delegate() noexcept : _src(0), _stub(0) {} 24 | inline R operator()(Args ... args) const { return (*_stub)(_src, args...); } 25 | inline Delegate& operator=(const Delegate& right) noexcept { _src = right._src; _stub = right._stub; return *this; } 26 | inline bool IsEmpty() const noexcept { return _src == 0 || _stub == 0; } 27 | inline void* RawSource() const { return _src; } 28 | inline FUNCTYPE RawFunc() const { return _stub; } 29 | 30 | template 31 | inline static Delegate From(T* src) noexcept { return Delegate(src, &Stub); } 32 | template 33 | inline static Delegate From(const T* src) noexcept { return Delegate(const_cast(src), &StubConst); } 34 | template 35 | inline static Delegate FromC() noexcept { return Delegate(0, &StubStateless); } 36 | template 37 | inline static Delegate FromC(T* src) noexcept { return Delegate((void*)src, (FUNCTYPE)&StubC); } 38 | template 39 | inline static Delegate FromC(const T* src) noexcept { return Delegate(const_cast(src), &StubConstC); } 40 | 41 | template 42 | static R Stub(void* src, Args... args) { return (static_cast(src)->*F)(args...); } 43 | template 44 | static R StubConst(void* src, Args... args) { return (static_cast(src)->*F)(args...); } 45 | static R StubLambda(void* src, Args... args) { return (*static_cast*>(src))(args...); } 46 | template 47 | static R StubStateless(void* src, Args... args) { return (*F)(args...); } 48 | template 49 | static R StubC(void* src, Args... args) { return (*F)(static_cast(src), args...); } 50 | template 51 | static R StubConstC(void* src, Args... args) { return (*F)(static_cast(src), args...); } 52 | static R StubEmbed(void* src, Args... args) { return ((COREFUNC)src)(args...); } 53 | 54 | protected: 55 | void* _src; 56 | R(*_stub)(void*, Args...); 57 | }; 58 | 59 | template 60 | struct StoreFunction : std::tuple 61 | { 62 | inline StoreFunction(R(*f)(Args...), Args&&... args) : std::tuple(std::forward(args)...), _f(f) {} 63 | BUN_FORCEINLINE R Call() const { return _unpack(std::index_sequence_for{}); } 64 | BUN_FORCEINLINE R operator()() const { return Call(); } 65 | 66 | R(*_f)(Args...); 67 | 68 | private: 69 | template BUN_FORCEINLINE R _unpack(std::index_sequence) const { return _f(std::get(*this) ...); } 70 | }; 71 | 72 | template 73 | struct StoreDelegate : std::tuple 74 | { 75 | inline StoreDelegate(Delegate fn, Args&&... args) : std::tuple(std::forward(args)...), _fn(fn) {} 76 | BUN_FORCEINLINE R Call() const { return _unpack(std::index_sequence_for{}); } 77 | BUN_FORCEINLINE R operator()() const { return Call(); } 78 | 79 | Delegate _fn; 80 | 81 | private: 82 | template BUN_FORCEINLINE R _unpack(std::index_sequence) const { return _fn(std::get(*this) ...); } 83 | }; 84 | 85 | template 86 | struct DeferFunction : StoreFunction 87 | { 88 | inline DeferFunction(R(*f)(Args...), Args&&... args) : StoreFunction(f, std::forward(args)...) {} 89 | inline ~DeferFunction() { this->Call(); } 90 | }; 91 | 92 | template 93 | struct DeferDelegate : StoreDelegate 94 | { 95 | inline DeferDelegate(Delegate fn, Args&&... args) : StoreDelegate(fn, std::forward(args)...) {} 96 | inline ~DeferDelegate() { this->Call(); } 97 | }; 98 | 99 | template 100 | BUN_FORCEINLINE DeferDelegate defer(Delegate fn, Args&&... args) { return DeferDelegate(fn, std::forward(args)...); } 101 | template 102 | BUN_FORCEINLINE DeferFunction defer(R(*stub)(Args...), Args&&... args) { return DeferFunction(stub, std::forward(args)...); } 103 | } 104 | 105 | #endif 106 | -------------------------------------------------------------------------------- /include/buntils/GreedyBlockAlloc.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_ALLOC_GREEDY_BLOCK_H__ 5 | #define __BUN_ALLOC_GREEDY_BLOCK_H__ 6 | 7 | #include "Alloc.h" 8 | #include "buntils.h" 9 | 10 | namespace bun { 11 | // A simplified single-threaded greedy allocator specifically designed for high-speed block allocations. 12 | template 13 | class BUN_COMPILER_DLLEXPORT GreedyBlockPolicy 14 | { 15 | public: 16 | // Block Chunk Alloc 17 | BUN_ALIGN(alignof(T)) union Node 18 | { 19 | struct { 20 | size_t size; 21 | Node* next; 22 | }; 23 | char align[alignof(T)]; 24 | }; 25 | 26 | inline GreedyBlockPolicy(GreedyBlockPolicy&& mov) : _root(mov._root), _curpos(mov._curpos) 27 | { 28 | mov._root = 0; 29 | mov._curpos = 0; 30 | } 31 | inline explicit GreedyBlockPolicy(size_t init = 8) : _root(0), _curpos(0) 32 | { 33 | _allocChunk(init); 34 | } 35 | 36 | inline ~GreedyBlockPolicy() 37 | { 38 | Node* hold = _root; 39 | 40 | while((_root = hold)) 41 | { 42 | hold = hold->next; 43 | ALIGNEDFREE(_root); 44 | } 45 | } 46 | inline T* allocate(size_t sz, const T* ptr = 0, size_t old = 0) noexcept 47 | { 48 | assert(!ptr); 49 | sz = AlignSize(sz * sizeof(T), alignof(T)); 50 | #ifdef BUN_DISABLE_CUSTOM_ALLOCATORS 51 | return ALIGNEDALLOC(sz * sizeof(T), alignof(T)); 52 | #endif 53 | size_t r = _curpos; 54 | _curpos += sz; 55 | if(_curpos > _root->size) 56 | { 57 | _allocChunk(fbnext(_curpos)); 58 | r = 0; 59 | _curpos = sz; 60 | } 61 | T* p = reinterpret_cast(reinterpret_cast(_root + 1) + r); 62 | assert(!(reinterpret_cast(p) % alignof(T))); 63 | return p; 64 | } 65 | inline void deallocate(void* p, size_t num = 0) noexcept 66 | { 67 | #ifdef BUN_DISABLE_CUSTOM_ALLOCATORS 68 | ALIGNEDFREE(p); 69 | return; 70 | #endif 71 | #ifdef BUN_DEBUG 72 | Node* cur = _root; 73 | bool found = false; 74 | 75 | while(cur) 76 | { 77 | if(p >= reinterpret_cast(cur + 1) && p < (reinterpret_cast(cur + 1) + cur->size)) { found = true; break; } 78 | cur = cur->next; 79 | } 80 | 81 | assert(found); 82 | #endif 83 | } 84 | void Clear() noexcept 85 | { 86 | _curpos = 0; 87 | 88 | if(!_root->next) 89 | return; 90 | 91 | size_t nsize = 0; 92 | Node* hold; 93 | 94 | while(_root) 95 | { 96 | hold = _root->next; 97 | nsize += _root->size; 98 | ALIGNEDFREE(_root); 99 | _root = hold; 100 | } 101 | 102 | _allocChunk(nsize); //consolidates all memory into one chunk to try and take advantage of data locality 103 | } 104 | protected: 105 | BUN_FORCEINLINE void _allocChunk(size_t nsize) noexcept 106 | { 107 | nsize = AlignSize(nsize, sizeof(T)); 108 | nsize = AlignSize(nsize, alignof(T)); 109 | Node* retval = reinterpret_cast(ALIGNEDALLOC(sizeof(Node) + nsize, alignof(T))); 110 | assert(retval != 0); 111 | retval->next = _root; 112 | retval->size = nsize; 113 | assert(_prepDEBUG(retval)); 114 | _root = retval; 115 | } 116 | #ifdef BUN_DEBUG 117 | BUN_FORCEINLINE static bool _prepDEBUG(Node* root) noexcept 118 | { 119 | if(!root) return false; 120 | memset(reinterpret_cast(root + 1), 0xfd, root->size); 121 | return true; 122 | } 123 | #endif 124 | 125 | Node* _root; 126 | size_t _curpos; 127 | }; 128 | } 129 | 130 | #endif -------------------------------------------------------------------------------- /include/buntils/HighPrecisionTimer.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __HIGHPRECISIONTIMER_H__BUN__ 5 | #define __HIGHPRECISIONTIMER_H__BUN__ 6 | 7 | #include "defines.h" 8 | #include 9 | #ifndef BUN_PLATFORM_WIN32 10 | #include 11 | 12 | #ifdef _POSIX_MONOTONIC_CLOCK 13 | #ifdef CLOCK_MONOTONIC_RAW 14 | #define BUN_POSIX_CLOCK CLOCK_MONOTONIC_RAW 15 | #else 16 | #define BUN_POSIX_CLOCK CLOCK_MONOTONIC 17 | #endif 18 | #else 19 | #define BUN_POSIX_CLOCK CLOCK_REALTIME 20 | #endif 21 | 22 | #ifdef _POSIX_CPUTIME 23 | #define BUN_POSIX_CLOCK_PROFILER CLOCK_PROCESS_CPUTIME_ID 24 | #else 25 | #define BUN_POSIX_CLOCK_PROFILER BUN_POSIX_CLOCK 26 | #endif 27 | #endif 28 | 29 | namespace bun { 30 | // High precision timer class with nanosecond precision. 31 | class BUN_DLLEXPORT HighPrecisionTimer 32 | { 33 | public: 34 | // Starts the timer and takes an initial sample. If you want to reset the time or delta to zero later, call ResetTime() or ResetDelta() 35 | HighPrecisionTimer(const HighPrecisionTimer& copy) = default; 36 | HighPrecisionTimer(); 37 | // Resamples the timer, updating the current time and setting the delta to the difference between the last time and the current time. 38 | double Update(); 39 | // Resamples the timer, but warps the resulting increment by the timewarp argument 40 | double Update(double timewarp); 41 | // Updates the timer to prime it for the next update, but overrides the delta for this tick with a custom value. 42 | void Override(uint64_t nsdelta); 43 | void Override(double delta); 44 | // Gets the difference in milliseconds between the last call to Update() and the one before it. Does NOT resample the timer. 45 | inline double GetDelta() const { return _delta; } 46 | // Gets the delta in nanoseconds 47 | inline uint64_t GetDeltaNS() const { return _nsDelta; } 48 | // Gets the current time in milliseconds that has elapsed since the creation of the timer, or a call to ResetTime. 49 | inline double GetTime() const { return _time; } 50 | // Gets the current time that has elapsed in nanoseconds, as a precise 64-bit integer. 51 | inline uint64_t GetTimeNS() const { return _nsTime; } 52 | // Resets the time to 0 (preserves delta) 53 | inline void ResetTime() { _time = 0; _nsTime = 0; } 54 | // Resets the delta to 0, and resamples the timer. 55 | inline void ResetDelta() 56 | { 57 | _queryTime(&_curTime); 58 | _delta = 0; 59 | _nsDelta = 0; 60 | } 61 | 62 | HighPrecisionTimer& operator=(const HighPrecisionTimer&) = default; 63 | // Converts two nanosecond counts to seconds and returns the difference as a double. 64 | BUN_FORCEINLINE static double NanosecondDiff(uint64_t now, uint64_t old) { return (now - old) / 1000000000.0; } 65 | 66 | // Starts a profiler call 67 | BUN_FORCEINLINE static uint64_t OpenProfiler() 68 | { 69 | uint64_t ret; 70 | #ifdef BUN_PLATFORM_WIN32 71 | _queryTime(&ret); 72 | #else 73 | _queryTime(&ret, BUN_POSIX_CLOCK_PROFILER); 74 | #endif 75 | return ret; 76 | } 77 | // Closes a profiler and returns the number of nanoseconds that elapsed between the open and close function calls. 78 | BUN_FORCEINLINE static uint64_t CloseProfiler(uint64_t begin) 79 | { 80 | uint64_t compare; 81 | #ifdef BUN_PLATFORM_WIN32 82 | _queryTime(&compare); 83 | return ((compare - begin) * 1000000000) / _getFrequency(); //convert to nanoseconds 84 | #else 85 | _queryTime(&compare, BUN_POSIX_CLOCK_PROFILER); 86 | return compare - begin; 87 | #endif 88 | } 89 | 90 | protected: 91 | double _delta; // milliseconds 92 | double _time; // milliseconds 93 | uint64_t _curTime; 94 | uint64_t _nsTime; // total time passed in nanoseconds 95 | uint64_t _nsDelta; // Delta in nanoseconds; 96 | 97 | #ifdef BUN_PLATFORM_WIN32 98 | static void _queryTime(uint64_t* _pval); 99 | static uint64_t _getFrequency(); 100 | #else 101 | static void _queryTime(uint64_t* _pval, clockid_t clock = BUN_POSIX_CLOCK); 102 | #endif 103 | }; 104 | } 105 | 106 | #endif 107 | -------------------------------------------------------------------------------- /include/buntils/INIentry.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __INIENTRY_H__BUN__ 5 | #define __INIENTRY_H__BUN__ 6 | 7 | #include "Str.h" 8 | 9 | namespace bun { 10 | // Stores an INI entry and allows it to be accessed via multiple type translations 11 | struct BUN_DLLEXPORT INIentry 12 | { 13 | INIentry(const INIentry&) = default; 14 | INIentry(INIentry&&) = default; 15 | INIentry(); 16 | INIentry(const char* key, const char* svalue, int64_t ivalue, double dvalue); 17 | INIentry(const char* key, const char* data); 18 | ~INIentry(); 19 | void Set(const char* data); 20 | void SetInt(int64_t data); 21 | void SetFloat(double data); 22 | BUN_FORCEINLINE const char* GetKey() const { return _key; } 23 | //BUN_FORCEINLINE uint32_t GetIndex() const { return _index; } 24 | BUN_FORCEINLINE const char* GetString() const { return _svalue; } 25 | BUN_FORCEINLINE int64_t GetInt() const { return _ivalue; } 26 | BUN_FORCEINLINE double GetDouble() const { return _dvalue; } 27 | BUN_FORCEINLINE bool IsValid() const { return !_key.empty(); } 28 | 29 | BUN_FORCEINLINE operator bool() const { return _ivalue != 0; } 30 | BUN_FORCEINLINE operator char() const { return static_cast(_ivalue); } 31 | BUN_FORCEINLINE operator short() const { return static_cast(_ivalue); } 32 | BUN_FORCEINLINE operator int() const { return static_cast(_ivalue); } 33 | BUN_FORCEINLINE operator int64_t() const { return static_cast(_ivalue); } 34 | BUN_FORCEINLINE operator uint8_t() const { return static_cast(_ivalue); } 35 | BUN_FORCEINLINE operator uint16_t() const { return static_cast(_ivalue); } 36 | BUN_FORCEINLINE operator uint32_t() const { return static_cast(_ivalue); } 37 | BUN_FORCEINLINE operator uint64_t() const { return static_cast(_ivalue); } 38 | BUN_FORCEINLINE operator float() const { return static_cast(_dvalue); } 39 | BUN_FORCEINLINE operator double() const { return _dvalue; } 40 | BUN_FORCEINLINE operator const char*() const { return _svalue; } 41 | 42 | bool operator ==(INIentry &other) const; //these can't be inlined because the compare function is different. 43 | inline bool operator !=(INIentry &other) const { return !operator==(other); } 44 | INIentry& operator=(INIentry&&) = default; 45 | INIentry& operator=(const INIentry&) = default; 46 | inline INIentry& operator=(const char* s) { Set(s); return *this; } 47 | inline INIentry& operator=(int64_t s) { SetInt(s); return *this; } 48 | inline INIentry& operator=(double s) { SetFloat(s); return *this; } 49 | 50 | private: 51 | Str _key; 52 | Str _svalue; 53 | int64_t _ivalue; 54 | double _dvalue; 55 | }; 56 | } 57 | 58 | #endif 59 | -------------------------------------------------------------------------------- /include/buntils/INIparse.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __INIPARSE_H__BUN__ 5 | #define __INIPARSE_H__BUN__ 6 | 7 | #include "defines.h" 8 | #include 9 | #include 10 | 11 | #ifdef __cplusplus 12 | extern "C" { 13 | #endif 14 | 15 | #define MAXLINELENGTH 1024 16 | 17 | typedef struct { 18 | //const char* file; 19 | //const char* curloc; 20 | //const char* end; 21 | //unsigned int length; 22 | FILE* file; 23 | char* curvalue; 24 | char* curkey; 25 | char* cursection; 26 | char newsection; //set to 1 if a new section was found during parsing 27 | char buf[MAXLINELENGTH]; 28 | } INIParser; 29 | 30 | typedef struct { 31 | const void* start; 32 | const void* end; 33 | } INICHUNK; 34 | 35 | extern char bun_InitINI(INIParser* init, FILE* stream); 36 | extern char bun_DestroyINI(INIParser* destroy); 37 | extern char bun_ParseLine(INIParser* parse); 38 | extern INICHUNK bun_FindINISection(const void* data, size_t length, const char* section, size_t instance); 39 | extern INICHUNK bun_FindINIEntry(INICHUNK section, const char* key, size_t instance); 40 | 41 | #ifdef __cplusplus 42 | } 43 | #endif 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/buntils/INIsection.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __INISECTION_H__BUN__ 5 | #define __INISECTION_H__BUN__ 6 | 7 | #include "INIentry.h" 8 | #include "Hash.h" 9 | #include "Array.h" 10 | #include "LLBase.h" 11 | #include "BlockAllocMT.h" 12 | 13 | namespace bun { 14 | class INIstorage; 15 | 16 | // Stores an INI section, denoted by [name], as a linked list of entries, also stored as a hash for O(1) time operations. 17 | class BUN_DLLEXPORT INIsection 18 | { 19 | public: 20 | // Internal INI linked list node 21 | template 22 | struct BUN_COMPILER_DLLEXPORT _INInode : public LLBase<_INInode> 23 | { 24 | Array<_INInode*> instances; // If this is not the only instance, points to an array of all the other instances 25 | T val; 26 | }; 27 | 28 | using _NODE = _INInode; 29 | template 30 | struct INIiterator : LLIterator<_INInode> { 31 | using LLIterator<_INInode>::cur; 32 | inline explicit INIiterator(_INInode* node) : LLIterator<_INInode>(node) {} 33 | inline T& operator*() const { return cur->val; } 34 | inline T* operator->() const { return &cur->val; } 35 | }; 36 | 37 | // Constructors 38 | INIsection(const INIsection& copy); 39 | INIsection(INIsection&& mov); 40 | INIsection(); 41 | INIsection(const char* name, INIstorage* parent, size_t index); 42 | // Destructors 43 | ~INIsection(); 44 | // Gets the specified key with the given index. On failure returns an empty sentinel reference 45 | INIentry& GetEntry(const char* key, size_t instance = 0) const; 46 | // Gets the specified key with the given index. Returns null on failure. 47 | INIentry* GetEntryPtr(const char* key, size_t instance = 0) const; 48 | // Gets number of entries with the given name 49 | size_t GetNumEntries(const char* section) const; 50 | // Gets the specified key node for iteration with the given index. Returns null on failure. 51 | _NODE* GetEntryNode(const char* key, size_t instance = 0) const; 52 | // Changes the specified entry data with the given index, if data is nullptr the entry is deleted. if instance is -1 the entry is inserted. 53 | inline char EditEntry(const char* key, const char* data, size_t instance = 0); 54 | // Gets the root node of the section linked list 55 | inline const _NODE* Front() const { return _root; } 56 | // Gets the last node of the section linked list 57 | inline const _NODE* Back() const { return _last; } 58 | // Iterators for standard containers 59 | inline INIiterator begin() { return INIiterator(_root); } 60 | inline INIiterator end() { return INIiterator(0); } 61 | 62 | BUN_FORCEINLINE INIstorage* GetParent() const { return _parent; } 63 | BUN_FORCEINLINE const char* GetName() const { return _name; } 64 | BUN_FORCEINLINE size_t GetIndex() const { return _index; } 65 | 66 | BUN_FORCEINLINE INIentry& operator[](const char* key) const { return GetEntry(key, 0); } 67 | INIsection& operator=(const INIsection& right); 68 | INIsection& operator=(INIsection&& mov); 69 | 70 | protected: 71 | friend class INIstorage; 72 | 73 | void _destroy(); 74 | void _addEntry(const char* key, const char* data); 75 | void _copy(const INIsection& copy); 76 | 77 | static INIentry _entrysentinel; 78 | static LocklessBlockPolicy<_NODE> _alloc; 79 | 80 | Str _name; 81 | size_t _index; 82 | _NODE* _root; 83 | _NODE* _last; 84 | HashIns _entries; 85 | INIstorage* _parent; 86 | }; 87 | } 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /include/buntils/INIstorage.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __INISTORAGE_H__BUN__ 5 | #define __INISTORAGE_H__BUN__ 6 | 7 | #include "INIsection.h" 8 | 9 | namespace bun { 10 | // Stores an INI file as a linked list of sections, also stored via hash for O(1) time operations. 11 | class BUN_DLLEXPORT INIstorage 12 | { 13 | public: 14 | using _NODE = INIsection::_INInode; 15 | 16 | // Constructors 17 | INIstorage(const INIstorage& copy); 18 | INIstorage(INIstorage&& mov); 19 | INIstorage(const char* file = 0, std::ostream* logger = 0); 20 | INIstorage(FILE* file, std::ostream* logger = 0); 21 | // Destructor 22 | ~INIstorage(); 23 | // Gets a section based on name and instance 24 | INIsection* GetSection(const char* section, size_t instance = 0) const; 25 | // Gets number of sections with the given name 26 | size_t GetNumSections(const char* section) const; 27 | // Gets a section node based on name and instance 28 | _NODE* GetSectionNode(const char* section, size_t instance = 0) const; 29 | // Gets a convertable INI entry 30 | INIentry* GetEntryPtr(const char *section, const char* key, size_t keyinstance = 0, size_t secinstance = 0) const; 31 | // Gets an INI entry node for iteration 32 | INIsection::_NODE* GetEntryNode(const char *section, const char* key, size_t keyinstance = 0, size_t secinstance = 0) const; 33 | // Gets the root node of the section linked list 34 | inline const _NODE* Front() const { return _root; } 35 | // Gets the last node of the section linked list 36 | inline const _NODE* Back() const { return _last; } 37 | // iterators for standard containers 38 | inline INIsection::INIiterator begin() { return INIsection::INIiterator(_root); } 39 | inline INIsection::INIiterator end() { return INIsection::INIiterator(0); } 40 | 41 | INIsection& AddSection(const char* name); 42 | bool RemoveSection(const char* name, size_t instance = 0); 43 | char EditEntry(const char* section, const char* key, const char* nvalue = 0, size_t keyinstance = 0, size_t secinstance = 0); //if nvalue is 0 the entry is deleted. if either instance is -1 it triggers an insert 44 | inline char EditAddEntry(const char* section, const char* key, const char* nvalue = 0, size_t keyinstance = 0, size_t secinstance = 0) { return EditEntry(section, key, nvalue, GetEntryPtr(section, key, keyinstance, secinstance) == 0 ? -1 : keyinstance, GetSection(section, secinstance) == 0 ? -1 : secinstance); } 45 | void EndINIEdit(const char* overridepath = 0); //Saves changes to file (INI files are automatically opened when an edit operation is done) 46 | void DiscardINIEdit(); 47 | 48 | BUN_FORCEINLINE INIsection& operator [](const char *section) const { INIsection* ret = GetSection(section, 0); return !ret ? _sectionsentinel : *ret; } 49 | INIstorage& operator=(const INIstorage& right); 50 | INIstorage& operator=(INIstorage&& mov); 51 | inline const char* GetPath() const { return _path; } //gets path to folder this INI was in 52 | inline INIentry& GetEntry(const char *section, const char* key, size_t keyinstance = 0, size_t secinstance = 0) const { INIentry* ret = GetEntryPtr(section, key, keyinstance, secinstance); return !ret ? INIsection::_entrysentinel : *ret; } 53 | void DEBUGTEST() 54 | { 55 | for(auto[k,v] : _sections) 56 | { 57 | auto& p = v->instances; 58 | assert(!p.Capacity() == !p.begin()); 59 | } 60 | } 61 | 62 | protected: 63 | friend class INIsection; 64 | 65 | void _loadINI(FILE* file); 66 | void _openINI(); 67 | void _setFilePath(const char* path); 68 | INIsection* _addSection(const char* name); 69 | void _copy(const INIstorage& copy); 70 | void _destroy(); 71 | 72 | static INIsection _sectionsentinel; 73 | static LocklessBlockPolicy<_NODE> _alloc; 74 | 75 | HashIns _sections; 76 | Str _path; //holds path to INI 77 | Str _filename; //holds INI filename; 78 | Str* _ini; //holds entire INI file. Made a pointer so we can distinguish between an empty INI file and an unopened file. 79 | std::ostream* _logger; //Holds a pointer to a logger object 80 | _NODE* _root; 81 | _NODE* _last; 82 | }; 83 | } 84 | 85 | #endif 86 | -------------------------------------------------------------------------------- /include/buntils/Logger.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_LOG_H__ 5 | #define __BUN_LOG_H__ 6 | 7 | #include "buntils.h" 8 | #include "Array.h" 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #define BUNLOG(logger,level,...) ((logger).Log(0,__FILE__,__LINE__,(level),__VA_ARGS__)) 16 | 17 | namespace bun { 18 | class StreamSplitter; 19 | 20 | // Log class that can be converted into a stream and redirected to various different stream targets 21 | class BUN_DLLEXPORT Logger 22 | { 23 | Logger(const Logger& copy) = delete; 24 | Logger& operator=(const Logger& right) = delete; 25 | 26 | public: 27 | // Move semantics only 28 | Logger(Logger&& mov); 29 | // Constructor - takes a stream and adds it 30 | explicit Logger(std::ostream* log = 0); 31 | // Constructor - takes either a stream or a file (or both) and adds them 32 | explicit Logger(const char* logfile, std::ostream* log = 0); 33 | #ifdef BUN_PLATFORM_WIN32 34 | Logger(const wchar_t* logfile, std::ostream* log); 35 | #endif 36 | // Destructor - destroys any file streams 37 | ~Logger(); 38 | // Redirects an existing stream to write to this log's buffer 39 | void Assimilate(std::ostream& stream); 40 | // Adds a target stream to post logs to 41 | void AddTarget(std::ostream& stream); 42 | //void AddTarget(std::wostream& stream); 43 | void AddTarget(const char* file); 44 | #ifdef BUN_PLATFORM_WIN32 45 | void AddTarget(const wchar_t* file); 46 | #endif 47 | // Sets the format for the beginning of the log entry. Defaults to "[{4}] {0} ({1}:{2}) {3}" 48 | void SetFormat(const char* format); 49 | // An optional format for log entries with a null source. Defaults to "[{4}] ({1}:{2}) {3}" 50 | void SetNullFormat(const char* format); 51 | // Clears all targets and closes all files 52 | void ClearTargets(); 53 | // Gets the stream for this log 54 | inline std::ostream& GetStream() { return _stream; } 55 | // Sets a level string (which should be a constant, not something that will get deallocated) 56 | void SetLevel(uint8_t level, const char* str); 57 | // Sets the maximum level that will be logged. Useful for excluding unnecessary debug logs from release builds 58 | void SetMaxLevel(uint8_t level); 59 | 60 | Logger& operator=(Logger&& right); 61 | inline operator std::ostream&() { return _stream; } 62 | 63 | inline int PrintLog(const char* source, const char* file, size_t line, int8_t level, const char* format, ...) 64 | { 65 | va_list vl; 66 | va_start(vl, format); 67 | int r = PrintLogV(source, file, line, level, format, vl); 68 | va_end(vl); 69 | return r; 70 | } 71 | int PrintLogV(const char* source, const char* file, size_t line, int8_t level, const char* format, va_list args); 72 | 73 | template 74 | BUN_FORCEINLINE void Log(const char* source, const char* file, size_t line, int8_t level, Args... args) 75 | { 76 | if(level >= _maxlevel) 77 | return; 78 | _writeLog(LogHeader(source, file, line, level), args...); 79 | } 80 | template 81 | BUN_FORCEINLINE void LogFormat(const char* source, const char* file, size_t line, int8_t level, const char* format, Args... args) 82 | { 83 | if(level >= _maxlevel) 84 | return; 85 | 86 | std::vformat_to(std::ostream_iterator(LogHeader(source, file, line, level)), format, std::make_format_args(source, file, line, level, _tz)); 87 | _stream << std::endl; 88 | } 89 | BUN_FORCEINLINE std::ostream& LogHeader(const char* source, const char* file, size_t line, int8_t level) 90 | { 91 | assert(level < _levels.Capacity()); 92 | return _logHeader(source, file, line, (level < 0) ? "" : _levels[level]); 93 | } 94 | static const char* _trimPath(const char* path); 95 | 96 | static const char* DEFAULTFORMAT; 97 | static const char* DEFAULTNULLFORMAT; 98 | 99 | protected: 100 | template 101 | static inline void _writeLog(std::ostream& o, Arg arg, Args... args) { o << arg; _writeLog(o, args...); } 102 | static inline void _writeLog(std::ostream& o) { o << std::endl; } 103 | std::ostream& _logHeader(const char* source, const char* file, size_t line, const char* level); 104 | static void _header(std::ostream& o, int n, const char* source, const char* file, size_t line, const char* level, long tz); 105 | static bool _writeDateTime(long timezone, std::ostream& log, bool timeonly); 106 | void _levelDefaults(); 107 | 108 | Array _levels; 109 | int8_t _maxlevel; 110 | StreamSplitter* _split; 111 | const char* _format; 112 | const char* _nullformat; 113 | long _tz; 114 | #pragma warning(push) 115 | #pragma warning(disable:4251) 116 | std::vector> _backup; 117 | std::ostream _stream; 118 | 119 | #ifdef BUN_COMPILER_GCC // Until GCC fixes its fucking broken standard implementation, we're going to have to do this the hard way. 120 | std::vector> _files; 121 | #else 122 | std::vector _files; 123 | #endif 124 | #pragma warning(pop) 125 | }; 126 | } 127 | 128 | #endif 129 | -------------------------------------------------------------------------------- /include/buntils/Map.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __MAP_H__BUN__ 5 | #define __MAP_H__BUN__ 6 | 7 | #include "ArraySort.h" 8 | #include 9 | 10 | namespace bun { 11 | // A map class implemented as an associative sorted array 12 | template, 15 | typename CType = size_t, 16 | typename Alloc = StandardAllocator>> 17 | class BUN_COMPILER_DLLEXPORT Map : protected ArraySort, &CompTuple, 0, CFunc>, CType, Alloc> 18 | { 19 | protected: 20 | using pair_t = std::tuple; 21 | using BASE = ArraySort, CType, Alloc>; 22 | using constref = const Data&; 23 | using CKEYREF = const Key&; 24 | using BASE::_array; 25 | using CT = typename BASE::CT; 26 | using Ty = typename BASE::Ty; 27 | 28 | public: 29 | explicit Map(CT init, const Alloc& alloc) : BASE(init, alloc) {} 30 | explicit Map(CT init = 1) : BASE(init) {} 31 | Map(const Map& copy) = default; 32 | Map(Map&& mov) = default; 33 | //~Map() {} 34 | BUN_FORCEINLINE void Clear() { BASE::Clear(); } 35 | BUN_FORCEINLINE void Discard(CT num) { BASE::Discard(num); } 36 | BUN_FORCEINLINE CT Insert(CKEYREF key, constref data) { return BASE::Insert(pair_t(key, data)); } 37 | BUN_FORCEINLINE CT Insert(CKEYREF key, Data&& data) { return BASE::Insert(pair_t(key, std::move(data))); } 38 | inline CT Get(CKEYREF key) const 39 | { 40 | CT retval = GetNear(key, true); 41 | return (retval != (CT)(-1) && !CFunc(key, std::get<0>(_array[retval]))) ? retval : (CT)(-1); 42 | } 43 | inline constref GetData(CKEYREF key) const { return DataIndex(GetNear(key, true)); } //this has no checking 44 | inline constref DataIndex(CT index) const { return std::get<1>(_array[index]); } 45 | inline CKEYREF KeyIndex(CT index) const { return std::get<0>(_array[index]); } 46 | inline CT Remove(CKEYREF key) { CT retval = Get(key); BASE::Remove(retval); return retval; } 47 | BUN_FORCEINLINE CT RemoveIndex(CT index) { return BASE::Remove(index); } 48 | BUN_FORCEINLINE CT Replace(CT index, CKEYREF key, constref data) { return BASE::ReplaceData(index, pair_t(key, data)); } 49 | BUN_FORCEINLINE CT Replace(CT index, CKEYREF key, Data&& data) { return BASE::ReplaceData(index, pair_t(key, std::move(data))); } 50 | inline CT ReplaceKey(CT index, CKEYREF key) 51 | { 52 | if(index < 0 || index >= Length()) 53 | return (CT)(-1); 54 | return BASE::ReplaceData(index, pair_t(key, std::get<1>(_array[index]))); 55 | } 56 | BUN_FORCEINLINE CT Length() const { return BASE::Length(); } 57 | BUN_FORCEINLINE void Expand(CT size) { BASE::Expand(size); } 58 | inline CT Set(CKEYREF key, constref data) 59 | { 60 | CT retval = GetNear(key, true); 61 | if(retval != (CT)(-1)) 62 | { 63 | auto&[k, v] = _array[retval]; 64 | if(!CFunc(key, k)) 65 | v = data; 66 | } 67 | return retval; 68 | } 69 | BUN_FORCEINLINE static char mapComp(const Key& a, const pair_t& b) { return CFunc(a, std::get<0>(b)); } 70 | CT GetNear(CKEYREF key, bool before) const 71 | { 72 | CT retval = before ? (BinarySearchNear, -1>(_array.begin(), key, 0, Length()) - 1) : BinarySearchNear, 1>(_array.begin(), key, 0, Length()); 73 | return (retval < Length()) ? retval : (CT)(-1); // This is only needed for before=false in case it returns a value outside the range. 74 | } 75 | inline const pair_t* begin() const { return _array.begin(); } 76 | inline const pair_t* end() const { return _array.end(); } 77 | inline pair_t* begin() { return _array.begin(); } 78 | inline pair_t* end() { return _array.end(); } 79 | inline const pair_t& Front() const { return _array.Front(); } 80 | inline pair_t& Front() { return _array.Front(); } 81 | inline const pair_t& Back() const { return _array.Back(); } 82 | inline pair_t& Back() { return _array.Back(); } 83 | inline CT size() const noexcept { return _array.size(); } 84 | inline pair_t* data() noexcept { return _array.data(); } 85 | inline const pair_t* data() const noexcept { return _array.data(); } 86 | 87 | inline Map& operator =(const Map& right) = default; 88 | inline Map& operator =(Map&& right) = default; 89 | inline const pair_t& operator [](CT index) const { return _array[index]; } 90 | inline pair_t& operator [](CT index) { return _array[index]; } 91 | inline constref operator ()(CT index) const { return std::get<1>(_array[index]); } 92 | inline Data& operator ()(CT index) { return std::get<1>(_array[index]); } 93 | 94 | using BASE::SerializerArray; 95 | template 96 | void Serialize(Serializer& s, const char* id) { BASE::template Serialize(s, id); } 97 | }; 98 | } 99 | 100 | #endif -------------------------------------------------------------------------------- /include/buntils/PriorityQueue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __PRIORITY_QUEUE_H__BUN__ 5 | #define __PRIORITY_QUEUE_H__BUN__ 6 | 7 | #include "BinaryHeap.h" 8 | 9 | namespace bun { 10 | // PriorityQueue that can be implemented as either a maxheap or a minheap 11 | template, 14 | typename CT_ = size_t, 15 | typename Alloc = StandardAllocator>> 16 | class BUN_COMPILER_DLLEXPORT PriorityQueue : protected BinaryHeap, CT_, CompTFirst, Alloc> 17 | { 18 | using PAIR = std::pair; 19 | using BASE = BinaryHeap, CT_, CompTFirst, Alloc>; 20 | 21 | public: 22 | PriorityQueue(const PriorityQueue& copy) = default; 23 | PriorityQueue(PriorityQueue&& mov) = default; 24 | explicit PriorityQueue(const Alloc& alloc) : BASE(alloc) {} 25 | PriorityQueue() {} 26 | ~PriorityQueue() {} 27 | BUN_FORCEINLINE void Push(const K& key, D value) { BASE::Insert(PAIR(key, value)); } 28 | BUN_FORCEINLINE void Push(K&& key, D value) { BASE::Insert(PAIR(std::move(key), value)); } 29 | BUN_FORCEINLINE const PAIR& Peek() { return BASE::Peek(); } 30 | BUN_FORCEINLINE void Discard() { BASE::Remove(0); } 31 | BUN_FORCEINLINE PAIR Pop() { return std::move(BASE::Pop()); } 32 | BUN_FORCEINLINE bool Empty() { return BASE::Empty(); } 33 | BUN_FORCEINLINE const PAIR& Get(CT_ index) { return BASE::Get(index); } 34 | BUN_FORCEINLINE bool Remove(CT_ index) { return BASE::Remove(index); } 35 | BUN_FORCEINLINE void Clear() { BASE::Clear(); } 36 | inline CT_ Length() { return BASE::_length; } 37 | 38 | inline PriorityQueue& operator=(const PriorityQueue& copy) = default; 39 | inline PriorityQueue& operator=(PriorityQueue&& mov) = default; 40 | 41 | using BASE::SerializerArray; 42 | template 43 | void Serialize(Serializer& s, const char* id) { BASE::template Serialize(s, id); } 44 | }; 45 | 46 | namespace internal { 47 | template 48 | struct MFUNC_PRIORITY { 49 | BUN_FORCEINLINE static void MFunc(const T& item, CT_ i, MFUNC_PRIORITY* p) { p->_subarray[item.first] = i; } 50 | Array _subarray; 51 | }; 52 | } 53 | 54 | template, 57 | typename Alloc = StandardAllocator>> 58 | class BUN_COMPILER_DLLEXPORT PriorityHeap : protected BinaryHeap, CT_, CompTSecond, Alloc, internal::MFUNC_PRIORITY, CT_>> 59 | { 60 | using PAIR = std::pair; 61 | using BASE = BinaryHeap, CT_, CompTSecond, Alloc, internal::MFUNC_PRIORITY, CT_>>; 62 | using BASE::_subarray; 63 | 64 | public: 65 | PriorityHeap(const PriorityHeap& copy) : BASE(copy), _freelist(copy._freelist) { _subarray = copy._subarray; } 66 | PriorityHeap(PriorityHeap&& mov) : BASE(std::move(mov)), _freelist(mov._freelist) { _subarray = std::move(mov._subarray); } 67 | explicit PriorityHeap(const Alloc& alloc) : BASE(alloc), _freelist((CT_)-1) {} 68 | PriorityHeap() : _freelist((CT_)-1) {} 69 | ~PriorityHeap() {} 70 | BUN_FORCEINLINE CT_ Push(const D& value) { CT_ k = _getNext(); BASE::Insert(PAIR(k, value)); return k; } 71 | BUN_FORCEINLINE CT_ Push(D&& value) { CT_ k = _getNext(); BASE::Insert(PAIR(k, std::move(value))); return k; } 72 | BUN_FORCEINLINE const D& Peek() { return BASE::Peek().second; } 73 | BUN_FORCEINLINE void Discard() { BASE::Remove(0); } 74 | BUN_FORCEINLINE D Pop() { return BASE::Pop().second; } 75 | BUN_FORCEINLINE bool Empty() { return BASE::Empty(); } 76 | BUN_FORCEINLINE const D& Get(CT_ key) { return BASE::Get(_subarray[key]).second; } 77 | BUN_FORCEINLINE bool Remove(CT_ key) { return BASE::Remove(_subarray[key]); } 78 | BUN_FORCEINLINE bool Set(CT_ key, const D& value) { return BASE::Set(_subarray[key], PAIR(key, value)); } 79 | BUN_FORCEINLINE bool Set(CT_ key, D&& value) { return BASE::Set(_subarray[key], PAIR(key, std::move(value))); } 80 | BUN_FORCEINLINE void Clear() { BASE::Clear(); } 81 | inline CT_ Length() { return BASE::_length; } 82 | 83 | inline PriorityHeap& operator=(const PriorityHeap& copy) 84 | { 85 | BASE::operator=(copy); 86 | _freelist = copy._freelist; 87 | return *this; 88 | } 89 | inline PriorityHeap& operator=(PriorityHeap&& mov) 90 | { 91 | BASE::operator=(std::move(mov)); 92 | _freelist = mov._freelist; 93 | return *this; 94 | } 95 | 96 | using BASE::SerializerArray; 97 | template 98 | void Serialize(Serializer& s, const char* id) { BASE::template Serialize(s, id); } 99 | 100 | protected: 101 | CT_ _getNext() 102 | { 103 | if(_freelist == (CT_)-1) 104 | { 105 | CT_ size = _subarray.Capacity(); 106 | _subarray.SetCapacity(fbnext(size)); 107 | _initFreeList(size); 108 | } 109 | 110 | CT_ r = _freelist; 111 | _freelist = _subarray[r]; 112 | return r; 113 | } 114 | void _initFreeList(CT_ start) 115 | { 116 | for(CT_ i = start; i < _subarray.Capacity(); ++i) 117 | { 118 | _subarray[i] = _freelist; 119 | _freelist = i; 120 | } 121 | } 122 | 123 | CT_ _freelist; 124 | }; 125 | } 126 | 127 | #endif 128 | -------------------------------------------------------------------------------- /include/buntils/Profiler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __PROFILER_H__BUN__ 5 | #define __PROFILER_H__BUN__ 6 | 7 | #include "HighPrecisionTimer.h" 8 | #include "Array.h" 9 | #include "BlockAlloc.h" 10 | #include 11 | 12 | #ifndef BUN_ENABLE_PROFILER 13 | #define PROFILE_BEGIN(name) 14 | #define PROFILE_END(name) 15 | #define PROFILE_BLOCK(name) 16 | #define PROFILE_FUNC() 17 | #define PROFILE_OUTPUT(file,output) 18 | #else 19 | #define __PROFILE_STATBLOCK(name,str) static bun::Profiler::ProfilerData PROFDATA_##name(str,__FILE__,__LINE__) 20 | #define __PROFILE_ZONE(name) bun::ProfilerBlock BLOCK_##name(PROFDATA_##name .id, bun::Profiler::profiler.GetCur()) 21 | #define PROFILE_BEGIN(name) __PROFILE_STATBLOCK(name, TXT(name)); bun::Profiler::PROF_TRIENODE* PROFCACHE_##name = bun::Profiler::profiler.GetCur(); uint64_t PROFTIME_##name = bun::Profiler::profiler.StartProfile(PROFDATA_##name .id) 22 | #define PROFILE_END(name) bun::Profiler::profiler.EndProfile(PROFTIME_##name, PROFCACHE_##name) 23 | #define PROFILE_BLOCK(name) __PROFILE_STATBLOCK(name, TXT(name)); __PROFILE_ZONE(name); 24 | #define PROFILE_FUNC() __PROFILE_STATBLOCK(func, __FUNCTION__); __PROFILE_ZONE(func) 25 | #define PROFILE_OUTPUT(file,output) bun::Profiler::profiler.WriteToFile(file,output) 26 | #endif 27 | 28 | namespace bun { 29 | namespace internal { 30 | struct PROF_HEATNODE; 31 | struct PROF_FLATOUT; 32 | } 33 | 34 | struct BUN_DLLEXPORT Profiler 35 | { 36 | typedef uint16_t ProfilerInt; 37 | 38 | struct PROF_TRIENODE 39 | { 40 | PROF_TRIENODE* _children[16]; 41 | double avg; 42 | double codeavg; 43 | //double variance; 44 | uint64_t total; // If total is -1 this isn't a terminating node 45 | uint64_t inner; 46 | }; 47 | 48 | struct ProfilerData 49 | { 50 | const char* name; 51 | const char* file; 52 | size_t line; 53 | ProfilerInt id; 54 | 55 | inline ProfilerData(const char* Name, const char* File, size_t Line) : name(Name), file(File), line(Line), id(++total) 56 | { 57 | Profiler::profiler.AddData(id, this); 58 | } 59 | }; 60 | 61 | BUN_FORCEINLINE uint64_t StartProfile(ProfilerInt id) 62 | { 63 | PROF_TRIENODE** r = &_cur; 64 | 65 | while(id > 0) 66 | { 67 | r = &(*r)->_children[id % 16]; 68 | id = (id >> 4); 69 | if(!*r) 70 | *r = _allocNode(); 71 | } 72 | 73 | _cur = *r; 74 | if(_cur->total == (uint64_t)-1) 75 | _cur->total = 0; 76 | _cur->inner = 0; 77 | return HighPrecisionTimer::OpenProfiler(); 78 | } 79 | BUN_FORCEINLINE void EndProfile(uint64_t time, PROF_TRIENODE* old) 80 | { 81 | time = HighPrecisionTimer::CloseProfiler(time); 82 | _cur->avg = bun_Avg(_cur->avg, (double)time, ++_cur->total); 83 | _cur->codeavg = bun_Avg(_cur->codeavg, (double)(time - _cur->inner), _cur->total); 84 | _cur = old; 85 | _cur->inner += time; 86 | } 87 | BUN_FORCEINLINE PROF_TRIENODE* GetRoot() { return _trie; } 88 | BUN_FORCEINLINE PROF_TRIENODE* GetCur() { return _cur; } 89 | void AddData(ProfilerInt id, ProfilerData* p); 90 | enum OUTPUT_DATA : uint8_t { OUTPUT_FLAT = 1, OUTPUT_TREE = 2, OUTPUT_HEATMAP = 4, OUTPUT_ALL = 1 | 2 | 4 }; 91 | void WriteToFile(const char* s, uint8_t output); 92 | void WriteToStream(std::ostream& stream, uint8_t output); 93 | 94 | static Profiler profiler; 95 | static const ProfilerInt BUFSIZE = 4096; 96 | 97 | private: 98 | Profiler(); 99 | PROF_TRIENODE* _allocNode(); 100 | void _treeOut(std::ostream& stream, PROF_TRIENODE* node, ProfilerInt id, size_t level, ProfilerInt idlevel); 101 | void _heatOut(internal::PROF_HEATNODE& heat, PROF_TRIENODE* node, ProfilerInt id, ProfilerInt idlevel); 102 | void _heatWrite(std::ostream& stream, internal::PROF_HEATNODE& node, size_t level, double max); 103 | double _heatFindMax(internal::PROF_HEATNODE& heat); 104 | static void _flatOut(internal::PROF_FLATOUT* avg, PROF_TRIENODE* node, ProfilerInt id, ProfilerInt idlevel); 105 | static const char* _trimPath(const char* path); 106 | static void _timeFormat(std::ostream& stream, double avg, double variance, uint64_t num); 107 | static ProfilerInt total; 108 | 109 | Array _data; 110 | PROF_TRIENODE* _trie; 111 | PROF_TRIENODE* _cur; 112 | BlockPolicy _alloc; 113 | size_t _totalnodes; 114 | }; 115 | 116 | inline static bool __DEBUG_VERIFY(Profiler::PROF_TRIENODE* node) 117 | { 118 | if(!node) 119 | return true; 120 | 121 | if(!std::isfinite(node->avg) || !std::isfinite(node->codeavg)) 122 | return false; 123 | 124 | for(int i = 0; i < 16; ++i) 125 | if(!__DEBUG_VERIFY(node->_children[i])) 126 | return false; 127 | 128 | return true; 129 | } 130 | 131 | struct ProfilerBlock 132 | { 133 | BUN_FORCEINLINE ProfilerBlock(Profiler::ProfilerInt id, Profiler::PROF_TRIENODE* cache) : _cache(cache), _time(Profiler::profiler.StartProfile(id)) {} 134 | BUN_FORCEINLINE ~ProfilerBlock() { Profiler::profiler.EndProfile(_time, _cache); } 135 | Profiler::PROF_TRIENODE* _cache; 136 | uint64_t _time; 137 | }; 138 | } 139 | 140 | #endif 141 | -------------------------------------------------------------------------------- /include/buntils/Queue.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_QUEUE_H__ 5 | #define __BUN_QUEUE_H__ 6 | 7 | #include "ArrayCircular.h" 8 | 9 | namespace bun { 10 | // Fast, tiny circular array-based queue. Pop and Peek are only valid if there is an item in the stack; this check must be done by the user. 11 | template> 12 | class BUN_COMPILER_DLLEXPORT Queue : protected ArrayCircular 13 | { 14 | protected: 15 | using BASE = ArrayCircular; 16 | using BASE::_length; 17 | 18 | public: 19 | inline Queue(const Queue& copy) = default; 20 | inline Queue(Queue&& mov) = default; 21 | inline Queue(CType init, const Alloc& alloc) : BASE(init, alloc) {} 22 | inline explicit Queue(CType init = 0) : BASE(init) {} 23 | inline ~Queue() {} 24 | // Pushes a value into the queue in FIFO order. 25 | BUN_FORCEINLINE void Push(const T& value) { _push(value); } 26 | BUN_FORCEINLINE void Push(T&& value) { _push(std::move(value)); } 27 | // Pops a value out of the queue in FIFO order. If there is no value to pop, calling this is illegal and will crash. 28 | BUN_FORCEINLINE T Pop() { assert(_length != 0); return BASE::PopBack(); } 29 | // Peeks at the value at the top of the queue but does not remove it. If there is no value, this is an illegal call. 30 | BUN_FORCEINLINE T& Peek() { assert(_length != 0); return BASE::Back(); } 31 | BUN_FORCEINLINE const T& Peek() const { assert(_length != 0); return BASE::Back(); } 32 | BUN_FORCEINLINE void Discard() { --_length; } 33 | // Returns true if there are no values in the queue (indicating that Pop() and Peek() cannot be called) 34 | BUN_FORCEINLINE bool Empty() { return !_length; } 35 | BUN_FORCEINLINE void Clear() { BASE::Clear(); } 36 | // Returns the underlying capacity of the circular array 37 | BUN_FORCEINLINE CType Capacity() const { return BASE::Capacity(); } 38 | // Returns how many items are currently in the queue. Calling Pop or Peek when this is 0 is illegal. 39 | BUN_FORCEINLINE CType Length() const { return _length; } 40 | 41 | inline Queue& operator=(const Queue& copy) = default; 42 | inline Queue& operator=(Queue&& mov) = default; 43 | 44 | using BASE::SerializerArray; 45 | template 46 | void Serialize(Serializer& s, const char* id) { BASE::template Serialize(s, id); } 47 | 48 | protected: 49 | template 50 | void _push(U && value) 51 | { 52 | if(_length >= BASE::_capacity) 53 | BASE::SetCapacity(T_FBNEXT(_length)); 54 | BASE::_push(std::forward(value)); 55 | } 56 | }; 57 | } 58 | 59 | #endif 60 | -------------------------------------------------------------------------------- /include/buntils/RefCounter.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __REFCOUNTER_H__BUN__ //These are used in case this header file is used by two different projects dependent on each other, resulting in duplicates which cannot be differentiated by #pragma once 5 | #define __REFCOUNTER_H__BUN__ 6 | 7 | #include "compiler.h" 8 | #include 9 | 10 | namespace bun { 11 | // A reference counter class that is entirely inline 12 | class BUN_COMPILER_DLLEXPORT RefCounter 13 | { 14 | public: 15 | // Increments and returns the reference counter 16 | BUN_FORCEINLINE int Grab() noexcept { return ++_refs; } 17 | BUN_FORCEINLINE int Grab(int num) noexcept { return _refs += num; } 18 | // Decrements the reference counter and calls delete this; if it is equal to or less then 0 19 | BUN_FORCEINLINE int Drop() 20 | { 21 | assert(_refs > 0); 22 | 23 | if(--_refs > 0) 24 | return _refs; 25 | 26 | DestroyThis(); 27 | return 0; 28 | } 29 | 30 | protected: 31 | // Constructor - Reference is set to 0 because you may or may not have a persistent reference to this, or something else will try to grab it or whatever 32 | inline RefCounter() { _refs = 0; } 33 | inline RefCounter(const RefCounter& copy) { _refs = 0; } 34 | // Destructor - Does nothing, but because it is virtual, ensures that all superclasses get destroyed as well 35 | virtual ~RefCounter() {} 36 | // Destroys this object - made a seperate virtual function so it is overridable to ensure it is deleted in the proper DLL 37 | virtual void DestroyThis() { delete this; } 38 | 39 | inline RefCounter& operator=(const RefCounter& right) { return *this; } // This does not actually change the reference count 40 | 41 | int _refs; //holds the number of references held for this object 42 | }; 43 | 44 | // Implementation of an automatic reference tracker for use in conjunction with RefCounter. Mimics a pointer. 45 | template 46 | class BUN_COMPILER_DLLEXPORT ref_ptr 47 | { 48 | public: 49 | inline ref_ptr(const ref_ptr& copy) : _p(copy._p) { if(_p != nullptr) _p->Grab(); } 50 | inline ref_ptr(ref_ptr&& mov) : _p(mov._p) { mov._p = nullptr; } 51 | inline ref_ptr(T* p = nullptr) : _p(p) { if(_p != nullptr) _p->Grab(); } 52 | inline ~ref_ptr() { if(_p != nullptr) _p->Drop(); } 53 | 54 | inline bool operator !() const noexcept { return !_p; } 55 | inline bool operator ==(const T* right) const noexcept { return _p == right; } 56 | inline bool operator !=(const T* right) const noexcept { return _p != right; } 57 | inline operator T*() noexcept { return _p; } 58 | inline operator const T*() const noexcept { return _p; } 59 | inline T* operator->() noexcept { return _p; } 60 | inline const T* operator->() const noexcept { return _p; } 61 | inline T& operator*() noexcept { return *_p; } 62 | inline const T& operator*() const noexcept { return *_p; } 63 | inline ref_ptr& operator=(const ref_ptr& right) { return operator=(right._p); } 64 | inline ref_ptr& operator=(ref_ptr&& right) 65 | { 66 | if(_p != nullptr) 67 | _p->Drop(); 68 | 69 | _p = right._p; 70 | right._p = nullptr; 71 | return *this; 72 | } 73 | inline ref_ptr& operator=(T* right) 74 | { 75 | if(_p != nullptr) 76 | _p->Drop(); 77 | 78 | _p = right; 79 | if(_p != nullptr) 80 | _p->Grab(); 81 | 82 | return *this; 83 | } 84 | 85 | protected: 86 | T* _p; 87 | }; 88 | } 89 | 90 | #endif 91 | -------------------------------------------------------------------------------- /include/buntils/Scheduler.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __SCHEDULER_H__BUN__ 5 | #define __SCHEDULER_H__BUN__ 6 | 7 | #include "HighPrecisionTimer.h" 8 | #include "BinaryHeap.h" 9 | 10 | namespace bun { 11 | // Scheduler object that lets you schedule events that happen x milliseconds into the future. If the event returns a number greater than 0,it will be rescheduled. 12 | template>> //std::function 13 | class BUN_COMPILER_DLLEXPORT Scheduler : protected HighPrecisionTimer, protected BinaryHeap, ST, CompTFirst>, Alloc> 14 | { 15 | using BASE = BinaryHeap, ST, CompTFirst>>; 16 | public: 17 | // Constructor 18 | inline explicit Scheduler(const Alloc& alloc) : BASE(alloc) {} 19 | inline Scheduler() {} 20 | inline Scheduler(const Scheduler& copy) : BASE(copy), HighPrecisionTimer(copy) {} 21 | inline Scheduler(Scheduler&& mov) : BASE(std::move(mov)), HighPrecisionTimer(mov) {} 22 | inline Scheduler(double t, const F& f) { Add(t, f); } 23 | inline Scheduler(double t, F&& f) { Add(t, std::move(f)); } 24 | inline ~Scheduler() {} 25 | // Gets number of events 26 | BUN_FORCEINLINE ST Length() const { return BASE::_length; } 27 | // Adds an event that will happen t milliseconds in the future, starting from the current time 28 | BUN_FORCEINLINE void Add(double t, const F& f) { BASE::Insert(std::pair(t + _time, f)); } 29 | BUN_FORCEINLINE void Add(double t, F&& f) { BASE::Insert(std::pair(t + _time, std::move(f))); } 30 | // Updates the scheduler, setting off any events that need to be set off 31 | inline void Update() 32 | { 33 | HighPrecisionTimer::Update(); 34 | 35 | while(BASE::Peek().first <= _time) 36 | { 37 | double r = BASE::Peek().second(); 38 | 39 | if(r == 0.0) 40 | BASE::Remove(0); 41 | else 42 | BASE::Set(0, std::pair(r + _time, BASE::Peek().second)); // This is why we don't use the actual priority queue data structure 43 | } 44 | } 45 | }; 46 | } 47 | 48 | #endif -------------------------------------------------------------------------------- /include/buntils/Singleton.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __SINGLETON_H__BUN__ //These are used in case this header file is used by two different projects dependent on each other, resulting in duplicates which cannot be differentiated by #pragma once 5 | #define __SINGLETON_H__BUN__ 6 | 7 | #include "compiler.h" 8 | 9 | namespace bun { 10 | template 11 | class BUN_COMPILER_DLLEXPORT Singleton //exported to make VC++ shut up 12 | { 13 | inline Singleton(const Singleton&) = delete; 14 | inline Singleton& operator=(const Singleton&) = delete; 15 | public: 16 | inline Singleton(Singleton&& mov) { if(_instance == static_cast(&mov)) _instance = static_cast(this); } 17 | inline Singleton() { _instance = static_cast(this); } 18 | inline ~Singleton() { if(_instance == static_cast(this)) _instance = 0; } 19 | 20 | //inline static T* Instance() { return _instance; } // You have to provide this so it gets called from the correct DLL 21 | 22 | inline Singleton& operator=(Singleton&& mov) { if(_instance == static_cast(&mov)) _instance = static_cast(this); return *this; } 23 | 24 | protected: 25 | static T* _instance; 26 | }; 27 | } 28 | 29 | #endif 30 | -------------------------------------------------------------------------------- /include/buntils/Stack.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_STACK_H__ 5 | #define __BUN_STACK_H__ 6 | 7 | #include "DynArray.h" 8 | 9 | namespace bun { 10 | // Fast, tiny array-based stack. Pop and Top are only valid if there is an item in the stack; this check must be done by the user. 11 | template> 12 | class BUN_COMPILER_DLLEXPORT Stack 13 | { 14 | public: 15 | inline Stack(const Stack& copy) : _array(copy) {} 16 | inline Stack(Stack&& mov) : _array(std::move(mov)) {} 17 | inline Stack(CType init, const Alloc& alloc) : _array(init, alloc) {} 18 | inline explicit Stack(CType init = 0) : _array(init) {} 19 | inline ~Stack() {} 20 | // Pushes an item on to the stack in LIFO order. 21 | BUN_FORCEINLINE void Push(const T& value) { _array.Add(value); } 22 | BUN_FORCEINLINE void Push(T&& value) { _array.Add(std::move(value)); } 23 | // Pops an item off the stack in LIFO order. If there is no item to pop, this call is illegal and will crash. 24 | BUN_FORCEINLINE T Pop() { T r(std::move(_array.Back())); _array.RemoveLast(); return std::move(r); } 25 | // Peeks at the item on top of the stack, but does not remove it. If there is no item to look at, this is illegal. 26 | BUN_FORCEINLINE T& Peek() { return _array.Back(); } 27 | BUN_FORCEINLINE const T& Peek() const { return _array.Back(); } 28 | // Throws away the item on top of the stack. 29 | BUN_FORCEINLINE void Discard() { _array.RemoveLast(); } 30 | BUN_FORCEINLINE void Clear() { _array.Clear(); } 31 | // Gets how many items are on the stack. If this is 0, Push and Pop cannot be called. 32 | BUN_FORCEINLINE CType Length() const { return _array.Length(); } 33 | // Sets how many items are on the stack. Is usually used to truncate the stack, but can also be used to extend it. The stack 34 | // will follow the same rules that govern extending it's base array, so in a simple array, the values will be uninitialized. 35 | BUN_FORCEINLINE void SetLength(CType length) { _array.SetLength(length); } 36 | // Gets the capacity of the underlying array. 37 | BUN_FORCEINLINE CType Capacity() const { return _array.Capacity(); } 38 | inline Stack& operator=(const Stack& copy) { _array = copy._array; return *this; } 39 | inline Stack& operator=(Stack&& mov) { _array = std::move(mov._array); return *this; } 40 | // Gets an item at an arbitrary point on the stack. Valid only if i < _length 41 | inline const T& operator[](CType i) const { return _array[i]; } 42 | inline T& operator[](CType i) { return _array[i]; } 43 | 44 | typedef typename DynArray::SerializerArray SerializerArray; 45 | template 46 | void Serialize(Serializer& s, const char* id) { _array.template Serialize(s, id); } 47 | 48 | protected: 49 | DynArray _array; 50 | }; 51 | } 52 | 53 | #endif 54 | -------------------------------------------------------------------------------- /include/buntils/Thread.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __THREAD_H__BUN__ 5 | #define __THREAD_H__BUN__ 6 | 7 | #include "defines.h" 8 | #include 9 | #include 10 | #ifdef BUN_PLATFORM_WIN32 11 | #include "win32_includes.h" 12 | #include 13 | #else // Assume BUN_PLATFORM_POSIX 14 | #include 15 | #include 16 | #endif 17 | 18 | namespace bun { 19 | #pragma warning(push) 20 | #pragma warning(disable:4275) 21 | // Cross-platform implementation of a semaphore, initialized to 0 (locked). 22 | class Semaphore 23 | { 24 | public: 25 | #ifdef BUN_PLATFORM_WIN32 26 | inline Semaphore(Semaphore&& mov) : _sem(mov._sem) { mov._sem = NULL; } 27 | inline Semaphore() : _sem(CreateSemaphore(NULL, 0, 65535, NULL)) {} 28 | inline ~Semaphore() { if(_sem != NULL) CloseHandle(_sem); } 29 | // Unlocks the semaphore by incrementing the current value 30 | inline bool Notify(size_t count = 1) 31 | { 32 | LONG prev; 33 | return ReleaseSemaphore(_sem, (LONG)count, &prev) != 0; 34 | } 35 | // Waits on the semaphore by waiting until it can decrement the value by 1 (which requires the semaphore is greater than zero). 36 | inline bool Wait() { return WaitForSingleObject(_sem, INFINITE) != WAIT_FAILED; } 37 | 38 | protected: 39 | HANDLE _sem; 40 | #else 41 | inline Semaphore(Semaphore&& mov) : _sem(mov._sem) { sem_init(&mov._sem, 0, 0); } 42 | inline Semaphore() { sem_init(&_sem, 0, 0); } 43 | inline ~Semaphore() { } 44 | inline bool Notify(size_t count = 1) 45 | { 46 | for(size_t i = 0; i < count; ++i) 47 | if(sem_post(&_sem)) 48 | return false; 49 | return true; 50 | } 51 | inline bool Wait() { return !sem_wait(&_sem); } 52 | 53 | protected: 54 | sem_t _sem; 55 | #endif 56 | }; 57 | // This extends std::thread and adds support for joining with a timeout 58 | class BUN_COMPILER_DLLEXPORT Thread : public std::thread 59 | { 60 | #pragma warning(pop) 61 | inline Thread(const Thread&) = delete; 62 | Thread& operator=(const Thread&) = delete; 63 | public: 64 | template 65 | explicit Thread(_Fn&& _Fx, _Args&&... _Ax) : std::thread(std::forward<_Fn>(_Fx), std::forward<_Args>(_Ax)...) {} 66 | inline Thread(Thread&& mov) : std::thread(std::move((std::thread&&)mov)) { } // Move constructor only 67 | inline Thread() { } 68 | inline ~Thread() 69 | { 70 | if(joinable()) // Ensures we don't crash if the thread hasn't been joined or detached yet. 71 | std::thread::join(); 72 | } 73 | // Blocks until either the thread has terminated, or 'timeout' milliseconds have elapsed. If a timeout occurs, returns -1. 74 | BUN_FORCEINLINE size_t join(size_t mstimeout) 75 | { 76 | size_t ret = (size_t)~0; 77 | if(joinable()) 78 | { 79 | #ifdef BUN_PLATFORM_WIN32 80 | if(WaitForSingleObject((HANDLE)native_handle(), (DWORD)mstimeout) != 0) 81 | return (size_t)~0; 82 | GetExitCodeThread((HANDLE)native_handle(), (DWORD*)&ret); // size_t is gaurenteed to be big enough to hold DWORD 83 | std::thread::join(); 84 | #else // BUN_PLATFORM_POSIX 85 | struct timespec ts; 86 | 87 | if(!mstimeout || clock_gettime(CLOCK_REALTIME, &ts) == -1) 88 | { 89 | if(pthread_tryjoin_np(native_handle(), (void**)&ret) != 0) // If failed, thread is either still busy or something blew up, so return -1 90 | return (size_t)~0; 91 | } 92 | else 93 | { 94 | ts.tv_sec += mstimeout / 1000; 95 | ts.tv_nsec += (mstimeout % 1000) * 1000000; 96 | if(pthread_timedjoin_np(native_handle(), (void**)&ret, &ts) != 0) // size_t is defined as being big enough to hold a pointer 97 | return (size_t)~0; 98 | } 99 | 100 | *((std::thread::id*)(this)) = std::thread::id();// Insanely horrible hack to manually make the ID not joinable 101 | #endif 102 | } 103 | 104 | return ret; 105 | } 106 | BUN_FORCEINLINE void join() { std::thread::join(); } 107 | 108 | Thread& operator=(Thread&& mov) { std::thread::operator=(std::move((std::thread&&)mov)); return *this; } 109 | }; 110 | } 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /include/buntils/ThreadPool.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __THREAD_POOL_H__BUN__ 5 | #define __THREAD_POOL_H__BUN__ 6 | 7 | #include "Thread.h" 8 | #include "LocklessQueue.h" 9 | #include "DynArray.h" 10 | #include "Delegate.h" 11 | #include 12 | #include 13 | 14 | namespace bun { 15 | // Stores a pool of threads that execute tasks. 16 | class ThreadPool 17 | { 18 | typedef void(*FN)(void*); 19 | using TASK = std::pair; 20 | using ALLOC = LocklessBlockCollection<512>; 21 | 22 | ThreadPool(const ThreadPool&) = delete; 23 | ThreadPool& operator=(const ThreadPool&) = delete; 24 | 25 | public: 26 | ThreadPool(ThreadPool&& mov) : _run(mov._run.load(std::memory_order_relaxed)), 27 | _tasks(mov._tasks.load(std::memory_order_relaxed)), 28 | _tasklist(std::move(mov._tasklist)), _threads(std::move(mov._threads)) 29 | { 30 | mov._run.store(0, std::memory_order_release); 31 | } 32 | explicit ThreadPool(size_t count) : _run(0), _tasks(0), _policy(), _tasklist(PolicyAllocator, LocklessBlockPolicy>{_policy}) 33 | { 34 | AddThreads(count); 35 | } 36 | ThreadPool() : _run(0), _tasks(0), _policy(), _tasklist(PolicyAllocator, LocklessBlockPolicy>{_policy}) 37 | { 38 | AddThreads(IdealWorkerCount()); 39 | } 40 | ~ThreadPool() 41 | { 42 | Wait(); 43 | _run.store(-_run.load(std::memory_order_acquire), std::memory_order_release); // Negate the stop count, then wait for it to reach 0 44 | _lock.Notify(_threads.Length()); 45 | while(_run.load(std::memory_order_acquire) < 0); 46 | } 47 | void AddTask(FN f, void* arg, size_t instances = 1) 48 | { 49 | if(!instances) 50 | instances = (size_t)_threads.Length(); 51 | 52 | TASK task(f, arg); 53 | _tasks.fetch_add(instances, std::memory_order_release); 54 | 55 | for(size_t i = 0; i < instances; ++i) 56 | _tasklist.Push(task); 57 | 58 | _lock.Notify(instances); 59 | } 60 | 61 | template 62 | void AddFunc(R(*f)(Args...), Args... args) 63 | { 64 | std::pair, ALLOC*>* fn = _falloc.allocT, ALLOC*>>(1); 65 | new (&fn->first) StoreFunction(f, std::forward(args)...); 66 | fn->second = &_falloc; // This could just be a pointer to this thread pool, but it's easier if it's a direct pointer to the allocator we need. 67 | AddTask(_callfn, fn); 68 | } 69 | 70 | void AddThreads(size_t num = 1) 71 | { 72 | for(size_t i = 0; i < num; ++i) 73 | { 74 | _run.fetch_add(1, std::memory_order_release); 75 | _threads.AddConstruct(_worker, std::ref(*this)); 76 | } 77 | } 78 | void Wait() 79 | { 80 | TASK task; // It is absolutely crucial that the main thread also process tasks to avoid the issue of orphaned tasks 81 | while(_run.load(std::memory_order_acquire) > 0 && _tasklist.Pop(task)) 82 | { 83 | (*task.first)(task.second); 84 | _tasks.fetch_sub(1, std::memory_order_release); 85 | } 86 | 87 | while(_tasks.load(std::memory_order_relaxed) > 0); // Wait until all tasks actually stop processing 88 | } 89 | inline size_t Busy() const { return _tasks.load(std::memory_order_relaxed); } 90 | 91 | static size_t IdealWorkerCount() 92 | { 93 | size_t c = std::thread::hardware_concurrency(); 94 | return c <= 1 ? 1 : (c - 1); 95 | } 96 | 97 | protected: 98 | static void _worker(ThreadPool& pool) 99 | { 100 | while(pool._run.load(std::memory_order_acquire) > 0) 101 | { 102 | pool._lock.Wait(); 103 | TASK task; 104 | while(pool._tasklist.Pop(task)) 105 | { 106 | (*task.first)(task.second); 107 | pool._tasks.fetch_sub(1, std::memory_order_release); 108 | } 109 | } 110 | 111 | pool._run.fetch_add(1, std::memory_order_release); 112 | } 113 | 114 | template 115 | static void _callfn(void* p) 116 | { 117 | std::pair, ALLOC*>* fn = (std::pair, ALLOC*>*)p; 118 | fn->first.Call(); 119 | fn->first.~StoreFunction(); 120 | fn->second->deallocT(fn, 1); 121 | } 122 | 123 | 124 | LocklessBlockPolicy> _policy; 125 | MicroLockQueue _tasklist; 126 | std::atomic _tasks; // Count of tasks still being processed (this includes tasks that have been removed from the queue, but haven't finished yet) 127 | DynArray _threads; 128 | std::atomic _run; 129 | Semaphore _lock; 130 | ALLOC _falloc; 131 | }; 132 | 133 | template 134 | class Future : StoreFunction 135 | { 136 | inline Future(ThreadPool& pool, R(*f)(Args...), Args&&... args) : StoreFunction(f, std::forward(args)...) { pool.AddTask(_eval, this); } 137 | ~Future() { assert(_finished.load(std::memory_order_acquire)); } 138 | R* Result() { return _finished.load(std::memory_order_acquire) ? &result : 0; } 139 | 140 | protected: 141 | R result; 142 | std::atomic_bool _finished; 143 | 144 | static void _eval(void* arg) 145 | { 146 | Future* p = (Future*)arg; 147 | p->result = p->Call(); 148 | p->_finished.store(true, std::memory_order_release); 149 | } 150 | }; 151 | } 152 | 153 | #endif -------------------------------------------------------------------------------- /include/buntils/XorshiftEngine.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_XORSHIFT_ENGINE_H__ 5 | #define __BUN_XORSHIFT_ENGINE_H__ 6 | 7 | #include "compiler.h" 8 | #include 9 | #include 10 | #include 11 | 12 | namespace bun { 13 | // Implementation of an xorshift64star generator. x serves as the generator state, which should initially be set to the RNG seed. 14 | inline uint64_t xorshift64star(uint64_t& x) 15 | { 16 | x ^= x >> 12; 17 | x ^= x << 25; 18 | x ^= x >> 27; 19 | return x * UINT64_C(2685821657736338717); 20 | } 21 | 22 | // Implementation of 2^1024-1 period xorshift generator. x is the 16*64 bit state, plus 1 extra integer for counting indices. 23 | inline uint64_t xorshift1024star(uint64_t(&x)[17]) 24 | { 25 | uint64_t x0 = x[x[16]]; 26 | uint64_t x1 = x[x[16] = (x[16] + 1) & 15]; 27 | x1 ^= x1 << 31; // a 28 | x1 ^= x1 >> 11; // b 29 | x0 ^= x0 >> 30; // c 30 | return (x[x[16]] = x0 ^ x1) * UINT64_C(1181783497276652981); 31 | } 32 | 33 | // Generates a seed for xorshift1024star from a 64-bit value 34 | inline void GenXor1024Seed(uint64_t x, uint64_t(&seed)[17]) 35 | { 36 | xorshift64star(x); 37 | for(uint8_t i = 0; i < 16; ++i) 38 | seed[i] = xorshift64star(x); 39 | seed[16] = 0; 40 | } 41 | 42 | namespace internal { 43 | template 44 | class xorshift_engine_base 45 | { 46 | public: 47 | BUN_FORCEINLINE static constexpr T base_min() { return std::numeric_limits::min(); } 48 | BUN_FORCEINLINE static constexpr T base_max() { return std::numeric_limits::max(); } 49 | BUN_FORCEINLINE static constexpr T base_transform(uint64_t x) { return (T)x; } 50 | }; 51 | 52 | // DISABLED: There is no nice way of mapping randomly generated values to floating point values because floating point has a log2 distribution and denormals. 53 | // Instead, use gencanonical to map generated random integers to a [0.0,1.0) range. 54 | /*template<> 55 | class xorshift_engine_base 56 | { 57 | public: 58 | BUN_FORCEINLINE static float base_min() { return base_transform(0xFFFFFFFFFFFFFFFF); } 59 | BUN_FORCEINLINE static float base_max() { return base_transform(0x7FFFFFFFFFFFFFFF); } 60 | BUN_FORCEINLINE static float base_transform(uint64_t x) 61 | { 62 | uint32_t y=(uint32_t)x; 63 | y = (y&0xBFFFFFFF)+0x1F800000; // Mask out the top exponent bit to force exponent to 0-127 range, then add 63 to the exponent to get it in [63,190] range ([-64,63] when biased) 64 | return *(float*)(&y); // convert our integer into a float, assuming IEEE format 65 | } 66 | }; 67 | 68 | template<> 69 | class BUN_COMPILER_DLLEXPORT xorshift_engine_base 70 | { 71 | public: 72 | BUN_FORCEINLINE static double base_min() { return base_transform(0xFFFFFFFFFFFFFFFF); } 73 | BUN_FORCEINLINE static double base_max() { return base_transform(0x7FFFFFFFFFFFFFFF); } 74 | BUN_FORCEINLINE static double base_transform(uint64_t x) 75 | { 76 | x = (x&0xBFFFFFFFFFFFFFFF)+0x1FF0000000000000; // Mask out the top exponent bit to force exponent to 0-1023 range, then add 511 to the exponent to get it in [511,1534] range ([-512,511] when biased) 77 | return *(double*)(&x); // convert our integer into a double, assuming IEEE format 78 | } 79 | };*/ 80 | } 81 | 82 | template 83 | class BUN_COMPILER_DLLEXPORT XorshiftEngine : protected internal::xorshift_engine_base 84 | { 85 | public: 86 | XorshiftEngine() { seed(); } 87 | explicit XorshiftEngine(uint64_t s) { seed(s); } 88 | explicit XorshiftEngine(uint64_t s[16]) { seed(s); } 89 | void seed() 90 | { 91 | std::random_device rd; 92 | GenXor1024Seed(rd(), _state); 93 | } 94 | void seed(uint64_t s) { GenXor1024Seed(s, _state); } 95 | void seed(uint64_t s[16]) 96 | { 97 | for(int i = 0; i < 16; ++i) 98 | _state[i] = s[i]; 99 | _state[16] = 0; 100 | } 101 | void discard(unsigned long long z) 102 | { 103 | for(int i = 0; i < z; ++i) 104 | xorshift1024star(_state); 105 | } 106 | 107 | inline constexpr static T min() { return internal::xorshift_engine_base::base_min(); } 108 | inline constexpr static T max() { return internal::xorshift_engine_base::base_max(); } 109 | 110 | inline constexpr T operator()() { return internal::xorshift_engine_base::base_transform(xorshift1024star(_state)); } // Truncate to return_value size. 111 | bool operator ==(const XorshiftEngine& r) const 112 | { 113 | for(int i = 0; i < 17; ++i) 114 | if(_state[i] != r._state[i]) 115 | return false; 116 | return true; 117 | } 118 | bool operator !=(const XorshiftEngine& r) const { return !operator==(r); } 119 | 120 | using result_type = T; 121 | 122 | protected: 123 | uint64_t _state[17]; 124 | }; 125 | 126 | inline uint64_t XorshiftRand(uint64_t seed = 0) 127 | { 128 | static uint64_t state[17]; 129 | if(seed) GenXor1024Seed(seed, state); 130 | return xorshift1024star(state); 131 | } 132 | typedef XorshiftEngine XorshiftEngine64; 133 | } 134 | 135 | #endif -------------------------------------------------------------------------------- /include/buntils/algo.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/include/buntils/algo.h -------------------------------------------------------------------------------- /include/buntils/buntils_c.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_UTIL_C_H__ 5 | #define __BUN_UTIL_C_H__ 6 | 7 | #include "compiler.h" 8 | #include 9 | 10 | #ifdef __cplusplus 11 | extern "C" { 12 | #endif 13 | enum CPU_FLAGS { 14 | CPU_CMPXCHG8b = 1, 15 | CPU_CMPXCHG16b = 2, 16 | CPU_AMD_SSE4a = 4, 17 | CPU_CMOV = 8, 18 | CPU_CFLUSH = 16, 19 | CPU_POPCNT = 32, 20 | }; 21 | 22 | struct bunCPUInfo { 23 | unsigned int cores; // Number of logical cores (not physical cores). 24 | enum { 25 | SSE_MMX = 1, 26 | SSE_SSE1, 27 | SSE_SSE2, 28 | SSE_SSE3, 29 | SSE_SSSE3, 30 | SSE_SSE4_1, 31 | SSE_SSE4_2, 32 | SSE_AVX, 33 | SSE_AVX2, 34 | } sse; 35 | unsigned int flags; // CPU_FLAGS 36 | }; 37 | 38 | extern BUN_DLLEXPORT const bun_VersionInfo bun_Version; 39 | struct tm; 40 | 41 | extern BUN_DLLEXPORT struct bunCPUInfo bunGetCPUInfo(); 42 | extern BUN_DLLEXPORT int itoa_r(int value, char* buffer, int size, unsigned int radix); // For various stupid reasons we must reimplement multiple threadsafe versions of various functions because MinGW doesn't have them. 43 | extern BUN_DLLEXPORT const char* GetProgramPath(); 44 | extern BUN_DLLEXPORT size_t GetWorkingSet(); 45 | extern BUN_DLLEXPORT size_t GetPeakWorkingSet(); 46 | extern BUN_DLLEXPORT void SetWorkDirToCur(); //Sets the working directory to the actual goddamn location of the EXE instead of the freaking start menu, or possibly the desktop. The possibilities are endless! Fuck you, windows. 47 | extern BUN_DLLEXPORT void ForceWin64Crash(); // I can't believe this function exists (forces 64-bit windows to not silently ignore fatal errors) 48 | extern BUN_DLLEXPORT unsigned long long bun_FileSize(const char* path); 49 | extern BUN_DLLEXPORT unsigned long long bun_FileSizeW(const wchar_t* path); 50 | extern BUN_DLLEXPORT long GetTimeZoneMinutes(); //Returns the current time zone difference from UTC in minutes 51 | //extern BUN_DLLEXPORT struct tm* gmtime64_r(const long long*BUN_RESTRICT clock, struct tm*BUN_RESTRICT result); 52 | #ifdef BUN_PLATFORM_MINGW 53 | extern BUN_DLLEXPORT char* strtok_r(char* s, const char* delim, char** lasts); 54 | extern BUN_DLLEXPORT wchar_t* wcstok_r(wchar_t* s, const wchar_t* delim, wchar_t** lasts); 55 | #endif 56 | 57 | #ifdef __cplusplus 58 | } 59 | 60 | // templatized implementation of itoa_r so it can work with stack allocated arrays 61 | template 62 | BUN_FORCEINLINE int _itoa_r(int value, char(&buffer)[SZ], unsigned int radix) { return itoa_r(value, buffer, SZ, radix); } 63 | #endif 64 | 65 | #endif 66 | -------------------------------------------------------------------------------- /include/buntils/compare.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_COMPARE_H__ 5 | #define __BUN_COMPARE_H__ 6 | 7 | #include "defines.h" 8 | #include 9 | #include 10 | 11 | #define SGNCOMPARE(left,right) (((left)>(right))-((left)<(right))) 12 | #define PRICOMPARE(left,right,p) (SGNCOMPARE(left,right)< // Returns -1,0,1 if lr, respectively 16 | BUN_FORCEINLINE char CompT(const T& left, const T& right) noexcept { return SGNCOMPARE(left, right); } 17 | 18 | template // Returns -1,0,1 if lr, respectively 19 | BUN_FORCEINLINE char CompTInv(const T& left, const T& right) noexcept { return SGNCOMPARE(right, left); } 20 | 21 | template // Returns -1 if l // Returns 1 if l>r or 0 otherwise 25 | BUN_FORCEINLINE char CompT_GT(const T& left, const T& right) noexcept { return (left > right); } 26 | 27 | template 28 | BUN_FORCEINLINE bool CompT_EQ(const T& left, const T& right) noexcept { return (left == right); } 29 | 30 | template 31 | BUN_FORCEINLINE bool CompT_NEQ(const T& left, const T& right) noexcept { return (left != right); } 32 | 33 | template> 34 | BUN_FORCEINLINE char CompTFirst(const std::pair& left, const std::pair& right) noexcept { return CompF(left.first, right.first); } 35 | 36 | template> 37 | BUN_FORCEINLINE char CompTSecond(const std::pair& left, const std::pair& right) noexcept { return CompS(left.second, right.second); } 38 | 39 | template, char(*CompS)(const T2&, const T2&) = &CompT> 40 | BUN_FORCEINLINE char CompTBoth(const std::pair& left, const std::pair& right) noexcept { char c = CompF(left.first, right.first); return !c ? CompS(left.second, right.second) : c; } 41 | 42 | template&, const std::tuple_element_t&) = &CompT>> 43 | BUN_FORCEINLINE char CompTuple(const T& left, const T& right) { return CompF(std::get(left), std::get(right)); } 44 | 45 | template 46 | BUN_FORCEINLINE char CompStr(const T& left, const T& right) 47 | { 48 | int result = strcmp(left, right); 49 | return SGNCOMPARE(result, 0); 50 | } 51 | template 52 | BUN_FORCEINLINE char CompIStr(const T& left, const T& right) 53 | { 54 | int result = STRICMP(left, right); 55 | return SGNCOMPARE(result, 0); 56 | } 57 | template 58 | BUN_FORCEINLINE bool CompStrLT(const T& left, const T& right) { return strcmp(left, right) < 0; } 59 | template 60 | BUN_FORCEINLINE bool CompIStrLT(const T& left, const T& right) { return STRICMP(left, right) < 0; } 61 | template 62 | BUN_FORCEINLINE char CompStrW(const T& left, const T& right) 63 | { 64 | int result = wcscmp(left, right); 65 | return SGNCOMPARE(result, 0); 66 | } 67 | template 68 | BUN_FORCEINLINE char CompIStrW(const T& left, const T& right) 69 | { 70 | int result = WCSICMP(left, right); 71 | return SGNCOMPARE(result, 0); 72 | } 73 | } 74 | 75 | #endif 76 | -------------------------------------------------------------------------------- /include/buntils/literals.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2014 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_LITERALS_H__ 5 | #define __BUN_LITERALS_H__ 6 | 7 | #include "buntils.h" 8 | #include "Dual.h" 9 | #include "Rational.h" 10 | 11 | constexpr BUN_FORCEINLINE long double operator "" _deg(long double d) noexcept { return d*(bun::PI / 180.0); } 12 | constexpr BUN_FORCEINLINE long double operator "" _deg(unsigned long long d) noexcept { return d*(bun::PI/180.0); } 13 | constexpr BUN_FORCEINLINE long double operator "" _rad(long double d) noexcept { return d*(180.0 / bun::PI); } 14 | constexpr BUN_FORCEINLINE long double operator "" _rad(unsigned long long d) noexcept { return d*(180.0/ bun::PI); } 15 | BUN_FORCEINLINE bun::Rational operator "" _recip(unsigned long long d) noexcept { return bun::Rational(1, d); } 16 | constexpr BUN_FORCEINLINE size_t operator "" _sz(unsigned long long d) noexcept { return (size_t)d; } 17 | 18 | #endif 19 | -------------------------------------------------------------------------------- /include/buntils/os.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_OS_H__ 5 | #define __BUN_OS_H__ 6 | 7 | #include "buntils.h" // bun_DLLDelete 8 | #include "Str.h" 9 | 10 | #ifdef BUN_PLATFORM_WIN32 11 | struct HWND__; 12 | struct HKEY__; //Include WinReg.h to get access to the root key handles (e.g. HKEY_LOCAL_MACHINE) 13 | #endif 14 | 15 | namespace bun { 16 | BUN_COMPILER_DLLEXPORT extern void AlertBox(const char* text, const char* caption, int type = 0); 17 | BUN_COMPILER_DLLEXPORT extern std::unique_ptr> FileDialog(bool open, unsigned long flags, const char* file, const char* filter = "All Files (*.*)\0*.*\0", const char* initdir = 0, const char* defext = 0); 18 | BUN_COMPILER_DLLEXPORT extern std::unique_ptr> GetFontPath(const char* family, int weight, bool italic); 19 | 20 | #ifdef BUN_PLATFORM_WIN32 21 | BUN_COMPILER_DLLEXPORT extern void AlertBoxW(const wchar_t* text, const wchar_t* caption, int type = 0); 22 | 23 | BUN_COMPILER_DLLEXPORT extern std::unique_ptr> FileDialog(bool open, unsigned long flags, const wchar_t* file, const wchar_t* filter = L"All Files (*.*)\0*.*\0", const wchar_t* initdir = 0, const wchar_t* defext = 0, HWND__* owner = 0); 24 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValue(HKEY__* hOpenKey, const char* szKey, const char* szValue, const char* szData); 25 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValueW(HKEY__* hOpenKey, const wchar_t* szKey, const wchar_t* szValue, const char* szData); 26 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValue(HKEY__* hOpenKey, const char* szKey, const char* szValue, int32_t szData); 27 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValueW(HKEY__* hOpenKey, const wchar_t* szKey, const wchar_t* szValue, int32_t szData); 28 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValue64(HKEY__* hOpenKey, const char* szKey, const char* szValue, int64_t szData); 29 | BUN_COMPILER_DLLEXPORT extern int SetRegistryValue64W(HKEY__* hOpenKey, const wchar_t* szKey, const wchar_t* szValue, int64_t szData); 30 | BUN_COMPILER_DLLEXPORT extern int DelRegistryNode(HKEY__* hKeyRoot, const char* lpSubKey); 31 | BUN_COMPILER_DLLEXPORT extern int DelRegistryNodeW(HKEY__* hKeyRoot, const wchar_t* lpSubKey); 32 | BUN_COMPILER_DLLEXPORT extern int64_t GetRegistryValue(HKEY__* hKeyRoot, const char* szKey, const char* szValue, unsigned char* data, unsigned long sz); 33 | BUN_COMPILER_DLLEXPORT extern int64_t GetRegistryValueW(HKEY__* hKeyRoot, const wchar_t* szKey, const wchar_t* szValue, unsigned char* data, unsigned long sz); 34 | BUN_COMPILER_DLLEXPORT extern int GetRegistryValueDWORD(HKEY__* hKeyRoot, const char* szKey, const char* szValue, unsigned long* data); 35 | BUN_COMPILER_DLLEXPORT extern int GetRegistryValueDWORDW(HKEY__* hKeyRoot, const wchar_t* szKey, const wchar_t* szValue, unsigned long* data); 36 | BUN_COMPILER_DLLEXPORT extern int GetRegistryValueQWORD(HKEY__* hKeyRoot, const char* szKey, const char* szValue, unsigned long long* data); 37 | BUN_COMPILER_DLLEXPORT extern int GetRegistryValueQWORDW(HKEY__* hKeyRoot, const wchar_t* szKey, const wchar_t* szValue, unsigned long long* data); 38 | #else 39 | BUN_COMPILER_DLLEXPORT extern int ListDir(const char* dir, std::vector& files, char flags); // Setting flags to 1 will do a recursive search. Setting flags to 2 will return directory+file names. Setting flags to 3 will both be recursive and return directory names. 40 | #endif 41 | } 42 | 43 | #endif 44 | -------------------------------------------------------------------------------- /include/buntils/utf_conv.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __UTF_CONV_H__BUN__ 5 | #define __UTF_CONV_H__BUN__ 6 | 7 | #include "compiler.h" 8 | #include 9 | #include 10 | #include 11 | 12 | #ifdef __cplusplus 13 | extern "C" { 14 | #endif 15 | 16 | extern BUN_DLLEXPORT size_t UTF8toUTF16(const char*BUN_RESTRICT input, ptrdiff_t srclen, wchar_t*BUN_RESTRICT output, size_t buflen); 17 | extern BUN_DLLEXPORT size_t UTF16toUTF8(const wchar_t*BUN_RESTRICT input, ptrdiff_t srclen, char*BUN_RESTRICT output, size_t buflen); 18 | extern BUN_DLLEXPORT size_t UTF8toUTF32(const char*BUN_RESTRICT input, ptrdiff_t srclen, char32_t*BUN_RESTRICT output, size_t buflen); 19 | extern BUN_DLLEXPORT size_t UTF32toUTF8(const char32_t*BUN_RESTRICT input, ptrdiff_t srclen, char*BUN_RESTRICT output, size_t buflen); 20 | extern BUN_DLLEXPORT size_t UTF32toUTF16(const char32_t*BUN_RESTRICT input, ptrdiff_t srclen, wchar_t*BUN_RESTRICT output, size_t buflen); 21 | extern BUN_DLLEXPORT size_t UTF16toUTF32(const wchar_t*BUN_RESTRICT input, ptrdiff_t srclen, char32_t*BUN_RESTRICT output, size_t buflen); 22 | 23 | #ifdef __cplusplus 24 | } 25 | #endif 26 | 27 | #endif -------------------------------------------------------------------------------- /include/buntils/vector.h: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/include/buntils/vector.h -------------------------------------------------------------------------------- /include/buntils/win32_includes.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_WIN32_INCLUDES_H__ 5 | #define __BUN_WIN32_INCLUDES_H__ 6 | #pragma pack(push) 7 | #pragma pack(8) 8 | #define WINVER 0x0501 //_WIN32_WINNT_WINXP 9 | #define _WIN32_WINNT 0x0501 10 | #define NTDDI_VERSION 0x05010300 //NTDDI_WINXPSP3 11 | #define WIN32_LEAN_AND_MEAN 12 | #ifndef NOMINMAX // Some compilers enable this by default 13 | #define NOMINMAX 14 | #endif 15 | #define NODRAWTEXT 16 | #define NOBITMAP 17 | #define NOMCX 18 | #define NOSERVICE 19 | #define NOHELP 20 | #include 21 | #pragma pack(pop) 22 | #endif 23 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | .PHONY: all clean distclean 2 | 3 | all: 4 | make -f buntils.mk 5 | make -f test.mk 6 | 7 | clean: 8 | make clean -f buntils.mk 9 | make clean -f test.mk 10 | 11 | dist: all distclean 12 | tar -czf buntils-posix.tar.gz * 13 | 14 | distclean: 15 | make distclean -f buntils.mk 16 | make distclean -f test.mk 17 | 18 | debug: 19 | make debug -f buntils.mk 20 | make debug -f test.mk 21 | 22 | install: all 23 | make install -f buntils.mk 24 | 25 | uninstall: 26 | make uninstall -f buntils.mk -------------------------------------------------------------------------------- /pack.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | md "..\Packages\buntils" 3 | 4 | :: So, uh, apparently XCOPY deletes empty subdirectories in your destination. 5 | XCOPY "*.cpp" "..\Packages\buntils" /S /C /I /R /Y 6 | XCOPY "*.c" "..\Packages\buntils" /S /C /I /R /Y 7 | XCOPY "test\*.h" "..\Packages\buntils\test" /S /C /I /R /Y 8 | XCOPY "test\*.rc" "..\Packages\buntils\test" /S /C /I /R /Y 9 | XCOPY "test\*.ico" "..\Packages\buntils\test" /S /C /I /R /Y 10 | XCOPY "*.vcxproj" "..\Packages\buntils" /S /C /I /R /Y 11 | XCOPY "*.filters" "..\Packages\buntils" /S /C /I /R /Y 12 | XCOPY "*.sln" "..\Packages\buntils" /S /C /I /R /Y 13 | XCOPY "buntils\*.rc" "..\Packages\buntils\buntils" /C /I /R /Y 14 | 15 | md "..\Packages\buntils\include" 16 | md "..\Packages\buntils\bin" 17 | md "..\Packages\buntils\bin32" 18 | md "..\Packages\buntils\test" 19 | 20 | XCOPY "*.md" "..\Packages\buntils" /C /I /Y 21 | XCOPY "LICENSE*" "..\Packages\buntils" /C /I /Y 22 | XCOPY "include\*.h" "..\Packages\buntils\include" /S /C /I /R /Y 23 | XCOPY "bin\buntils*.dll" "..\Packages\buntils\bin" /C /I /Y 24 | XCOPY "bin\buntils*.lib" "..\Packages\buntils\bin" /C /I /Y 25 | XCOPY "bin\buntils*.pdb" "..\Packages\buntils\bin" /C /I /Y 26 | XCOPY "bin32\buntils*.dll" "..\Packages\buntils\bin32" /C /I /Y 27 | XCOPY "bin32\buntils*.lib" "..\Packages\buntils\bin32" /C /I /Y 28 | XCOPY "bin32\buntils*.pdb" "..\Packages\buntils\bin32" /C /I /Y 29 | XCOPY "bin\test.exe" "..\Packages\buntils\bin" /C /I /Y 30 | XCOPY "bin32\test.exe" "..\Packages\buntils\bin32" /C /I /Y 31 | 32 | Pause -------------------------------------------------------------------------------- /test.mk: -------------------------------------------------------------------------------- 1 | TARGET := test 2 | SRCDIR := test 3 | BUILDDIR := bin 4 | OBJDIR := bin/obj 5 | C_SRCS := $(wildcard $(SRCDIR)/*.c) 6 | CXX_SRCS := $(wildcard $(SRCDIR)/*.cpp) 7 | INCLUDE_DIRS := include 8 | LIBRARY_DIRS := 9 | LIBRARIES := buntils rt pthread 10 | 11 | CPPFLAGS += -std=c++20 -pthread -DLIBICONV_PLUG -Wall -Wshadow -Wno-attributes -Wno-unknown-pragmas -Wno-reorder -Wno-missing-braces -Wno-unused-function -Wno-comment -Wno-char-subscripts -Wno-sign-compare -Wno-unused-variable -Wno-switch -fsanitize=signed-integer-overflow -fuse-ld=gold -Wno-class-memaccess 12 | LDFLAGS += -L./bin/ 13 | 14 | include base.mk 15 | 16 | PRECOMPILE: 17 | $(COMPILE.cpp) $(SRCDIR)/test.h -o $(SRCDIR)/test.h.gch 18 | 19 | $(OBJS): PRECOMPILE 20 | 21 | distclean: 22 | @- $(RM) $(OBJS) 23 | @- $(RM) -r $(OBJDIR) 24 | @- $(RM) bin/*.txt 25 | @- $(RM) bin/*.ini 26 | @- $(RM) bin/*.json 27 | @- $(RM) bin/*.ubj 28 | @- $(RM) bin/*.xml 29 | @- $(RM) $(SRCDIR)/test.h.gch 30 | 31 | -------------------------------------------------------------------------------- /test/buntils.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/test/buntils.ico -------------------------------------------------------------------------------- /test/test.rc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ErikMcClure/buntils/90175f870ab281a87ab2df6d6b994137c434f119/test/test.rc -------------------------------------------------------------------------------- /test/test_aatree.cpp: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #include "test.h" 5 | #include "buntils/AATree.h" 6 | #include "buntils/algo.h" 7 | #include 8 | 9 | using namespace bun; 10 | 11 | TESTDEF::RETPAIR test_AA_TREE() 12 | { 13 | BEGINTEST; 14 | 15 | BlockPolicy> fixedaa; 16 | AATree, PolicyAllocator, BlockPolicy>> aat(PolicyAllocator, BlockPolicy>{fixedaa}); 17 | 18 | XorshiftEngine64 e; 19 | 20 | Shuffle(testnums, TESTNUM, e); 21 | 22 | //uint64_t prof=HighPrecisionTimer::OpenProfiler(); 23 | for(size_t i = 0; i a(p); 15 | size_t counts[7] = { 0 }; 16 | for(size_t i = 0; i < COUNT; ++i) 17 | ++counts[a()]; 18 | double real[7] = { 0.0 }; 19 | for(size_t i = 0; i < 7; ++i) 20 | real[i] = counts[i] / double(COUNT); 21 | for(size_t i = 0; i < 7; ++i) 22 | TEST(fCompare(p[i], real[i], (1LL << 45))); 23 | a(bun_getdefaultengine()); 24 | a.Get(bun_getdefaultengine()); 25 | 26 | AliasTable b; 27 | b = AliasTable(p); 28 | bun_Fill(counts); 29 | for(size_t i = 0; i < COUNT; ++i) 30 | ++counts[b()]; 31 | for(size_t i = 0; i < 7; ++i) 32 | real[i] = counts[i] / double(COUNT); 33 | for(size_t i = 0; i < 7; ++i) 34 | TEST(fCompare(p[i], real[i], (1LL << 46))); 35 | 36 | ENDTEST; 37 | } -------------------------------------------------------------------------------- /test/test_alloc.h: -------------------------------------------------------------------------------- 1 | // Copyright (c)2023 Erik McClure 2 | // For conditions of distribution and use, see copyright notice in "buntils.h" 3 | 4 | #ifndef __BUN_TEST_ALLOC_H__ 5 | #define __BUN_TEST_ALLOC_H__ 6 | 7 | #include "buntils/Map.h" 8 | #include "buntils/algo.h" 9 | #include "test.h" 10 | #include "buntils/Thread.h" 11 | #include "buntils/CacheAlloc.h" 12 | #include "buntils/literals.h" 13 | 14 | #pragma warning(disable:4101) 15 | 16 | template