From 996151a56ab5a90fd281e2f060cd06615a71a881 Mon Sep 17 00:00:00 2001 From: Timothy Prepscius Date: Wed, 25 Feb 2026 12:43:06 -0500 Subject: [PATCH] flatten 20260225 --- .gitignore | 6 + Core_Zero.xcodeproj/project.pbxproj | 2221 ++ .../contents.xcworkspacedata | 7 + .../xcshareddata/IDEWorkspaceChecks.plist | 8 + .../xcschemes/Core_Zero_Tests.xcscheme | 224 + Examples.cpp | 188 + LICENSE | 26 + Makefile | 8 + Makefile.def | 11 + Makefile.project | 51 + ReadMe.md | 141 + core | 0 tests/Makefile | 1 + tests/Makefile.project | 36 + tests/Run.cpp | 21 + tjp/core/Precompile.pch | 29 + tjp/core/algorithm/ExecuteOnDestruct.h | 12 + tjp/core/algorithm/ExecuteOnDestruct.hpp | 73 + tjp/core/algorithm/_tests/all_are.cpp | 43 + .../algorithm/_tests/container_erase_if.cpp | 54 + .../_tests/container_erase_if_one.cpp | 53 + .../_tests/container_erase_value_all.cpp | 47 + .../_tests/container_erase_value_one.cpp | 47 + .../algorithm/_tests/container_find_if.cpp | 40 + .../algorithm/_tests/container_get_if.cpp | 85 + .../_tests/container_get_if_optional.cpp | 45 + .../container_get_if_optional_erase.cpp | 54 + .../_tests/container_get_optional_erase.cpp | 48 + tjp/core/algorithm/_tests/container_has.cpp | 44 + .../algorithm/_tests/container_has_if.cpp | 50 + tjp/core/algorithm/_tests/copy_clear.cpp | 38 + tjp/core/algorithm/_tests/copy_of.cpp | 38 + tjp/core/algorithm/_tests/emplace.cpp | 42 + tjp/core/algorithm/_tests/empty_of.cpp | 38 + tjp/core/algorithm/_tests/ends_with.cpp | 33 + tjp/core/algorithm/_tests/has_last.cpp | 33 + .../algorithm/_tests/in_range_segment.cpp | 31 + tjp/core/algorithm/_tests/is_in.cpp | 30 + tjp/core/algorithm/_tests/is_zero.cpp | 34 + .../_tests/last_of_parameter_pack.cpp | 29 + tjp/core/algorithm/_tests/list_erase_if.cpp | 54 + .../algorithm/_tests/list_erase_if_value.cpp | 54 + tjp/core/algorithm/_tests/map_erase.cpp | 54 + tjp/core/algorithm/_tests/map_erase_if.cpp | 54 + .../algorithm/_tests/map_erase_if_key.cpp | 54 + .../algorithm/_tests/map_erase_if_value.cpp | 54 + .../algorithm/_tests/map_for_each_value.cpp | 33 + tjp/core/algorithm/_tests/map_has.cpp | 44 + tjp/core/algorithm/_tests/map_has_key.cpp | 44 + .../_tests/map_iterator_or_insert.cpp | 34 + tjp/core/algorithm/_tests/map_value.cpp | 37 + .../algorithm/_tests/map_value_require.cpp | 37 + tjp/core/algorithm/_tests/no_throw.cpp | 34 + tjp/core/algorithm/_tests/not_zero.cpp | 34 + tjp/core/algorithm/_tests/on_destruct.cpp | 77 + tjp/core/algorithm/_tests/one_is.cpp | 38 + tjp/core/algorithm/_tests/optional_value.cpp | 28 + .../_tests/optional_value_or_default.cpp | 27 + tjp/core/algorithm/_tests/set_empty.cpp | 27 + tjp/core/algorithm/_tests/small_cmp.cpp | 192 + tjp/core/algorithm/_tests/small_copy.cpp | 127 + tjp/core/algorithm/_tests/starts_with.cpp | 33 + tjp/core/algorithm/_tests/vector_append.cpp | 41 + .../_tests/vector_erase_if_value.cpp | 54 + .../_tests/vector_erase_value_all.cpp | 47 + .../_tests/vector_erase_value_one.cpp | 52 + tjp/core/algorithm/all_are.hpp | 19 + tjp/core/algorithm/cmp.hpp | 18 + tjp/core/algorithm/container_count_if.hpp | 22 + tjp/core/algorithm/container_erase_if.hpp | 27 + .../container_erase_if_imp_use_iterator.hpp | 31 + tjp/core/algorithm/container_erase_if_one.hpp | 25 + .../algorithm/container_erase_value_all.hpp | 31 + .../algorithm/container_erase_value_one.hpp | 25 + tjp/core/algorithm/container_find_if.hpp | 18 + tjp/core/algorithm/container_get_if.hpp | 26 + .../algorithm/container_get_if_optional.hpp | 25 + .../container_get_if_optional_erase.hpp | 27 + .../container_get_optional_erase.hpp | 27 + tjp/core/algorithm/container_has.hpp | 17 + tjp/core/algorithm/container_has_if.hpp | 17 + tjp/core/algorithm/copy_clear.hpp | 26 + tjp/core/algorithm/copy_clear_delete.hpp | 20 + tjp/core/algorithm/copy_of.hpp | 15 + tjp/core/algorithm/emplace.hpp | 23 + tjp/core/algorithm/empty_of.hpp | 16 + tjp/core/algorithm/ends_with.hpp | 40 + tjp/core/algorithm/has_last.hpp | 15 + tjp/core/algorithm/has_sequence.hpp | 38 + tjp/core/algorithm/in_range_segment.hpp | 16 + tjp/core/algorithm/is_in.hpp | 17 + tjp/core/algorithm/is_zero.hpp | 14 + tjp/core/algorithm/last_of_parameter_pack.hpp | 17 + tjp/core/algorithm/list_erase_if.hpp | 17 + tjp/core/algorithm/list_erase_if_value.hpp | 17 + tjp/core/algorithm/list_erase_value_all.hpp | 17 + tjp/core/algorithm/list_erase_value_one.hpp | 17 + tjp/core/algorithm/map_erase.hpp | 24 + tjp/core/algorithm/map_erase_get_optional.hpp | 26 + tjp/core/algorithm/map_erase_if.hpp | 29 + tjp/core/algorithm/map_erase_if_key.hpp | 29 + tjp/core/algorithm/map_erase_if_value.hpp | 29 + tjp/core/algorithm/map_for_each_value.hpp | 16 + tjp/core/algorithm/map_has.hpp | 17 + tjp/core/algorithm/map_has_key.hpp | 17 + tjp/core/algorithm/map_insert.hpp | 19 + tjp/core/algorithm/map_iterator_or_insert.hpp | 35 + tjp/core/algorithm/map_pair.hpp | 32 + .../algorithm/map_set_or_erase_optional.hpp | 20 + tjp/core/algorithm/map_value.hpp | 25 + tjp/core/algorithm/map_value_erase.hpp | 28 + tjp/core/algorithm/map_value_optional.hpp | 25 + tjp/core/algorithm/map_value_or_default.hpp | 19 + tjp/core/algorithm/map_value_or_insert.hpp | 21 + .../algorithm/map_value_or_insert_value.hpp | 16 + tjp/core/algorithm/map_value_require.hpp | 21 + tjp/core/algorithm/mem_copy.hpp | 30 + tjp/core/algorithm/mem_copy_asan_safe.hpp | 18 + tjp/core/algorithm/no_throw.hpp | 26 + tjp/core/algorithm/not_zero.hpp | 14 + tjp/core/algorithm/numeric_limits.hpp | 26 + tjp/core/algorithm/on_destruct.hpp | 16 + tjp/core/algorithm/one_is.hpp | 19 + tjp/core/algorithm/optional_of_ptr.hpp | 17 + tjp/core/algorithm/optional_set_if_empty.hpp | 21 + tjp/core/algorithm/optional_value.hpp | 20 + .../algorithm/optional_value_or_default.hpp | 17 + tjp/core/algorithm/remove_const_of_var.hpp | 22 + tjp/core/algorithm/set_empty.hpp | 15 + tjp/core/algorithm/set_erase.hpp | 22 + tjp/core/algorithm/set_erase_if_value.hpp | 17 + .../algorithm/set_erase_optional_value.hpp | 29 + .../set_erase_optional_value_move.hpp | 31 + tjp/core/algorithm/set_has.hpp | 17 + tjp/core/algorithm/set_insert.hpp | 19 + tjp/core/algorithm/set_insert_mutable.hpp | 19 + tjp/core/algorithm/set_insert_once.hpp | 16 + tjp/core/algorithm/set_once.hpp | 26 + tjp/core/algorithm/set_value.hpp | 22 + tjp/core/algorithm/set_value_mutable.hpp | 22 + tjp/core/algorithm/small_cmp.hpp | 282 + tjp/core/algorithm/small_copy.hpp | 228 + tjp/core/algorithm/starts_with.hpp | 37 + tjp/core/algorithm/starts_with_value.hpp | 18 + tjp/core/algorithm/string_has.hpp | 22 + tjp/core/algorithm/tuple_has_value.hpp | 33 + tjp/core/algorithm/unused.hpp | 11 + tjp/core/algorithm/update_if_different.hpp | 19 + tjp/core/algorithm/vector_append.hpp | 16 + tjp/core/algorithm/vector_erase_if_value.hpp | 32 + tjp/core/algorithm/vector_erase_value_all.hpp | 32 + tjp/core/algorithm/vector_erase_value_one.hpp | 35 + .../vector_get_optional_erase_if.hpp | 36 + tjp/core/algorithm/vector_has.hpp | 25 + tjp/core/algorithm/vector_has_if.hpp | 17 + tjp/core/algorithm/vector_value.hpp | 28 + tjp/core/algorithm/vector_value_at.hpp | 22 + tjp/core/algorithm/vector_value_before_if.hpp | 27 + tjp/core/algorithm/vector_value_if.hpp | 26 + tjp/core/algorithm/vector_value_if_index.hpp | 26 + tjp/core/algorithm/vector_value_index_if.hpp | 25 + tjp/core/assert/debug_assert.cpp | 12 + tjp/core/assert/debug_assert.h | 13 + tjp/core/assert/debug_assert_complex.h | 34 + tjp/core/assert/debug_assert_simple.h | 25 + tjp/core/assert/handle_assert.cpp | 35 + tjp/core/assert/handle_assert.hpp | 18 + tjp/core/assert/handle_assert_complex.hpp | 40 + tjp/core/assert/handle_assert_simple.hpp | 14 + tjp/core/assert/release_assert.h | 15 + tjp/core/const_expr/Str+IO.hpp | 23 + tjp/core/const_expr/Str.hpp | 96 + tjp/core/const_expr/_tests/Str.cpp | 27 + tjp/core/const_expr/_tests/concat.cpp | 39 + tjp/core/const_expr/_tests/length.cpp | 24 + tjp/core/const_expr/_tests/remove_char.cpp | 99 + tjp/core/const_expr/concat.hpp | 26 + tjp/core/const_expr/count_char.hpp | 35 + tjp/core/const_expr/length.hpp | 21 + tjp/core/const_expr/remove_char.hpp | 40 + tjp/core/const_hash/Hash+simple.hpp | 33 + tjp/core/const_hash/Hash+zltan+expected.inl | 50 + tjp/core/const_hash/Hash+zltan.hpp | 123 + tjp/core/const_hash/Hash.cpp | 32 + tjp/core/const_hash/Hash.h | 19 + tjp/core/const_hash/Hash.hpp | 252 + tjp/core/const_hash/_tests/Hash.cpp | 85 + tjp/core/const_hash/_tests/HashExpected.cpp | 60 + tjp/core/const_hash/smhasher/CMakeLists.txt | 44 + tjp/core/const_hash/smhasher/Platform.h | 94 + tjp/core/const_hash/smhasher/ZLTanP.cpp | 17 + tjp/core/const_hash/smhasher/ZLTanP.h | 46 + tjp/core/const_hash/smhasher/ZLTanP.hpp | 1 + tjp/core/const_hash/smhasher/clone.txt | 19 + tjp/core/const_hash/smhasher/main.cpp | 603 + tjp/core/containers/Align.h | 13 + tjp/core/containers/Array+IO.hpp | 36 + tjp/core/containers/Array.h | 14 + tjp/core/containers/Array.hpp | 7 + tjp/core/containers/ByF.hpp | 34 + tjp/core/containers/ById.hpp | 31 + tjp/core/containers/ByPtr.hpp | 31 + tjp/core/containers/ByPtrId.hpp | 42 + tjp/core/containers/ByStrongPtrId.hpp | 34 + tjp/core/containers/FilledArray.h | 18 + tjp/core/containers/FilledArray.hpp | 66 + tjp/core/containers/FilledArrayThreadSafe.h | 20 + tjp/core/containers/FilledArrayThreadSafe.hpp | 34 + tjp/core/containers/Function.h | 14 + tjp/core/containers/Function.hpp | 7 + tjp/core/containers/InPlaceArray+iterator.inl | 64 + tjp/core/containers/InPlaceArray.h | 17 + tjp/core/containers/InPlaceArray.hpp | 137 + tjp/core/containers/InPlaceArray.inl | 333 + tjp/core/containers/List.h | 14 + tjp/core/containers/List.hpp | 7 + tjp/core/containers/Map.h | 14 + tjp/core/containers/Map.hpp | 7 + tjp/core/containers/MemoryArray.h | 23 + tjp/core/containers/MemoryArray.hpp | 170 + tjp/core/containers/MemorySegment.h | 13 + tjp/core/containers/MemorySegment.hpp | 75 + tjp/core/containers/MultiContainer.hpp | 232 + tjp/core/containers/Optional+IO.hpp | 17 + tjp/core/containers/Optional.h | 14 + tjp/core/containers/Optional.hpp | 7 + tjp/core/containers/Pack.h | 13 + tjp/core/containers/Pair.h | 14 + tjp/core/containers/Pair.hpp | 7 + tjp/core/containers/PtrOnly.h | 14 + tjp/core/containers/PtrOnly.hpp | 59 + tjp/core/containers/PtrOrValue.h | 14 + tjp/core/containers/PtrOrValue.hpp | 70 + tjp/core/containers/Queue.h | 16 + tjp/core/containers/QueueThreadSafe.hpp | 80 + tjp/core/containers/Reversed.h | 17 + tjp/core/containers/Reversed.hpp | 67 + tjp/core/containers/SafeIteration+IO.h | 17 + tjp/core/containers/SafeIteration.h | 31 + tjp/core/containers/SafeIteration.hpp | 7 + .../SafeIteration_v_all_mutable.hpp | 369 + .../containers/SafeIteration_v_consts.hpp | 364 + tjp/core/containers/Set.h | 17 + tjp/core/containers/Set.hpp | 7 + tjp/core/containers/StackArray+IO.hpp | 13 + tjp/core/containers/StackArray+hash.hpp | 34 + tjp/core/containers/StackArray.h | 14 + tjp/core/containers/StackArray.hpp | 13 + tjp/core/containers/StackArray_v2+IO.hpp | 51 + tjp/core/containers/StackArray_v2+hash.hpp | 12 + tjp/core/containers/StackArray_v2.h | 18 + tjp/core/containers/StackArray_v2.hpp | 120 + tjp/core/containers/StackArray_v2.inl | 411 + tjp/core/containers/TransparentLess.hpp | 20 + tjp/core/containers/Tuple.h | 14 + tjp/core/containers/Tuple.hpp | 7 + tjp/core/containers/UnorderedMap.h | 14 + tjp/core/containers/UnorderedMap.hpp | 7 + tjp/core/containers/UnorderedSet.h | 14 + tjp/core/containers/UnorderedSet.hpp | 7 + tjp/core/containers/Vector.h | 14 + tjp/core/containers/Vector.hpp | 7 + tjp/core/containers/_tests/InPlaceArray.cpp | 187 + tjp/core/containers/_tests/MultiContainer.cpp | 108 + tjp/core/containers/_tests/SafeIteration.cpp | 114 + tjp/core/containers/_tests/StackArray_v2.cpp | 91 + tjp/core/debug/Allocations.cpp | 42 + tjp/core/debug/Allocations.h | 58 + tjp/core/debug/Allocations.hpp | 25 + tjp/core/debug/CompileTimeSizeOf.h | 14 + tjp/core/debug/Debug.h | 34 + tjp/core/debug/RUN_IF.h | 7 + tjp/core/debug/Stack.h | 23 + tjp/core/debug/StackUsage.cpp | 99 + tjp/core/debug/StackUsage.h | 13 + tjp/core/debug/android/Stack.cpp | 81 + tjp/core/debug/debug_break.h | 24 + tjp/core/debug/glib/Stack.cpp | 43 + tjp/core/exception/Exception+IO.hpp | 19 + tjp/core/exception/Exception.cpp | 16 + tjp/core/exception/Exception.h | 20 + tjp/core/exception/Exception.hpp | 71 + tjp/core/exception/NotImplemented.h | 13 + tjp/core/exception/NotImplemented.hpp | 16 + tjp/core/exception/NullPointer.h | 15 + tjp/core/exception/NullPointer.hpp | 15 + tjp/core/exception/OutOfBounds.h | 15 + tjp/core/exception/OutOfBounds.hpp | 16 + tjp/core/exception/debug_throw.h | 41 + tjp/core/header_only/compile.h | 12 + tjp/core/io/memstream.h | 15 + tjp/core/io/memstream.hpp | 110 + tjp/core/iterators/_tests/enumerate.cpp | 105 + .../iterators/_tests/fail_on_copy_vector.hpp | 31 + tjp/core/iterators/_tests/is_first.cpp | 42 + tjp/core/iterators/_tests/no_first.cpp | 76 + tjp/core/iterators/_tests/no_last.cpp | 76 + tjp/core/iterators/_tests/range.cpp | 61 + tjp/core/iterators/_tests/range_with.cpp | 57 + tjp/core/iterators/_tests/reverse.cpp | 43 + tjp/core/iterators/_tests/safe_next.cpp | 85 + tjp/core/iterators/_tests/transform_with.cpp | 75 + tjp/core/iterators/_tests/zip.cpp | 96 + tjp/core/iterators/enumerate.hpp | 88 + tjp/core/iterators/is_first.hpp | 39 + tjp/core/iterators/macro_min_max.h | 14 + tjp/core/iterators/no_first.hpp | 42 + tjp/core/iterators/no_last.hpp | 42 + tjp/core/iterators/range.hpp | 85 + tjp/core/iterators/range_with.hpp | 70 + tjp/core/iterators/reverse.hpp | 30 + tjp/core/iterators/safe_next.hpp | 89 + tjp/core/iterators/safe_next_with.hpp | 87 + tjp/core/iterators/transform_with.hpp | 67 + tjp/core/iterators/zip.hpp | 151 + tjp/core/log/Color.cpp | 68 + tjp/core/log/Color.hpp | 95 + tjp/core/log/Color.inl | 21 + tjp/core/log/Detail.cpp | 244 + tjp/core/log/Detail.h | 10 + tjp/core/log/Detail.hpp | 126 + tjp/core/log/Log+Precision.h | 14 + tjp/core/log/Log.cpp | 171 + tjp/core/log/Log.h | 242 + tjp/core/log/LogOf.h | 192 + tjp/core/log/Util.inl | 170 + tjp/core/log/_tests/LogOf.cpp | 96 + tjp/core/log/demangle.cpp | 16 + tjp/core/log/demangle.h | 11 + tjp/core/math/Float16.h | 13 + tjp/core/math/Float16.hpp | 74 + tjp/core/math/Float16.inl | 186 + tjp/core/math/_tests/Float16.cpp | 113 + tjp/core/ptr/Ptr+IO.h | 18 + tjp/core/ptr/Ptr+Log.hpp | 32 + tjp/core/ptr/Ptr+Version.h | 9 + tjp/core/ptr/Ptr.h | 49 + tjp/core/ptr/Ptr.hpp | 42 + tjp/core/ptr/_tests/Ptr.cpp | 152 + tjp/core/ptr/std/CustomControlBlock.h | 63 + tjp/core/ptr/std/Ptr+Debug.h | 12 + tjp/core/ptr/std/Ptr+GCC.h | 129 + tjp/core/ptr/std/Ptr+IO.h | 34 + tjp/core/ptr/std/Ptr+LLVM.h | 78 + tjp/core/ptr/std/Ptr+Log.h | 38 + tjp/core/ptr/std/Ptr.h | 140 + tjp/core/ptr/strong_emplace.hpp | 22 + tjp/core/ptr/strong_init.hpp | 22 + tjp/core/ptr/strong_of.hpp | 24 + tjp/core/ptr/using_info/Ptr+Debug.h | 14 + tjp/core/ptr/using_info/Ptr+IO.h | 55 + tjp/core/ptr/using_info/Ptr+Log.cpp | 13 + tjp/core/ptr/using_info/Ptr+Log.h | 27 + tjp/core/ptr/using_info/Ptr+Logging.cpp | 46 + tjp/core/ptr/using_info/Ptr.cpp | 26 + tjp/core/ptr/using_info/Ptr.h | 95 + tjp/core/ptr/using_info/Ptr.hpp | 315 + tjp/core/ptr/using_info/Ptr.inl | 545 + tjp/core/ptr/using_info/_tests/Ptr.cpp | 65 + tjp/core/ptr/using_maps/Ptr+Debug.h | 14 + tjp/core/ptr/using_maps/Ptr+IO.h | 41 + tjp/core/ptr/using_maps/Ptr+Log.h | 25 + tjp/core/ptr/using_maps/Ptr+Logging.cpp | 70 + tjp/core/ptr/using_maps/Ptr.cpp | 37 + tjp/core/ptr/using_maps/Ptr.h | 61 + tjp/core/ptr/using_maps/Ptr.hpp | 598 + tjp/core/ptr/using_maps/_tests/Ptr.cpp | 68 + tjp/core/rtti/RTTI+custom.hpp | 165 + tjp/core/rtti/RTTI+std.hpp | 48 + tjp/core/rtti/RTTI.cpp | 162 + tjp/core/rtti/RTTI.hpp | 20 + tjp/core/rtti/TypeName+custom.hpp | 139 + tjp/core/rtti/TypeName.hpp | 38 + tjp/core/rtti/_tests/All.cxx | 382 + tjp/core/rtti/_tests/TypeName.cpp | 77 + tjp/core/sfinae/_tests/if_or.cpp | 26 + tjp/core/sfinae/if_or.hpp | 20 + tjp/core/string/Dictionary.h | 90 + tjp/core/string/Dictionary.inl | 233 + tjp/core/string/Str+IO.h | 40 + tjp/core/string/Str+IO.inl | 26 + tjp/core/string/Str.cpp | 10 + tjp/core/string/Str.h | 150 + tjp/core/string/Str.hpp | 58 + tjp/core/string/Str.inl | 464 + tjp/core/string/String.h | 13 + tjp/core/string/String.hpp | 7 + tjp/core/string/StringView+concat.hpp | 81 + tjp/core/string/StringView+less.hpp | 25 + tjp/core/string/StringView.h | 13 + tjp/core/string/StringView.hpp | 7 + tjp/core/string/String_.h | 13 + tjp/core/string/ToString.hpp | 40 + tjp/core/string/Tokenizer.h | 17 + tjp/core/string/Tokenizer.hpp | 132 + tjp/core/string/_tests/Dictionary.cpp | 41 + tjp/core/string/_tests/Str.cpp | 54 + tjp/core/string/_tests/cmp_case.cpp | 59 + tjp/core/string/_tests/join.cpp | 53 + tjp/core/string/_tests/replace.cpp | 58 + tjp/core/string/_tests/split_once.cpp | 48 + tjp/core/string/_tests/strncasecmp.cpp | 50 + tjp/core/string/_tests/strncmp.cpp | 50 + tjp/core/string/_tests/trim.cpp | 57 + tjp/core/string/as_string.hpp | 25 + tjp/core/string/as_string_view.hpp | 17 + tjp/core/string/as_vector.hpp | 37 + tjp/core/string/auto_to_string.hpp | 25 + tjp/core/string/cmp.cpp | 50 + tjp/core/string/cmp.hpp | 20 + tjp/core/string/cmp_case.cpp | 52 + tjp/core/string/cmp_case.hpp | 25 + tjp/core/string/ends_with.hpp | 7 + tjp/core/string/find_after.hpp | 26 + tjp/core/string/find_if.hpp | 23 + tjp/core/string/from_string.cpp | 69 + tjp/core/string/from_string.h | 25 + tjp/core/string/from_string.hpp | 14 + tjp/core/string/from_string.inl | 44 + tjp/core/string/has.hpp | 17 + tjp/core/string/has_prefix.hpp | 17 + tjp/core/string/join.hpp | 72 + tjp/core/string/replace.cpp | 37 + tjp/core/string/replace.h | 19 + tjp/core/string/replaced.cpp | 23 + tjp/core/string/replaced.h | 15 + tjp/core/string/split.hpp | 16 + tjp/core/string/split.inl | 49 + tjp/core/string/split_once.hpp | 26 + tjp/core/string/starts_with.hpp | 7 + tjp/core/string/str_find.cpp | 62 + tjp/core/string/str_find.h | 16 + tjp/core/string/strncasecmp.cpp | 32 + tjp/core/string/strncasecmp.h | 17 + tjp/core/string/strncmp.cpp | 28 + tjp/core/string/strncmp.h | 13 + tjp/core/string/sxprintf.h | 21 + tjp/core/string/to_lower.hpp | 27 + tjp/core/string/to_string.h | 23 + tjp/core/string/to_string.hpp | 40 + tjp/core/string/trim.h | 32 + tjp/core/string/trim.inl | 49 + tjp/core/string/unprefix.hpp | 21 + tjp/core/system/Debug.h | 17 + tjp/core/system/DisableWarningsAllPop.h | 12 + tjp/core/system/DisableWarningsAllPush.h | 16 + tjp/core/system/DisableWarningsPop.h | 14 + tjp/core/system/DisableWarningsPush.h | 28 + tjp/core/system/Optimization.h | 26 + tjp/core/system/System.h | 54 + tjp/core/testing/Defines.h | 11 + tjp/core/testing/NO_WHEN.h | 11 + tjp/core/testing/TESTING_ONLY.h | 12 + tjp/core/testing/TEST_SIGNAL.cpp | 182 + tjp/core/testing/TEST_SIGNAL.h | 163 + tjp/core/testing/THEN_REQUIRE.h | 8 + tjp/core/testing/_tests/TEST_SIGNAL.cpp | 59 + tjp/core/testing/catch.cpp | 27 + tjp/core/testing/catch.hpp | 21 + tjp/core/testing/catch2.hpp | 17802 ++++++++++++++++ tjp/core/testing/wait_until.h | 43 + tjp/core/threads/Atomic.h | 14 + tjp/core/threads/Atomic.hpp | 7 + tjp/core/threads/Lock.h | 12 + tjp/core/threads/Lock.hpp | 12 + tjp/core/threads/LockedBy.h | 12 + tjp/core/threads/LockedBy.hpp | 56 + tjp/core/threads/Pin.h | 11 + tjp/core/threads/Pin.hpp | 27 + tjp/core/threads/SharedLockGuard.hpp | 43 + tjp/core/threads/SpinMutex.cpp | 25 + tjp/core/threads/SpinMutex.hpp | 129 + tjp/core/threads/TestCollision.h | 79 + tjp/core/threads/TestMutex.h | 12 + tjp/core/threads/TestMutex.hpp | 70 + tjp/core/threads/TestMutex.inl | 92 + tjp/core/threads/ThreadSafe.h | 12 + tjp/core/threads/ThreadSafe.hpp | 65 + tjp/core/threads/TryLockGuard.hpp | 34 + tjp/core/threads/UnlockGuard.hpp | 27 + tjp/core/threads/_tests/Lock.cpp | 25 + tjp/core/threads/_tests/TestMutex.cpp | 5 + tjp/core/threads/micropause.hpp | 30 + tjp/core/threads/process_queue.hpp | 39 + tjp/core/threads/std/Lock.h | 17 + tjp/core/threads/std/Lock.hpp | 227 + tjp/core/threads/with_lock.hpp | 16 + tjp/core/threads/with_lock_value.hpp | 16 + tjp/core/time/Source.cpp | 17 + tjp/core/time/Source.h | 12 + tjp/core/time/Source.hpp | 17 + tjp/core/time/Time+IO.cpp | 30 + tjp/core/time/Time+IO.hpp | 32 + tjp/core/time/Time+chrono+misc.hpp | 31 + tjp/core/time/Time+chrono.hpp | 37 + tjp/core/time/Time+operations.hpp | 216 + tjp/core/time/Time+timestamp.hpp | 59 + tjp/core/time/Time.cpp | 12 + tjp/core/time/Time.h | 17 + tjp/core/time/Time.hpp | 59 + tjp/core/timer/Timer.h | 11 + tjp/core/timer/Timer.hpp | 96 + tjp/core/timer/_tests/Timer.cpp | 30 + tjp/core/type_traits/_tests/is_map.cpp | 5 + tjp/core/type_traits/_tests/is_vector.cpp | 5 + tjp/core/type_traits/always_false.hpp | 13 + tjp/core/type_traits/is_callable.hpp | 102 + .../type_traits/is_callable_with_two_args.hpp | 30 + tjp/core/type_traits/is_comparable.hpp | 422 + tjp/core/type_traits/is_iterable.hpp | 24 + tjp/core/type_traits/is_map.hpp | 22 + tjp/core/type_traits/is_mappish.hpp | 33 + tjp/core/type_traits/is_string.hpp | 30 + tjp/core/type_traits/is_vector.hpp | 22 + tjp/core/types/CounterFor.h | 55 + tjp/core/types/Definitions.h | 33 + tjp/core/types/Types+IO.cpp | 58 + tjp/core/types/Types+IO.h | 19 + tjp/core/types/Types.h | 24 + tjp/core/types/Types_.h | 14 + tjp/core/types/linux/Types.h | 21 + 521 files changed, 46722 insertions(+) create mode 100644 .gitignore create mode 100644 Core_Zero.xcodeproj/project.pbxproj create mode 100644 Core_Zero.xcodeproj/project.xcworkspace/contents.xcworkspacedata create mode 100644 Core_Zero.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist create mode 100644 Core_Zero.xcodeproj/xcshareddata/xcschemes/Core_Zero_Tests.xcscheme create mode 100644 Examples.cpp create mode 100755 LICENSE create mode 100644 Makefile create mode 100755 Makefile.def create mode 100755 Makefile.project create mode 100755 ReadMe.md create mode 100644 core create mode 120000 tests/Makefile create mode 100755 tests/Makefile.project create mode 100644 tests/Run.cpp create mode 100644 tjp/core/Precompile.pch create mode 100755 tjp/core/algorithm/ExecuteOnDestruct.h create mode 100755 tjp/core/algorithm/ExecuteOnDestruct.hpp create mode 100755 tjp/core/algorithm/_tests/all_are.cpp create mode 100755 tjp/core/algorithm/_tests/container_erase_if.cpp create mode 100755 tjp/core/algorithm/_tests/container_erase_if_one.cpp create mode 100755 tjp/core/algorithm/_tests/container_erase_value_all.cpp create mode 100755 tjp/core/algorithm/_tests/container_erase_value_one.cpp create mode 100755 tjp/core/algorithm/_tests/container_find_if.cpp create mode 100755 tjp/core/algorithm/_tests/container_get_if.cpp create mode 100755 tjp/core/algorithm/_tests/container_get_if_optional.cpp create mode 100755 tjp/core/algorithm/_tests/container_get_if_optional_erase.cpp create mode 100755 tjp/core/algorithm/_tests/container_get_optional_erase.cpp create mode 100755 tjp/core/algorithm/_tests/container_has.cpp create mode 100755 tjp/core/algorithm/_tests/container_has_if.cpp create mode 100755 tjp/core/algorithm/_tests/copy_clear.cpp create mode 100755 tjp/core/algorithm/_tests/copy_of.cpp create mode 100755 tjp/core/algorithm/_tests/emplace.cpp create mode 100755 tjp/core/algorithm/_tests/empty_of.cpp create mode 100755 tjp/core/algorithm/_tests/ends_with.cpp create mode 100755 tjp/core/algorithm/_tests/has_last.cpp create mode 100755 tjp/core/algorithm/_tests/in_range_segment.cpp create mode 100755 tjp/core/algorithm/_tests/is_in.cpp create mode 100755 tjp/core/algorithm/_tests/is_zero.cpp create mode 100755 tjp/core/algorithm/_tests/last_of_parameter_pack.cpp create mode 100755 tjp/core/algorithm/_tests/list_erase_if.cpp create mode 100755 tjp/core/algorithm/_tests/list_erase_if_value.cpp create mode 100755 tjp/core/algorithm/_tests/map_erase.cpp create mode 100755 tjp/core/algorithm/_tests/map_erase_if.cpp create mode 100755 tjp/core/algorithm/_tests/map_erase_if_key.cpp create mode 100755 tjp/core/algorithm/_tests/map_erase_if_value.cpp create mode 100755 tjp/core/algorithm/_tests/map_for_each_value.cpp create mode 100755 tjp/core/algorithm/_tests/map_has.cpp create mode 100755 tjp/core/algorithm/_tests/map_has_key.cpp create mode 100755 tjp/core/algorithm/_tests/map_iterator_or_insert.cpp create mode 100755 tjp/core/algorithm/_tests/map_value.cpp create mode 100755 tjp/core/algorithm/_tests/map_value_require.cpp create mode 100755 tjp/core/algorithm/_tests/no_throw.cpp create mode 100755 tjp/core/algorithm/_tests/not_zero.cpp create mode 100755 tjp/core/algorithm/_tests/on_destruct.cpp create mode 100755 tjp/core/algorithm/_tests/one_is.cpp create mode 100755 tjp/core/algorithm/_tests/optional_value.cpp create mode 100755 tjp/core/algorithm/_tests/optional_value_or_default.cpp create mode 100755 tjp/core/algorithm/_tests/set_empty.cpp create mode 100755 tjp/core/algorithm/_tests/small_cmp.cpp create mode 100755 tjp/core/algorithm/_tests/small_copy.cpp create mode 100755 tjp/core/algorithm/_tests/starts_with.cpp create mode 100755 tjp/core/algorithm/_tests/vector_append.cpp create mode 100755 tjp/core/algorithm/_tests/vector_erase_if_value.cpp create mode 100755 tjp/core/algorithm/_tests/vector_erase_value_all.cpp create mode 100755 tjp/core/algorithm/_tests/vector_erase_value_one.cpp create mode 100755 tjp/core/algorithm/all_are.hpp create mode 100755 tjp/core/algorithm/cmp.hpp create mode 100755 tjp/core/algorithm/container_count_if.hpp create mode 100755 tjp/core/algorithm/container_erase_if.hpp create mode 100755 tjp/core/algorithm/container_erase_if_imp_use_iterator.hpp create mode 100755 tjp/core/algorithm/container_erase_if_one.hpp create mode 100755 tjp/core/algorithm/container_erase_value_all.hpp create mode 100755 tjp/core/algorithm/container_erase_value_one.hpp create mode 100755 tjp/core/algorithm/container_find_if.hpp create mode 100755 tjp/core/algorithm/container_get_if.hpp create mode 100755 tjp/core/algorithm/container_get_if_optional.hpp create mode 100755 tjp/core/algorithm/container_get_if_optional_erase.hpp create mode 100755 tjp/core/algorithm/container_get_optional_erase.hpp create mode 100755 tjp/core/algorithm/container_has.hpp create mode 100755 tjp/core/algorithm/container_has_if.hpp create mode 100755 tjp/core/algorithm/copy_clear.hpp create mode 100755 tjp/core/algorithm/copy_clear_delete.hpp create mode 100755 tjp/core/algorithm/copy_of.hpp create mode 100755 tjp/core/algorithm/emplace.hpp create mode 100755 tjp/core/algorithm/empty_of.hpp create mode 100755 tjp/core/algorithm/ends_with.hpp create mode 100755 tjp/core/algorithm/has_last.hpp create mode 100755 tjp/core/algorithm/has_sequence.hpp create mode 100755 tjp/core/algorithm/in_range_segment.hpp create mode 100755 tjp/core/algorithm/is_in.hpp create mode 100755 tjp/core/algorithm/is_zero.hpp create mode 100755 tjp/core/algorithm/last_of_parameter_pack.hpp create mode 100755 tjp/core/algorithm/list_erase_if.hpp create mode 100755 tjp/core/algorithm/list_erase_if_value.hpp create mode 100755 tjp/core/algorithm/list_erase_value_all.hpp create mode 100755 tjp/core/algorithm/list_erase_value_one.hpp create mode 100755 tjp/core/algorithm/map_erase.hpp create mode 100755 tjp/core/algorithm/map_erase_get_optional.hpp create mode 100755 tjp/core/algorithm/map_erase_if.hpp create mode 100755 tjp/core/algorithm/map_erase_if_key.hpp create mode 100755 tjp/core/algorithm/map_erase_if_value.hpp create mode 100755 tjp/core/algorithm/map_for_each_value.hpp create mode 100755 tjp/core/algorithm/map_has.hpp create mode 100755 tjp/core/algorithm/map_has_key.hpp create mode 100755 tjp/core/algorithm/map_insert.hpp create mode 100755 tjp/core/algorithm/map_iterator_or_insert.hpp create mode 100755 tjp/core/algorithm/map_pair.hpp create mode 100755 tjp/core/algorithm/map_set_or_erase_optional.hpp create mode 100755 tjp/core/algorithm/map_value.hpp create mode 100755 tjp/core/algorithm/map_value_erase.hpp create mode 100755 tjp/core/algorithm/map_value_optional.hpp create mode 100755 tjp/core/algorithm/map_value_or_default.hpp create mode 100755 tjp/core/algorithm/map_value_or_insert.hpp create mode 100755 tjp/core/algorithm/map_value_or_insert_value.hpp create mode 100755 tjp/core/algorithm/map_value_require.hpp create mode 100755 tjp/core/algorithm/mem_copy.hpp create mode 100755 tjp/core/algorithm/mem_copy_asan_safe.hpp create mode 100755 tjp/core/algorithm/no_throw.hpp create mode 100755 tjp/core/algorithm/not_zero.hpp create mode 100755 tjp/core/algorithm/numeric_limits.hpp create mode 100755 tjp/core/algorithm/on_destruct.hpp create mode 100755 tjp/core/algorithm/one_is.hpp create mode 100755 tjp/core/algorithm/optional_of_ptr.hpp create mode 100755 tjp/core/algorithm/optional_set_if_empty.hpp create mode 100755 tjp/core/algorithm/optional_value.hpp create mode 100755 tjp/core/algorithm/optional_value_or_default.hpp create mode 100644 tjp/core/algorithm/remove_const_of_var.hpp create mode 100755 tjp/core/algorithm/set_empty.hpp create mode 100755 tjp/core/algorithm/set_erase.hpp create mode 100755 tjp/core/algorithm/set_erase_if_value.hpp create mode 100755 tjp/core/algorithm/set_erase_optional_value.hpp create mode 100755 tjp/core/algorithm/set_erase_optional_value_move.hpp create mode 100755 tjp/core/algorithm/set_has.hpp create mode 100755 tjp/core/algorithm/set_insert.hpp create mode 100755 tjp/core/algorithm/set_insert_mutable.hpp create mode 100755 tjp/core/algorithm/set_insert_once.hpp create mode 100755 tjp/core/algorithm/set_once.hpp create mode 100755 tjp/core/algorithm/set_value.hpp create mode 100755 tjp/core/algorithm/set_value_mutable.hpp create mode 100755 tjp/core/algorithm/small_cmp.hpp create mode 100755 tjp/core/algorithm/small_copy.hpp create mode 100755 tjp/core/algorithm/starts_with.hpp create mode 100755 tjp/core/algorithm/starts_with_value.hpp create mode 100755 tjp/core/algorithm/string_has.hpp create mode 100755 tjp/core/algorithm/tuple_has_value.hpp create mode 100644 tjp/core/algorithm/unused.hpp create mode 100644 tjp/core/algorithm/update_if_different.hpp create mode 100755 tjp/core/algorithm/vector_append.hpp create mode 100755 tjp/core/algorithm/vector_erase_if_value.hpp create mode 100755 tjp/core/algorithm/vector_erase_value_all.hpp create mode 100755 tjp/core/algorithm/vector_erase_value_one.hpp create mode 100755 tjp/core/algorithm/vector_get_optional_erase_if.hpp create mode 100755 tjp/core/algorithm/vector_has.hpp create mode 100755 tjp/core/algorithm/vector_has_if.hpp create mode 100755 tjp/core/algorithm/vector_value.hpp create mode 100755 tjp/core/algorithm/vector_value_at.hpp create mode 100755 tjp/core/algorithm/vector_value_before_if.hpp create mode 100755 tjp/core/algorithm/vector_value_if.hpp create mode 100755 tjp/core/algorithm/vector_value_if_index.hpp create mode 100755 tjp/core/algorithm/vector_value_index_if.hpp create mode 100755 tjp/core/assert/debug_assert.cpp create mode 100755 tjp/core/assert/debug_assert.h create mode 100755 tjp/core/assert/debug_assert_complex.h create mode 100755 tjp/core/assert/debug_assert_simple.h create mode 100755 tjp/core/assert/handle_assert.cpp create mode 100755 tjp/core/assert/handle_assert.hpp create mode 100755 tjp/core/assert/handle_assert_complex.hpp create mode 100755 tjp/core/assert/handle_assert_simple.hpp create mode 100755 tjp/core/assert/release_assert.h create mode 100755 tjp/core/const_expr/Str+IO.hpp create mode 100755 tjp/core/const_expr/Str.hpp create mode 100755 tjp/core/const_expr/_tests/Str.cpp create mode 100755 tjp/core/const_expr/_tests/concat.cpp create mode 100755 tjp/core/const_expr/_tests/length.cpp create mode 100644 tjp/core/const_expr/_tests/remove_char.cpp create mode 100755 tjp/core/const_expr/concat.hpp create mode 100755 tjp/core/const_expr/count_char.hpp create mode 100755 tjp/core/const_expr/length.hpp create mode 100755 tjp/core/const_expr/remove_char.hpp create mode 100644 tjp/core/const_hash/Hash+simple.hpp create mode 100644 tjp/core/const_hash/Hash+zltan+expected.inl create mode 100644 tjp/core/const_hash/Hash+zltan.hpp create mode 100644 tjp/core/const_hash/Hash.cpp create mode 100644 tjp/core/const_hash/Hash.h create mode 100644 tjp/core/const_hash/Hash.hpp create mode 100644 tjp/core/const_hash/_tests/Hash.cpp create mode 100644 tjp/core/const_hash/_tests/HashExpected.cpp create mode 100644 tjp/core/const_hash/smhasher/CMakeLists.txt create mode 100644 tjp/core/const_hash/smhasher/Platform.h create mode 100644 tjp/core/const_hash/smhasher/ZLTanP.cpp create mode 100644 tjp/core/const_hash/smhasher/ZLTanP.h create mode 120000 tjp/core/const_hash/smhasher/ZLTanP.hpp create mode 100644 tjp/core/const_hash/smhasher/clone.txt create mode 100644 tjp/core/const_hash/smhasher/main.cpp create mode 100755 tjp/core/containers/Align.h create mode 100755 tjp/core/containers/Array+IO.hpp create mode 100755 tjp/core/containers/Array.h create mode 100755 tjp/core/containers/Array.hpp create mode 100755 tjp/core/containers/ByF.hpp create mode 100755 tjp/core/containers/ById.hpp create mode 100755 tjp/core/containers/ByPtr.hpp create mode 100755 tjp/core/containers/ByPtrId.hpp create mode 100755 tjp/core/containers/ByStrongPtrId.hpp create mode 100755 tjp/core/containers/FilledArray.h create mode 100755 tjp/core/containers/FilledArray.hpp create mode 100755 tjp/core/containers/FilledArrayThreadSafe.h create mode 100755 tjp/core/containers/FilledArrayThreadSafe.hpp create mode 100755 tjp/core/containers/Function.h create mode 100755 tjp/core/containers/Function.hpp create mode 100755 tjp/core/containers/InPlaceArray+iterator.inl create mode 100755 tjp/core/containers/InPlaceArray.h create mode 100755 tjp/core/containers/InPlaceArray.hpp create mode 100755 tjp/core/containers/InPlaceArray.inl create mode 100755 tjp/core/containers/List.h create mode 100755 tjp/core/containers/List.hpp create mode 100755 tjp/core/containers/Map.h create mode 100755 tjp/core/containers/Map.hpp create mode 100755 tjp/core/containers/MemoryArray.h create mode 100755 tjp/core/containers/MemoryArray.hpp create mode 100755 tjp/core/containers/MemorySegment.h create mode 100755 tjp/core/containers/MemorySegment.hpp create mode 100755 tjp/core/containers/MultiContainer.hpp create mode 100755 tjp/core/containers/Optional+IO.hpp create mode 100755 tjp/core/containers/Optional.h create mode 100755 tjp/core/containers/Optional.hpp create mode 100755 tjp/core/containers/Pack.h create mode 100755 tjp/core/containers/Pair.h create mode 100755 tjp/core/containers/Pair.hpp create mode 100755 tjp/core/containers/PtrOnly.h create mode 100755 tjp/core/containers/PtrOnly.hpp create mode 100755 tjp/core/containers/PtrOrValue.h create mode 100755 tjp/core/containers/PtrOrValue.hpp create mode 100755 tjp/core/containers/Queue.h create mode 100755 tjp/core/containers/QueueThreadSafe.hpp create mode 100755 tjp/core/containers/Reversed.h create mode 100755 tjp/core/containers/Reversed.hpp create mode 100755 tjp/core/containers/SafeIteration+IO.h create mode 100755 tjp/core/containers/SafeIteration.h create mode 100755 tjp/core/containers/SafeIteration.hpp create mode 100755 tjp/core/containers/SafeIteration_v_all_mutable.hpp create mode 100755 tjp/core/containers/SafeIteration_v_consts.hpp create mode 100755 tjp/core/containers/Set.h create mode 100755 tjp/core/containers/Set.hpp create mode 100755 tjp/core/containers/StackArray+IO.hpp create mode 100755 tjp/core/containers/StackArray+hash.hpp create mode 100755 tjp/core/containers/StackArray.h create mode 100755 tjp/core/containers/StackArray.hpp create mode 100755 tjp/core/containers/StackArray_v2+IO.hpp create mode 100755 tjp/core/containers/StackArray_v2+hash.hpp create mode 100755 tjp/core/containers/StackArray_v2.h create mode 100755 tjp/core/containers/StackArray_v2.hpp create mode 100755 tjp/core/containers/StackArray_v2.inl create mode 100755 tjp/core/containers/TransparentLess.hpp create mode 100755 tjp/core/containers/Tuple.h create mode 100755 tjp/core/containers/Tuple.hpp create mode 100755 tjp/core/containers/UnorderedMap.h create mode 100755 tjp/core/containers/UnorderedMap.hpp create mode 100755 tjp/core/containers/UnorderedSet.h create mode 100755 tjp/core/containers/UnorderedSet.hpp create mode 100755 tjp/core/containers/Vector.h create mode 100755 tjp/core/containers/Vector.hpp create mode 100755 tjp/core/containers/_tests/InPlaceArray.cpp create mode 100755 tjp/core/containers/_tests/MultiContainer.cpp create mode 100755 tjp/core/containers/_tests/SafeIteration.cpp create mode 100755 tjp/core/containers/_tests/StackArray_v2.cpp create mode 100755 tjp/core/debug/Allocations.cpp create mode 100755 tjp/core/debug/Allocations.h create mode 100644 tjp/core/debug/Allocations.hpp create mode 100755 tjp/core/debug/CompileTimeSizeOf.h create mode 100755 tjp/core/debug/Debug.h create mode 100755 tjp/core/debug/RUN_IF.h create mode 100755 tjp/core/debug/Stack.h create mode 100755 tjp/core/debug/StackUsage.cpp create mode 100755 tjp/core/debug/StackUsage.h create mode 100755 tjp/core/debug/android/Stack.cpp create mode 100755 tjp/core/debug/debug_break.h create mode 100755 tjp/core/debug/glib/Stack.cpp create mode 100755 tjp/core/exception/Exception+IO.hpp create mode 100755 tjp/core/exception/Exception.cpp create mode 100755 tjp/core/exception/Exception.h create mode 100755 tjp/core/exception/Exception.hpp create mode 100755 tjp/core/exception/NotImplemented.h create mode 100755 tjp/core/exception/NotImplemented.hpp create mode 100755 tjp/core/exception/NullPointer.h create mode 100755 tjp/core/exception/NullPointer.hpp create mode 100755 tjp/core/exception/OutOfBounds.h create mode 100755 tjp/core/exception/OutOfBounds.hpp create mode 100755 tjp/core/exception/debug_throw.h create mode 100755 tjp/core/header_only/compile.h create mode 100755 tjp/core/io/memstream.h create mode 100755 tjp/core/io/memstream.hpp create mode 100755 tjp/core/iterators/_tests/enumerate.cpp create mode 100755 tjp/core/iterators/_tests/fail_on_copy_vector.hpp create mode 100755 tjp/core/iterators/_tests/is_first.cpp create mode 100755 tjp/core/iterators/_tests/no_first.cpp create mode 100755 tjp/core/iterators/_tests/no_last.cpp create mode 100755 tjp/core/iterators/_tests/range.cpp create mode 100755 tjp/core/iterators/_tests/range_with.cpp create mode 100755 tjp/core/iterators/_tests/reverse.cpp create mode 100755 tjp/core/iterators/_tests/safe_next.cpp create mode 100755 tjp/core/iterators/_tests/transform_with.cpp create mode 100755 tjp/core/iterators/_tests/zip.cpp create mode 100755 tjp/core/iterators/enumerate.hpp create mode 100755 tjp/core/iterators/is_first.hpp create mode 100755 tjp/core/iterators/macro_min_max.h create mode 100755 tjp/core/iterators/no_first.hpp create mode 100755 tjp/core/iterators/no_last.hpp create mode 100755 tjp/core/iterators/range.hpp create mode 100755 tjp/core/iterators/range_with.hpp create mode 100755 tjp/core/iterators/reverse.hpp create mode 100755 tjp/core/iterators/safe_next.hpp create mode 100755 tjp/core/iterators/safe_next_with.hpp create mode 100755 tjp/core/iterators/transform_with.hpp create mode 100755 tjp/core/iterators/zip.hpp create mode 100755 tjp/core/log/Color.cpp create mode 100755 tjp/core/log/Color.hpp create mode 100755 tjp/core/log/Color.inl create mode 100755 tjp/core/log/Detail.cpp create mode 100755 tjp/core/log/Detail.h create mode 100755 tjp/core/log/Detail.hpp create mode 100755 tjp/core/log/Log+Precision.h create mode 100755 tjp/core/log/Log.cpp create mode 100755 tjp/core/log/Log.h create mode 100755 tjp/core/log/LogOf.h create mode 100755 tjp/core/log/Util.inl create mode 100755 tjp/core/log/_tests/LogOf.cpp create mode 100755 tjp/core/log/demangle.cpp create mode 100755 tjp/core/log/demangle.h create mode 100644 tjp/core/math/Float16.h create mode 100644 tjp/core/math/Float16.hpp create mode 100644 tjp/core/math/Float16.inl create mode 100755 tjp/core/math/_tests/Float16.cpp create mode 100755 tjp/core/ptr/Ptr+IO.h create mode 100755 tjp/core/ptr/Ptr+Log.hpp create mode 100755 tjp/core/ptr/Ptr+Version.h create mode 100755 tjp/core/ptr/Ptr.h create mode 100755 tjp/core/ptr/Ptr.hpp create mode 100755 tjp/core/ptr/_tests/Ptr.cpp create mode 100755 tjp/core/ptr/std/CustomControlBlock.h create mode 100755 tjp/core/ptr/std/Ptr+Debug.h create mode 100755 tjp/core/ptr/std/Ptr+GCC.h create mode 100755 tjp/core/ptr/std/Ptr+IO.h create mode 100755 tjp/core/ptr/std/Ptr+LLVM.h create mode 100755 tjp/core/ptr/std/Ptr+Log.h create mode 100755 tjp/core/ptr/std/Ptr.h create mode 100755 tjp/core/ptr/strong_emplace.hpp create mode 100755 tjp/core/ptr/strong_init.hpp create mode 100755 tjp/core/ptr/strong_of.hpp create mode 100755 tjp/core/ptr/using_info/Ptr+Debug.h create mode 100755 tjp/core/ptr/using_info/Ptr+IO.h create mode 100755 tjp/core/ptr/using_info/Ptr+Log.cpp create mode 100755 tjp/core/ptr/using_info/Ptr+Log.h create mode 100755 tjp/core/ptr/using_info/Ptr+Logging.cpp create mode 100755 tjp/core/ptr/using_info/Ptr.cpp create mode 100755 tjp/core/ptr/using_info/Ptr.h create mode 100755 tjp/core/ptr/using_info/Ptr.hpp create mode 100755 tjp/core/ptr/using_info/Ptr.inl create mode 100755 tjp/core/ptr/using_info/_tests/Ptr.cpp create mode 100755 tjp/core/ptr/using_maps/Ptr+Debug.h create mode 100755 tjp/core/ptr/using_maps/Ptr+IO.h create mode 100755 tjp/core/ptr/using_maps/Ptr+Log.h create mode 100755 tjp/core/ptr/using_maps/Ptr+Logging.cpp create mode 100755 tjp/core/ptr/using_maps/Ptr.cpp create mode 100755 tjp/core/ptr/using_maps/Ptr.h create mode 100755 tjp/core/ptr/using_maps/Ptr.hpp create mode 100755 tjp/core/ptr/using_maps/_tests/Ptr.cpp create mode 100755 tjp/core/rtti/RTTI+custom.hpp create mode 100755 tjp/core/rtti/RTTI+std.hpp create mode 100755 tjp/core/rtti/RTTI.cpp create mode 100755 tjp/core/rtti/RTTI.hpp create mode 100755 tjp/core/rtti/TypeName+custom.hpp create mode 100755 tjp/core/rtti/TypeName.hpp create mode 100755 tjp/core/rtti/_tests/All.cxx create mode 100755 tjp/core/rtti/_tests/TypeName.cpp create mode 100755 tjp/core/sfinae/_tests/if_or.cpp create mode 100644 tjp/core/sfinae/if_or.hpp create mode 100644 tjp/core/string/Dictionary.h create mode 100644 tjp/core/string/Dictionary.inl create mode 100755 tjp/core/string/Str+IO.h create mode 100755 tjp/core/string/Str+IO.inl create mode 100644 tjp/core/string/Str.cpp create mode 100755 tjp/core/string/Str.h create mode 100755 tjp/core/string/Str.hpp create mode 100644 tjp/core/string/Str.inl create mode 100755 tjp/core/string/String.h create mode 100755 tjp/core/string/String.hpp create mode 100755 tjp/core/string/StringView+concat.hpp create mode 100755 tjp/core/string/StringView+less.hpp create mode 100755 tjp/core/string/StringView.h create mode 100755 tjp/core/string/StringView.hpp create mode 100755 tjp/core/string/String_.h create mode 100644 tjp/core/string/ToString.hpp create mode 100644 tjp/core/string/Tokenizer.h create mode 100644 tjp/core/string/Tokenizer.hpp create mode 100644 tjp/core/string/_tests/Dictionary.cpp create mode 100755 tjp/core/string/_tests/Str.cpp create mode 100755 tjp/core/string/_tests/cmp_case.cpp create mode 100755 tjp/core/string/_tests/join.cpp create mode 100755 tjp/core/string/_tests/replace.cpp create mode 100755 tjp/core/string/_tests/split_once.cpp create mode 100755 tjp/core/string/_tests/strncasecmp.cpp create mode 100755 tjp/core/string/_tests/strncmp.cpp create mode 100755 tjp/core/string/_tests/trim.cpp create mode 100755 tjp/core/string/as_string.hpp create mode 100755 tjp/core/string/as_string_view.hpp create mode 100755 tjp/core/string/as_vector.hpp create mode 100644 tjp/core/string/auto_to_string.hpp create mode 100755 tjp/core/string/cmp.cpp create mode 100755 tjp/core/string/cmp.hpp create mode 100755 tjp/core/string/cmp_case.cpp create mode 100755 tjp/core/string/cmp_case.hpp create mode 100755 tjp/core/string/ends_with.hpp create mode 100755 tjp/core/string/find_after.hpp create mode 100755 tjp/core/string/find_if.hpp create mode 100755 tjp/core/string/from_string.cpp create mode 100755 tjp/core/string/from_string.h create mode 100755 tjp/core/string/from_string.hpp create mode 100755 tjp/core/string/from_string.inl create mode 100755 tjp/core/string/has.hpp create mode 100755 tjp/core/string/has_prefix.hpp create mode 100755 tjp/core/string/join.hpp create mode 100755 tjp/core/string/replace.cpp create mode 100755 tjp/core/string/replace.h create mode 100755 tjp/core/string/replaced.cpp create mode 100755 tjp/core/string/replaced.h create mode 100755 tjp/core/string/split.hpp create mode 100755 tjp/core/string/split.inl create mode 100755 tjp/core/string/split_once.hpp create mode 100755 tjp/core/string/starts_with.hpp create mode 100755 tjp/core/string/str_find.cpp create mode 100755 tjp/core/string/str_find.h create mode 100755 tjp/core/string/strncasecmp.cpp create mode 100755 tjp/core/string/strncasecmp.h create mode 100755 tjp/core/string/strncmp.cpp create mode 100755 tjp/core/string/strncmp.h create mode 100755 tjp/core/string/sxprintf.h create mode 100755 tjp/core/string/to_lower.hpp create mode 100755 tjp/core/string/to_string.h create mode 100755 tjp/core/string/to_string.hpp create mode 100755 tjp/core/string/trim.h create mode 100755 tjp/core/string/trim.inl create mode 100755 tjp/core/string/unprefix.hpp create mode 100644 tjp/core/system/Debug.h create mode 100644 tjp/core/system/DisableWarningsAllPop.h create mode 100644 tjp/core/system/DisableWarningsAllPush.h create mode 100644 tjp/core/system/DisableWarningsPop.h create mode 100644 tjp/core/system/DisableWarningsPush.h create mode 100644 tjp/core/system/Optimization.h create mode 100644 tjp/core/system/System.h create mode 100644 tjp/core/testing/Defines.h create mode 100644 tjp/core/testing/NO_WHEN.h create mode 100644 tjp/core/testing/TESTING_ONLY.h create mode 100644 tjp/core/testing/TEST_SIGNAL.cpp create mode 100644 tjp/core/testing/TEST_SIGNAL.h create mode 100644 tjp/core/testing/THEN_REQUIRE.h create mode 100644 tjp/core/testing/_tests/TEST_SIGNAL.cpp create mode 100644 tjp/core/testing/catch.cpp create mode 100644 tjp/core/testing/catch.hpp create mode 100644 tjp/core/testing/catch2.hpp create mode 100644 tjp/core/testing/wait_until.h create mode 100755 tjp/core/threads/Atomic.h create mode 100755 tjp/core/threads/Atomic.hpp create mode 100755 tjp/core/threads/Lock.h create mode 100755 tjp/core/threads/Lock.hpp create mode 100755 tjp/core/threads/LockedBy.h create mode 100755 tjp/core/threads/LockedBy.hpp create mode 100755 tjp/core/threads/Pin.h create mode 100755 tjp/core/threads/Pin.hpp create mode 100755 tjp/core/threads/SharedLockGuard.hpp create mode 100755 tjp/core/threads/SpinMutex.cpp create mode 100755 tjp/core/threads/SpinMutex.hpp create mode 100755 tjp/core/threads/TestCollision.h create mode 100755 tjp/core/threads/TestMutex.h create mode 100755 tjp/core/threads/TestMutex.hpp create mode 100755 tjp/core/threads/TestMutex.inl create mode 100755 tjp/core/threads/ThreadSafe.h create mode 100755 tjp/core/threads/ThreadSafe.hpp create mode 100755 tjp/core/threads/TryLockGuard.hpp create mode 100755 tjp/core/threads/UnlockGuard.hpp create mode 100755 tjp/core/threads/_tests/Lock.cpp create mode 100755 tjp/core/threads/_tests/TestMutex.cpp create mode 100755 tjp/core/threads/micropause.hpp create mode 100755 tjp/core/threads/process_queue.hpp create mode 100755 tjp/core/threads/std/Lock.h create mode 100755 tjp/core/threads/std/Lock.hpp create mode 100755 tjp/core/threads/with_lock.hpp create mode 100755 tjp/core/threads/with_lock_value.hpp create mode 100644 tjp/core/time/Source.cpp create mode 100644 tjp/core/time/Source.h create mode 100644 tjp/core/time/Source.hpp create mode 100644 tjp/core/time/Time+IO.cpp create mode 100644 tjp/core/time/Time+IO.hpp create mode 100644 tjp/core/time/Time+chrono+misc.hpp create mode 100644 tjp/core/time/Time+chrono.hpp create mode 100644 tjp/core/time/Time+operations.hpp create mode 100644 tjp/core/time/Time+timestamp.hpp create mode 100644 tjp/core/time/Time.cpp create mode 100644 tjp/core/time/Time.h create mode 100644 tjp/core/time/Time.hpp create mode 100644 tjp/core/timer/Timer.h create mode 100644 tjp/core/timer/Timer.hpp create mode 100755 tjp/core/timer/_tests/Timer.cpp create mode 100644 tjp/core/type_traits/_tests/is_map.cpp create mode 100644 tjp/core/type_traits/_tests/is_vector.cpp create mode 100644 tjp/core/type_traits/always_false.hpp create mode 100644 tjp/core/type_traits/is_callable.hpp create mode 100644 tjp/core/type_traits/is_callable_with_two_args.hpp create mode 100644 tjp/core/type_traits/is_comparable.hpp create mode 100644 tjp/core/type_traits/is_iterable.hpp create mode 100644 tjp/core/type_traits/is_map.hpp create mode 100644 tjp/core/type_traits/is_mappish.hpp create mode 100644 tjp/core/type_traits/is_string.hpp create mode 100644 tjp/core/type_traits/is_vector.hpp create mode 100755 tjp/core/types/CounterFor.h create mode 100644 tjp/core/types/Definitions.h create mode 100644 tjp/core/types/Types+IO.cpp create mode 100644 tjp/core/types/Types+IO.h create mode 100644 tjp/core/types/Types.h create mode 100644 tjp/core/types/Types_.h create mode 100644 tjp/core/types/linux/Types.h diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..62c3c9a --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +.DS_Store +*.pyc +xcuserdata +.bin +transfer-to-* +temp diff --git a/Core_Zero.xcodeproj/project.pbxproj b/Core_Zero.xcodeproj/project.pbxproj new file mode 100644 index 0000000..9cf401e --- /dev/null +++ b/Core_Zero.xcodeproj/project.pbxproj @@ -0,0 +1,2221 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 55; + objects = { + +/* Begin PBXBuildFile section */ + F608A8A828269A12005C276B /* TestMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D2A281F0124004C92E9 /* TestMutex.cpp */; }; + F608A8CC28269D0D005C276B /* Str.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8BA28269B63005C276B /* Str.cpp */; }; + F608A90D2826A681005C276B /* Dictionary.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8BB28269B63005C276B /* Dictionary.cpp */; }; + F608A9332826A7AE005C276B /* Str.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8BC28269B63005C276B /* Str.cpp */; }; + F616E9DA2B34683A00C6DD09 /* debug_assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F616E9D92B34681200C6DD09 /* debug_assert.cpp */; }; + F616E9DB2B34683A00C6DD09 /* debug_assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F616E9D92B34681200C6DD09 /* debug_assert.cpp */; }; + F61DB8032857682300B74C99 /* InPlaceArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61DB8022857682300B74C99 /* InPlaceArray.cpp */; }; + F61DB8042857685A00B74C99 /* StackArray_v2.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97DBD281F439A004C92E9 /* StackArray_v2.cpp */; }; + F61EA27C2A78A28500DF7BFA /* StackUsage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61EA27B2A78A28500DF7BFA /* StackUsage.cpp */; }; + F61EA27D2A78A28500DF7BFA /* StackUsage.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61EA27B2A78A28500DF7BFA /* StackUsage.cpp */; }; + F61F9BB02C6D965E00F79137 /* reverse.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F61F9BAF2C6D965D00F79137 /* reverse.cpp */; }; + F61F9BFD2C6EEE7200F79137 /* Ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9272826A6F9005C276B /* Ptr.cpp */; }; + F61F9BFE2C6EEE7B00F79137 /* Ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A91B2826A6F8005C276B /* Ptr.cpp */; }; + F61F9BFF2C6EEE9A00F79137 /* Ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A92D2826A6F9005C276B /* Ptr.cpp */; }; + F61F9C002C6EEEA500F79137 /* Ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9202826A6F8005C276B /* Ptr.cpp */; }; + F62919ED2CB6A3B3002060E0 /* cmp_case.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F62919EC2CB6A3B3002060E0 /* cmp_case.cpp */; }; + F62919F02CB6A468002060E0 /* strncasecmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F62919EF2CB6A468002060E0 /* strncasecmp.cpp */; }; + F62919F42CB6A83F002060E0 /* strncmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F62919F32CB6A83F002060E0 /* strncmp.cpp */; }; + F6291A022CB6B2EA002060E0 /* strncasecmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6291A002CB6B128002060E0 /* strncasecmp.cpp */; }; + F6291A032CB6B2EB002060E0 /* strncasecmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6291A002CB6B128002060E0 /* strncasecmp.cpp */; }; + F6291A042CB6B2F0002060E0 /* strncmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6291A012CB6B149002060E0 /* strncmp.cpp */; }; + F6291A052CB6B2F0002060E0 /* strncmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6291A012CB6B149002060E0 /* strncmp.cpp */; }; + F63B041A2C76A07A00417011 /* HashExpected.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63B04192C76A07A00417011 /* HashExpected.cpp */; }; + F63B042B2C77676200417011 /* is_vector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63B042A2C77674A00417011 /* is_vector.cpp */; }; + F63B042E2C7767AA00417011 /* is_map.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63B042D2C7767AA00417011 /* is_map.cpp */; }; + F63B04372C778EDA00417011 /* concat.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63B04362C778EBF00417011 /* concat.cpp */; }; + F63D85122D10B73D00FF3624 /* handle_assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63D85112D10B73D00FF3624 /* handle_assert.cpp */; }; + F63D85132D10B73D00FF3624 /* handle_assert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F63D85112D10B73D00FF3624 /* handle_assert.cpp */; }; + F6436EC5285955F2003241E0 /* small_cmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6436EC4285955F2003241E0 /* small_cmp.cpp */; }; + F64407082B39EF9800A2477F /* Time.h in Headers */ = {isa = PBXBuildFile; fileRef = F64406FB2B39EF9800A2477F /* Time.h */; }; + F64407092B39EF9800A2477F /* Time.h in Headers */ = {isa = PBXBuildFile; fileRef = F64406FB2B39EF9800A2477F /* Time.h */; }; + F64407102B39EF9900A2477F /* Source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407002B39EF9800A2477F /* Source.cpp */; }; + F64407112B39EF9900A2477F /* Source.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407002B39EF9800A2477F /* Source.cpp */; }; + F64407122B39EF9900A2477F /* Time+chrono.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407012B39EF9800A2477F /* Time+chrono.hpp */; }; + F64407132B39EF9900A2477F /* Time+chrono.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407012B39EF9800A2477F /* Time+chrono.hpp */; }; + F64407142B39EF9900A2477F /* Time.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407022B39EF9800A2477F /* Time.hpp */; }; + F64407152B39EF9900A2477F /* Time.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407022B39EF9800A2477F /* Time.hpp */; }; + F64407162B39EF9900A2477F /* Time+operations.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407032B39EF9800A2477F /* Time+operations.hpp */; }; + F64407172B39EF9900A2477F /* Time+operations.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407032B39EF9800A2477F /* Time+operations.hpp */; }; + F64407182B39EF9900A2477F /* Time+IO.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407042B39EF9800A2477F /* Time+IO.hpp */; }; + F64407192B39EF9900A2477F /* Time+IO.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407042B39EF9800A2477F /* Time+IO.hpp */; }; + F644071A2B39EF9900A2477F /* Time+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407052B39EF9800A2477F /* Time+IO.cpp */; }; + F644071B2B39EF9900A2477F /* Time+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407052B39EF9800A2477F /* Time+IO.cpp */; }; + F644071C2B39EF9900A2477F /* Source.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407062B39EF9800A2477F /* Source.hpp */; }; + F644071D2B39EF9900A2477F /* Source.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F64407062B39EF9800A2477F /* Source.hpp */; }; + F644071E2B39EF9900A2477F /* Time.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407072B39EF9800A2477F /* Time.cpp */; }; + F644071F2B39EF9900A2477F /* Time.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64407072B39EF9800A2477F /* Time.cpp */; }; + F64714A62C74A137002A8087 /* Timer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714A52C74A0E9002A8087 /* Timer.cpp */; }; + F64714AC2C74B09D002A8087 /* trim.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714AB2C74B09D002A8087 /* trim.cpp */; }; + F64714AE2C74B4BE002A8087 /* replace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714AD2C74B4BE002A8087 /* replace.cpp */; }; + F64714B12C74B5DF002A8087 /* join.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714B02C74B5DF002A8087 /* join.cpp */; }; + F64714B32C74BE4A002A8087 /* transform_with.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714B22C74BE4A002A8087 /* transform_with.cpp */; }; + F64714B52C74CD29002A8087 /* fail_on_copy_vector.hpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714B42C74CD29002A8087 /* fail_on_copy_vector.hpp */; }; + F64714B72C74CF7A002A8087 /* Lock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64714B62C74CF1F002A8087 /* Lock.cpp */; }; + F64C65222AC5ABC900FCF1DD /* RTTI.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F64C65212AC5AA2800FCF1DD /* RTTI.cpp */; }; + F65B59992C6C4C4800059339 /* is_first.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F65B59982C6C4C4800059339 /* is_first.cpp */; }; + F65B599B2C6C4E5C00059339 /* safe_next.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F65B599A2C6C4E5C00059339 /* safe_next.cpp */; }; + F660402B286A654F00C07DC0 /* Types+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660402A286A63F000C07DC0 /* Types+IO.cpp */; }; + F660402C286A655000C07DC0 /* Types+IO.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F660402A286A63F000C07DC0 /* Types+IO.cpp */; }; + F67119DC2C8A636700F72EE9 /* libCore_Zero.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F6E97D00281EF4BF004C92E9 /* libCore_Zero.a */; }; + F67119DD2C8A636700F72EE9 /* libCore_Allocator.a in Frameworks */ = {isa = PBXBuildFile; fileRef = F65B59DA2C6C53EF00059339 /* libCore_Allocator.a */; }; + F67CE9082D83D1ED004400C3 /* list_erase_if_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9072D83D1ED004400C3 /* list_erase_if_value.cpp */; }; + F67CE90A2D83D213004400C3 /* map_erase_if_key.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9092D83D213004400C3 /* map_erase_if_key.cpp */; }; + F67CE90C2D83D2A8004400C3 /* map_erase_if_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE90B2D83D2A8004400C3 /* map_erase_if_value.cpp */; }; + F67CE90E2D83D2F4004400C3 /* map_erase_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE90D2D83D2F4004400C3 /* map_erase_if.cpp */; }; + F67CE9102D83D329004400C3 /* map_erase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE90F2D83D329004400C3 /* map_erase.cpp */; }; + F67CE9122D83D3B1004400C3 /* map_has.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9112D83D3B1004400C3 /* map_has.cpp */; }; + F67CE9142D83D404004400C3 /* map_has_key.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9132D83D404004400C3 /* map_has_key.cpp */; }; + F67CE9162D83D4F8004400C3 /* map_for_each_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9152D83D4F8004400C3 /* map_for_each_value.cpp */; }; + F67CE9182D83D595004400C3 /* map_iterator_or_insert.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9172D83D595004400C3 /* map_iterator_or_insert.cpp */; }; + F67CE91A2D83D65D004400C3 /* map_value_require.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9192D83D65D004400C3 /* map_value_require.cpp */; }; + F67CE91C2D83D6E0004400C3 /* map_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE91B2D83D6E0004400C3 /* map_value.cpp */; }; + F67CE91E2D83D73B004400C3 /* not_zero.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE91D2D83D73B004400C3 /* not_zero.cpp */; }; + F67CE9202D83D790004400C3 /* on_destruct.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE91F2D83D790004400C3 /* on_destruct.cpp */; }; + F67CE9272D83D8E5004400C3 /* optional_value_or_default.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9262D83D8E5004400C3 /* optional_value_or_default.cpp */; }; + F67CE9292D83D951004400C3 /* optional_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9282D83D951004400C3 /* optional_value.cpp */; }; + F67CE92B2D83D99D004400C3 /* set_empty.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE92A2D83D99D004400C3 /* set_empty.cpp */; }; + F67CE92F2D83DD63004400C3 /* if_or.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE92E2D83DD1C004400C3 /* if_or.cpp */; }; + F67CE9312D844BAF004400C3 /* vector_append.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9302D844BAF004400C3 /* vector_append.cpp */; }; + F67CE9332D844CA2004400C3 /* vector_erase_if_value.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9322D844CA2004400C3 /* vector_erase_if_value.cpp */; }; + F67CE9352D844CDC004400C3 /* vector_erase_value_one.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9342D844CDB004400C3 /* vector_erase_value_one.cpp */; }; + F67CE9392D845039004400C3 /* vector_erase_value_all.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE9382D845039004400C3 /* vector_erase_value_all.cpp */; }; + F67CE93C2D8450BA004400C3 /* container_erase_value_all.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE93B2D8450BA004400C3 /* container_erase_value_all.cpp */; }; + F67CE94C2D84583F004400C3 /* Examples.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F67CE94B2D84583F004400C3 /* Examples.cpp */; }; + F68BA8452E940E6D0040FA70 /* Detail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F68BA8412E93F2700040FA70 /* Detail.cpp */; }; + F68BA8462E940E6D0040FA70 /* Detail.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F68BA8412E93F2700040FA70 /* Detail.cpp */; }; + F68BA8482E940EB00040FA70 /* Color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F68BA8472E940E720040FA70 /* Color.cpp */; }; + F68BA8492E940EB00040FA70 /* Color.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F68BA8472E940E720040FA70 /* Color.cpp */; }; + F695489E28288C55005D1B64 /* from_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8C628269B64005C276B /* from_string.cpp */; }; + F69548A028288C70005D1B64 /* str_find.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8C728269B64005C276B /* str_find.cpp */; }; + F69548A128288C74005D1B64 /* replace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AD28269B63005C276B /* replace.cpp */; }; + F69548A328288C83005D1B64 /* cmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AE28269B63005C276B /* cmp.cpp */; }; + F69548A428288C85005D1B64 /* cmp_case.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AC28269B63005C276B /* cmp_case.cpp */; }; + F6971F11282B1129008FBD17 /* cmp_case.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AC28269B63005C276B /* cmp_case.cpp */; }; + F6971F12282B1129008FBD17 /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D1F281EF724004C92E9 /* Log.cpp */; }; + F6971F13282B1129008FBD17 /* demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D1B281EF724004C92E9 /* demangle.cpp */; }; + F6971F14282B1129008FBD17 /* cmp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AE28269B63005C276B /* cmp.cpp */; }; + F6971F15282B1129008FBD17 /* replace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8AD28269B63005C276B /* replace.cpp */; }; + F6971F16282B1129008FBD17 /* str_find.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8C728269B64005C276B /* str_find.cpp */; }; + F6971F17282B1129008FBD17 /* Str.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8BC28269B63005C276B /* Str.cpp */; }; + F6971F19282B1129008FBD17 /* from_string.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A8C628269B64005C276B /* from_string.cpp */; }; + F6971F1B282B1129008FBD17 /* Stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D3B281F0A65004C92E9 /* Stack.cpp */; }; + F69832AC2D7B3FB400D911E4 /* catch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69832AB2D7B3F4E00D911E4 /* catch.cpp */; }; + F69832AD2D7B3FB400D911E4 /* catch.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69832AB2D7B3F4E00D911E4 /* catch.cpp */; }; + F69832BA2D7B7B0700D911E4 /* copy_clear.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69832B82D7B7A7000D911E4 /* copy_clear.cpp */; }; + F69AB77D2B16D4BA000115BC /* TypeName.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69AB77C2B16D4BA000115BC /* TypeName.cpp */; }; + F69AB7F32B19310E000115BC /* Hash.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F69AB7F12B193108000115BC /* Hash.cpp */; }; + F6A994792D827C5900AA4FEE /* starts_with.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6A994782D827C5900AA4FEE /* starts_with.cpp */; }; + F6A9947B2D827CBB00AA4FEE /* length.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6A9947A2D827CBB00AA4FEE /* length.cpp */; }; + F6ADBA3B28381C8A005131D9 /* TEST_SIGNAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AB9B282832FB005C276B /* TEST_SIGNAL.cpp */; }; + F6ADBA3C28381C8F005131D9 /* TEST_SIGNAL.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608AB9B282832FB005C276B /* TEST_SIGNAL.cpp */; }; + F6B1537D2C7042830063C622 /* range_with.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6B1537C2C7042830063C622 /* range_with.cpp */; }; + F6B4CFC72A6ECF8F004B9AB5 /* Ptr.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F608A9242826A6F8005C276B /* Ptr.cpp */; }; + F6C855E52DB7321E006D6C48 /* split_once.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6C855E42DB7321E006D6C48 /* split_once.cpp */; }; + F6CA318A292BCD8F008EE166 /* SpinMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CA3189292BCD57008EE166 /* SpinMutex.cpp */; }; + F6CA318B292BCD90008EE166 /* SpinMutex.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CA3189292BCD57008EE166 /* SpinMutex.cpp */; }; + F6CA9B5A294E7BBD00D9A375 /* range.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6CA9B59294E7B4600D9A375 /* range.cpp */; }; + F6CFD87F2E1ED23C00CDDC2E /* Time+timestamp.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F6CFD87E2E1ED23C00CDDC2E /* Time+timestamp.hpp */; }; + F6CFD8802E1ED23C00CDDC2E /* Time+timestamp.hpp in Headers */ = {isa = PBXBuildFile; fileRef = F6CFD87E2E1ED23C00CDDC2E /* Time+timestamp.hpp */; }; + F6DC70D72D81E375004DA34D /* all_are.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70D62D81E375004DA34D /* all_are.cpp */; }; + F6DC70D92D81E43B004DA34D /* one_is.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70D82D81E43B004DA34D /* one_is.cpp */; }; + F6DC70DB2D81E493004DA34D /* container_erase_if_one.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70DA2D81E493004DA34D /* container_erase_if_one.cpp */; }; + F6DC70DD2D81E5D1004DA34D /* container_erase_value_one.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70DC2D81E5D1004DA34D /* container_erase_value_one.cpp */; }; + F6DC70DF2D81E6B7004DA34D /* container_erase_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70DE2D81E6B7004DA34D /* container_erase_if.cpp */; }; + F6DC70E12D81E735004DA34D /* container_find_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70E02D81E735004DA34D /* container_find_if.cpp */; }; + F6DC70E32D81E804004DA34D /* container_get_if_optional_erase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70E22D81E804004DA34D /* container_get_if_optional_erase.cpp */; }; + F6DC70E52D81E8E9004DA34D /* container_get_if_optional.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70E42D81E8E9004DA34D /* container_get_if_optional.cpp */; }; + F6DC70E72D81E937004DA34D /* container_get_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70E62D81E937004DA34D /* container_get_if.cpp */; }; + F6DC70E92D81EAB4004DA34D /* container_get_optional_erase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70E82D81EAB4004DA34D /* container_get_optional_erase.cpp */; }; + F6DC70EB2D81EBEF004DA34D /* container_has_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70EA2D81EBEF004DA34D /* container_has_if.cpp */; }; + F6DC70ED2D81EC4D004DA34D /* container_has.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70EC2D81EC4D004DA34D /* container_has.cpp */; }; + F6DC70EF2D81ECE1004DA34D /* copy_of.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70EE2D81ECE1004DA34D /* copy_of.cpp */; }; + F6DC70F12D81EE72004DA34D /* empty_of.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70F02D81EE72004DA34D /* empty_of.cpp */; }; + F6DC70F32D81EF1B004DA34D /* emplace.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70F22D81EF1B004DA34D /* emplace.cpp */; }; + F6DC70F52D81EFBB004DA34D /* ends_with.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70F42D81EFBB004DA34D /* ends_with.cpp */; }; + F6DC70F82D81F062004DA34D /* has_last.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70F72D81F062004DA34D /* has_last.cpp */; }; + F6DC70FA2D81F0F5004DA34D /* in_range_segment.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70F92D81F0F5004DA34D /* in_range_segment.cpp */; }; + F6DC70FC2D81F1A8004DA34D /* is_in.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70FB2D81F1A8004DA34D /* is_in.cpp */; }; + F6DC70FE2D81F1EC004DA34D /* is_zero.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70FD2D81F1EC004DA34D /* is_zero.cpp */; }; + F6DC71002D81F2F8004DA34D /* last_of_parameter_pack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC70FF2D81F2F8004DA34D /* last_of_parameter_pack.cpp */; }; + F6DC71022D81F397004DA34D /* list_erase_if.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DC71012D81F397004DA34D /* list_erase_if.cpp */; }; + F6DCDBB52858F65F00696085 /* small_copy.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6DCDBB42858F61B00696085 /* small_copy.cpp */; }; + F6E5495528CCD688007010BC /* Allocations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E5495428CCD3BA007010BC /* Allocations.cpp */; }; + F6E5495628CCD689007010BC /* Allocations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E5495428CCD3BA007010BC /* Allocations.cpp */; }; + F6E6208F2B30AFD70016DEED /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97DCC281F48BD004C92E9 /* Exception.cpp */; }; + F6E620902B30AFDA0016DEED /* Exception.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97DCC281F48BD004C92E9 /* Exception.cpp */; }; + F6E97D19281EF66D004C92E9 /* Run.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D0C281EF604004C92E9 /* Run.cpp */; }; + F6E97D22281EF729004C92E9 /* demangle.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D1B281EF724004C92E9 /* demangle.cpp */; }; + F6E97D23281EF72C004C92E9 /* Log.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D1F281EF724004C92E9 /* Log.cpp */; }; + F6E97D60281F1078004C92E9 /* Stack.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D3B281F0A65004C92E9 /* Stack.cpp */; }; + F6E97D62281F3A5F004C92E9 /* LogOf.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97D1E281EF724004C92E9 /* LogOf.cpp */; }; + F6E97DC5281F43F3004C92E9 /* SafeIteration.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6E97DBE281F439A004C92E9 /* SafeIteration.cpp */; }; + F6F721702C5DB54E00A8E8D1 /* enumerate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F7216F2C5DB54E00A8E8D1 /* enumerate.cpp */; }; + F6F721722C5DB73400A8E8D1 /* no_last.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F721712C5DB73400A8E8D1 /* no_last.cpp */; }; + F6F721742C5DB81F00A8E8D1 /* no_first.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F721732C5DB81F00A8E8D1 /* no_first.cpp */; }; + F6F721762C5DB85200A8E8D1 /* zip.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F721752C5DB85200A8E8D1 /* zip.cpp */; }; + F6F7A2F42F49EFAB008BF0C6 /* no_throw.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F7A2F32F49EFAB008BF0C6 /* no_throw.cpp */; }; + F6F7A3012F4A2516008BF0C6 /* remove_char.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F7A3002F4A2516008BF0C6 /* remove_char.cpp */; }; + F6F7A3032F4A26A3008BF0C6 /* Str.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F7A3022F4A26A3008BF0C6 /* Str.cpp */; }; + F6F9CF402E4F899A00576DEF /* Float16.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6F9CF3F2E4F899A00576DEF /* Float16.cpp */; }; + F6FADA9A29490462006125E1 /* MultiContainer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F6FADA972949041B006125E1 /* MultiContainer.cpp */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + F67119DE2C8A636C00F72EE9 /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = F6E97CF8281EF4BF004C92E9 /* Project object */; + proxyType = 1; + remoteGlobalIDString = F6E97CFF281EF4BF004C92E9; + remoteInfo = Core_Zero; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + F6E97D0F281EF664004C92E9 /* CopyFiles */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = /usr/share/man/man1/; + dstSubfolderSpec = 0; + files = ( + ); + runOnlyForDeploymentPostprocessing = 1; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + F6010641286E4B5900FD2E40 /* vector_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value.hpp; sourceTree = ""; }; + F601313F2873B3E70088443B /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = ""; }; + F6086EE0287A05A900CA017D /* Ptr+Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Log.h"; sourceTree = ""; }; + F60892482864C85000174811 /* map_erase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_erase.hpp; sourceTree = ""; }; + F608925028656DC900174811 /* set_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_value.hpp; sourceTree = ""; }; + F60892512865DA9F00174811 /* set_insert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_insert.hpp; sourceTree = ""; }; + F608A8882825CA7C005C276B /* MemoryArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MemoryArray.h; sourceTree = ""; }; + F608A8892825CA7C005C276B /* is_first.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_first.hpp; sourceTree = ""; }; + F608A88A2825CA7C005C276B /* enumerate.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = enumerate.hpp; sourceTree = ""; }; + F608A88B2825CA7D005C276B /* macro_min_max.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = macro_min_max.h; sourceTree = ""; }; + F608A88C2825CA7D005C276B /* no_last.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = no_last.hpp; sourceTree = ""; }; + F608A88D2825CA7D005C276B /* range.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = range.hpp; sourceTree = ""; }; + F608A88E2825CA7D005C276B /* safe_next.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = safe_next.hpp; sourceTree = ""; }; + F608A88F2825CA7D005C276B /* MemoryArray.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MemoryArray.hpp; sourceTree = ""; }; + F608A8902825CA7E005C276B /* reverse.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = reverse.hpp; sourceTree = ""; }; + F608A8912825CA7E005C276B /* transform_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = transform_with.hpp; sourceTree = ""; }; + F608A8922825CAC1005C276B /* no_first.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = no_first.hpp; sourceTree = ""; }; + F608A8AC28269B63005C276B /* cmp_case.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cmp_case.cpp; sourceTree = ""; }; + F608A8AD28269B63005C276B /* replace.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = replace.cpp; sourceTree = ""; }; + F608A8AE28269B63005C276B /* cmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cmp.cpp; sourceTree = ""; }; + F608A8AF28269B63005C276B /* Str+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Str+IO.h"; sourceTree = ""; }; + F608A8B028269B63005C276B /* starts_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = starts_with.hpp; sourceTree = ""; }; + F608A8B328269B63005C276B /* to_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = to_string.hpp; sourceTree = ""; }; + F608A8B428269B63005C276B /* Tokenizer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Tokenizer.h; sourceTree = ""; }; + F608A8B528269B63005C276B /* from_string.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = from_string.inl; sourceTree = ""; }; + F608A8B628269B63005C276B /* split.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = split.hpp; sourceTree = ""; }; + F608A8B728269B63005C276B /* from_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = from_string.hpp; sourceTree = ""; }; + F608A8B828269B63005C276B /* join.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = join.hpp; sourceTree = ""; }; + F608A8B928269B63005C276B /* replace.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = replace.h; sourceTree = ""; }; + F608A8BA28269B63005C276B /* Str.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Str.cpp; sourceTree = ""; }; + F608A8BB28269B63005C276B /* Dictionary.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Dictionary.cpp; sourceTree = ""; }; + F608A8BC28269B63005C276B /* Str.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Str.cpp; sourceTree = ""; }; + F608A8BD28269B64005C276B /* cmp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = cmp.hpp; sourceTree = ""; }; + F608A8BE28269B64005C276B /* str_find.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = str_find.h; sourceTree = ""; }; + F608A8BF28269B64005C276B /* cmp_case.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = cmp_case.hpp; sourceTree = ""; }; + F608A8C028269B64005C276B /* Dictionary.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Dictionary.h; sourceTree = ""; }; + F608A8C228269B64005C276B /* Str+IO.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Str+IO.inl"; sourceTree = ""; }; + F608A8C328269B64005C276B /* Tokenizer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Tokenizer.hpp; sourceTree = ""; }; + F608A8C428269B64005C276B /* to_string.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = to_string.h; sourceTree = ""; }; + F608A8C528269B64005C276B /* Dictionary.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Dictionary.inl; sourceTree = ""; }; + F608A8C628269B64005C276B /* from_string.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = from_string.cpp; sourceTree = ""; }; + F608A8C728269B64005C276B /* str_find.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = str_find.cpp; sourceTree = ""; }; + F608A8C828269B64005C276B /* Str.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Str.h; sourceTree = ""; }; + F608A8C928269B64005C276B /* trim.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = trim.h; sourceTree = ""; }; + F608A8CA28269BFE005C276B /* Str.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Str.hpp; sourceTree = ""; }; + F608A8CD28269D82005C276B /* StringView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StringView.h; sourceTree = ""; }; + F608A8CE28269D83005C276B /* StringView.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StringView.hpp; sourceTree = ""; }; + F608A90A2826A4A5005C276B /* debug_assert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug_assert.h; sourceTree = ""; }; + F608A90F2826A6F8005C276B /* Ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ptr.h; sourceTree = ""; }; + F608A9102826A6F8005C276B /* Ptr+Version.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Version.h"; sourceTree = ""; }; + F608A9122826A6F8005C276B /* Ptr+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+IO.h"; sourceTree = ""; }; + F608A9132826A6F8005C276B /* CustomControlBlock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CustomControlBlock.h; sourceTree = ""; }; + F608A9142826A6F8005C276B /* Ptr+Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Debug.h"; sourceTree = ""; }; + F608A9162826A6F8005C276B /* Ptr+GCC.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+GCC.h"; sourceTree = ""; }; + F608A9172826A6F8005C276B /* Ptr+LLVM.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+LLVM.h"; sourceTree = ""; }; + F608A9182826A6F8005C276B /* Ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ptr.h; sourceTree = ""; }; + F608A91B2826A6F8005C276B /* Ptr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ptr.cpp; sourceTree = ""; }; + F608A91C2826A6F8005C276B /* Ptr+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+IO.h"; sourceTree = ""; }; + F608A91D2826A6F8005C276B /* Ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Ptr.hpp; sourceTree = ""; }; + F608A91F2826A6F8005C276B /* Ptr+Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Debug.h"; sourceTree = ""; }; + F608A9202826A6F8005C276B /* Ptr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ptr.cpp; sourceTree = ""; }; + F608A9212826A6F8005C276B /* Ptr+Logging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Ptr+Logging.cpp"; sourceTree = ""; }; + F608A9222826A6F8005C276B /* Ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ptr.h; sourceTree = ""; }; + F608A9232826A6F8005C276B /* Ptr+Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Log.h"; sourceTree = ""; }; + F608A9242826A6F8005C276B /* Ptr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ptr.cpp; sourceTree = ""; }; + F608A9252826A6F9005C276B /* Ptr+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+IO.h"; sourceTree = ""; }; + F608A9272826A6F9005C276B /* Ptr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ptr.cpp; sourceTree = ""; }; + F608A9282826A6F9005C276B /* Ptr.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Ptr.inl; sourceTree = ""; }; + F608A9292826A6F9005C276B /* Ptr+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+IO.h"; sourceTree = ""; }; + F608A92A2826A6F9005C276B /* Ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Ptr.hpp; sourceTree = ""; }; + F608A92B2826A6F9005C276B /* Ptr+Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Ptr+Log.cpp"; sourceTree = ""; }; + F608A92C2826A6F9005C276B /* Ptr+Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Debug.h"; sourceTree = ""; }; + F608A92D2826A6F9005C276B /* Ptr.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Ptr.cpp; sourceTree = ""; }; + F608A92E2826A6F9005C276B /* Ptr+Logging.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Ptr+Logging.cpp"; sourceTree = ""; }; + F608A92F2826A6F9005C276B /* Ptr.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Ptr.h; sourceTree = ""; }; + F608A9302826A6F9005C276B /* Ptr+Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Ptr+Log.h"; sourceTree = ""; }; + F608A9312826A6F9005C276B /* Ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Ptr.hpp; sourceTree = ""; }; + F608A9322826A6F9005C276B /* Ptr+Log.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Ptr+Log.hpp"; sourceTree = ""; }; + F608A9352826A974005C276B /* Makefile.def */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.def; sourceTree = ""; }; + F608A9362826A975005C276B /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F608A9372826AC4E005C276B /* Precompile.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Precompile.pch; sourceTree = ""; }; + F608AA902826C008005C276B /* Timer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Timer.hpp; sourceTree = ""; }; + F608AA912826C008005C276B /* Timer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Timer.h; sourceTree = ""; }; + F608AA922826C072005C276B /* mem_copy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = mem_copy.hpp; sourceTree = ""; }; + F608AAB728271640005C276B /* if_or.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = if_or.hpp; sourceTree = ""; }; + F608AB4B282778B7005C276B /* memstream.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = memstream.h; sourceTree = ""; }; + F608AB4C2827E6BA005C276B /* ExecuteOnDestruct.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ExecuteOnDestruct.h; sourceTree = ""; }; + F608AB4D2827E6BA005C276B /* ExecuteOnDestruct.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ExecuteOnDestruct.hpp; sourceTree = ""; }; + F608AB4E2827E70A005C276B /* on_destruct.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = on_destruct.hpp; sourceTree = ""; }; + F608AB712827F644005C276B /* Optional.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optional.h; sourceTree = ""; }; + F608AB722827F644005C276B /* Optional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Optional.hpp; sourceTree = ""; }; + F608AB732827F6F3005C276B /* Tuple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Tuple.h; sourceTree = ""; }; + F608AB742827F6F4005C276B /* Tuple.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Tuple.hpp; sourceTree = ""; }; + F608AB7528280B85005C276B /* ThreadSafe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ThreadSafe.h; sourceTree = ""; }; + F608AB7628280B86005C276B /* ThreadSafe.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ThreadSafe.hpp; sourceTree = ""; }; + F608AB902828261B005C276B /* map_value_or_default.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_or_default.hpp; sourceTree = ""; }; + F608AB9228282705005C276B /* ends_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ends_with.hpp; sourceTree = ""; }; + F608AB96282832FB005C276B /* TEST_SIGNAL.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TEST_SIGNAL.h; sourceTree = ""; }; + F608AB97282832FB005C276B /* TESTING_ONLY.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TESTING_ONLY.h; sourceTree = ""; }; + F608AB98282832FB005C276B /* NO_WHEN.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NO_WHEN.h; sourceTree = ""; }; + F608AB99282832FB005C276B /* TEST_SIGNAL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TEST_SIGNAL.cpp; sourceTree = ""; }; + F608AB9A282832FB005C276B /* wait_until.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = wait_until.h; sourceTree = ""; }; + F608AB9B282832FB005C276B /* TEST_SIGNAL.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TEST_SIGNAL.cpp; sourceTree = ""; }; + F608AB9C282832FB005C276B /* Defines.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Defines.h; sourceTree = ""; }; + F60BC3042D3B0180005C1EB6 /* with_lock_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = with_lock_value.hpp; sourceTree = ""; }; + F60EC5222A13C3FD00A00C4C /* string_has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = string_has.hpp; sourceTree = ""; }; + F6112BB72BA3FBAD00410E6F /* optional_value_or_default.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = optional_value_or_default.hpp; sourceTree = ""; }; + F611B4362EB40A22003349BE /* micropause.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = micropause.hpp; sourceTree = ""; }; + F61247072AF1EBE500B77DC1 /* tuple_has_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = tuple_has_value.hpp; sourceTree = ""; }; + F612B9382B9D0E0400519EB6 /* Align.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Align.h; sourceTree = ""; }; + F616E9D92B34681200C6DD09 /* debug_assert.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = debug_assert.cpp; sourceTree = ""; }; + F6170F5E2B4847C5007F87B0 /* Hash.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Hash.cpp; sourceTree = ""; }; + F61BD5662B51965F00277906 /* Pin.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pin.h; sourceTree = ""; }; + F61BD5682B51966E00277906 /* Pin.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pin.hpp; sourceTree = ""; }; + F61BF89E2D1236DE0061A507 /* map_value_require.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_require.hpp; sourceTree = ""; }; + F61BF8A92D1279C10061A507 /* as_string_view.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = as_string_view.hpp; sourceTree = ""; }; + F61C393D2DEDFAA2005B42E7 /* StringView+less.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StringView+less.hpp"; sourceTree = ""; }; + F61C393E2DEDFC75005B42E7 /* TransparentLess.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TransparentLess.hpp; sourceTree = ""; }; + F61D45ED2B5953CF00AD2EED /* PtrOnly.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PtrOnly.h; sourceTree = ""; }; + F61D45EE2B5953CF00AD2EED /* PtrOnly.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PtrOnly.hpp; sourceTree = ""; }; + F61DA0002D75F7D000FE2AEB /* as_vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = as_vector.hpp; sourceTree = ""; }; + F61DB7FF2857652300B74C99 /* InPlaceArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = InPlaceArray.h; sourceTree = ""; }; + F61DB8002857653200B74C99 /* InPlaceArray.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = InPlaceArray.hpp; sourceTree = ""; }; + F61DB8012857680F00B74C99 /* InPlaceArray.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = InPlaceArray.inl; sourceTree = ""; }; + F61DB8022857682300B74C99 /* InPlaceArray.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = InPlaceArray.cpp; sourceTree = ""; }; + F61DB805285772AF00B74C99 /* StackArray_v2.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = StackArray_v2.inl; sourceTree = ""; }; + F61DB806285772AF00B74C99 /* StackArray_v2.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StackArray_v2.h; sourceTree = ""; }; + F61DB807285772AF00B74C99 /* StackArray_v2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackArray_v2.hpp; sourceTree = ""; }; + F61DB80A28577A8600B74C99 /* StackArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StackArray.h; sourceTree = ""; }; + F61DB80B28577A8E00B74C99 /* StackArray.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = StackArray.hpp; sourceTree = ""; }; + F61EA27A2A78A26700DF7BFA /* StackUsage.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StackUsage.h; sourceTree = ""; }; + F61EA27B2A78A28500DF7BFA /* StackUsage.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StackUsage.cpp; sourceTree = ""; }; + F61F56232BFE937D00A3FD8D /* update_if_different.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = update_if_different.hpp; sourceTree = ""; }; + F61F89E829BE1AF500B407AE /* numeric_limits.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = numeric_limits.hpp; sourceTree = ""; }; + F61F9BAF2C6D965D00F79137 /* reverse.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = reverse.cpp; sourceTree = ""; }; + F61F9BCE2C6DB5A600F79137 /* DisableWarningsAllPush.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisableWarningsAllPush.h; sourceTree = ""; }; + F61F9BD42C6DCA3300F79137 /* Makefile.project */ = {isa = PBXFileReference; lastKnownFileType = text; path = Makefile.project; sourceTree = ""; }; + F61F9C042C6EF65100F79137 /* Hash+simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Hash+simple.hpp"; sourceTree = ""; }; + F61F9C052C6EF81D00F79137 /* Hash+zltan.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Hash+zltan.hpp"; sourceTree = ""; }; + F61F9C092C6F3CD400F79137 /* smhasher */ = {isa = PBXFileReference; lastKnownFileType = folder; path = smhasher; sourceTree = ""; }; + F6231C6B2C42AFC200DC8CD3 /* map_has_key.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_has_key.hpp; sourceTree = ""; }; + F6231C772C42B1AC00DC8CD3 /* container_get_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_get_if.hpp; sourceTree = ""; }; + F6231C7A2C42B25700DC8CD3 /* container_has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_has.hpp; sourceTree = ""; }; + F6231C7C2C42B37900DC8CD3 /* container_get_if_optional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_get_if_optional.hpp; sourceTree = ""; }; + F6231C7D2C42B3C700DC8CD3 /* container_get_optional_erase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_get_optional_erase.hpp; sourceTree = ""; }; + F6231C7E2C42B41A00DC8CD3 /* container_erase_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_erase_if.hpp; sourceTree = ""; }; + F6231C7F2C42B43B00DC8CD3 /* container_find_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_find_if.hpp; sourceTree = ""; }; + F6231C802C42B4DD00DC8CD3 /* container_erase_value_one.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_erase_value_one.hpp; sourceTree = ""; }; + F6231C812C42B52F00DC8CD3 /* container_erase_if_one.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_erase_if_one.hpp; sourceTree = ""; }; + F6231C822C42B88B00DC8CD3 /* container_get_if_optional_erase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_get_if_optional_erase.hpp; sourceTree = ""; }; + F6231C882C42BC2000DC8CD3 /* container_has_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_has_if.hpp; sourceTree = ""; }; + F624DBEB2E53E99D00A1D4D8 /* set_insert_once.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_insert_once.hpp; sourceTree = ""; }; + F627353F28523A7B004BB4BC /* map_value_erase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_erase.hpp; sourceTree = ""; }; + F6273596285389F3004BB4BC /* strong_of.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strong_of.hpp; sourceTree = ""; }; + F62735D92853A619004BB4BC /* strong_init.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strong_init.hpp; sourceTree = ""; }; + F62757BC2B30872200655557 /* StackArray_v2+hash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StackArray_v2+hash.hpp"; sourceTree = ""; }; + F62757BD2B30874800655557 /* StackArray+hash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StackArray+hash.hpp"; sourceTree = ""; }; + F628790D29E8A3B8009CC2A9 /* is_callable_with_two_args.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_callable_with_two_args.hpp; sourceTree = ""; }; + F62919EC2CB6A3B3002060E0 /* cmp_case.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = cmp_case.cpp; sourceTree = ""; }; + F62919EE2CB6A435002060E0 /* strncasecmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = strncasecmp.h; sourceTree = ""; }; + F62919EF2CB6A468002060E0 /* strncasecmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strncasecmp.cpp; sourceTree = ""; }; + F62919F22CB6A7C6002060E0 /* strncmp.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = strncmp.h; sourceTree = ""; }; + F62919F32CB6A83F002060E0 /* strncmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strncmp.cpp; sourceTree = ""; }; + F6291A002CB6B128002060E0 /* strncasecmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strncasecmp.cpp; sourceTree = ""; }; + F6291A012CB6B149002060E0 /* strncmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = strncmp.cpp; sourceTree = ""; }; + F6291A0D2CB6F816002060E0 /* Exception.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Exception.hpp; sourceTree = ""; }; + F6291A0E2CB6F89E002060E0 /* NullPointer.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NullPointer.h; sourceTree = ""; }; + F6291A0F2CB6F8AE002060E0 /* NullPointer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NullPointer.hpp; sourceTree = ""; }; + F6291A102CB6F8CB002060E0 /* NotImplemented.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NotImplemented.h; sourceTree = ""; }; + F6291A112CB6F971002060E0 /* OutOfBounds.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = OutOfBounds.hpp; sourceTree = ""; }; + F6291A122CB6F971002060E0 /* OutOfBounds.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = OutOfBounds.h; sourceTree = ""; }; + F62C1BE0286246F20093EFBE /* handle_assert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = handle_assert.hpp; sourceTree = ""; }; + F62C1C3F2863555B0093EFBE /* range_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = range_with.hpp; sourceTree = ""; }; + F62C2C0A2A526838007B43A3 /* SafeIteration_v_consts.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SafeIteration_v_consts.hpp; sourceTree = ""; }; + F62C2C0B2A52686F007B43A3 /* SafeIteration.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SafeIteration.hpp; sourceTree = ""; }; + F62D7B52290B0A1B001285AE /* list_erase_if_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = list_erase_if_value.hpp; sourceTree = ""; }; + F63321FA2B079E1D00CEEDAF /* UnlockGuard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = UnlockGuard.hpp; sourceTree = ""; }; + F636F39D2C1223B300FAC66D /* debug_throw.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug_throw.h; sourceTree = ""; }; + F636F39F2C1226DE00FAC66D /* Stack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Stack.cpp; sourceTree = ""; }; + F638B4C22999A21A006D27EE /* copy_of.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = copy_of.hpp; sourceTree = ""; }; + F6390DF12D1F287C0060EB75 /* all_are.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = all_are.hpp; sourceTree = ""; }; + F6390DF22D1F65B10060EB75 /* is_zero.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_zero.hpp; sourceTree = ""; }; + F6390DF32D1F66FD0060EB75 /* one_is.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = one_is.hpp; sourceTree = ""; }; + F6390DF42D1F67170060EB75 /* not_zero.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = not_zero.hpp; sourceTree = ""; }; + F63B04152C76297F00417011 /* InPlaceArray+iterator.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "InPlaceArray+iterator.inl"; sourceTree = ""; }; + F63B04182C76896800417011 /* debug_break.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug_break.h; sourceTree = ""; }; + F63B04192C76A07A00417011 /* HashExpected.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = HashExpected.cpp; sourceTree = ""; }; + F63B041B2C76A2CF00417011 /* Hash+zltan+expected.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = "Hash+zltan+expected.inl"; sourceTree = ""; }; + F63B04262C7759D400417011 /* Definitions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Definitions.h; sourceTree = ""; }; + F63B04282C7766B600417011 /* is_vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_vector.hpp; sourceTree = ""; }; + F63B042A2C77674A00417011 /* is_vector.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = is_vector.cpp; sourceTree = ""; }; + F63B042C2C77677600417011 /* is_map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_map.hpp; sourceTree = ""; }; + F63B042D2C7767AA00417011 /* is_map.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = is_map.cpp; sourceTree = ""; }; + F63B04322C778D2800417011 /* concat.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = concat.hpp; sourceTree = ""; }; + F63B04362C778EBF00417011 /* concat.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = concat.cpp; sourceTree = ""; }; + F63B04392C77C2EE00417011 /* count_char.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = count_char.hpp; sourceTree = ""; }; + F63B043A2C77C32900417011 /* remove_char.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = remove_char.hpp; sourceTree = ""; }; + F63B043F2C77EDF800417011 /* Str.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Str.hpp; sourceTree = ""; }; + F63B04402C77F11300417011 /* Str+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Str+IO.hpp"; sourceTree = ""; }; + F63B04412C7802A500417011 /* length.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = length.hpp; sourceTree = ""; }; + F63B04422C78AA5000417011 /* All.cxx */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = All.cxx; sourceTree = ""; }; + F63D85112D10B73D00FF3624 /* handle_assert.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = handle_assert.cpp; sourceTree = ""; }; + F63DCC5B2EDA437B003BEE7C /* has_prefix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = has_prefix.hpp; sourceTree = ""; }; + F642D7872B4B8C51008BD947 /* UnorderedSet.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = UnorderedSet.hpp; sourceTree = ""; }; + F642D7882B4B8C51008BD947 /* UnorderedSet.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnorderedSet.h; sourceTree = ""; }; + F6436EC3285955F2003241E0 /* small_cmp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = small_cmp.hpp; sourceTree = ""; }; + F6436EC4285955F2003241E0 /* small_cmp.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = small_cmp.cpp; sourceTree = ""; }; + F6436EC628597E68003241E0 /* Str.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Str.inl; sourceTree = ""; }; + F643C8C528D3D4C3006380F5 /* map_iterator_or_insert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_iterator_or_insert.hpp; sourceTree = ""; }; + F64406FB2B39EF9800A2477F /* Time.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Time.h; sourceTree = ""; }; + F64407002B39EF9800A2477F /* Source.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Source.cpp; sourceTree = ""; }; + F64407012B39EF9800A2477F /* Time+chrono.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = "Time+chrono.hpp"; sourceTree = ""; }; + F64407022B39EF9800A2477F /* Time.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Time.hpp; sourceTree = ""; }; + F64407032B39EF9800A2477F /* Time+operations.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = "Time+operations.hpp"; sourceTree = ""; }; + F64407042B39EF9800A2477F /* Time+IO.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = "Time+IO.hpp"; sourceTree = ""; }; + F64407052B39EF9800A2477F /* Time+IO.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = "Time+IO.cpp"; sourceTree = ""; }; + F64407062B39EF9800A2477F /* Source.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = Source.hpp; sourceTree = ""; }; + F64407072B39EF9800A2477F /* Time.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Time.cpp; sourceTree = ""; }; + F6446A1C28B181E700871176 /* last_of_parameter_pack.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = last_of_parameter_pack.hpp; sourceTree = ""; }; + F64714A52C74A0E9002A8087 /* Timer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Timer.cpp; sourceTree = ""; }; + F64714AB2C74B09D002A8087 /* trim.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = trim.cpp; sourceTree = ""; }; + F64714AD2C74B4BE002A8087 /* replace.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = replace.cpp; sourceTree = ""; }; + F64714B02C74B5DF002A8087 /* join.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = join.cpp; sourceTree = ""; }; + F64714B22C74BE4A002A8087 /* transform_with.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = transform_with.cpp; sourceTree = ""; }; + F64714B42C74CD29002A8087 /* fail_on_copy_vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = fail_on_copy_vector.hpp; sourceTree = ""; }; + F64714B62C74CF1F002A8087 /* Lock.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Lock.cpp; sourceTree = ""; }; + F647A68B28982211009E67C8 /* Optimization.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Optimization.h; sourceTree = ""; }; + F64BF9C02C760BF70088647E /* trim.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = trim.inl; sourceTree = ""; }; + F64C651D2AC4F1C900FCF1DD /* RTTI+std.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "RTTI+std.hpp"; sourceTree = ""; }; + F64C651E2AC4F1C900FCF1DD /* RTTI+custom.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "RTTI+custom.hpp"; sourceTree = ""; }; + F64C651F2AC4F1C900FCF1DD /* RTTI.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = RTTI.hpp; sourceTree = ""; }; + F64C65212AC5AA2800FCF1DD /* RTTI.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = RTTI.cpp; sourceTree = ""; }; + F64D834C2E4B6F58009AD431 /* debug_assert_complex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug_assert_complex.h; sourceTree = ""; }; + F64D834D2E4B6F83009AD431 /* handle_assert_simple.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = handle_assert_simple.hpp; sourceTree = ""; }; + F64D834E2E4B6F8C009AD431 /* handle_assert_complex.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = handle_assert_complex.hpp; sourceTree = ""; }; + F64D83502E4B73F3009AD431 /* compile.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = compile.h; sourceTree = ""; }; + F658605A29525602009B5C15 /* zip.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = zip.hpp; sourceTree = ""; }; + F658606729535BB4009B5C15 /* ByF.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ByF.hpp; sourceTree = ""; }; + F659287329B11B8C00EE781F /* NotImplemented.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = NotImplemented.hpp; sourceTree = ""; }; + F65B59982C6C4C4800059339 /* is_first.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = is_first.cpp; sourceTree = ""; }; + F65B599A2C6C4E5C00059339 /* safe_next.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = safe_next.cpp; sourceTree = ""; }; + F65B59DA2C6C53EF00059339 /* libCore_Allocator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libCore_Allocator.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F65D0FCD29AD6C15000247E6 /* Pack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pack.h; sourceTree = ""; }; + F65E5A8028BE7D3200772521 /* list_erase_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = list_erase_if.hpp; sourceTree = ""; }; + F65FC144283E5F2D00DEA3F9 /* set_has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_has.hpp; sourceTree = ""; }; + F65FC147283E6FC500DEA3F9 /* split.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = split.inl; sourceTree = ""; }; + F65FD5E52A83EB850022A4CC /* optional_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = optional_value.hpp; sourceTree = ""; }; + F65FD5F02A8551240022A4CC /* PtrOrValue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = PtrOrValue.h; sourceTree = ""; }; + F65FD5F12A8551380022A4CC /* PtrOrValue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = PtrOrValue.hpp; sourceTree = ""; }; + F66033A3294CD68D0035F0D8 /* map_value_or_insert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_or_insert.hpp; sourceTree = ""; }; + F66033B0294CEE160035F0D8 /* Pair.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Pair.h; sourceTree = ""; }; + F66033B1294CEE2E0035F0D8 /* Pair.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Pair.hpp; sourceTree = ""; }; + F6604029286A63C400C07DC0 /* Types+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Types+IO.h"; sourceTree = ""; }; + F660402A286A63F000C07DC0 /* Types+IO.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = "Types+IO.cpp"; sourceTree = ""; }; + F6652EAF2D11A37D00C448BB /* as_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = as_string.hpp; sourceTree = ""; }; + F668F0482E25633A000A6B71 /* Log+Precision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "Log+Precision.h"; sourceTree = ""; }; + F668F04E2E25A814000A6B71 /* set_once.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_once.hpp; sourceTree = ""; }; + F66F8971292D0FFC00E723E8 /* map_value_or_insert_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_or_insert_value.hpp; sourceTree = ""; }; + F67119D22C8A231E00F72EE9 /* vector_get_optional_erase_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_get_optional_erase_if.hpp; sourceTree = ""; }; + F67635BA2E00447C0059296C /* debug_assert_simple.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = debug_assert_simple.h; sourceTree = ""; }; + F67636512E01ACB20059296C /* Types_.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types_.h; sourceTree = ""; }; + F67636522E01ADB50059296C /* String_.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = String_.h; sourceTree = ""; }; + F6763ECE2E8C384300EC53ED /* container_count_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_count_if.hpp; sourceTree = ""; }; + F676D4CD285E0AE00072143D /* vector_erase_if_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_erase_if_value.hpp; sourceTree = ""; }; + F67786782D85DD1F00C8308C /* vector_value_at.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value_at.hpp; sourceTree = ""; }; + F67786BF2D85FD4D00C8308C /* map_insert.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_insert.hpp; sourceTree = ""; }; + F67786C92D86032B00C8308C /* vector_value_before_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value_before_if.hpp; sourceTree = ""; }; + F67B008028673277002A7A43 /* ByPtr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ByPtr.hpp; sourceTree = ""; }; + F67B008728673903002A7A43 /* Function.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Function.h; sourceTree = ""; }; + F67B00882867392D002A7A43 /* Function.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Function.hpp; sourceTree = ""; }; + F67CE9072D83D1ED004400C3 /* list_erase_if_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = list_erase_if_value.cpp; sourceTree = ""; }; + F67CE9092D83D213004400C3 /* map_erase_if_key.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_erase_if_key.cpp; sourceTree = ""; }; + F67CE90B2D83D2A8004400C3 /* map_erase_if_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_erase_if_value.cpp; sourceTree = ""; }; + F67CE90D2D83D2F4004400C3 /* map_erase_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_erase_if.cpp; sourceTree = ""; }; + F67CE90F2D83D329004400C3 /* map_erase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_erase.cpp; sourceTree = ""; }; + F67CE9112D83D3B1004400C3 /* map_has.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_has.cpp; sourceTree = ""; }; + F67CE9132D83D404004400C3 /* map_has_key.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_has_key.cpp; sourceTree = ""; }; + F67CE9152D83D4F8004400C3 /* map_for_each_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_for_each_value.cpp; sourceTree = ""; }; + F67CE9172D83D595004400C3 /* map_iterator_or_insert.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_iterator_or_insert.cpp; sourceTree = ""; }; + F67CE9192D83D65D004400C3 /* map_value_require.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_value_require.cpp; sourceTree = ""; }; + F67CE91B2D83D6E0004400C3 /* map_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = map_value.cpp; sourceTree = ""; }; + F67CE91D2D83D73B004400C3 /* not_zero.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = not_zero.cpp; sourceTree = ""; }; + F67CE91F2D83D790004400C3 /* on_destruct.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = on_destruct.cpp; sourceTree = ""; }; + F67CE9262D83D8E5004400C3 /* optional_value_or_default.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = optional_value_or_default.cpp; sourceTree = ""; }; + F67CE9282D83D951004400C3 /* optional_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = optional_value.cpp; sourceTree = ""; }; + F67CE92A2D83D99D004400C3 /* set_empty.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = set_empty.cpp; sourceTree = ""; }; + F67CE92C2D83DAD0004400C3 /* container_erase_if_imp_use_iterator.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_erase_if_imp_use_iterator.hpp; sourceTree = ""; }; + F67CE92E2D83DD1C004400C3 /* if_or.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = if_or.cpp; sourceTree = ""; }; + F67CE9302D844BAF004400C3 /* vector_append.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vector_append.cpp; sourceTree = ""; }; + F67CE9322D844CA2004400C3 /* vector_erase_if_value.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vector_erase_if_value.cpp; sourceTree = ""; }; + F67CE9342D844CDB004400C3 /* vector_erase_value_one.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vector_erase_value_one.cpp; sourceTree = ""; }; + F67CE9362D844E39004400C3 /* container_erase_value_all.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = container_erase_value_all.hpp; sourceTree = ""; }; + F67CE9372D844FA2004400C3 /* list_erase_value_all.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = list_erase_value_all.hpp; sourceTree = ""; }; + F67CE9382D845039004400C3 /* vector_erase_value_all.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = vector_erase_value_all.cpp; sourceTree = ""; }; + F67CE93A2D84504D004400C3 /* vector_erase_value_one.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_erase_value_one.hpp; sourceTree = ""; }; + F67CE93B2D8450BA004400C3 /* container_erase_value_all.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_erase_value_all.cpp; sourceTree = ""; }; + F67CE94B2D84583F004400C3 /* Examples.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Examples.cpp; sourceTree = ""; }; + F67CE9562D84752D004400C3 /* LICENSE */ = {isa = PBXFileReference; lastKnownFileType = text; path = LICENSE; sourceTree = ""; }; + F67F33E92D7E15510043E2D8 /* replaced.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = replaced.h; sourceTree = ""; }; + F67F33EA2D7E156D0043E2D8 /* replaced.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = replaced.cpp; sourceTree = ""; }; + F683F5192A648CA700191850 /* CounterFor.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CounterFor.h; sourceTree = ""; }; + F683F51A2A65C2E200191850 /* memstream.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = memstream.hpp; sourceTree = ""; }; + F683F51B2A65C3FE00191850 /* from_string.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = from_string.h; sourceTree = ""; }; + F6847CE82C3F0F4E00D14916 /* sxprintf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = sxprintf.h; sourceTree = ""; }; + F685900B2DF39549004A2DD8 /* to_lower.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = to_lower.hpp; sourceTree = ""; }; + F68657732F0D539100F17333 /* map_value_optional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value_optional.hpp; sourceTree = ""; }; + F68657742F0D549900F17333 /* map_set_or_erase_optional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_set_or_erase_optional.hpp; sourceTree = ""; }; + F68657762F0DC03B00F17333 /* Exception+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Exception+IO.hpp"; sourceTree = ""; }; + F68839B22D39D5B7003E6FC2 /* with_lock.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = with_lock.hpp; sourceTree = ""; }; + F68898CE2A5E156400CE7B3B /* MemorySegment.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = MemorySegment.h; sourceTree = ""; }; + F68898CF2A5E15F800CE7B3B /* MemorySegment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MemorySegment.hpp; sourceTree = ""; }; + F688EF882C78F6430087B561 /* Time+chrono+misc.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Time+chrono+misc.hpp"; sourceTree = ""; }; + F68A80A82929491400F77389 /* SpinMutex.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SpinMutex.hpp; sourceTree = ""; }; + F68BA83F2E93F1410040FA70 /* Detail.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Detail.h; sourceTree = ""; }; + F68BA8402E93F14F0040FA70 /* Detail.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Detail.hpp; sourceTree = ""; }; + F68BA8412E93F2700040FA70 /* Detail.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Detail.cpp; sourceTree = ""; }; + F68BA8422E93F3BB0040FA70 /* Color.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Color.hpp; sourceTree = ""; }; + F68BA8442E93FCD30040FA70 /* Util.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Util.inl; sourceTree = ""; }; + F68BA8472E940E720040FA70 /* Color.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Color.cpp; sourceTree = ""; }; + F68BF1F32D6366E600DA1DD9 /* emplace.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = emplace.hpp; sourceTree = ""; }; + F68C13602E06E384003C3717 /* ToString.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ToString.hpp; sourceTree = ""; }; + F68C13612E06E855003C3717 /* auto_to_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = auto_to_string.hpp; sourceTree = ""; }; + F68CE3222D3753D4004F9466 /* TryLockGuard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TryLockGuard.hpp; sourceTree = ""; }; + F69345B229B794B2008B7AEB /* ByPtrId.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ByPtrId.hpp; sourceTree = ""; }; + F69345B329B7973F008B7AEB /* ByStrongPtrId.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ByStrongPtrId.hpp; sourceTree = ""; }; + F69345BD29B7A69E008B7AEB /* UnorderedMap.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = UnorderedMap.hpp; sourceTree = ""; }; + F69345BE29B7A6AC008B7AEB /* UnorderedMap.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = UnorderedMap.h; sourceTree = ""; }; + F69365FA2E29B3F100DFD771 /* vector_value_if_index.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value_if_index.hpp; sourceTree = ""; }; + F69534642D84DED000C9AFA0 /* StringView+concat.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StringView+concat.hpp"; sourceTree = ""; }; + F69553A12AEECB8400FC8A36 /* vector_erase_value_all.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_erase_value_all.hpp; sourceTree = ""; }; + F6960CB32D8842C800767451 /* map_erase_get_optional.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_erase_get_optional.hpp; sourceTree = ""; }; + F6971F21282B1129008FBD17 /* libCore_Zero_iOS.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Zero_iOS.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F698285C2B11774100EEACE9 /* CompileTimeSizeOf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = CompileTimeSizeOf.h; sourceTree = ""; }; + F69832AA2D7B3EFA00D911E4 /* catch2.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = catch2.hpp; sourceTree = ""; }; + F69832AB2D7B3F4E00D911E4 /* catch.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = catch.cpp; sourceTree = ""; }; + F69832B72D7B6E7300D911E4 /* copy_clear.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = copy_clear.hpp; sourceTree = ""; }; + F69832B82D7B7A7000D911E4 /* copy_clear.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = copy_clear.cpp; sourceTree = ""; }; + F69AB7792B16D158000115BC /* TypeName+custom.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "TypeName+custom.hpp"; sourceTree = ""; }; + F69AB77B2B16D365000115BC /* TypeName.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TypeName.hpp; sourceTree = ""; }; + F69AB77C2B16D4BA000115BC /* TypeName.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TypeName.cpp; sourceTree = ""; }; + F69AB7F02B193108000115BC /* Hash.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Hash.hpp; sourceTree = ""; }; + F69AB7F12B193108000115BC /* Hash.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Hash.cpp; sourceTree = ""; }; + F69AB7F22B193108000115BC /* Hash.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Hash.h; sourceTree = ""; }; + F69B59C12BDD7E7400280B50 /* strong_emplace.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = strong_emplace.hpp; sourceTree = ""; }; + F69C7BDF28A5AB15008385A2 /* set_empty.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_empty.hpp; sourceTree = ""; }; + F69CC2592D297F2800FB29DE /* in_range_segment.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = in_range_segment.hpp; sourceTree = ""; }; + F69D521D295641D100B5875A /* map_erase_if_key.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_erase_if_key.hpp; sourceTree = ""; }; + F69F8D882DCED15A0038CCDC /* mem_copy_asan_safe.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = mem_copy_asan_safe.hpp; sourceTree = ""; }; + F6A994782D827C5900AA4FEE /* starts_with.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = starts_with.cpp; sourceTree = ""; }; + F6A9947A2D827CBB00AA4FEE /* length.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = length.cpp; sourceTree = ""; }; + F6ADDF65285F742300404CBA /* safe_next_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = safe_next_with.hpp; sourceTree = ""; }; + F6B1537C2C7042830063C622 /* range_with.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = range_with.cpp; sourceTree = ""; }; + F6B348C82872545200A9CE7E /* cmp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = cmp.hpp; sourceTree = ""; }; + F6BACA11285C03CA00694BBE /* starts_with_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = starts_with_value.hpp; sourceTree = ""; }; + F6BF9BDF2E38F728002E6AF0 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = ""; }; + F6BFE18A285A181C002A95C3 /* map_erase_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_erase_if.hpp; sourceTree = ""; }; + F6BFE18B285A18AF002A95C3 /* map_erase_if_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_erase_if_value.hpp; sourceTree = ""; }; + F6BFE18C285A1BF9002A95C3 /* map_for_each_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_for_each_value.hpp; sourceTree = ""; }; + F6C3C1F628B279E30093BD9B /* empty_of.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = empty_of.hpp; sourceTree = ""; }; + F6C8084A2B14C19B00D8068D /* Optional+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Optional+IO.hpp"; sourceTree = ""; }; + F6C855E32DB6F04C006D6C48 /* split_once.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = split_once.hpp; sourceTree = ""; }; + F6C855E42DB7321E006D6C48 /* split_once.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = split_once.cpp; sourceTree = ""; }; + F6CA3189292BCD57008EE166 /* SpinMutex.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SpinMutex.cpp; sourceTree = ""; }; + F6CA9B59294E7B4600D9A375 /* range.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = range.cpp; sourceTree = ""; }; + F6CD1F7E28BBB7DC00509B3D /* list_erase_value_one.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = list_erase_value_one.hpp; sourceTree = ""; }; + F6CD9E9F2A0977CC001FA01D /* vector_has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_has.hpp; sourceTree = ""; }; + F6CF968628329DF00072B6C1 /* map_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_value.hpp; sourceTree = ""; }; + F6CF968A2832A1C90072B6C1 /* map_pair.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_pair.hpp; sourceTree = ""; }; + F6CFD87E2E1ED23C00CDDC2E /* Time+timestamp.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Time+timestamp.hpp"; sourceTree = ""; }; + F6D08E2B2DD406000018ED2C /* has_sequence.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = has_sequence.hpp; sourceTree = ""; }; + F6D08E2C2DD406B10018ED2C /* has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = has.hpp; sourceTree = ""; }; + F6D114802D3D9AA600BFA3B3 /* Source.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Source.h; sourceTree = ""; }; + F6D4106D29D89E5F00C9C2F9 /* vector_append.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_append.hpp; sourceTree = ""; }; + F6D6CE432DA80127002B7253 /* unprefix.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unprefix.hpp; sourceTree = ""; }; + F6D7D60428764AF50015548D /* set_erase_if_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_erase_if_value.hpp; sourceTree = ""; }; + F6D8CD972E0981C6000A4ED2 /* vector_has_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_has_if.hpp; sourceTree = ""; }; + F6DC70D62D81E375004DA34D /* all_are.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = all_are.cpp; sourceTree = ""; }; + F6DC70D82D81E43B004DA34D /* one_is.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = one_is.cpp; sourceTree = ""; }; + F6DC70DA2D81E493004DA34D /* container_erase_if_one.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_erase_if_one.cpp; sourceTree = ""; }; + F6DC70DC2D81E5D1004DA34D /* container_erase_value_one.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_erase_value_one.cpp; sourceTree = ""; }; + F6DC70DE2D81E6B7004DA34D /* container_erase_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_erase_if.cpp; sourceTree = ""; }; + F6DC70E02D81E735004DA34D /* container_find_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_find_if.cpp; sourceTree = ""; }; + F6DC70E22D81E804004DA34D /* container_get_if_optional_erase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_get_if_optional_erase.cpp; sourceTree = ""; }; + F6DC70E42D81E8E9004DA34D /* container_get_if_optional.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_get_if_optional.cpp; sourceTree = ""; }; + F6DC70E62D81E937004DA34D /* container_get_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_get_if.cpp; sourceTree = ""; }; + F6DC70E82D81EAB4004DA34D /* container_get_optional_erase.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_get_optional_erase.cpp; sourceTree = ""; }; + F6DC70EA2D81EBEF004DA34D /* container_has_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_has_if.cpp; sourceTree = ""; }; + F6DC70EC2D81EC4D004DA34D /* container_has.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = container_has.cpp; sourceTree = ""; }; + F6DC70EE2D81ECE1004DA34D /* copy_of.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = copy_of.cpp; sourceTree = ""; }; + F6DC70F02D81EE72004DA34D /* empty_of.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = empty_of.cpp; sourceTree = ""; }; + F6DC70F22D81EF1B004DA34D /* emplace.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = emplace.cpp; sourceTree = ""; }; + F6DC70F42D81EFBB004DA34D /* ends_with.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = ends_with.cpp; sourceTree = ""; }; + F6DC70F72D81F062004DA34D /* has_last.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = has_last.cpp; sourceTree = ""; }; + F6DC70F92D81F0F5004DA34D /* in_range_segment.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = in_range_segment.cpp; sourceTree = ""; }; + F6DC70FB2D81F1A8004DA34D /* is_in.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = is_in.cpp; sourceTree = ""; }; + F6DC70FD2D81F1EC004DA34D /* is_zero.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = is_zero.cpp; sourceTree = ""; }; + F6DC70FF2D81F2F8004DA34D /* last_of_parameter_pack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = last_of_parameter_pack.cpp; sourceTree = ""; }; + F6DC71012D81F397004DA34D /* list_erase_if.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = list_erase_if.cpp; sourceTree = ""; }; + F6DCDBB32858F58700696085 /* small_copy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = small_copy.hpp; sourceTree = ""; }; + F6DCDBB42858F61B00696085 /* small_copy.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = small_copy.cpp; sourceTree = ""; }; + F6DDE78C2DB27B84005F94FC /* set_erase_optional_value.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_erase_optional_value.hpp; sourceTree = ""; }; + F6DE207C2D3EA99900E039E4 /* RUN_IF.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = RUN_IF.h; sourceTree = ""; }; + F6DEAAAA2CB3639800E8E7C8 /* DisableWarningsAllPop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisableWarningsAllPop.h; sourceTree = ""; }; + F6E0AFA52F1BCBE40058412E /* optional_of_ptr.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = optional_of_ptr.hpp; sourceTree = ""; }; + F6E5495328CCD24C007010BC /* Allocations.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Allocations.h; sourceTree = ""; }; + F6E5495428CCD3BA007010BC /* Allocations.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Allocations.cpp; sourceTree = ""; }; + F6E595A72850D6B40040841E /* ById.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ById.hpp; sourceTree = ""; }; + F6E595A82850D79B0040841E /* set_erase.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_erase.hpp; sourceTree = ""; }; + F6E97D00281EF4BF004C92E9 /* libCore_Zero.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libCore_Zero.a; sourceTree = BUILT_PRODUCTS_DIR; }; + F6E97D0A281EF5ED004C92E9 /* catch.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = catch.hpp; sourceTree = ""; }; + F6E97D0C281EF604004C92E9 /* Run.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Run.cpp; sourceTree = ""; }; + F6E97D11281EF664004C92E9 /* Core_Zero_Tests */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = Core_Zero_Tests; sourceTree = BUILT_PRODUCTS_DIR; }; + F6E97D1B281EF724004C92E9 /* demangle.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = demangle.cpp; sourceTree = ""; }; + F6E97D1C281EF724004C92E9 /* Log.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Log.h; sourceTree = ""; }; + F6E97D1D281EF724004C92E9 /* Color.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Color.inl; sourceTree = ""; }; + F6E97D1E281EF724004C92E9 /* LogOf.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = LogOf.cpp; sourceTree = ""; }; + F6E97D1F281EF724004C92E9 /* Log.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Log.cpp; sourceTree = ""; }; + F6E97D20281EF724004C92E9 /* demangle.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = demangle.h; sourceTree = ""; }; + F6E97D21281EF724004C92E9 /* LogOf.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LogOf.h; sourceTree = ""; }; + F6E97D29281F0124004C92E9 /* TestCollision.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestCollision.h; sourceTree = ""; }; + F6E97D2A281F0124004C92E9 /* TestMutex.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = TestMutex.cpp; sourceTree = ""; }; + F6E97D2B281F0124004C92E9 /* TestMutex.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = TestMutex.inl; sourceTree = ""; }; + F6E97D2C281F0124004C92E9 /* TestMutex.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = TestMutex.h; sourceTree = ""; }; + F6E97D2D281F0125004C92E9 /* TestMutex.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = TestMutex.hpp; sourceTree = ""; }; + F6E97D2E281F0125004C92E9 /* Lock.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Lock.hpp; sourceTree = ""; }; + F6E97D2F281F0125004C92E9 /* LockedBy.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = LockedBy.hpp; sourceTree = ""; }; + F6E97D31281F0125004C92E9 /* Lock.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Lock.hpp; sourceTree = ""; }; + F6E97D32281F0125004C92E9 /* Lock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Lock.h; sourceTree = ""; }; + F6E97D33281F0125004C92E9 /* SharedLockGuard.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SharedLockGuard.hpp; sourceTree = ""; }; + F6E97D34281F0125004C92E9 /* Lock.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Lock.h; sourceTree = ""; }; + F6E97D35281F0155004C92E9 /* LockedBy.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = LockedBy.h; sourceTree = ""; }; + F6E97D3A281F0A65004C92E9 /* Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Debug.h; sourceTree = ""; }; + F6E97D3B281F0A65004C92E9 /* Stack.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Stack.cpp; sourceTree = ""; }; + F6E97D3C281F0A65004C92E9 /* Stack.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Stack.h; sourceTree = ""; }; + F6E97D3E281F0A65004C92E9 /* Types.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Types.h; sourceTree = ""; }; + F6E97D3F281F0A65004C92E9 /* unused.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = unused.hpp; sourceTree = ""; }; + F6E97D44281F0A65004C92E9 /* DisableWarningsPop.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisableWarningsPop.h; sourceTree = ""; }; + F6E97D45281F0A65004C92E9 /* Debug.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Debug.h; sourceTree = ""; }; + F6E97D47281F0A65004C92E9 /* DisableWarningsPush.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DisableWarningsPush.h; sourceTree = ""; }; + F6E97D4E281F0A65004C92E9 /* System.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = System.h; sourceTree = ""; }; + F6E97D52281F0C30004C92E9 /* is_in.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_in.hpp; sourceTree = ""; }; + F6E97D53281F0D03004C92E9 /* Map.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Map.hpp; sourceTree = ""; }; + F6E97D54281F0D3F004C92E9 /* Set.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Set.hpp; sourceTree = ""; }; + F6E97D55281F0D63004C92E9 /* String.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = String.hpp; sourceTree = ""; }; + F6E97D56281F0D8A004C92E9 /* List.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = List.hpp; sourceTree = ""; }; + F6E97D57281F0DBB004C92E9 /* Atomic.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Atomic.hpp; sourceTree = ""; }; + F6E97D5A281F0E8B004C92E9 /* release_assert.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = release_assert.h; sourceTree = ""; }; + F6E97D5B281F0EDB004C92E9 /* List.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = List.h; sourceTree = ""; }; + F6E97D5C281F0EDB004C92E9 /* Set.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Set.h; sourceTree = ""; }; + F6E97D5D281F0EDB004C92E9 /* Map.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Map.h; sourceTree = ""; }; + F6E97D5E281F0EDC004C92E9 /* String.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = String.h; sourceTree = ""; }; + F6E97D5F281F0EDC004C92E9 /* Atomic.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Atomic.h; sourceTree = ""; }; + F6E97D64281F3AA3004C92E9 /* always_false.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = always_false.hpp; sourceTree = ""; }; + F6E97D65281F3AA3004C92E9 /* is_string.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_string.hpp; sourceTree = ""; }; + F6E97D67281F3AA3004C92E9 /* is_callable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_callable.hpp; sourceTree = ""; }; + F6E97D68281F3AA3004C92E9 /* is_iterable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_iterable.hpp; sourceTree = ""; }; + F6E97D69281F3AA3004C92E9 /* remove_const_of_var.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = remove_const_of_var.hpp; sourceTree = ""; }; + F6E97D6A281F3AA3004C92E9 /* is_comparable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_comparable.hpp; sourceTree = ""; }; + F6E97D6B281F3AA3004C92E9 /* is_mappish.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = is_mappish.hpp; sourceTree = ""; }; + F6E97D6C281F3ACB004C92E9 /* Vector.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Vector.hpp; sourceTree = ""; }; + F6E97D6D281F3ACB004C92E9 /* Vector.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = ""; }; + F6E97DB0281F3F25004C92E9 /* ReadMe.md */ = {isa = PBXFileReference; lastKnownFileType = net.daringfireball.markdown; path = ReadMe.md; sourceTree = ""; }; + F6E97DB5281F4077004C92E9 /* starts_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = starts_with.hpp; sourceTree = ""; }; + F6E97DB6281F408A004C92E9 /* ends_with.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = ends_with.hpp; sourceTree = ""; }; + F6E97DB7281F41D0004C92E9 /* has_last.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = has_last.hpp; sourceTree = ""; }; + F6E97DB9281F439A004C92E9 /* SafeIteration_v_all_mutable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = SafeIteration_v_all_mutable.hpp; sourceTree = ""; }; + F6E97DBC281F439A004C92E9 /* Reversed.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Reversed.hpp; sourceTree = ""; }; + F6E97DBD281F439A004C92E9 /* StackArray_v2.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = StackArray_v2.cpp; sourceTree = ""; }; + F6E97DBE281F439A004C92E9 /* SafeIteration.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = SafeIteration.cpp; sourceTree = ""; }; + F6E97DBF281F439A004C92E9 /* Reversed.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Reversed.h; sourceTree = ""; }; + F6E97DC0281F439A004C92E9 /* QueueThreadSafe.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = QueueThreadSafe.hpp; sourceTree = ""; }; + F6E97DC1281F439A004C92E9 /* SafeIteration.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SafeIteration.h; sourceTree = ""; }; + F6E97DC2281F439A004C92E9 /* Queue.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Queue.h; sourceTree = ""; }; + F6E97DC3281F439A004C92E9 /* SafeIteration+IO.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SafeIteration+IO.h"; sourceTree = ""; }; + F6E97DC6281F4470004C92E9 /* FilledArray.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FilledArray.hpp; sourceTree = ""; }; + F6E97DC7281F4470004C92E9 /* FilledArrayThreadSafe.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = FilledArrayThreadSafe.hpp; sourceTree = ""; }; + F6E97DC8281F4470004C92E9 /* FilledArray.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilledArray.h; sourceTree = ""; }; + F6E97DC9281F4470004C92E9 /* FilledArrayThreadSafe.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = FilledArrayThreadSafe.h; sourceTree = ""; }; + F6E97DCB281F4877004C92E9 /* Exception.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Exception.h; sourceTree = ""; }; + F6E97DCC281F48BD004C92E9 /* Exception.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Exception.cpp; sourceTree = ""; }; + F6EB9F602858B55C007B3EFB /* process_queue.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = process_queue.hpp; sourceTree = ""; }; + F6EC55F52ECBA6C60052CD0A /* find_after.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = find_after.hpp; sourceTree = ""; }; + F6EC55F62ECBAADB0052CD0A /* find_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = find_if.hpp; sourceTree = ""; }; + F6EC57352ECC27D20052CD0A /* optional_set_if_empty.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = optional_set_if_empty.hpp; sourceTree = ""; }; + F6EE06D1284EB03700D659F9 /* map_has.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = map_has.hpp; sourceTree = ""; }; + F6F04D962DC2ADCA00A99D3E /* copy_clear_delete.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = copy_clear_delete.hpp; sourceTree = ""; }; + F6F10D1C2E37C1DC0082E9D9 /* Array+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "Array+IO.hpp"; sourceTree = ""; }; + F6F363C929A64A6000D9F857 /* Array.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Array.h; sourceTree = ""; }; + F6F363CA29A64A7A00D9F857 /* Array.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Array.hpp; sourceTree = ""; }; + F6F3B0862D7091150075B3DC /* THEN_REQUIRE.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = THEN_REQUIRE.h; sourceTree = ""; }; + F6F598B4287303A300588A26 /* vector_value_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value_if.hpp; sourceTree = ""; }; + F6F598B5287303F800588A26 /* vector_value_index_if.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = vector_value_index_if.hpp; sourceTree = ""; }; + F6F7216F2C5DB54E00A8E8D1 /* enumerate.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = enumerate.cpp; sourceTree = ""; }; + F6F721712C5DB73400A8E8D1 /* no_last.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = no_last.cpp; sourceTree = ""; }; + F6F721732C5DB81F00A8E8D1 /* no_first.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = no_first.cpp; sourceTree = ""; }; + F6F721752C5DB85200A8E8D1 /* zip.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = zip.cpp; sourceTree = ""; }; + F6F7A2F32F49EFAB008BF0C6 /* no_throw.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = no_throw.cpp; sourceTree = ""; }; + F6F7A2F52F49EFBD008BF0C6 /* no_throw.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = no_throw.hpp; sourceTree = ""; }; + F6F7A2FD2F4A14D4008BF0C6 /* set_erase_optional_value_move.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_erase_optional_value_move.hpp; sourceTree = ""; }; + F6F7A2FE2F4A15DC008BF0C6 /* set_insert_mutable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_insert_mutable.hpp; sourceTree = ""; }; + F6F7A2FF2F4A17F0008BF0C6 /* set_value_mutable.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = set_value_mutable.hpp; sourceTree = ""; }; + F6F7A3002F4A2516008BF0C6 /* remove_char.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = remove_char.cpp; sourceTree = ""; }; + F6F7A3022F4A26A3008BF0C6 /* Str.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Str.cpp; sourceTree = ""; }; + F6F9CF3F2E4F899A00576DEF /* Float16.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = Float16.cpp; sourceTree = ""; }; + F6F9CF5F2E4FB72900576DEF /* Float16.inl */ = {isa = PBXFileReference; lastKnownFileType = text; path = Float16.inl; sourceTree = ""; }; + F6FADA962948FF90006125E1 /* MultiContainer.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = MultiContainer.hpp; sourceTree = ""; }; + F6FADA972949041B006125E1 /* MultiContainer.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = MultiContainer.cpp; sourceTree = ""; }; + F6FBAABD2B28E9A500F0243C /* StackArray+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StackArray+IO.hpp"; sourceTree = ""; }; + F6FBAABE2B28E9BE00F0243C /* StackArray_v2+IO.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = "StackArray_v2+IO.hpp"; sourceTree = ""; }; + F6FBBCA22E4E59FF00B3DCE2 /* Float16.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = Float16.h; sourceTree = ""; }; + F6FBBCA32E4E5A4200B3DCE2 /* Float16.hpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.h; path = Float16.hpp; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + F6971F1D282B1129008FBD17 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6E97CFE281EF4BF004C92E9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6E97D0E281EF664004C92E9 /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + F67119DC2C8A636700F72EE9 /* libCore_Zero.a in Frameworks */, + F67119DD2C8A636700F72EE9 /* libCore_Allocator.a in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + F601313E2873B3E30088443B /* linux */ = { + isa = PBXGroup; + children = ( + F601313F2873B3E70088443B /* Types.h */, + ); + path = linux; + sourceTree = ""; + }; + F608A8872825C91C005C276B /* iterators */ = { + isa = PBXGroup; + children = ( + F61F9BB12C6D980000F79137 /* _tests */, + F608A88A2825CA7C005C276B /* enumerate.hpp */, + F608A8892825CA7C005C276B /* is_first.hpp */, + F608A88B2825CA7D005C276B /* macro_min_max.h */, + F608A8922825CAC1005C276B /* no_first.hpp */, + F608A88C2825CA7D005C276B /* no_last.hpp */, + F62C1C3F2863555B0093EFBE /* range_with.hpp */, + F608A88D2825CA7D005C276B /* range.hpp */, + F608A8902825CA7E005C276B /* reverse.hpp */, + F6ADDF65285F742300404CBA /* safe_next_with.hpp */, + F608A88E2825CA7D005C276B /* safe_next.hpp */, + F608A8912825CA7E005C276B /* transform_with.hpp */, + F658605A29525602009B5C15 /* zip.hpp */, + ); + path = iterators; + sourceTree = ""; + }; + F608A8AB28269A65005C276B /* string */ = { + isa = PBXGroup; + children = ( + F61F9BDA2C6E0F6800F79137 /* _tests */, + F6652EAF2D11A37D00C448BB /* as_string.hpp */, + F61BF8A92D1279C10061A507 /* as_string_view.hpp */, + F61DA0002D75F7D000FE2AEB /* as_vector.hpp */, + F608A8AC28269B63005C276B /* cmp_case.cpp */, + F608A8BF28269B64005C276B /* cmp_case.hpp */, + F68C13602E06E384003C3717 /* ToString.hpp */, + F68C13612E06E855003C3717 /* auto_to_string.hpp */, + F608A8AE28269B63005C276B /* cmp.cpp */, + F608A8BD28269B64005C276B /* cmp.hpp */, + F608A8C028269B64005C276B /* Dictionary.h */, + F608A8C528269B64005C276B /* Dictionary.inl */, + F608AB9228282705005C276B /* ends_with.hpp */, + F608A8C628269B64005C276B /* from_string.cpp */, + F683F51B2A65C3FE00191850 /* from_string.h */, + F608A8B728269B63005C276B /* from_string.hpp */, + F608A8B528269B63005C276B /* from_string.inl */, + F608A8B828269B63005C276B /* join.hpp */, + F6D08E2C2DD406B10018ED2C /* has.hpp */, + F608A8AD28269B63005C276B /* replace.cpp */, + F6EC55F52ECBA6C60052CD0A /* find_after.hpp */, + F6EC55F62ECBAADB0052CD0A /* find_if.hpp */, + F608A8B928269B63005C276B /* replace.h */, + F67F33EA2D7E156D0043E2D8 /* replaced.cpp */, + F67F33E92D7E15510043E2D8 /* replaced.h */, + F608A8B628269B63005C276B /* split.hpp */, + F65FC147283E6FC500DEA3F9 /* split.inl */, + F6C855E32DB6F04C006D6C48 /* split_once.hpp */, + F608A8B028269B63005C276B /* starts_with.hpp */, + F608A8C728269B64005C276B /* str_find.cpp */, + F608A8BE28269B64005C276B /* str_find.h */, + F608A8BC28269B63005C276B /* Str.cpp */, + F608A8C828269B64005C276B /* Str.h */, + F608A8CA28269BFE005C276B /* Str.hpp */, + F6436EC628597E68003241E0 /* Str.inl */, + F608A8AF28269B63005C276B /* Str+IO.h */, + F608A8C228269B64005C276B /* Str+IO.inl */, + F67636522E01ADB50059296C /* String_.h */, + F6E97D5E281F0EDC004C92E9 /* String.h */, + F6E97D55281F0D63004C92E9 /* String.hpp */, + F608A8CD28269D82005C276B /* StringView.h */, + F608A8CE28269D83005C276B /* StringView.hpp */, + F69534642D84DED000C9AFA0 /* StringView+concat.hpp */, + F61C393D2DEDFAA2005B42E7 /* StringView+less.hpp */, + F6291A002CB6B128002060E0 /* strncasecmp.cpp */, + F62919EE2CB6A435002060E0 /* strncasecmp.h */, + F6291A012CB6B149002060E0 /* strncmp.cpp */, + F62919F22CB6A7C6002060E0 /* strncmp.h */, + F6847CE82C3F0F4E00D14916 /* sxprintf.h */, + F608A8C428269B64005C276B /* to_string.h */, + F608A8B328269B63005C276B /* to_string.hpp */, + F685900B2DF39549004A2DD8 /* to_lower.hpp */, + F6D6CE432DA80127002B7253 /* unprefix.hpp */, + F63DCC5B2EDA437B003BEE7C /* has_prefix.hpp */, + F608A8B428269B63005C276B /* Tokenizer.h */, + F608A8C328269B64005C276B /* Tokenizer.hpp */, + F608A8C928269B64005C276B /* trim.h */, + F64BF9C02C760BF70088647E /* trim.inl */, + ); + path = string; + sourceTree = ""; + }; + F608A90E2826A6E7005C276B /* ptr */ = { + isa = PBXGroup; + children = ( + F61F9BB62C6D9F0A00F79137 /* _tests */, + F608A90F2826A6F8005C276B /* Ptr.h */, + F608A9312826A6F9005C276B /* Ptr.hpp */, + F608A9252826A6F9005C276B /* Ptr+IO.h */, + F608A9322826A6F9005C276B /* Ptr+Log.hpp */, + F608A9102826A6F8005C276B /* Ptr+Version.h */, + F608A9112826A6F8005C276B /* std */, + F69B59C12BDD7E7400280B50 /* strong_emplace.hpp */, + F62735D92853A619004BB4BC /* strong_init.hpp */, + F6273596285389F3004BB4BC /* strong_of.hpp */, + F608A9262826A6F9005C276B /* using_info */, + F608A91A2826A6F8005C276B /* using_maps */, + ); + path = ptr; + sourceTree = ""; + }; + F608A9112826A6F8005C276B /* std */ = { + isa = PBXGroup; + children = ( + F608A9132826A6F8005C276B /* CustomControlBlock.h */, + F608A9182826A6F8005C276B /* Ptr.h */, + F608A9142826A6F8005C276B /* Ptr+Debug.h */, + F608A9162826A6F8005C276B /* Ptr+GCC.h */, + F608A9122826A6F8005C276B /* Ptr+IO.h */, + F608A9172826A6F8005C276B /* Ptr+LLVM.h */, + F6086EE0287A05A900CA017D /* Ptr+Log.h */, + ); + path = std; + sourceTree = ""; + }; + F608A91A2826A6F8005C276B /* using_maps */ = { + isa = PBXGroup; + children = ( + F61F9BDC2C6E103C00F79137 /* _tests */, + F608A9202826A6F8005C276B /* Ptr.cpp */, + F608A9222826A6F8005C276B /* Ptr.h */, + F608A91D2826A6F8005C276B /* Ptr.hpp */, + F608A91F2826A6F8005C276B /* Ptr+Debug.h */, + F608A91C2826A6F8005C276B /* Ptr+IO.h */, + F608A9232826A6F8005C276B /* Ptr+Log.h */, + F608A9212826A6F8005C276B /* Ptr+Logging.cpp */, + ); + path = using_maps; + sourceTree = ""; + }; + F608A9262826A6F9005C276B /* using_info */ = { + isa = PBXGroup; + children = ( + F61F9BDB2C6E103100F79137 /* _tests */, + F608A92D2826A6F9005C276B /* Ptr.cpp */, + F608A92F2826A6F9005C276B /* Ptr.h */, + F608A92A2826A6F9005C276B /* Ptr.hpp */, + F608A9282826A6F9005C276B /* Ptr.inl */, + F608A92C2826A6F9005C276B /* Ptr+Debug.h */, + F608A9292826A6F9005C276B /* Ptr+IO.h */, + F608A92B2826A6F9005C276B /* Ptr+Log.cpp */, + F608A9302826A6F9005C276B /* Ptr+Log.h */, + F608A92E2826A6F9005C276B /* Ptr+Logging.cpp */, + ); + path = using_info; + sourceTree = ""; + }; + F608AA8F2826BFE6005C276B /* timer */ = { + isa = PBXGroup; + children = ( + F64714A42C74A0DC002A8087 /* _tests */, + F608AA912826C008005C276B /* Timer.h */, + F608AA902826C008005C276B /* Timer.hpp */, + ); + path = timer; + sourceTree = ""; + }; + F608AAB6282715FD005C276B /* sfinae */ = { + isa = PBXGroup; + children = ( + F67CE92D2D83DCF2004400C3 /* _tests */, + F608AAB728271640005C276B /* if_or.hpp */, + ); + path = sfinae; + sourceTree = ""; + }; + F608AB4A28277879005C276B /* io */ = { + isa = PBXGroup; + children = ( + F608AB4B282778B7005C276B /* memstream.h */, + F683F51A2A65C2E200191850 /* memstream.hpp */, + ); + path = io; + sourceTree = ""; + }; + F61D7C3C2E3815F8002A1AED /* tjp */ = { + isa = PBXGroup; + children = ( + F6E97D07281EF4ED004C92E9 /* core */, + ); + path = tjp; + sourceTree = ""; + }; + F61F9BB12C6D980000F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F6F7216F2C5DB54E00A8E8D1 /* enumerate.cpp */, + F64714B42C74CD29002A8087 /* fail_on_copy_vector.hpp */, + F65B59982C6C4C4800059339 /* is_first.cpp */, + F6F721732C5DB81F00A8E8D1 /* no_first.cpp */, + F6F721712C5DB73400A8E8D1 /* no_last.cpp */, + F6B1537C2C7042830063C622 /* range_with.cpp */, + F6CA9B59294E7B4600D9A375 /* range.cpp */, + F61F9BAF2C6D965D00F79137 /* reverse.cpp */, + F65B599A2C6C4E5C00059339 /* safe_next.cpp */, + F64714B22C74BE4A002A8087 /* transform_with.cpp */, + F6F721752C5DB85200A8E8D1 /* zip.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB22C6D98B900F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F6DC70D62D81E375004DA34D /* all_are.cpp */, + F6DC70DA2D81E493004DA34D /* container_erase_if_one.cpp */, + F6DC70DE2D81E6B7004DA34D /* container_erase_if.cpp */, + F6DC70DC2D81E5D1004DA34D /* container_erase_value_one.cpp */, + F67CE93B2D8450BA004400C3 /* container_erase_value_all.cpp */, + F6DC70E02D81E735004DA34D /* container_find_if.cpp */, + F6DC70E22D81E804004DA34D /* container_get_if_optional_erase.cpp */, + F6DC70E42D81E8E9004DA34D /* container_get_if_optional.cpp */, + F6DC70E62D81E937004DA34D /* container_get_if.cpp */, + F6DC70E82D81EAB4004DA34D /* container_get_optional_erase.cpp */, + F6DC70EA2D81EBEF004DA34D /* container_has_if.cpp */, + F6DC70EC2D81EC4D004DA34D /* container_has.cpp */, + F69832B82D7B7A7000D911E4 /* copy_clear.cpp */, + F6DC70EE2D81ECE1004DA34D /* copy_of.cpp */, + F6DC70F22D81EF1B004DA34D /* emplace.cpp */, + F6DC70F02D81EE72004DA34D /* empty_of.cpp */, + F6DC70F42D81EFBB004DA34D /* ends_with.cpp */, + F6DC70F72D81F062004DA34D /* has_last.cpp */, + F6DC70F92D81F0F5004DA34D /* in_range_segment.cpp */, + F6DC70FB2D81F1A8004DA34D /* is_in.cpp */, + F6DC70FD2D81F1EC004DA34D /* is_zero.cpp */, + F6DC70FF2D81F2F8004DA34D /* last_of_parameter_pack.cpp */, + F67CE9072D83D1ED004400C3 /* list_erase_if_value.cpp */, + F6DC71012D81F397004DA34D /* list_erase_if.cpp */, + F67CE9322D844CA2004400C3 /* vector_erase_if_value.cpp */, + F67CE9342D844CDB004400C3 /* vector_erase_value_one.cpp */, + F67CE9382D845039004400C3 /* vector_erase_value_all.cpp */, + F67CE9092D83D213004400C3 /* map_erase_if_key.cpp */, + F67CE90B2D83D2A8004400C3 /* map_erase_if_value.cpp */, + F67CE90D2D83D2F4004400C3 /* map_erase_if.cpp */, + F67CE90F2D83D329004400C3 /* map_erase.cpp */, + F67CE9152D83D4F8004400C3 /* map_for_each_value.cpp */, + F67CE9132D83D404004400C3 /* map_has_key.cpp */, + F67CE9112D83D3B1004400C3 /* map_has.cpp */, + F67CE9172D83D595004400C3 /* map_iterator_or_insert.cpp */, + F67CE9192D83D65D004400C3 /* map_value_require.cpp */, + F67CE91B2D83D6E0004400C3 /* map_value.cpp */, + F67CE91D2D83D73B004400C3 /* not_zero.cpp */, + F6F7A2F32F49EFAB008BF0C6 /* no_throw.cpp */, + F67CE91F2D83D790004400C3 /* on_destruct.cpp */, + F6DC70D82D81E43B004DA34D /* one_is.cpp */, + F67CE9262D83D8E5004400C3 /* optional_value_or_default.cpp */, + F67CE9282D83D951004400C3 /* optional_value.cpp */, + F67CE92A2D83D99D004400C3 /* set_empty.cpp */, + F67CE9302D844BAF004400C3 /* vector_append.cpp */, + F6436EC4285955F2003241E0 /* small_cmp.cpp */, + F6DCDBB42858F61B00696085 /* small_copy.cpp */, + F6A994782D827C5900AA4FEE /* starts_with.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB32C6D98E100F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F63B04192C76A07A00417011 /* HashExpected.cpp */, + F69AB7F12B193108000115BC /* Hash.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB42C6D99D400F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F6FADA972949041B006125E1 /* MultiContainer.cpp */, + F6E97DBE281F439A004C92E9 /* SafeIteration.cpp */, + F6E97DBD281F439A004C92E9 /* StackArray_v2.cpp */, + F61DB8022857682300B74C99 /* InPlaceArray.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB52C6D9EF100F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F6E97D1E281EF724004C92E9 /* LogOf.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB62C6D9F0A00F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608A9242826A6F8005C276B /* Ptr.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BB72C6D9F9A00F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F63B04422C78AA5000417011 /* All.cxx */, + F69AB77C2B16D4BA000115BC /* TypeName.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BDA2C6E0F6800F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F62919EC2CB6A3B3002060E0 /* cmp_case.cpp */, + F608A8BB28269B63005C276B /* Dictionary.cpp */, + F64714B02C74B5DF002A8087 /* join.cpp */, + F6C855E42DB7321E006D6C48 /* split_once.cpp */, + F64714AD2C74B4BE002A8087 /* replace.cpp */, + F608A8BA28269B63005C276B /* Str.cpp */, + F62919EF2CB6A468002060E0 /* strncasecmp.cpp */, + F62919F32CB6A83F002060E0 /* strncmp.cpp */, + F64714AB2C74B09D002A8087 /* trim.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BDB2C6E103100F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608A9272826A6F9005C276B /* Ptr.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BDC2C6E103C00F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608A91B2826A6F8005C276B /* Ptr.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BDD2C6E2B8A00F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F608AB99282832FB005C276B /* TEST_SIGNAL.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F61F9BFA2C6EEB1C00F79137 /* _tests */ = { + isa = PBXGroup; + children = ( + F64714B62C74CF1F002A8087 /* Lock.cpp */, + F6E97D2A281F0124004C92E9 /* TestMutex.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F636F39E2C1226D800FAC66D /* android */ = { + isa = PBXGroup; + children = ( + F636F39F2C1226DE00FAC66D /* Stack.cpp */, + ); + path = android; + sourceTree = ""; + }; + F636F3A02C1227CD00FAC66D /* glib */ = { + isa = PBXGroup; + children = ( + F6E97D3B281F0A65004C92E9 /* Stack.cpp */, + ); + path = glib; + sourceTree = ""; + }; + F63B04292C77674600417011 /* _tests */ = { + isa = PBXGroup; + children = ( + F63B042D2C7767AA00417011 /* is_map.cpp */, + F63B042A2C77674A00417011 /* is_vector.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F63B04312C778D2100417011 /* const_expr */ = { + isa = PBXGroup; + children = ( + F63B04352C778EBB00417011 /* _tests */, + F63B04322C778D2800417011 /* concat.hpp */, + F63B04392C77C2EE00417011 /* count_char.hpp */, + F63B04412C7802A500417011 /* length.hpp */, + F63B043A2C77C32900417011 /* remove_char.hpp */, + F63B043F2C77EDF800417011 /* Str.hpp */, + F63B04402C77F11300417011 /* Str+IO.hpp */, + ); + path = const_expr; + sourceTree = ""; + }; + F63B04352C778EBB00417011 /* _tests */ = { + isa = PBXGroup; + children = ( + F6F7A3002F4A2516008BF0C6 /* remove_char.cpp */, + F6F7A3022F4A26A3008BF0C6 /* Str.cpp */, + F6A9947A2D827CBB00AA4FEE /* length.cpp */, + F63B04362C778EBF00417011 /* concat.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F64406FA2B39EF9800A2477F /* time */ = { + isa = PBXGroup; + children = ( + F69534212D84C68000C9AFA0 /* _tests */, + F64407002B39EF9800A2477F /* Source.cpp */, + F64407062B39EF9800A2477F /* Source.hpp */, + F6D114802D3D9AA600BFA3B3 /* Source.h */, + F64407072B39EF9800A2477F /* Time.cpp */, + F64406FB2B39EF9800A2477F /* Time.h */, + F64407022B39EF9800A2477F /* Time.hpp */, + F64407012B39EF9800A2477F /* Time+chrono.hpp */, + F6CFD87E2E1ED23C00CDDC2E /* Time+timestamp.hpp */, + F688EF882C78F6430087B561 /* Time+chrono+misc.hpp */, + F64407052B39EF9800A2477F /* Time+IO.cpp */, + F64407042B39EF9800A2477F /* Time+IO.hpp */, + F64407032B39EF9800A2477F /* Time+operations.hpp */, + ); + path = time; + sourceTree = ""; + }; + F64714A42C74A0DC002A8087 /* _tests */ = { + isa = PBXGroup; + children = ( + F64714A52C74A0E9002A8087 /* Timer.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F64C651C2AC4F1C900FCF1DD /* rtti */ = { + isa = PBXGroup; + children = ( + F61F9BB72C6D9F9A00F79137 /* _tests */, + F64C65212AC5AA2800FCF1DD /* RTTI.cpp */, + F64C651F2AC4F1C900FCF1DD /* RTTI.hpp */, + F64C651E2AC4F1C900FCF1DD /* RTTI+custom.hpp */, + F64C651D2AC4F1C900FCF1DD /* RTTI+std.hpp */, + F69AB77B2B16D365000115BC /* TypeName.hpp */, + F69AB7792B16D158000115BC /* TypeName+custom.hpp */, + ); + path = rtti; + sourceTree = ""; + }; + F64D834F2E4B73A1009AD431 /* header_only */ = { + isa = PBXGroup; + children = ( + F64D83502E4B73F3009AD431 /* compile.h */, + ); + path = header_only; + sourceTree = ""; + }; + F67CE92D2D83DCF2004400C3 /* _tests */ = { + isa = PBXGroup; + children = ( + F67CE92E2D83DD1C004400C3 /* if_or.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F69534212D84C68000C9AFA0 /* _tests */ = { + isa = PBXGroup; + children = ( + ); + path = _tests; + sourceTree = ""; + }; + F69AB7EF2B193108000115BC /* const_hash */ = { + isa = PBXGroup; + children = ( + F61F9BB32C6D98E100F79137 /* _tests */, + F6170F5E2B4847C5007F87B0 /* Hash.cpp */, + F69AB7F22B193108000115BC /* Hash.h */, + F69AB7F02B193108000115BC /* Hash.hpp */, + F61F9C042C6EF65100F79137 /* Hash+simple.hpp */, + F61F9C052C6EF81D00F79137 /* Hash+zltan.hpp */, + F63B041B2C76A2CF00417011 /* Hash+zltan+expected.inl */, + F61F9C092C6F3CD400F79137 /* smhasher */, + ); + path = const_hash; + sourceTree = ""; + }; + F6E97CF7281EF4BF004C92E9 = { + isa = PBXGroup; + children = ( + F67CE94B2D84583F004400C3 /* Examples.cpp */, + F6E97D24281EF966004C92E9 /* Frameworks */, + F67CE9562D84752D004400C3 /* LICENSE */, + F6BF9BDF2E38F728002E6AF0 /* Makefile */, + F608A9352826A974005C276B /* Makefile.def */, + F608A9362826A975005C276B /* Makefile.project */, + F6E97D01281EF4BF004C92E9 /* Products */, + F6E97DB0281F3F25004C92E9 /* ReadMe.md */, + F6E97D08281EF544004C92E9 /* tests */, + F61D7C3C2E3815F8002A1AED /* tjp */, + ); + sourceTree = ""; + }; + F6E97D01281EF4BF004C92E9 /* Products */ = { + isa = PBXGroup; + children = ( + F6E97D00281EF4BF004C92E9 /* libCore_Zero.a */, + F6E97D11281EF664004C92E9 /* Core_Zero_Tests */, + F6971F21282B1129008FBD17 /* libCore_Zero_iOS.a */, + ); + name = Products; + sourceTree = ""; + }; + F6E97D07281EF4ED004C92E9 /* core */ = { + isa = PBXGroup; + children = ( + F6E97D58281F0DFB004C92E9 /* algorithm */, + F6E97D59281F0E8B004C92E9 /* assert */, + F63B04312C778D2100417011 /* const_expr */, + F69AB7EF2B193108000115BC /* const_hash */, + F6E97D50281F0C05004C92E9 /* containers */, + F6E97D39281F0A65004C92E9 /* debug */, + F6E97DCA281F485F004C92E9 /* exception */, + F64D834F2E4B73A1009AD431 /* header_only */, + F608AB4A28277879005C276B /* io */, + F608A8872825C91C005C276B /* iterators */, + F6E97D1A281EF6C4004C92E9 /* log */, + F6FBBCA42E4E5A4F00B3DCE2 /* math */, + F608A9372826AC4E005C276B /* Precompile.pch */, + F608A90E2826A6E7005C276B /* ptr */, + F64C651C2AC4F1C900FCF1DD /* rtti */, + F608AAB6282715FD005C276B /* sfinae */, + F608A8AB28269A65005C276B /* string */, + F6E97D40281F0A65004C92E9 /* system */, + F6E97D09281EF59E004C92E9 /* testing */, + F6E97D36281F065A004C92E9 /* threads */, + F64406FA2B39EF9800A2477F /* time */, + F608AA8F2826BFE6005C276B /* timer */, + F6E97D63281F3A7F004C92E9 /* type_traits */, + F6E97D3D281F0A65004C92E9 /* types */, + ); + path = core; + sourceTree = ""; + }; + F6E97D08281EF544004C92E9 /* tests */ = { + isa = PBXGroup; + children = ( + F61F9BD42C6DCA3300F79137 /* Makefile.project */, + F6E97D0C281EF604004C92E9 /* Run.cpp */, + ); + path = tests; + sourceTree = ""; + }; + F6E97D09281EF59E004C92E9 /* testing */ = { + isa = PBXGroup; + children = ( + F61F9BDD2C6E2B8A00F79137 /* _tests */, + F6E97D0A281EF5ED004C92E9 /* catch.hpp */, + F69832AB2D7B3F4E00D911E4 /* catch.cpp */, + F69832AA2D7B3EFA00D911E4 /* catch2.hpp */, + F608AB9C282832FB005C276B /* Defines.h */, + F608AB98282832FB005C276B /* NO_WHEN.h */, + F6F3B0862D7091150075B3DC /* THEN_REQUIRE.h */, + F608AB9B282832FB005C276B /* TEST_SIGNAL.cpp */, + F608AB96282832FB005C276B /* TEST_SIGNAL.h */, + F608AB97282832FB005C276B /* TESTING_ONLY.h */, + F608AB9A282832FB005C276B /* wait_until.h */, + ); + path = testing; + sourceTree = ""; + }; + F6E97D1A281EF6C4004C92E9 /* log */ = { + isa = PBXGroup; + children = ( + F61F9BB52C6D9EF100F79137 /* _tests */, + F6E97D1B281EF724004C92E9 /* demangle.cpp */, + F6E97D20281EF724004C92E9 /* demangle.h */, + F6E97D1F281EF724004C92E9 /* Log.cpp */, + F6E97D1C281EF724004C92E9 /* Log.h */, + F68BA8422E93F3BB0040FA70 /* Color.hpp */, + F68BA8472E940E720040FA70 /* Color.cpp */, + F6E97D1D281EF724004C92E9 /* Color.inl */, + F68BA8442E93FCD30040FA70 /* Util.inl */, + F68BA83F2E93F1410040FA70 /* Detail.h */, + F68BA8402E93F14F0040FA70 /* Detail.hpp */, + F68BA8412E93F2700040FA70 /* Detail.cpp */, + F668F0482E25633A000A6B71 /* Log+Precision.h */, + F6E97D21281EF724004C92E9 /* LogOf.h */, + ); + path = log; + sourceTree = ""; + }; + F6E97D24281EF966004C92E9 /* Frameworks */ = { + isa = PBXGroup; + children = ( + F65B59DA2C6C53EF00059339 /* libCore_Allocator.a */, + ); + name = Frameworks; + sourceTree = ""; + }; + F6E97D30281F0125004C92E9 /* std */ = { + isa = PBXGroup; + children = ( + F6E97D31281F0125004C92E9 /* Lock.hpp */, + F6E97D32281F0125004C92E9 /* Lock.h */, + ); + path = std; + sourceTree = ""; + }; + F6E97D36281F065A004C92E9 /* threads */ = { + isa = PBXGroup; + children = ( + F61F9BFA2C6EEB1C00F79137 /* _tests */, + F6E97D5F281F0EDC004C92E9 /* Atomic.h */, + F6E97D57281F0DBB004C92E9 /* Atomic.hpp */, + F6E97D34281F0125004C92E9 /* Lock.h */, + F6E97D2E281F0125004C92E9 /* Lock.hpp */, + F611B4362EB40A22003349BE /* micropause.hpp */, + F68839B22D39D5B7003E6FC2 /* with_lock.hpp */, + F60BC3042D3B0180005C1EB6 /* with_lock_value.hpp */, + F6E97D35281F0155004C92E9 /* LockedBy.h */, + F6E97D2F281F0125004C92E9 /* LockedBy.hpp */, + F61BD5662B51965F00277906 /* Pin.h */, + F61BD5682B51966E00277906 /* Pin.hpp */, + F6EB9F602858B55C007B3EFB /* process_queue.hpp */, + F6E97D33281F0125004C92E9 /* SharedLockGuard.hpp */, + F6CA3189292BCD57008EE166 /* SpinMutex.cpp */, + F68A80A82929491400F77389 /* SpinMutex.hpp */, + F6E97D30281F0125004C92E9 /* std */, + F6E97D29281F0124004C92E9 /* TestCollision.h */, + F6E97D2C281F0124004C92E9 /* TestMutex.h */, + F6E97D2D281F0125004C92E9 /* TestMutex.hpp */, + F6E97D2B281F0124004C92E9 /* TestMutex.inl */, + F608AB7528280B85005C276B /* ThreadSafe.h */, + F608AB7628280B86005C276B /* ThreadSafe.hpp */, + F68CE3222D3753D4004F9466 /* TryLockGuard.hpp */, + F63321FA2B079E1D00CEEDAF /* UnlockGuard.hpp */, + ); + path = threads; + sourceTree = ""; + }; + F6E97D39281F0A65004C92E9 /* debug */ = { + isa = PBXGroup; + children = ( + F6E5495428CCD3BA007010BC /* Allocations.cpp */, + F6E5495328CCD24C007010BC /* Allocations.h */, + F636F39E2C1226D800FAC66D /* android */, + F698285C2B11774100EEACE9 /* CompileTimeSizeOf.h */, + F63B04182C76896800417011 /* debug_break.h */, + F6E97D3A281F0A65004C92E9 /* Debug.h */, + F6DE207C2D3EA99900E039E4 /* RUN_IF.h */, + F636F3A02C1227CD00FAC66D /* glib */, + F6E97D3C281F0A65004C92E9 /* Stack.h */, + F61EA27B2A78A28500DF7BFA /* StackUsage.cpp */, + F61EA27A2A78A26700DF7BFA /* StackUsage.h */, + ); + path = debug; + sourceTree = ""; + }; + F6E97D3D281F0A65004C92E9 /* types */ = { + isa = PBXGroup; + children = ( + F683F5192A648CA700191850 /* CounterFor.h */, + F63B04262C7759D400417011 /* Definitions.h */, + F601313E2873B3E30088443B /* linux */, + F6E97D3E281F0A65004C92E9 /* Types.h */, + F67636512E01ACB20059296C /* Types_.h */, + F660402A286A63F000C07DC0 /* Types+IO.cpp */, + F6604029286A63C400C07DC0 /* Types+IO.h */, + ); + path = types; + sourceTree = ""; + }; + F6E97D40281F0A65004C92E9 /* system */ = { + isa = PBXGroup; + children = ( + F6E97D45281F0A65004C92E9 /* Debug.h */, + F6DEAAAA2CB3639800E8E7C8 /* DisableWarningsAllPop.h */, + F61F9BCE2C6DB5A600F79137 /* DisableWarningsAllPush.h */, + F6E97D44281F0A65004C92E9 /* DisableWarningsPop.h */, + F6E97D47281F0A65004C92E9 /* DisableWarningsPush.h */, + F647A68B28982211009E67C8 /* Optimization.h */, + F6E97D4E281F0A65004C92E9 /* System.h */, + ); + path = system; + sourceTree = ""; + }; + F6E97D50281F0C05004C92E9 /* containers */ = { + isa = PBXGroup; + children = ( + F61F9BB42C6D99D400F79137 /* _tests */, + F612B9382B9D0E0400519EB6 /* Align.h */, + F6F363C929A64A6000D9F857 /* Array.h */, + F6F363CA29A64A7A00D9F857 /* Array.hpp */, + F6F10D1C2E37C1DC0082E9D9 /* Array+IO.hpp */, + F658606729535BB4009B5C15 /* ByF.hpp */, + F6E595A72850D6B40040841E /* ById.hpp */, + F67B008028673277002A7A43 /* ByPtr.hpp */, + F69345B229B794B2008B7AEB /* ByPtrId.hpp */, + F69345B329B7973F008B7AEB /* ByStrongPtrId.hpp */, + F6E97DC8281F4470004C92E9 /* FilledArray.h */, + F6E97DC6281F4470004C92E9 /* FilledArray.hpp */, + F6E97DC9281F4470004C92E9 /* FilledArrayThreadSafe.h */, + F6E97DC7281F4470004C92E9 /* FilledArrayThreadSafe.hpp */, + F67B008728673903002A7A43 /* Function.h */, + F67B00882867392D002A7A43 /* Function.hpp */, + F61DB7FF2857652300B74C99 /* InPlaceArray.h */, + F61DB8002857653200B74C99 /* InPlaceArray.hpp */, + F61DB8012857680F00B74C99 /* InPlaceArray.inl */, + F63B04152C76297F00417011 /* InPlaceArray+iterator.inl */, + F6E97D5B281F0EDB004C92E9 /* List.h */, + F6E97D56281F0D8A004C92E9 /* List.hpp */, + F6E97D5D281F0EDB004C92E9 /* Map.h */, + F6E97D53281F0D03004C92E9 /* Map.hpp */, + F608A8882825CA7C005C276B /* MemoryArray.h */, + F608A88F2825CA7D005C276B /* MemoryArray.hpp */, + F68898CE2A5E156400CE7B3B /* MemorySegment.h */, + F68898CF2A5E15F800CE7B3B /* MemorySegment.hpp */, + F6FADA962948FF90006125E1 /* MultiContainer.hpp */, + F608AB712827F644005C276B /* Optional.h */, + F608AB722827F644005C276B /* Optional.hpp */, + F6C8084A2B14C19B00D8068D /* Optional+IO.hpp */, + F65D0FCD29AD6C15000247E6 /* Pack.h */, + F66033B0294CEE160035F0D8 /* Pair.h */, + F66033B1294CEE2E0035F0D8 /* Pair.hpp */, + F61D45ED2B5953CF00AD2EED /* PtrOnly.h */, + F61D45EE2B5953CF00AD2EED /* PtrOnly.hpp */, + F65FD5F02A8551240022A4CC /* PtrOrValue.h */, + F65FD5F12A8551380022A4CC /* PtrOrValue.hpp */, + F6E97DC2281F439A004C92E9 /* Queue.h */, + F6E97DC0281F439A004C92E9 /* QueueThreadSafe.hpp */, + F6E97DBF281F439A004C92E9 /* Reversed.h */, + F6E97DBC281F439A004C92E9 /* Reversed.hpp */, + F61C393E2DEDFC75005B42E7 /* TransparentLess.hpp */, + F6E97DB9281F439A004C92E9 /* SafeIteration_v_all_mutable.hpp */, + F62C2C0A2A526838007B43A3 /* SafeIteration_v_consts.hpp */, + F6E97DC1281F439A004C92E9 /* SafeIteration.h */, + F62C2C0B2A52686F007B43A3 /* SafeIteration.hpp */, + F6E97DC3281F439A004C92E9 /* SafeIteration+IO.h */, + F6E97D5C281F0EDB004C92E9 /* Set.h */, + F6E97D54281F0D3F004C92E9 /* Set.hpp */, + F61DB806285772AF00B74C99 /* StackArray_v2.h */, + F61DB807285772AF00B74C99 /* StackArray_v2.hpp */, + F61DB805285772AF00B74C99 /* StackArray_v2.inl */, + F62757BC2B30872200655557 /* StackArray_v2+hash.hpp */, + F6FBAABE2B28E9BE00F0243C /* StackArray_v2+IO.hpp */, + F61DB80A28577A8600B74C99 /* StackArray.h */, + F61DB80B28577A8E00B74C99 /* StackArray.hpp */, + F62757BD2B30874800655557 /* StackArray+hash.hpp */, + F6FBAABD2B28E9A500F0243C /* StackArray+IO.hpp */, + F608AB732827F6F3005C276B /* Tuple.h */, + F608AB742827F6F4005C276B /* Tuple.hpp */, + F69345BE29B7A6AC008B7AEB /* UnorderedMap.h */, + F69345BD29B7A69E008B7AEB /* UnorderedMap.hpp */, + F642D7882B4B8C51008BD947 /* UnorderedSet.h */, + F642D7872B4B8C51008BD947 /* UnorderedSet.hpp */, + F6E97D6D281F3ACB004C92E9 /* Vector.h */, + F6E97D6C281F3ACB004C92E9 /* Vector.hpp */, + ); + path = containers; + sourceTree = ""; + }; + F6E97D58281F0DFB004C92E9 /* algorithm */ = { + isa = PBXGroup; + children = ( + F61F9BB22C6D98B900F79137 /* _tests */, + F6390DF12D1F287C0060EB75 /* all_are.hpp */, + F6B348C82872545200A9CE7E /* cmp.hpp */, + F6231C7E2C42B41A00DC8CD3 /* container_erase_if.hpp */, + F67CE92C2D83DAD0004400C3 /* container_erase_if_imp_use_iterator.hpp */, + F6231C812C42B52F00DC8CD3 /* container_erase_if_one.hpp */, + F67CE9362D844E39004400C3 /* container_erase_value_all.hpp */, + F6231C802C42B4DD00DC8CD3 /* container_erase_value_one.hpp */, + F6231C7F2C42B43B00DC8CD3 /* container_find_if.hpp */, + F6231C772C42B1AC00DC8CD3 /* container_get_if.hpp */, + F6231C7C2C42B37900DC8CD3 /* container_get_if_optional.hpp */, + F6231C822C42B88B00DC8CD3 /* container_get_if_optional_erase.hpp */, + F6231C7D2C42B3C700DC8CD3 /* container_get_optional_erase.hpp */, + F6231C7A2C42B25700DC8CD3 /* container_has.hpp */, + F6231C882C42BC2000DC8CD3 /* container_has_if.hpp */, + F6763ECE2E8C384300EC53ED /* container_count_if.hpp */, + F69832B72D7B6E7300D911E4 /* copy_clear.hpp */, + F6F04D962DC2ADCA00A99D3E /* copy_clear_delete.hpp */, + F638B4C22999A21A006D27EE /* copy_of.hpp */, + F68BF1F32D6366E600DA1DD9 /* emplace.hpp */, + F6C3C1F628B279E30093BD9B /* empty_of.hpp */, + F6E97DB6281F408A004C92E9 /* ends_with.hpp */, + F608AB4C2827E6BA005C276B /* ExecuteOnDestruct.h */, + F608AB4D2827E6BA005C276B /* ExecuteOnDestruct.hpp */, + F6E97DB7281F41D0004C92E9 /* has_last.hpp */, + F6D08E2B2DD406000018ED2C /* has_sequence.hpp */, + F69CC2592D297F2800FB29DE /* in_range_segment.hpp */, + F6E97D52281F0C30004C92E9 /* is_in.hpp */, + F6390DF22D1F65B10060EB75 /* is_zero.hpp */, + F6446A1C28B181E700871176 /* last_of_parameter_pack.hpp */, + F65E5A8028BE7D3200772521 /* list_erase_if.hpp */, + F62D7B52290B0A1B001285AE /* list_erase_if_value.hpp */, + F67CE9372D844FA2004400C3 /* list_erase_value_all.hpp */, + F6CD1F7E28BBB7DC00509B3D /* list_erase_value_one.hpp */, + F60892482864C85000174811 /* map_erase.hpp */, + F6960CB32D8842C800767451 /* map_erase_get_optional.hpp */, + F6BFE18A285A181C002A95C3 /* map_erase_if.hpp */, + F69D521D295641D100B5875A /* map_erase_if_key.hpp */, + F6BFE18B285A18AF002A95C3 /* map_erase_if_value.hpp */, + F6BFE18C285A1BF9002A95C3 /* map_for_each_value.hpp */, + F6EE06D1284EB03700D659F9 /* map_has.hpp */, + F6231C6B2C42AFC200DC8CD3 /* map_has_key.hpp */, + F67786BF2D85FD4D00C8308C /* map_insert.hpp */, + F643C8C528D3D4C3006380F5 /* map_iterator_or_insert.hpp */, + F6CF968A2832A1C90072B6C1 /* map_pair.hpp */, + F6CF968628329DF00072B6C1 /* map_value.hpp */, + F627353F28523A7B004BB4BC /* map_value_erase.hpp */, + F68657732F0D539100F17333 /* map_value_optional.hpp */, + F68657742F0D549900F17333 /* map_set_or_erase_optional.hpp */, + F608AB902828261B005C276B /* map_value_or_default.hpp */, + F66033A3294CD68D0035F0D8 /* map_value_or_insert.hpp */, + F66F8971292D0FFC00E723E8 /* map_value_or_insert_value.hpp */, + F61BF89E2D1236DE0061A507 /* map_value_require.hpp */, + F608AA922826C072005C276B /* mem_copy.hpp */, + F69F8D882DCED15A0038CCDC /* mem_copy_asan_safe.hpp */, + F6390DF42D1F67170060EB75 /* not_zero.hpp */, + F6F7A2F52F49EFBD008BF0C6 /* no_throw.hpp */, + F61F89E829BE1AF500B407AE /* numeric_limits.hpp */, + F608AB4E2827E70A005C276B /* on_destruct.hpp */, + F6390DF32D1F66FD0060EB75 /* one_is.hpp */, + F65FD5E52A83EB850022A4CC /* optional_value.hpp */, + F6E0AFA52F1BCBE40058412E /* optional_of_ptr.hpp */, + F6EC57352ECC27D20052CD0A /* optional_set_if_empty.hpp */, + F6112BB72BA3FBAD00410E6F /* optional_value_or_default.hpp */, + F6E97D69281F3AA3004C92E9 /* remove_const_of_var.hpp */, + F69C7BDF28A5AB15008385A2 /* set_empty.hpp */, + F6E595A82850D79B0040841E /* set_erase.hpp */, + F6D7D60428764AF50015548D /* set_erase_if_value.hpp */, + F6DDE78C2DB27B84005F94FC /* set_erase_optional_value.hpp */, + F6F7A2FD2F4A14D4008BF0C6 /* set_erase_optional_value_move.hpp */, + F65FC144283E5F2D00DEA3F9 /* set_has.hpp */, + F60892512865DA9F00174811 /* set_insert.hpp */, + F6F7A2FE2F4A15DC008BF0C6 /* set_insert_mutable.hpp */, + F668F04E2E25A814000A6B71 /* set_once.hpp */, + F608925028656DC900174811 /* set_value.hpp */, + F6F7A2FF2F4A17F0008BF0C6 /* set_value_mutable.hpp */, + F624DBEB2E53E99D00A1D4D8 /* set_insert_once.hpp */, + F6436EC3285955F2003241E0 /* small_cmp.hpp */, + F6DCDBB32858F58700696085 /* small_copy.hpp */, + F6E97DB5281F4077004C92E9 /* starts_with.hpp */, + F6BACA11285C03CA00694BBE /* starts_with_value.hpp */, + F60EC5222A13C3FD00A00C4C /* string_has.hpp */, + F61247072AF1EBE500B77DC1 /* tuple_has_value.hpp */, + F6E97D3F281F0A65004C92E9 /* unused.hpp */, + F61F56232BFE937D00A3FD8D /* update_if_different.hpp */, + F6D4106D29D89E5F00C9C2F9 /* vector_append.hpp */, + F676D4CD285E0AE00072143D /* vector_erase_if_value.hpp */, + F69553A12AEECB8400FC8A36 /* vector_erase_value_all.hpp */, + F67CE93A2D84504D004400C3 /* vector_erase_value_one.hpp */, + F67119D22C8A231E00F72EE9 /* vector_get_optional_erase_if.hpp */, + F6CD9E9F2A0977CC001FA01D /* vector_has.hpp */, + F6D8CD972E0981C6000A4ED2 /* vector_has_if.hpp */, + F6010641286E4B5900FD2E40 /* vector_value.hpp */, + F67786782D85DD1F00C8308C /* vector_value_at.hpp */, + F67786C92D86032B00C8308C /* vector_value_before_if.hpp */, + F6F598B4287303A300588A26 /* vector_value_if.hpp */, + F69365FA2E29B3F100DFD771 /* vector_value_if_index.hpp */, + F6F598B5287303F800588A26 /* vector_value_index_if.hpp */, + ); + path = algorithm; + sourceTree = ""; + }; + F6E97D59281F0E8B004C92E9 /* assert */ = { + isa = PBXGroup; + children = ( + F616E9D92B34681200C6DD09 /* debug_assert.cpp */, + F64D834C2E4B6F58009AD431 /* debug_assert_complex.h */, + F608A90A2826A4A5005C276B /* debug_assert.h */, + F67635BA2E00447C0059296C /* debug_assert_simple.h */, + F63D85112D10B73D00FF3624 /* handle_assert.cpp */, + F62C1BE0286246F20093EFBE /* handle_assert.hpp */, + F64D834D2E4B6F83009AD431 /* handle_assert_simple.hpp */, + F64D834E2E4B6F8C009AD431 /* handle_assert_complex.hpp */, + F6E97D5A281F0E8B004C92E9 /* release_assert.h */, + ); + path = assert; + sourceTree = ""; + }; + F6E97D63281F3A7F004C92E9 /* type_traits */ = { + isa = PBXGroup; + children = ( + F63B04292C77674600417011 /* _tests */, + F6E97D64281F3AA3004C92E9 /* always_false.hpp */, + F628790D29E8A3B8009CC2A9 /* is_callable_with_two_args.hpp */, + F6E97D67281F3AA3004C92E9 /* is_callable.hpp */, + F6E97D6A281F3AA3004C92E9 /* is_comparable.hpp */, + F6E97D68281F3AA3004C92E9 /* is_iterable.hpp */, + F63B042C2C77677600417011 /* is_map.hpp */, + F6E97D6B281F3AA3004C92E9 /* is_mappish.hpp */, + F6E97D65281F3AA3004C92E9 /* is_string.hpp */, + F63B04282C7766B600417011 /* is_vector.hpp */, + ); + path = type_traits; + sourceTree = ""; + }; + F6E97DCA281F485F004C92E9 /* exception */ = { + isa = PBXGroup; + children = ( + F636F39D2C1223B300FAC66D /* debug_throw.h */, + F6E97DCC281F48BD004C92E9 /* Exception.cpp */, + F6E97DCB281F4877004C92E9 /* Exception.h */, + F6291A0D2CB6F816002060E0 /* Exception.hpp */, + F68657762F0DC03B00F17333 /* Exception+IO.hpp */, + F6291A102CB6F8CB002060E0 /* NotImplemented.h */, + F659287329B11B8C00EE781F /* NotImplemented.hpp */, + F6291A0E2CB6F89E002060E0 /* NullPointer.h */, + F6291A0F2CB6F8AE002060E0 /* NullPointer.hpp */, + F6291A122CB6F971002060E0 /* OutOfBounds.h */, + F6291A112CB6F971002060E0 /* OutOfBounds.hpp */, + ); + path = exception; + sourceTree = ""; + }; + F6F9CF3E2E4F896A00576DEF /* _tests */ = { + isa = PBXGroup; + children = ( + F6F9CF3F2E4F899A00576DEF /* Float16.cpp */, + ); + path = _tests; + sourceTree = ""; + }; + F6FBBCA42E4E5A4F00B3DCE2 /* math */ = { + isa = PBXGroup; + children = ( + F6F9CF3E2E4F896A00576DEF /* _tests */, + F6FBBCA22E4E59FF00B3DCE2 /* Float16.h */, + F6F9CF5F2E4FB72900576DEF /* Float16.inl */, + F6FBBCA32E4E5A4200B3DCE2 /* Float16.hpp */, + ); + path = math; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + F6971F0F282B1129008FBD17 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F64407132B39EF9900A2477F /* Time+chrono.hpp in Headers */, + F644071D2B39EF9900A2477F /* Source.hpp in Headers */, + F64407172B39EF9900A2477F /* Time+operations.hpp in Headers */, + F64407092B39EF9800A2477F /* Time.h in Headers */, + F64407192B39EF9900A2477F /* Time+IO.hpp in Headers */, + F6CFD8802E1ED23C00CDDC2E /* Time+timestamp.hpp in Headers */, + F64407152B39EF9900A2477F /* Time.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6E97CFC281EF4BF004C92E9 /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + F64407122B39EF9900A2477F /* Time+chrono.hpp in Headers */, + F644071C2B39EF9900A2477F /* Source.hpp in Headers */, + F64407162B39EF9900A2477F /* Time+operations.hpp in Headers */, + F64407082B39EF9800A2477F /* Time.h in Headers */, + F64407182B39EF9900A2477F /* Time+IO.hpp in Headers */, + F6CFD87F2E1ED23C00CDDC2E /* Time+timestamp.hpp in Headers */, + F64407142B39EF9900A2477F /* Time.hpp in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + F6971F0E282B1129008FBD17 /* Core_Zero_iOS */ = { + isa = PBXNativeTarget; + buildConfigurationList = F6971F1E282B1129008FBD17 /* Build configuration list for PBXNativeTarget "Core_Zero_iOS" */; + buildPhases = ( + F6971F0F282B1129008FBD17 /* Headers */, + F6971F10282B1129008FBD17 /* Sources */, + F6971F1D282B1129008FBD17 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Zero_iOS; + productName = Core_Zero; + productReference = F6971F21282B1129008FBD17 /* libCore_Zero_iOS.a */; + productType = "com.apple.product-type.library.static"; + }; + F6E97CFF281EF4BF004C92E9 /* Core_Zero */ = { + isa = PBXNativeTarget; + buildConfigurationList = F6E97D04281EF4BF004C92E9 /* Build configuration list for PBXNativeTarget "Core_Zero" */; + buildPhases = ( + F6E97CFC281EF4BF004C92E9 /* Headers */, + F6E97CFD281EF4BF004C92E9 /* Sources */, + F6E97CFE281EF4BF004C92E9 /* Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = Core_Zero; + productName = Core_Zero; + productReference = F6E97D00281EF4BF004C92E9 /* libCore_Zero.a */; + productType = "com.apple.product-type.library.static"; + }; + F6E97D10281EF664004C92E9 /* Core_Zero_Tests */ = { + isa = PBXNativeTarget; + buildConfigurationList = F6E97D15281EF664004C92E9 /* Build configuration list for PBXNativeTarget "Core_Zero_Tests" */; + buildPhases = ( + F6E97D0D281EF664004C92E9 /* Sources */, + F6E97D0E281EF664004C92E9 /* Frameworks */, + F6E97D0F281EF664004C92E9 /* CopyFiles */, + ); + buildRules = ( + ); + dependencies = ( + F67119DF2C8A636C00F72EE9 /* PBXTargetDependency */, + ); + name = Core_Zero_Tests; + productName = Core_Zero_Tests; + productReference = F6E97D11281EF664004C92E9 /* Core_Zero_Tests */; + productType = "com.apple.product-type.tool"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + F6E97CF8281EF4BF004C92E9 /* Project object */ = { + isa = PBXProject; + attributes = { + BuildIndependentTargetsInParallel = 1; + LastUpgradeCheck = 1330; + TargetAttributes = { + F6E97CFF281EF4BF004C92E9 = { + CreatedOnToolsVersion = 13.3; + }; + F6E97D10281EF664004C92E9 = { + CreatedOnToolsVersion = 13.3; + }; + }; + }; + buildConfigurationList = F6E97CFB281EF4BF004C92E9 /* Build configuration list for PBXProject "Core_Zero" */; + compatibilityVersion = "Xcode 13.0"; + developmentRegion = en; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = F6E97CF7281EF4BF004C92E9; + productRefGroup = F6E97D01281EF4BF004C92E9 /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + F6E97CFF281EF4BF004C92E9 /* Core_Zero */, + F6971F0E282B1129008FBD17 /* Core_Zero_iOS */, + F6E97D10281EF664004C92E9 /* Core_Zero_Tests */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXSourcesBuildPhase section */ + F6971F10282B1129008FBD17 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F644071F2B39EF9900A2477F /* Time.cpp in Sources */, + F6ADBA3C28381C8F005131D9 /* TEST_SIGNAL.cpp in Sources */, + F6971F11282B1129008FBD17 /* cmp_case.cpp in Sources */, + F64407112B39EF9900A2477F /* Source.cpp in Sources */, + F6971F12282B1129008FBD17 /* Log.cpp in Sources */, + F660402B286A654F00C07DC0 /* Types+IO.cpp in Sources */, + F68BA8462E940E6D0040FA70 /* Detail.cpp in Sources */, + F6CA318B292BCD90008EE166 /* SpinMutex.cpp in Sources */, + F63D85132D10B73D00FF3624 /* handle_assert.cpp in Sources */, + F6971F13282B1129008FBD17 /* demangle.cpp in Sources */, + F6971F14282B1129008FBD17 /* cmp.cpp in Sources */, + F6971F15282B1129008FBD17 /* replace.cpp in Sources */, + F644071B2B39EF9900A2477F /* Time+IO.cpp in Sources */, + F6291A052CB6B2F0002060E0 /* strncmp.cpp in Sources */, + F6971F16282B1129008FBD17 /* str_find.cpp in Sources */, + F6E620902B30AFDA0016DEED /* Exception.cpp in Sources */, + F6E5495628CCD689007010BC /* Allocations.cpp in Sources */, + F6971F17282B1129008FBD17 /* Str.cpp in Sources */, + F6291A032CB6B2EB002060E0 /* strncasecmp.cpp in Sources */, + F616E9DB2B34683A00C6DD09 /* debug_assert.cpp in Sources */, + F6971F19282B1129008FBD17 /* from_string.cpp in Sources */, + F69832AD2D7B3FB400D911E4 /* catch.cpp in Sources */, + F68BA8492E940EB00040FA70 /* Color.cpp in Sources */, + F6971F1B282B1129008FBD17 /* Stack.cpp in Sources */, + F61EA27C2A78A28500DF7BFA /* StackUsage.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6E97CFD281EF4BF004C92E9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F644071E2B39EF9900A2477F /* Time.cpp in Sources */, + F6ADBA3B28381C8A005131D9 /* TEST_SIGNAL.cpp in Sources */, + F69548A428288C85005D1B64 /* cmp_case.cpp in Sources */, + F6291A022CB6B2EA002060E0 /* strncasecmp.cpp in Sources */, + F64407102B39EF9900A2477F /* Source.cpp in Sources */, + F61F9BFF2C6EEE9A00F79137 /* Ptr.cpp in Sources */, + F6291A042CB6B2F0002060E0 /* strncmp.cpp in Sources */, + F6E97D23281EF72C004C92E9 /* Log.cpp in Sources */, + F660402C286A655000C07DC0 /* Types+IO.cpp in Sources */, + F63D85122D10B73D00FF3624 /* handle_assert.cpp in Sources */, + F6CA318A292BCD8F008EE166 /* SpinMutex.cpp in Sources */, + F69832AC2D7B3FB400D911E4 /* catch.cpp in Sources */, + F68BA8452E940E6D0040FA70 /* Detail.cpp in Sources */, + F6E97D22281EF729004C92E9 /* demangle.cpp in Sources */, + F69548A328288C83005D1B64 /* cmp.cpp in Sources */, + F69548A128288C74005D1B64 /* replace.cpp in Sources */, + F68BA8482E940EB00040FA70 /* Color.cpp in Sources */, + F644071A2B39EF9900A2477F /* Time+IO.cpp in Sources */, + F69548A028288C70005D1B64 /* str_find.cpp in Sources */, + F6E6208F2B30AFD70016DEED /* Exception.cpp in Sources */, + F6E5495528CCD688007010BC /* Allocations.cpp in Sources */, + F61F9C002C6EEEA500F79137 /* Ptr.cpp in Sources */, + F608A9332826A7AE005C276B /* Str.cpp in Sources */, + F616E9DA2B34683A00C6DD09 /* debug_assert.cpp in Sources */, + F695489E28288C55005D1B64 /* from_string.cpp in Sources */, + F6E97D60281F1078004C92E9 /* Stack.cpp in Sources */, + F61EA27D2A78A28500DF7BFA /* StackUsage.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + F6E97D0D281EF664004C92E9 /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + F6DC70F52D81EFBB004DA34D /* ends_with.cpp in Sources */, + F6DC70E92D81EAB4004DA34D /* container_get_optional_erase.cpp in Sources */, + F6DC70FC2D81F1A8004DA34D /* is_in.cpp in Sources */, + F6E97D19281EF66D004C92E9 /* Run.cpp in Sources */, + F67CE9292D83D951004400C3 /* optional_value.cpp in Sources */, + F64714B52C74CD29002A8087 /* fail_on_copy_vector.hpp in Sources */, + F67CE92B2D83D99D004400C3 /* set_empty.cpp in Sources */, + F62919ED2CB6A3B3002060E0 /* cmp_case.cpp in Sources */, + F6DC70DF2D81E6B7004DA34D /* container_erase_if.cpp in Sources */, + F6DC71022D81F397004DA34D /* list_erase_if.cpp in Sources */, + F67CE9102D83D329004400C3 /* map_erase.cpp in Sources */, + F69AB7F32B19310E000115BC /* Hash.cpp in Sources */, + F67CE9082D83D1ED004400C3 /* list_erase_if_value.cpp in Sources */, + F63B041A2C76A07A00417011 /* HashExpected.cpp in Sources */, + F608A8A828269A12005C276B /* TestMutex.cpp in Sources */, + F608A8CC28269D0D005C276B /* Str.cpp in Sources */, + F67CE90E2D83D2F4004400C3 /* map_erase_if.cpp in Sources */, + F64714AE2C74B4BE002A8087 /* replace.cpp in Sources */, + F61F9BFE2C6EEE7B00F79137 /* Ptr.cpp in Sources */, + F67CE9272D83D8E5004400C3 /* optional_value_or_default.cpp in Sources */, + F64714AC2C74B09D002A8087 /* trim.cpp in Sources */, + F6F721762C5DB85200A8E8D1 /* zip.cpp in Sources */, + F6DC70E32D81E804004DA34D /* container_get_if_optional_erase.cpp in Sources */, + F6436EC5285955F2003241E0 /* small_cmp.cpp in Sources */, + F61F9BFD2C6EEE7200F79137 /* Ptr.cpp in Sources */, + F67CE90C2D83D2A8004400C3 /* map_erase_if_value.cpp in Sources */, + F6DCDBB52858F65F00696085 /* small_copy.cpp in Sources */, + F6DC70ED2D81EC4D004DA34D /* container_has.cpp in Sources */, + F67CE9182D83D595004400C3 /* map_iterator_or_insert.cpp in Sources */, + F67CE93C2D8450BA004400C3 /* container_erase_value_all.cpp in Sources */, + F67CE9392D845039004400C3 /* vector_erase_value_all.cpp in Sources */, + F6DC70D72D81E375004DA34D /* all_are.cpp in Sources */, + F6DC70E52D81E8E9004DA34D /* container_get_if_optional.cpp in Sources */, + F6DC70E12D81E735004DA34D /* container_find_if.cpp in Sources */, + F67CE9352D844CDC004400C3 /* vector_erase_value_one.cpp in Sources */, + F67CE9312D844BAF004400C3 /* vector_append.cpp in Sources */, + F6B4CFC72A6ECF8F004B9AB5 /* Ptr.cpp in Sources */, + F6DC70EB2D81EBEF004DA34D /* container_has_if.cpp in Sources */, + F67CE91E2D83D73B004400C3 /* not_zero.cpp in Sources */, + F6FADA9A29490462006125E1 /* MultiContainer.cpp in Sources */, + F6DC70E72D81E937004DA34D /* container_get_if.cpp in Sources */, + F64C65222AC5ABC900FCF1DD /* RTTI.cpp in Sources */, + F6DC70EF2D81ECE1004DA34D /* copy_of.cpp in Sources */, + F6DC70F12D81EE72004DA34D /* empty_of.cpp in Sources */, + F61DB8032857682300B74C99 /* InPlaceArray.cpp in Sources */, + F6DC70FA2D81F0F5004DA34D /* in_range_segment.cpp in Sources */, + F6DC70FE2D81F1EC004DA34D /* is_zero.cpp in Sources */, + F6A9947B2D827CBB00AA4FEE /* length.cpp in Sources */, + F64714B32C74BE4A002A8087 /* transform_with.cpp in Sources */, + F6A994792D827C5900AA4FEE /* starts_with.cpp in Sources */, + F67CE91A2D83D65D004400C3 /* map_value_require.cpp in Sources */, + F6F7A3012F4A2516008BF0C6 /* remove_char.cpp in Sources */, + F62919F42CB6A83F002060E0 /* strncmp.cpp in Sources */, + F6DC70D92D81E43B004DA34D /* one_is.cpp in Sources */, + F6CA9B5A294E7BBD00D9A375 /* range.cpp in Sources */, + F63B042B2C77676200417011 /* is_vector.cpp in Sources */, + F6DC70F82D81F062004DA34D /* has_last.cpp in Sources */, + F63B042E2C7767AA00417011 /* is_map.cpp in Sources */, + F65B59992C6C4C4800059339 /* is_first.cpp in Sources */, + F69832BA2D7B7B0700D911E4 /* copy_clear.cpp in Sources */, + F67CE9202D83D790004400C3 /* on_destruct.cpp in Sources */, + F6F721722C5DB73400A8E8D1 /* no_last.cpp in Sources */, + F67CE9122D83D3B1004400C3 /* map_has.cpp in Sources */, + F6F721702C5DB54E00A8E8D1 /* enumerate.cpp in Sources */, + F63B04372C778EDA00417011 /* concat.cpp in Sources */, + F67CE9332D844CA2004400C3 /* vector_erase_if_value.cpp in Sources */, + F6E97DC5281F43F3004C92E9 /* SafeIteration.cpp in Sources */, + F6F7A2F42F49EFAB008BF0C6 /* no_throw.cpp in Sources */, + F6F721742C5DB81F00A8E8D1 /* no_first.cpp in Sources */, + F67CE90A2D83D213004400C3 /* map_erase_if_key.cpp in Sources */, + F69AB77D2B16D4BA000115BC /* TypeName.cpp in Sources */, + F6DC70F32D81EF1B004DA34D /* emplace.cpp in Sources */, + F64714B72C74CF7A002A8087 /* Lock.cpp in Sources */, + F61DB8042857685A00B74C99 /* StackArray_v2.cpp in Sources */, + F62919F02CB6A468002060E0 /* strncasecmp.cpp in Sources */, + F6F7A3032F4A26A3008BF0C6 /* Str.cpp in Sources */, + F6DC70DB2D81E493004DA34D /* container_erase_if_one.cpp in Sources */, + F6B1537D2C7042830063C622 /* range_with.cpp in Sources */, + F65B599B2C6C4E5C00059339 /* safe_next.cpp in Sources */, + F61F9BB02C6D965E00F79137 /* reverse.cpp in Sources */, + F6C855E52DB7321E006D6C48 /* split_once.cpp in Sources */, + F67CE94C2D84583F004400C3 /* Examples.cpp in Sources */, + F64714A62C74A137002A8087 /* Timer.cpp in Sources */, + F6E97D62281F3A5F004C92E9 /* LogOf.cpp in Sources */, + F67CE9162D83D4F8004400C3 /* map_for_each_value.cpp in Sources */, + F6DC70DD2D81E5D1004DA34D /* container_erase_value_one.cpp in Sources */, + F6DC71002D81F2F8004DA34D /* last_of_parameter_pack.cpp in Sources */, + F6F9CF402E4F899A00576DEF /* Float16.cpp in Sources */, + F67CE9142D83D404004400C3 /* map_has_key.cpp in Sources */, + F64714B12C74B5DF002A8087 /* join.cpp in Sources */, + F67CE91C2D83D6E0004400C3 /* map_value.cpp in Sources */, + F608A90D2826A681005C276B /* Dictionary.cpp in Sources */, + F67CE92F2D83DD63004400C3 /* if_or.cpp in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + F67119DF2C8A636C00F72EE9 /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = F6E97CFF281EF4BF004C92E9 /* Core_Zero */; + targetProxy = F67119DE2C8A636C00F72EE9 /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin XCBuildConfiguration section */ + F6971F1F282B1129008FBD17 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F6971F20282B1129008FBD17 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SDKROOT = iphoneos; + SKIP_INSTALL = YES; + }; + name = Release; + }; + F6E97D02281EF4BF004C92E9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = dwarf; + ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_DYNAMIC_NO_PIC = NO; + GCC_ENABLE_CPP_RTTI = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_OPTIMIZATION_LEVEL = 0; + GCC_PREPROCESSOR_DEFINITIONS = ( + "DEBUG=1", + "$(inherited)", + ); + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE; + MTL_FAST_MATH = YES; + ONLY_ACTIVE_ARCH = YES; + OTHER_LDFLAGS = ( + "-lCore_Allocator", + "-lCore_Zero", + ); + SDKROOT = macosx; + USE_HEADERMAP = NO; + }; + name = Debug; + }; + F6E97D03281EF4BF004C92E9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "c++17"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_ENABLE_OBJC_WEAK = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = YES; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; + CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE; + CLANG_WARN_UNREACHABLE_CODE = YES; + CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; + COPY_PHASE_STRIP = NO; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + ENABLE_NS_ASSERTIONS = NO; + ENABLE_STRICT_OBJC_MSGSEND = YES; + GCC_C_LANGUAGE_STANDARD = gnu11; + GCC_ENABLE_CPP_RTTI = NO; + GCC_NO_COMMON_BLOCKS = YES; + GCC_SYMBOLS_PRIVATE_EXTERN = YES; + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 13.6; + MACOSX_DEPLOYMENT_TARGET = 10.15; + MTL_ENABLE_DEBUG_INFO = NO; + MTL_FAST_MATH = YES; + OTHER_LDFLAGS = ( + "-lCore_Allocator", + "-lCore_Zero", + ); + SDKROOT = macosx; + USE_HEADERMAP = NO; + }; + name = Release; + }; + F6E97D05281EF4BF004C92E9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Debug; + }; + F6E97D06281EF4BF004C92E9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + EXECUTABLE_PREFIX = lib; + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + }; + name = Release; + }; + F6E97D16281EF664004C92E9 /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Zero, + ); + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Debug; + }; + F6E97D17281EF664004C92E9 /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_STYLE = Automatic; + DEVELOPMENT_TEAM = T2M28D3T75; + ENABLE_HARDENED_RUNTIME = YES; + HEADER_SEARCH_PATHS = ( + "${inherited}", + ../Core_Zero, + ); + ONLY_ACTIVE_ARCH = YES; + PRODUCT_NAME = "$(TARGET_NAME)"; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + F6971F1E282B1129008FBD17 /* Build configuration list for PBXNativeTarget "Core_Zero_iOS" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6971F1F282B1129008FBD17 /* Debug */, + F6971F20282B1129008FBD17 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F6E97CFB281EF4BF004C92E9 /* Build configuration list for PBXProject "Core_Zero" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6E97D02281EF4BF004C92E9 /* Debug */, + F6E97D03281EF4BF004C92E9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F6E97D04281EF4BF004C92E9 /* Build configuration list for PBXNativeTarget "Core_Zero" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6E97D05281EF4BF004C92E9 /* Debug */, + F6E97D06281EF4BF004C92E9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + F6E97D15281EF664004C92E9 /* Build configuration list for PBXNativeTarget "Core_Zero_Tests" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + F6E97D16281EF664004C92E9 /* Debug */, + F6E97D17281EF664004C92E9 /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = F6E97CF8281EF4BF004C92E9 /* Project object */; +} diff --git a/Core_Zero.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Core_Zero.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..919434a --- /dev/null +++ b/Core_Zero.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Core_Zero.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist b/Core_Zero.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist new file mode 100644 index 0000000..18d9810 --- /dev/null +++ b/Core_Zero.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist @@ -0,0 +1,8 @@ + + + + + IDEDidComputeMac32BitWarning + + + diff --git a/Core_Zero.xcodeproj/xcshareddata/xcschemes/Core_Zero_Tests.xcscheme b/Core_Zero.xcodeproj/xcshareddata/xcschemes/Core_Zero_Tests.xcscheme new file mode 100644 index 0000000..c8dae6c --- /dev/null +++ b/Core_Zero.xcodeproj/xcshareddata/xcschemes/Core_Zero_Tests.xcscheme @@ -0,0 +1,224 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Examples.cpp b/Examples.cpp new file mode 100644 index 0000000..9d9b9cc --- /dev/null +++ b/Examples.cpp @@ -0,0 +1,188 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include +#include +#include +#include +#include +#include + +namespace my_base_namespace { + namespace ext = tjp::core; + using namespace ext; +} + +// or + +namespace my_base_namespace { + namespace ext = tjp::core; + + using ext::Mutex; +} + +namespace my_base_namespace::sub_name_space { + +void do_something() {} + +template +void do_something_with(T &&) {} + +// ---------------------------------------- +// example for locks +// ---------------------------------------- +void example_lock_tjp() +{ + Mutex mutex; + + auto lock = lock_of(mutex); + do_something(); + + auto should_send_signal = true; + if (should_send_signal) + { + auto unlock = unlock_of(mutex); + do_something(); + } +} + +// using std +void example_lock_cpp() +{ + std::mutex mutex; + std::lock_guard lock(mutex); + do_something(); + + auto should_send_signal = true; + if (should_send_signal) + { + try + { + mutex.unlock(); + do_something(); + mutex.lock(); + } + catch (...) + { + mutex.lock(); + } + } +} + + + + +// ---------------------------------------- +// example for maps +// ---------------------------------------- +void example_map_tjp() +{ + Map map; + if (auto value = map_value(map, 42)) + do_something_with(*value); + + if (auto value = map_value_erase(map, 42)) + do_something_with(*value); +} + + +// using std +void example_map_cpp() +{ + std::map map; + auto i = map.find(42); + if (i != map.end()) + { + do_something_with(*i); + } + + auto j = map.find(42); + if (j != map.end()) + { + auto v = std::move(j->second); + map.erase(j); + + do_something_with(v); + } +} + + + + + +// ---------------------------------------- +// example for range +// ---------------------------------------- + +void example_range_cpp() +{ + for (auto k=0; k<42; ++k) + do_something_with(k); +} + +void example_range_tjp() +{ + for (auto i: range(42)) + do_something_with(i); +} + +// ---------------------------------------- +// time +// ---------------------------------------- + +void example_time_duration_cpp() +{ + auto t1 = std::chrono::system_clock::now(); + do_something(); + auto t2 = std::chrono::system_clock::now(); + + auto duration = t2 - t1; + auto duration_serializable_number = std::chrono::duration_cast(duration).count(); + do_something_with(duration_serializable_number); + + auto duration_in_seconds = std::chrono::duration_cast(duration); + do_something_with(duration_in_seconds); + + auto two_second_after_t1 = t1 + std::chrono::seconds(2); + do_something_with(two_second_after_t1); + + auto meters = 32.; + auto seconds = std::chrono::seconds(2); + auto meters_per_second = meters / std::chrono::duration(seconds).count(); + do_something_with(meters_per_second); + + meters = std::chrono::duration(seconds).count() * meters_per_second; + do_something_with(meters); +} + +void example_time_duration_tjp() +{ + auto t1 = time::now(); + do_something(); + auto t2 = time::now(); + + auto duration = t2 - t1; + auto duration_serializable_number = duration.v; + do_something_with(duration_serializable_number); + + auto duration_in_seconds = duration / time::Seconds; + do_something_with(duration_in_seconds); + + auto two_second_after_t1 = t1 + time::Seconds(2); + auto two_second_after_t1_another = t1 + 2 * time::Seconds; + do_something_with(two_second_after_t1); + do_something_with(two_second_after_t1_another); + + auto meters = 32.; + auto seconds = 2 * time::Seconds; + auto meters_per_second = meters / seconds; + do_something_with(meters_per_second); + + meters = seconds * meters_per_second; + do_something_with(meters); +} + +} // namespace diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..f1db21f --- /dev/null +++ b/LICENSE @@ -0,0 +1,26 @@ +MIT NON-AI License + +Copyright (c) 2025, Timothy Prepscius + +Permission is hereby granted, free of charge, to any person obtaining a copy of the software and associated documentation files (the "Software"), +to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, +and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions. + +The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. + +In addition, the following restrictions apply: + +1. The Software and any modifications made to it may not be used for the purpose of training or improving machine learning algorithms, +including but not limited to artificial intelligence, natural language processing, or data mining. This condition applies to any derivatives, +modifications, or updates based on the Software code. Any usage of the Software in an AI-training dataset is considered a breach of this License. + +2. The Software may not be included in any dataset used for training or improving machine learning algorithms, +including but not limited to artificial intelligence, natural language processing, or data mining. + +3. Any person or organization found to be in violation of these restrictions will be subject to legal action and may be held liable +for any damages resulting from such use. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, +DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE +OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e971fb2 --- /dev/null +++ b/Makefile @@ -0,0 +1,8 @@ +################################### +# License: Modified MIT (NON-AI) +# Copyright 2025 Timothy Prepscius +# See the LICENSE file in the root directory for license information. +################################### + +ROOTDIR := $(realpath $(dir $(lastword $(MAKEFILE_LIST)))..) +include $(ROOTDIR)/Core_Make/tjp/Make/Makefile diff --git a/Makefile.def b/Makefile.def new file mode 100755 index 0000000..ef05e44 --- /dev/null +++ b/Makefile.def @@ -0,0 +1,11 @@ +################################### +# License: Modified MIT (NON-AI) +# Copyright 2025 Timothy Prepscius +# See the LICENSE file in the root directory for license information. +################################### + +timprepscius.core_zero.include := -I $(dir $(realpath $(lastword $(MAKEFILE_LIST)))) +timprepscius.core_zero.link := -L $(dir $(realpath $(lastword $(MAKEFILE_LIST))))/.bin/$(OBJDIR) + +timprepscius.core.include := $(timprepscius.core.include) $(timprepscius.core_zero.include) +timprepscius.core.link := $(timprepscius.core.link) $(timprepscius.core_zero.link) diff --git a/Makefile.project b/Makefile.project new file mode 100755 index 0000000..5ab61dc --- /dev/null +++ b/Makefile.project @@ -0,0 +1,51 @@ +################################### +# License: Modified MIT (NON-AI) +# Copyright 2025 Timothy Prepscius +# See the LICENSE file in the root directory for license information. +################################### + +include $(MAKEDIR)/Makefile.base + +PROJECTS := \ + tjp/core/algorithm \ + tjp/core/assert \ + tjp/core/containers \ + tjp/core/const_hash \ + tjp/core/debug \ + tjp/core/exception \ + tjp/core/io \ + tjp/core/iterators \ + tjp/core/log \ + tjp/core/ptr \ + tjp/core/ptr/std \ + tjp/core/ptr/using_maps \ + tjp/core/ptr/using_info \ + tjp/core/sfinae \ + tjp/core/string \ + tjp/core/system \ + tjp/core/testing \ + tjp/core/threads \ + tjp/core/threads/std \ + tjp/core/time \ + tjp/core/timer \ + tjp/core/type_traits \ + tjp/core/types \ + +ifeq (Android,$(SYS_NAME)) + + PROJECTS += \ + tjp/core/debug/android \ + +else + PROJECTS += \ + tjp/core/debug/glib \ + +endif + +SRC_PCH := tjp/core/Precompile.pch +INCPATH := $(timprepscius.libraries.cpp.include) +LIBFILE := libCore_Zero.a + +COPYTO := $(LIBRARIES_PROJECT) + +include $(MAKEDIR)/Makefile.lib diff --git a/ReadMe.md b/ReadMe.md new file mode 100755 index 0000000..7b9e256 --- /dev/null +++ b/ReadMe.md @@ -0,0 +1,141 @@ +# Core_Zero + +Basic foundational classes + + +## Building + +Most of Core_Zero is header-only. +To enable header-only use: + `#define TJP_CORE_HEADER_ONLY` + +The entire Core_Zero project will be converted to header only compatible soon. + +To build all of the project use these steps. + +``` +mkdir my_project +cd my_project + +git clone http://github.com/timprepscius/Core_Libraries +git clone http://github.com/timprepscius/Core_Zero +git clone http://github.com/timprepscius/Core_Make +cd Core_Zero +make + +cd tests +make +.bin/Core_Zero_Tests.exe + +``` + + +## How to use + +### Locks + +``` +// ---------------------------------------- +// example for locks +// ---------------------------------------- +void example_lock_tjp() +{ + Mutex mutex; + + auto lock = lock_of(mutex); + do_something(); + + auto should_send_signal = true; + if (should_send_signal) + { + auto unlock = unlock_of(mutex); + do_something(); + } +} + +// using std +void example_lock_cpp() +{ + std::mutex mutex; + std::lock_guard lock(mutex); + do_something(); + + auto should_send_signal = true; + if (should_send_signal) + { + try + { + mutex.unlock(); + do_something(); + mutex.lock(); + } + catch (...) + { + mutex.lock(); + } + } +} + +``` + +### Maps + +``` +// ---------------------------------------- +// example for maps +// ---------------------------------------- +void example_map_tjp() +{ + Map map; + if (auto value = map_value(map, 42)) + do_something_with(*value); + + if (auto value = map_value_erase(map, 42)) + do_something_with(*value); +} + + +// using std +void example_map_cpp() +{ + std::map map; + auto i = map.find(42); + if (i != map.end()) + { + do_something_with(*i); + } + + auto j = map.find(42); + if (j != map.end()) + { + auto v = std::move(j->second); + map.erase(j); + + do_something_with(v); + } +} +``` + +### Range iteration +``` +// ---------------------------------------- +// example for range +// ---------------------------------------- +void example_range_tjp() +{ + for (auto i: range(42)) + do_something_with(i); +} + +// using std +void example_range_cpp() +{ + for (auto k=0; k<42; ++k) + do_something_with(k); +} +``` + + +### Other examples + +Look at `Core_Zero/Examples.cpp` for more examples on how to use this library. diff --git a/core b/core new file mode 100644 index 0000000..e69de29 diff --git a/tests/Makefile b/tests/Makefile new file mode 120000 index 0000000..b8f87c1 --- /dev/null +++ b/tests/Makefile @@ -0,0 +1 @@ +../../Make/Makefile \ No newline at end of file diff --git a/tests/Makefile.project b/tests/Makefile.project new file mode 100755 index 0000000..4477b47 --- /dev/null +++ b/tests/Makefile.project @@ -0,0 +1,36 @@ +include $(MAKEDIR)/Makefile.base + +PROJECTS := \ + . \ + ../core/algorithm/_tests \ + ../core/const_hash/_tests \ + ../core/const_expr/_tests \ + ../core/containers/_tests \ + ../core/iterators/_tests \ + ../core/log/_tests \ + ../core/ptr/_tests \ + ../core/ptr/using_info/_tests \ + ../core/ptr/using_maps/_tests \ + ../core/rtti/_tests \ + ../core/testing/_tests \ + +INCPATH := \ + $(timprepscius.libraries.cpp.include) \ + $(timprepscius.core.include) + +LDPATH := \ + $(timprepscius.libraries.cpp.link) + +LIBS := \ + -lCore_Zero + +EXEFILE := Core_Zero_Tests.exe + +#COPYTO := $(ROOTDIR)/.bin + +ifeq (Darwin,$(SYS_NAME)) + LIBS += -lc++ +endif + + +include $(MAKEDIR)/Makefile.bin diff --git a/tests/Run.cpp b/tests/Run.cpp new file mode 100644 index 0000000..b0413b5 --- /dev/null +++ b/tests/Run.cpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#define CATCH_CONFIG_RUNNER +#include + +#include + +using namespace tjp; +using namespace core; + +int main( int argc, char* argv[] ) +{ + xLogInitialize(); + xLogActivateStory("testing"); + xLogActivateStory("debug"); + + int result = Catch::Session().run( argc, argv ); + return result; +} diff --git a/tjp/core/Precompile.pch b/tjp/core/Precompile.pch new file mode 100644 index 0000000..ca4c3a5 --- /dev/null +++ b/tjp/core/Precompile.pch @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#define USE_PRECOMPILED_HEADERS +#ifdef USE_PRECOMPILED_HEADERS + + #include + #include + + #include + #include + + #include + #include + #include + + #include + #include + #include + #include + + #include + + #include + #include + +#endif + diff --git a/tjp/core/algorithm/ExecuteOnDestruct.h b/tjp/core/algorithm/ExecuteOnDestruct.h new file mode 100755 index 0000000..32bfa25 --- /dev/null +++ b/tjp/core/algorithm/ExecuteOnDestruct.h @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +struct ExecuteOnDestruct; +using OnDestruct = ExecuteOnDestruct; + +} // namespace diff --git a/tjp/core/algorithm/ExecuteOnDestruct.hpp b/tjp/core/algorithm/ExecuteOnDestruct.hpp new file mode 100755 index 0000000..11063a7 --- /dev/null +++ b/tjp/core/algorithm/ExecuteOnDestruct.hpp @@ -0,0 +1,73 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "ExecuteOnDestruct.h" +#include +#include "../threads/TestMutex.hpp" +#include "no_throw.hpp" + +#include + +namespace tjp::core { + +struct ExecuteOnDestruct +{ + typedef std::function F; + + [[no_unique_address]] + TestMutex m; + + F f; + + struct Throws_{}; + static constexpr Throws_ Throws = Throws_{}; + + ExecuteOnDestruct(const ExecuteOnDestruct &) = delete; + + ExecuteOnDestruct() {} + + ExecuteOnDestruct(ExecuteOnDestruct &&rhs): + f(rhs.move()) + {} + + template + ExecuteOnDestruct(FU &&f_) : f(no_throw(std::forward(f_))) + {} + + + // note: throwing on destruction, *can* cause termination, weird but true as of 2026 + template + ExecuteOnDestruct(FU &&f_, Throws_) : f(std::forward(f_)) + {} + + F move() + { + auto l = lock_of(m); + F f_; + std::swap(f_, f); + return f_; + } + + ~ExecuteOnDestruct() noexcept(false) + { + execute(); + } + + void execute() + { + auto f = move(); + if (f) + f(); + } + + void clear () + { + move(); + } +} ; + + +} // namespace diff --git a/tjp/core/algorithm/_tests/all_are.cpp b/tjp/core/algorithm/_tests/all_are.cpp new file mode 100755 index 0000000..d68bf8a --- /dev/null +++ b/tjp/core/algorithm/_tests/all_are.cpp @@ -0,0 +1,43 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::all_are") +{ + GIVEN("a vector of values") + { + Vector v; + for (auto i=0; i<50; ++i) + v.push_back(42); + + auto all_are_42 = all_are(v, [](auto &v) { return v == 42; }); + REQUIRE(all_are_42); + + WHEN("one is not 42") + { + v[5] = 43; + auto all_are_42 = all_are(v, [](auto &v) { return v == 42; }); + REQUIRE(!all_are_42); + } + + WHEN("multiple are not 42") + { + v[2] = 40; + v[13] = 39; + auto all_are_42 = all_are(v, [](auto &v) { return v == 42; }); + REQUIRE(!all_are_42); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_erase_if.cpp b/tjp/core/algorithm/_tests/container_erase_if.cpp new file mode 100755 index 0000000..2993a28 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_erase_if.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_erase_if") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = container_erase_if( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(erased == 4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = container_erase_if( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = container_erase_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_erase_if_one.cpp b/tjp/core/algorithm/_tests/container_erase_if_one.cpp new file mode 100755 index 0000000..fc72964 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_erase_if_one.cpp @@ -0,0 +1,53 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_erase_if_one") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is erased") + { + auto erased = container_erase_if_one( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(erased); + REQUIRE(v.size() == 99); + + WHEN("42 is erased again") + { + auto erased = container_erase_if_one( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 99); + } + } + + WHEN("1000 is not erased") + { + auto erased = container_erase_if_one( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_erase_value_all.cpp b/tjp/core/algorithm/_tests/container_erase_value_all.cpp new file mode 100755 index 0000000..4fbf4ae --- /dev/null +++ b/tjp/core/algorithm/_tests/container_erase_value_all.cpp @@ -0,0 +1,47 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_erase_value_all") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = container_erase_value_all(v, 10); + REQUIRE(erased==4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = container_erase_value_all(v, 10); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = container_erase_value_all(v, 1000); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_erase_value_one.cpp b/tjp/core/algorithm/_tests/container_erase_value_one.cpp new file mode 100755 index 0000000..b976c97 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_erase_value_one.cpp @@ -0,0 +1,47 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_erase_value_one") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = container_erase_value_one(v, 10); + REQUIRE(erased); + REQUIRE(v.size() == 99); + + WHEN("10 is erased again") + { + auto erased = container_erase_value_one(v, 10); + REQUIRE(erased); + REQUIRE(v.size() == 98); + } + } + + WHEN("1000 is not erased") + { + auto erased = container_erase_value_one(v, 1000); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_find_if.cpp b/tjp/core/algorithm/_tests/container_find_if.cpp new file mode 100755 index 0000000..f786c41 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_find_if.cpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_find_if") +{ + GIVEN("a vector of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is found") + { + auto found = container_find_if(v, [](auto &v) { return v == 10; }); + + REQUIRE(found != v.end()); + } + + WHEN("1000 is not found") + { + auto found = container_find_if(v, [](auto &v) { return v == 1000; }); + + REQUIRE(found == v.end()); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_get_if.cpp b/tjp/core/algorithm/_tests/container_get_if.cpp new file mode 100755 index 0000000..361ed73 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_get_if.cpp @@ -0,0 +1,85 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_get_if") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = container_get_if( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(found); + REQUIRE(*found == 42); + + WHEN("1000 is not found") + { + auto found = container_get_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!found); + } + } + + WHEN("1000 is not found") + { + auto found = container_get_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!found); + REQUIRE(v.size() == 100); + } + +#ifdef CHECK_COMPILATION_FAILURE + WHEN("called with a temporary list") + { + int destructed = 0; + auto make_values = [&]() { + struct S { + int *destructed; + int value; + S(int *destructed_, int value_) : + destructed(destructed_), + value(value_) + {} + ~S() { (*destructed)++; } + }; + + + List temp; + temp.emplace_back(&destructed, 5); + temp.emplace_back(&destructed, 42); + return temp; + }; + + auto found = container_get_if( + make_values(), [&](auto &s) { + REQUIRE(destructed == 0); + return s.value == 42; + } + ); + + REQUIRE(destructed == 0); + } +#endif + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_get_if_optional.cpp b/tjp/core/algorithm/_tests/container_get_if_optional.cpp new file mode 100755 index 0000000..b21a395 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_get_if_optional.cpp @@ -0,0 +1,45 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_get_if_optional") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = container_get_if_optional( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(found); + REQUIRE(*found == 42); + } + + WHEN("1000 is not found") + { + auto found = container_get_if_optional( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!found); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_get_if_optional_erase.cpp b/tjp/core/algorithm/_tests/container_get_if_optional_erase.cpp new file mode 100755 index 0000000..3d698fb --- /dev/null +++ b/tjp/core/algorithm/_tests/container_get_if_optional_erase.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_get_if_optional_erase") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is erased") + { + auto erased = container_get_if_optional_erase( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(erased); + REQUIRE(*erased == 42); + REQUIRE(v.size() == 99); + + WHEN("42 is erased again") + { + auto erased = container_get_if_optional_erase( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 99); + } + } + + WHEN("1000 is not erased") + { + auto erased = container_get_if_optional_erase( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_get_optional_erase.cpp b/tjp/core/algorithm/_tests/container_get_optional_erase.cpp new file mode 100755 index 0000000..c499e0f --- /dev/null +++ b/tjp/core/algorithm/_tests/container_get_optional_erase.cpp @@ -0,0 +1,48 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_get_optional_erase") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is erased") + { + auto erased = container_get_optional_erase(v, 42); + REQUIRE(erased); + REQUIRE(*erased == 42); + REQUIRE(v.size() == 99); + + WHEN("42 is erased again") + { + auto erased = container_get_optional_erase(v, 42); + REQUIRE(!erased); + REQUIRE(v.size() == 99); + } + } + + WHEN("1000 is not found") + { + auto found = container_get_optional_erase(v, 1000); + REQUIRE(!found); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_has.cpp b/tjp/core/algorithm/_tests/container_has.cpp new file mode 100755 index 0000000..22e98e7 --- /dev/null +++ b/tjp/core/algorithm/_tests/container_has.cpp @@ -0,0 +1,44 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_has") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = container_has(v, 42); + REQUIRE(found); + + WHEN("1000 is not found") + { + auto found = container_has(v, 1000); + REQUIRE(!found); + } + } + + WHEN("1000 is not found") + { + auto found = container_has(v, 1000); + REQUIRE(!found); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/container_has_if.cpp b/tjp/core/algorithm/_tests/container_has_if.cpp new file mode 100755 index 0000000..feb247a --- /dev/null +++ b/tjp/core/algorithm/_tests/container_has_if.cpp @@ -0,0 +1,50 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::container_has_if") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i); + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = container_has_if( + v, [](auto &v) { return v == 42; } + ); + REQUIRE(found); + + WHEN("1000 is not found") + { + auto found = container_has_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!found); + } + } + + WHEN("1000 is not found") + { + auto found = container_has_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!found); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/copy_clear.cpp b/tjp/core/algorithm/_tests/copy_clear.cpp new file mode 100755 index 0000000..9fb469a --- /dev/null +++ b/tjp/core/algorithm/_tests/copy_clear.cpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::copy_clear") +{ + WHEN("simple value") + { + int i = 42; + auto v = copy_clear(i); + REQUIRE(i == 0); + REQUIRE(v == 42); + } + + WHEN("complex value") + { + String i = "hello"; + auto v = copy_clear(i); + REQUIRE(i == ""); + REQUIRE(v == "hello"); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/copy_of.cpp b/tjp/core/algorithm/_tests/copy_of.cpp new file mode 100755 index 0000000..08b34b8 --- /dev/null +++ b/tjp/core/algorithm/_tests/copy_of.cpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::copy_of") +{ + WHEN("simple value") + { + int i = 42; + auto v = copy_of(i); + REQUIRE(i == 42); + REQUIRE(v == 42); + } + + WHEN("complex value") + { + String i = "hello"; + auto v = copy_of(i); + REQUIRE(i == "hello"); + REQUIRE(v == "hello"); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/emplace.cpp b/tjp/core/algorithm/_tests/emplace.cpp new file mode 100755 index 0000000..448a5bd --- /dev/null +++ b/tjp/core/algorithm/_tests/emplace.cpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::emplace") +{ + WHEN("Vector value") + { + Vector v; + + WHEN("initializer list") + { + Vector expected = { 1, 2, 3, 4, 5}; + emplace(v, { 1, 2, 3, 4, 5}); + REQUIRE(v == expected); + } + + WHEN("init") + { + Vector expected = { 1, 1 }; + emplace(v, 2, 1); + REQUIRE(v == expected); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/empty_of.cpp b/tjp/core/algorithm/_tests/empty_of.cpp new file mode 100755 index 0000000..0a239f8 --- /dev/null +++ b/tjp/core/algorithm/_tests/empty_of.cpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::empty_of") +{ + WHEN("simple value") + { + using T = Vector; + auto &v = empty_of(); + REQUIRE(v.empty()); + } + + WHEN("complex value") + { + struct X { int y = 42; }; + + using T = X; + auto &v = empty_of(); + REQUIRE(v.y == 42); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/ends_with.cpp b/tjp/core/algorithm/_tests/ends_with.cpp new file mode 100755 index 0000000..18c2336 --- /dev/null +++ b/tjp/core/algorithm/_tests/ends_with.cpp @@ -0,0 +1,33 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::ends_with") +{ + WHEN("Vector value") + { + Vector v = { 1, 2, 3, 4, 5 }; + auto ends_with_345 = ends_with(v, Vector {3, 4, 5}); + REQUIRE(ends_with_345); + + auto ends_with_456 = ends_with(v, Vector {4,5,6}); + REQUIRE(!ends_with_456); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/has_last.cpp b/tjp/core/algorithm/_tests/has_last.cpp new file mode 100755 index 0000000..748a6c8 --- /dev/null +++ b/tjp/core/algorithm/_tests/has_last.cpp @@ -0,0 +1,33 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::has_last") +{ + WHEN("Vector value") + { + Vector v = { 1, 2, 3, 4, 5 }; + auto ends_with_5 = has_last(v, [](auto &v) { return v == 5; }); + REQUIRE(ends_with_5); + + auto ends_with_6 = has_last(v, [](auto &v) { return v == 6; }); + REQUIRE(!ends_with_6); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/in_range_segment.cpp b/tjp/core/algorithm/_tests/in_range_segment.cpp new file mode 100755 index 0000000..d5286c9 --- /dev/null +++ b/tjp/core/algorithm/_tests/in_range_segment.cpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::in_range_segment") +{ + WHEN("ranges") + { + static_assert(in_range_segment(1, 0, 10)); + static_assert(!in_range_segment(0, 1, 10)); + static_assert(!in_range_segment(11, 1, 10)); + static_assert(in_range_segment(10, 1, 10)); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/is_in.cpp b/tjp/core/algorithm/_tests/is_in.cpp new file mode 100755 index 0000000..c4a4435 --- /dev/null +++ b/tjp/core/algorithm/_tests/is_in.cpp @@ -0,0 +1,30 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::is_in") +{ + WHEN("ranges") + { + static_assert(is_in(0, 0, 1, 2, 3)); + static_assert(is_in(1, 0, 1, 2, 3)); + static_assert(!is_in(4, 0, 1, 2, 3)); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/is_zero.cpp b/tjp/core/algorithm/_tests/is_zero.cpp new file mode 100755 index 0000000..2f88c43 --- /dev/null +++ b/tjp/core/algorithm/_tests/is_zero.cpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::is_zero") +{ + WHEN("ranges") + { + auto minus_one = [](auto &&v) { return v - 1; }; + auto test_minus_one = is_zero(minus_one); + + REQUIRE(test_minus_one(1)); + REQUIRE(!test_minus_one(0)); + + } + +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/last_of_parameter_pack.cpp b/tjp/core/algorithm/_tests/last_of_parameter_pack.cpp new file mode 100755 index 0000000..27c70b6 --- /dev/null +++ b/tjp/core/algorithm/_tests/last_of_parameter_pack.cpp @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::last_of_parameter_pack") +{ + WHEN("ranges") + { + static_assert(last_of_parameter_pack(1,2,3,4) == 4); + } + +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/list_erase_if.cpp b/tjp/core/algorithm/_tests/list_erase_if.cpp new file mode 100755 index 0000000..16de02f --- /dev/null +++ b/tjp/core/algorithm/_tests/list_erase_if.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::list_erase_if") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = list_erase_if( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(erased == 4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = list_erase_if( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = list_erase_if( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/list_erase_if_value.cpp b/tjp/core/algorithm/_tests/list_erase_if_value.cpp new file mode 100755 index 0000000..85f3941 --- /dev/null +++ b/tjp/core/algorithm/_tests/list_erase_if_value.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::list_erase_if_value") +{ + GIVEN("a list of values") + { + List v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = list_erase_if_value( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(erased == 4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = list_erase_if_value( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = list_erase_if_value( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_erase.cpp b/tjp/core/algorithm/_tests/map_erase.cpp new file mode 100755 index 0000000..88f1e5a --- /dev/null +++ b/tjp/core/algorithm/_tests/map_erase.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_erase") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = map_erase( + v, 10 + ); + REQUIRE(erased); + REQUIRE(v.size() == 99); + + WHEN("evens are erased again") + { + auto erased = map_erase( + v, 10 + ); + REQUIRE(!erased); + REQUIRE(v.size() == 99); + } + } + + WHEN("1000 is not erased") + { + auto erased = map_erase( + v, 1000 + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_erase_if.cpp b/tjp/core/algorithm/_tests/map_erase_if.cpp new file mode 100755 index 0000000..364f1a9 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_erase_if.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_erase_if") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("evens are erased") + { + auto erased = map_erase_if( + v, [](auto &v) { return v.first % 2 == 0; } + ); + REQUIRE(erased == 50); + REQUIRE(v.size() == 50); + + WHEN("evens are erased again") + { + auto erased = map_erase_if( + v, [](auto &v) { return v.first % 2 == 0; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 50); + } + } + + WHEN("1000 is not erased") + { + auto erased = map_erase_if( + v, [](auto &v) { return v.first == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_erase_if_key.cpp b/tjp/core/algorithm/_tests/map_erase_if_key.cpp new file mode 100755 index 0000000..a629e55 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_erase_if_key.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_erase_if_key") +{ + GIVEN("a list of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("evens are erased") + { + auto erased = map_erase_if_key( + v, [](auto &v) { return v % 2 == 0; } + ); + REQUIRE(erased == 50); + REQUIRE(v.size() == 50); + + WHEN("evens are erased again") + { + auto erased = map_erase_if_key( + v, [](auto &v) { return v % 2 == 0; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 50); + } + } + + WHEN("1000 is not erased") + { + auto erased = map_erase_if_key( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_erase_if_value.cpp b/tjp/core/algorithm/_tests/map_erase_if_value.cpp new file mode 100755 index 0000000..05202ac --- /dev/null +++ b/tjp/core/algorithm/_tests/map_erase_if_value.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_erase_if_value") +{ + GIVEN("a list of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("evens are erased") + { + auto erased = map_erase_if_value( + v, [](auto &v) { return v % 2 == 0; } + ); + REQUIRE(erased == 50); + REQUIRE(v.size() == 50); + + WHEN("evens are erased again") + { + auto erased = map_erase_if_value( + v, [](auto &v) { return v % 2 == 0; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 50); + } + } + + WHEN("1000 is not erased") + { + auto erased = map_erase_if_value( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_for_each_value.cpp b/tjp/core/algorithm/_tests/map_for_each_value.cpp new file mode 100755 index 0000000..55660a4 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_for_each_value.cpp @@ -0,0 +1,33 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_for_each_value") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = 1; + + auto x = 0; + map_for_each_value( + v, + [&](auto &v) { x += v; } + ); + + REQUIRE(x == 100); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_has.cpp b/tjp/core/algorithm/_tests/map_has.cpp new file mode 100755 index 0000000..3bd51d5 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_has.cpp @@ -0,0 +1,44 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_has") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = map_has(v, 42); + REQUIRE(found); + + WHEN("1000 is not found") + { + auto found = map_has(v, 1000); + REQUIRE(!found); + } + } + + WHEN("1000 is not found") + { + auto found = map_has(v, 1000); + REQUIRE(!found); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_has_key.cpp b/tjp/core/algorithm/_tests/map_has_key.cpp new file mode 100755 index 0000000..90c74ae --- /dev/null +++ b/tjp/core/algorithm/_tests/map_has_key.cpp @@ -0,0 +1,44 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_has_key") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + auto found = map_has_key(v, 42); + REQUIRE(found); + + WHEN("1000 is not found") + { + auto found = map_has_key(v, 1000); + REQUIRE(!found); + } + } + + WHEN("1000 is not found") + { + auto found = map_has_key(v, 1000); + REQUIRE(!found); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_iterator_or_insert.cpp b/tjp/core/algorithm/_tests/map_iterator_or_insert.cpp new file mode 100755 index 0000000..ac4f5a8 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_iterator_or_insert.cpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_iterator_or_insert") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + map_iterator_insert(v, 0)->second = 42; + map_iterator_insert(v, 1000)->second = 42; + + REQUIRE(*map_value(v, 0) == 42); + REQUIRE(*map_value(v, 1000) == 42); + REQUIRE(*map_value(v, 1) == 1); + REQUIRE(map_value(v, 1001) == nullptr); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_value.cpp b/tjp/core/algorithm/_tests/map_value.cpp new file mode 100755 index 0000000..bab78c5 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_value.cpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_value") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + REQUIRE(map_value(v, 42) != nullptr); + REQUIRE(*map_value(v, 42) == 42); + } + + WHEN("1000 is not found") + { + REQUIRE(map_value(v, 1000) == nullptr); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/map_value_require.cpp b/tjp/core/algorithm/_tests/map_value_require.cpp new file mode 100755 index 0000000..f3c5444 --- /dev/null +++ b/tjp/core/algorithm/_tests/map_value_require.cpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::map_value_require") +{ + GIVEN("a map of values") + { + Map v; + for (auto i=0; i<100; ++i) + v[i] = i; + + REQUIRE(v.size() == 100); + WHEN("42 is found") + { + REQUIRE_NOTHROW(map_value_require(v, 42)); + REQUIRE(map_value_require(v, 42) == 42); + } + + WHEN("1000 is not found") + { + REQUIRE_THROWS(map_value_require(v, 1000)); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/no_throw.cpp b/tjp/core/algorithm/_tests/no_throw.cpp new file mode 100755 index 0000000..665bacb --- /dev/null +++ b/tjp/core/algorithm/_tests/no_throw.cpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::no_throw") +{ + GIVEN("throws") + { + auto throws = []() { + throw std::runtime_error("exception"); + }; + + auto nthrows = no_throw(throws); + + REQUIRE_NOTHROW(nthrows()); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/not_zero.cpp b/tjp/core/algorithm/_tests/not_zero.cpp new file mode 100755 index 0000000..982aa66 --- /dev/null +++ b/tjp/core/algorithm/_tests/not_zero.cpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::not_zero") +{ + WHEN("ranges") + { + auto minus_one = [](auto &&v) { return v - 1; }; + auto test_minus_one = not_zero(minus_one); + + REQUIRE(test_minus_one(2)); + REQUIRE(!test_minus_one(1)); + + } + +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/on_destruct.cpp b/tjp/core/algorithm/_tests/on_destruct.cpp new file mode 100755 index 0000000..92f0bf0 --- /dev/null +++ b/tjp/core/algorithm/_tests/on_destruct.cpp @@ -0,0 +1,77 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::on_destruct") +{ + GIVEN("a throw during destruct") + { + auto f = []() { + auto throws = []() { + throw std::runtime_error("exception"); + }; + + ExecuteOnDestruct x(throws, ExecuteOnDestruct::Throws); + }; + + REQUIRE_THROWS(f()); + } + + GIVEN("no throw during destruct") + { + auto f = []() { + auto throws = []() { + throw std::runtime_error("exception"); + }; + + ExecuteOnDestruct x(throws); + }; + + REQUIRE_NOTHROW(f()); + } + + GIVEN("a sequence of destructions") + { + Vector destructs; + { + auto one = on_destruct([&](){destructs.push_back(1);}); + auto two = on_destruct([&](){destructs.push_back(2);}); + auto three = on_destruct([&](){destructs.push_back(3);}); + auto four = on_destruct([&](){destructs.push_back(4);}); + } + + Vector expected = { 4, 3, 2, 1 }; + REQUIRE(destructs == expected); + } + + GIVEN("a destruct on destructs once") + { + int i = 0; + REQUIRE(i==0); + + { + auto destruct = on_destruct([&](){i++;}); + + destruct.execute(); + REQUIRE(i==1); + + destruct.execute(); + REQUIRE(i==1); + } + + REQUIRE(i==1); + } + +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/one_is.cpp b/tjp/core/algorithm/_tests/one_is.cpp new file mode 100755 index 0000000..ed0b8e4 --- /dev/null +++ b/tjp/core/algorithm/_tests/one_is.cpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::one_is") +{ + GIVEN("a vector of values") + { + Vector v; + for (auto i=0; i<50; ++i) + v.push_back(41); + + WHEN("none are 42") + { + auto one_is_42 = one_is(v, [](auto &v) { return v == 42; }); + REQUIRE(!one_is_42); + } + + WHEN("one is 42") + { + v[13] = 42; + auto one_is_42 = one_is(v, [](auto &v) { return v == 42; }); + REQUIRE(one_is_42); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/optional_value.cpp b/tjp/core/algorithm/_tests/optional_value.cpp new file mode 100755 index 0000000..854ffc7 --- /dev/null +++ b/tjp/core/algorithm/_tests/optional_value.cpp @@ -0,0 +1,28 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::optional_value") +{ + GIVEN("optional value") + { + Optional five = 5; + REQUIRE(optional_value(five) != nullptr); + REQUIRE(*optional_value(five) == 5); + + Optional empty; + REQUIRE(optional_value(empty) == nullptr); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/optional_value_or_default.cpp b/tjp/core/algorithm/_tests/optional_value_or_default.cpp new file mode 100755 index 0000000..d8623bc --- /dev/null +++ b/tjp/core/algorithm/_tests/optional_value_or_default.cpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::optional_value_or_default") +{ + GIVEN("optional value") + { + Optional five = 5; + REQUIRE(optional_value_or_default(five, 42) == 5); + + Optional empty; + REQUIRE(optional_value_or_default(empty, 42) == 42); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/set_empty.cpp b/tjp/core/algorithm/_tests/set_empty.cpp new file mode 100755 index 0000000..89c0e41 --- /dev/null +++ b/tjp/core/algorithm/_tests/set_empty.cpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::set_empty") +{ + GIVEN("optional value") + { + Set not_empty = { 1, 2, 3 }; + Set empty = {}; + + REQUIRE(set_empty(empty)); + REQUIRE(!set_empty(not_empty)); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/small_cmp.cpp b/tjp/core/algorithm/_tests/small_cmp.cpp new file mode 100755 index 0000000..0935784 --- /dev/null +++ b/tjp/core/algorithm/_tests/small_cmp.cpp @@ -0,0 +1,192 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::small_cmp") +{ + WHEN("cmp_small_a_lot") + { + Vector> profiles; + profiles.push_back({ 1, 4, 3, 7, 9, 14, 16, 8, 23, 4, 2, 3 }); + profiles.push_back({ 4, 4, 4, 4, 2, 2, 4, 4, 4, 8, 8, 8 }); + profiles.push_back({ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }); + profiles.push_back({ 16, 16, 8, 8, 8, 3, 2, 1, 1, 1, 4, 8 }); + profiles.push_back({ 4, 4, 8, 4, 8, 8, 4, 4, 2, 2, 2, 2 }); + + constexpr auto max = 2048; + char d_[max + 128]; + char s_[max + 128]; + + auto sum = 0; + + for (auto i=0; i 0 ? 1 : 0); + auto r1v = r1 < 0 ? -1 : (r1 > 0 ? 1 : 0); + if (r0v != r1v) + { + auto rx = small_cmp(d, readSize, s, readSize); + unused(rx); + REQUIRE(false); + } + + d += readSize; + s += readSize; + size += readSize; + } + } + + // ------- + + + timer.start(); + for (auto i=0; i + +#include +#include +#include + +#include "../../log/LogOf.h" + +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::small_copy") +{ + WHEN("read_small_a_lot") + { + Vector> profiles; + profiles.push_back({ 1, 4, 3, 7, 9, 14, 16, 8, 23, 4, 2, 3 }); + profiles.push_back({ 4, 4, 4, 4, 2, 2, 4, 4, 4, 8, 8, 8 }); + profiles.push_back({ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8 }); + profiles.push_back({ 16, 16, 8, 8, 8, 3, 2, 1, 1, 1, 4, 8 }); + profiles.push_back({ 4, 4, 8, 4, 8, 8, 4, 4, 2, 2, 2, 2 }); + + constexpr auto max = 2048; + char d_[max + 128]; + char s_[max + 128]; + auto numCycles = 32768; + + for (auto &chunks : profiles) + { + std::this_thread::sleep_for(std::chrono::milliseconds(100)); + + Timer timer(false); + + auto *reads = chunks.data(); + auto numReads = chunks.size(); + + timer.start(); + for (auto i=0; i + +#include +#include +#include +#include + +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::starts_with") +{ + WHEN("Vector value") + { + Vector v = { 1, 2, 3, 4, 5 }; + auto starts_with_123 = starts_with(v, Vector {1,2,3}); + REQUIRE(starts_with_123); + + auto starts_with_456 = starts_with(v, Vector {4,5,6}); + REQUIRE(!starts_with_456); + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/vector_append.cpp b/tjp/core/algorithm/_tests/vector_append.cpp new file mode 100755 index 0000000..13fd876 --- /dev/null +++ b/tjp/core/algorithm/_tests/vector_append.cpp @@ -0,0 +1,41 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::vector_append") +{ + GIVEN("vector") + { + WHEN("using an empty vector") + { + Vector empty = {}; + Vector append = { 4, 5, 6 }; + + vector_append(empty, append); + auto expected = append; + REQUIRE(empty == expected); + } + + WHEN("using a non empty vector") + { + Vector not_empty = { 1, 2, 3 }; + Vector append = { 4, 5, 6 }; + + vector_append(not_empty, append); + Vector expected = { 1, 2, 3, 4, 5, 6 }; + REQUIRE(not_empty == expected); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/vector_erase_if_value.cpp b/tjp/core/algorithm/_tests/vector_erase_if_value.cpp new file mode 100755 index 0000000..2714b05 --- /dev/null +++ b/tjp/core/algorithm/_tests/vector_erase_if_value.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::vector_erase_if_value") +{ + GIVEN("a list of values") + { + Vector v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = vector_erase_if_value( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(erased == 4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = vector_erase_if_value( + v, [](auto &v) { return v == 10; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = vector_erase_if_value( + v, [](auto &v) { return v == 1000; } + ); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/vector_erase_value_all.cpp b/tjp/core/algorithm/_tests/vector_erase_value_all.cpp new file mode 100755 index 0000000..68c38dc --- /dev/null +++ b/tjp/core/algorithm/_tests/vector_erase_value_all.cpp @@ -0,0 +1,47 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::vector_erase_value_all") +{ + GIVEN("a list of values") + { + Vector v; + for (auto i=0; i<100; ++i) + v.push_back(i / 4); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = vector_erase_value_all(v, 10); + REQUIRE(erased==4); + REQUIRE(v.size() == 96); + + WHEN("10 is erased again") + { + auto erased = vector_erase_value_all(v, 10); + REQUIRE(!erased); + REQUIRE(v.size() == 96); + } + } + + WHEN("1000 is not erased") + { + auto erased = vector_erase_value_all(v, 1000); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/_tests/vector_erase_value_one.cpp b/tjp/core/algorithm/_tests/vector_erase_value_one.cpp new file mode 100755 index 0000000..09e8076 --- /dev/null +++ b/tjp/core/algorithm/_tests/vector_erase_value_one.cpp @@ -0,0 +1,52 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include + +namespace tjp::core::algorithm { +namespace { + +SCENARIO("core::algorithm::vector_erase_value_one") +{ + GIVEN("a list of values") + { + Vector v; + for (auto i=0; i<98; ++i) + v.push_back(i / 4); + + v.push_back(9999); + v.push_back(999); + + REQUIRE(v.size() == 100); + WHEN("10 is erased") + { + auto erased = vector_erase_value_one(v, 10); + REQUIRE(erased); + REQUIRE(v.size() == 99); + REQUIRE(v[10 * 4] == 999); + + WHEN("10 is erased again") + { + auto erased = vector_erase_value_one(v, 10); + REQUIRE(erased); + REQUIRE(v.size() == 98); + REQUIRE(v[10 * 4 + 1] == 9999); + } + } + + WHEN("1000 is not erased") + { + auto erased = vector_erase_value_one(v, 1000); + REQUIRE(!erased); + REQUIRE(v.size() == 100); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/algorithm/all_are.hpp b/tjp/core/algorithm/all_are.hpp new file mode 100755 index 0000000..d843728 --- /dev/null +++ b/tjp/core/algorithm/all_are.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool all_are(const T &l, F &&f) +{ + for (auto &v: l) + if (!f(v)) + return false; + + return true; +} + +} // namespace diff --git a/tjp/core/algorithm/cmp.hpp b/tjp/core/algorithm/cmp.hpp new file mode 100755 index 0000000..d9fec13 --- /dev/null +++ b/tjp/core/algorithm/cmp.hpp @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +int cmp(const T &l, const T &r) +{ + if (l == r) + return 0; + + return l < r ? -1 : 1; +} + +} // namespace diff --git a/tjp/core/algorithm/container_count_if.hpp b/tjp/core/algorithm/container_count_if.hpp new file mode 100755 index 0000000..3f3f49c --- /dev/null +++ b/tjp/core/algorithm/container_count_if.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +size_t container_count_if (const T &c, F &&f) +{ + size_t count = 0; + for (auto &v: c) + if (f(v)) + count++; + + return count; +} + +} // namespace diff --git a/tjp/core/algorithm/container_erase_if.hpp b/tjp/core/algorithm/container_erase_if.hpp new file mode 100755 index 0000000..c5a7872 --- /dev/null +++ b/tjp/core/algorithm/container_erase_if.hpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../iterators/safe_next.hpp" + +namespace tjp::core { + +template +auto container_erase_if (T &c, F &&f) +{ + size_t erased = 0; + for (auto i: safe_next(c)) + { + if (f(*i)) + { + c.erase(i); + ++erased; + } + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/container_erase_if_imp_use_iterator.hpp b/tjp/core/algorithm/container_erase_if_imp_use_iterator.hpp new file mode 100755 index 0000000..849b102 --- /dev/null +++ b/tjp/core/algorithm/container_erase_if_imp_use_iterator.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_erase_if_imp_use_iterator(T &v, F &&f) +{ + size_t erased = 0; + + auto i = v.begin(); + while (i != v.end()) + { + if (f(*i)) + { + i = v.erase(i); + ++erased; + } + else + ++i; + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/container_erase_if_one.hpp b/tjp/core/algorithm/container_erase_if_one.hpp new file mode 100755 index 0000000..81ee6cb --- /dev/null +++ b/tjp/core/algorithm/container_erase_if_one.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_erase_if_one (T &c, F &&f) +{ + auto i = std::find_if(c.begin(), c.end(), std::forward(f)); + + if (i != c.end()) + { + c.erase(i); + return true; + } + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/container_erase_value_all.hpp b/tjp/core/algorithm/container_erase_value_all.hpp new file mode 100755 index 0000000..eba3449 --- /dev/null +++ b/tjp/core/algorithm/container_erase_value_all.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_erase_value_all (T &v, U &&u) +{ + size_t erased = 0; + + auto i = v.begin(); + while (i != v.end()) + { + if ((*i) == std::forward(u)) + { + i = v.erase(i); + ++erased; + } + else + ++i; + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/container_erase_value_one.hpp b/tjp/core/algorithm/container_erase_value_one.hpp new file mode 100755 index 0000000..9b3e972 --- /dev/null +++ b/tjp/core/algorithm/container_erase_value_one.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_erase_value_one (T &c, U &&u) +{ + auto i = std::find(c.begin(), c.end(), std::forward(u)); + + if (i != c.end()) + { + c.erase(i); + return true; + } + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/container_find_if.hpp b/tjp/core/algorithm/container_find_if.hpp new file mode 100755 index 0000000..68ccd63 --- /dev/null +++ b/tjp/core/algorithm/container_find_if.hpp @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_find_if (T &c, F &&f) +{ + return std::find_if(c.begin(), c.end(), std::forward(f)); +} + + +} // namespace diff --git a/tjp/core/algorithm/container_get_if.hpp b/tjp/core/algorithm/container_get_if.hpp new file mode 100755 index 0000000..c7e0818 --- /dev/null +++ b/tjp/core/algorithm/container_get_if.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto container_get_if (T &&c, F &&u) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + auto i = std::find_if(c.begin(), c.end(), std::forward(u)); + + if (i != c.end()) + { + return &*i; + } + + typedef decltype(&*i) R; + return (R)nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/container_get_if_optional.hpp b/tjp/core/algorithm/container_get_if_optional.hpp new file mode 100755 index 0000000..401d47b --- /dev/null +++ b/tjp/core/algorithm/container_get_if_optional.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto container_get_if_optional (const T &c, F &&u) +{ + auto i = std::find_if(c.begin(), c.end(), std::forward(u)); + + if (i != c.end()) + { + return std::make_optional(*i); + } + + return std::optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/container_get_if_optional_erase.hpp b/tjp/core/algorithm/container_get_if_optional_erase.hpp new file mode 100755 index 0000000..4b556a9 --- /dev/null +++ b/tjp/core/algorithm/container_get_if_optional_erase.hpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto container_get_if_optional_erase (T &c, F &&u) +{ + auto i = std::find_if(c.begin(), c.end(), std::forward(u)); + + if (i != c.end()) + { + auto result = std::make_optional(std::move(*i)); + c.erase(i); + return result; + } + + return std::optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/container_get_optional_erase.hpp b/tjp/core/algorithm/container_get_optional_erase.hpp new file mode 100755 index 0000000..94be859 --- /dev/null +++ b/tjp/core/algorithm/container_get_optional_erase.hpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto container_get_optional_erase (T &c, U &&u) +{ + auto i = std::find(c.begin(), c.end(), std::forward(u)); + + if (i != c.end()) + { + auto result = std::make_optional(*i); + c.erase(i); + return result; + } + + return std::optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/container_has.hpp b/tjp/core/algorithm/container_has.hpp new file mode 100755 index 0000000..2772b30 --- /dev/null +++ b/tjp/core/algorithm/container_has.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +bool container_has (const T &c, const U &v) +{ + return std::find(c.begin(), c.end(), v) != c.end(); +} + +} // namespace diff --git a/tjp/core/algorithm/container_has_if.hpp b/tjp/core/algorithm/container_has_if.hpp new file mode 100755 index 0000000..7230e9d --- /dev/null +++ b/tjp/core/algorithm/container_has_if.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +bool container_has_if (const T &c, F &&f) +{ + return std::find_if(c.begin(), c.end(), std::forward(f)) != c.end(); +} + +} // namespace diff --git a/tjp/core/algorithm/copy_clear.hpp b/tjp/core/algorithm/copy_clear.hpp new file mode 100755 index 0000000..88bd711 --- /dev/null +++ b/tjp/core/algorithm/copy_clear.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template::value || std::is_pointer::value), T>::type* = nullptr> +T copy_clear(T &t) +{ + T t_{0}; + std::swap(t, t_); + return t_; +} + +template::value || std::is_pointer::value), T>::type* = nullptr> +T copy_clear(T &t, T &&t_=T()) +{ + std::swap(t, t_); + return t_; +} + +} // namespace diff --git a/tjp/core/algorithm/copy_clear_delete.hpp b/tjp/core/algorithm/copy_clear_delete.hpp new file mode 100755 index 0000000..77f756d --- /dev/null +++ b/tjp/core/algorithm/copy_clear_delete.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto copy_clear_delete(T *&t) +{ + T *t_{0}; + std::swap(t, t_); + return unique_ptr(t_); +} + +} // namespace diff --git a/tjp/core/algorithm/copy_of.hpp b/tjp/core/algorithm/copy_of.hpp new file mode 100755 index 0000000..ccd4d0a --- /dev/null +++ b/tjp/core/algorithm/copy_of.hpp @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +T copy_of(const T &t) +{ + return t; +} + +} // namespace diff --git a/tjp/core/algorithm/emplace.hpp b/tjp/core/algorithm/emplace.hpp new file mode 100755 index 0000000..f8cc10b --- /dev/null +++ b/tjp/core/algorithm/emplace.hpp @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +void emplace(T &t, Args && ...args) +{ + t = T(std::forward(args)...); +} + +template +auto emplace(T &t, T &&rhs) +{ + t = std::move(rhs); +} + +} // namespace diff --git a/tjp/core/algorithm/empty_of.hpp b/tjp/core/algorithm/empty_of.hpp new file mode 100755 index 0000000..c260074 --- /dev/null +++ b/tjp/core/algorithm/empty_of.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +const M &empty_of() +{ + static M m; + return m; +} + +} // namespace diff --git a/tjp/core/algorithm/ends_with.hpp b/tjp/core/algorithm/ends_with.hpp new file mode 100755 index 0000000..835ecc2 --- /dev/null +++ b/tjp/core/algorithm/ends_with.hpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../string/StringView.hpp" + +namespace tjp::core { + +template +bool ends_with (const T &c1, const U &c2) +{ + if (c2.size() > c1.size()) + return false; + + auto offset = c1.size() - c2.size(); + + auto c1i = c1.begin() + offset; + auto c2i = c2.begin(); + while (c2i != c2.end()) + { + if (*c1i != *c2i) + return false; + + ++c1i; + ++c2i; + } + + return true; +} + +template +bool ends_with (const T &c1, const char *c2) +{ + return ends_with(c1, StringView(c2)); +} + + +} // namespace diff --git a/tjp/core/algorithm/has_last.hpp b/tjp/core/algorithm/has_last.hpp new file mode 100755 index 0000000..e380840 --- /dev/null +++ b/tjp/core/algorithm/has_last.hpp @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool has_last(T &t, F &&f) +{ + return !t.empty() && f(t.back()); +} + +} // namespace diff --git a/tjp/core/algorithm/has_sequence.hpp b/tjp/core/algorithm/has_sequence.hpp new file mode 100755 index 0000000..6f1e0f8 --- /dev/null +++ b/tjp/core/algorithm/has_sequence.hpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool has_sequence (const T &c1, const U &c2) +{ + if (c2.size() > c1.size()) + return false; + + auto end = c1.size() - c2.size(); + + for (auto offset = 0; offset <= end; ++offset) + { + auto c1i = c1.begin() + offset; + auto c2i = c2.begin(); + while (c2i != c2.end()) + { + if (*c1i != *c2i) + break; + + ++c1i; + ++c2i; + } + + if (c2i == c2.end()) + return true; + } + + return false; +} + + +} // namespace diff --git a/tjp/core/algorithm/in_range_segment.hpp b/tjp/core/algorithm/in_range_segment.hpp new file mode 100755 index 0000000..bf22c72 --- /dev/null +++ b/tjp/core/algorithm/in_range_segment.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +constexpr +bool in_range_segment(const V &v, const L &offset, const R &size) +{ + return (v >= offset) && (v < (offset + size)); +} + +} // namespace diff --git a/tjp/core/algorithm/is_in.hpp b/tjp/core/algorithm/is_in.hpp new file mode 100755 index 0000000..073f430 --- /dev/null +++ b/tjp/core/algorithm/is_in.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +// https://stackoverflow.com/questions/15181579/c-most-efficient-way-to-compare-a-variable-to-multiple-values + +#pragma once + +namespace tjp::core { + +template +constexpr bool is_in(First &&first, const T & ... t) +{ + return ((first == t) || ...); +} + +} // namespace diff --git a/tjp/core/algorithm/is_zero.hpp b/tjp/core/algorithm/is_zero.hpp new file mode 100755 index 0000000..a55f408 --- /dev/null +++ b/tjp/core/algorithm/is_zero.hpp @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +constexpr auto is_zero(F &&f) { + return [f](auto &&v) { return f(v) == 0; }; +} + +} // namespace diff --git a/tjp/core/algorithm/last_of_parameter_pack.hpp b/tjp/core/algorithm/last_of_parameter_pack.hpp new file mode 100755 index 0000000..73081c2 --- /dev/null +++ b/tjp/core/algorithm/last_of_parameter_pack.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +constexpr +decltype(auto) last_of_parameter_pack(Args&&... args){ + return (std::forward(args), ...); +} + +} // namespace diff --git a/tjp/core/algorithm/list_erase_if.hpp b/tjp/core/algorithm/list_erase_if.hpp new file mode 100755 index 0000000..5768115 --- /dev/null +++ b/tjp/core/algorithm/list_erase_if.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "container_erase_if_imp_use_iterator.hpp" + +namespace tjp::core { + +template +auto list_erase_if(T &v, F &&f) +{ + return container_erase_if_imp_use_iterator(v, std::forward(f)); +} + +} // namespace diff --git a/tjp/core/algorithm/list_erase_if_value.hpp b/tjp/core/algorithm/list_erase_if_value.hpp new file mode 100755 index 0000000..ef213ab --- /dev/null +++ b/tjp/core/algorithm/list_erase_if_value.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "list_erase_if.hpp" + +namespace tjp::core { + +template +auto list_erase_if_value(T &v, F &&f) +{ + return list_erase_if(v, std::forward(f)); +} + +} // namespace diff --git a/tjp/core/algorithm/list_erase_value_all.hpp b/tjp/core/algorithm/list_erase_value_all.hpp new file mode 100755 index 0000000..e5ff07c --- /dev/null +++ b/tjp/core/algorithm/list_erase_value_all.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "container_erase_value_all.hpp" + +namespace tjp::core { + +template +bool list_erase_value_all(M &m, K &&k) +{ + return container_erase_value_all(m, std::forward(k)); +} + +} // namespace diff --git a/tjp/core/algorithm/list_erase_value_one.hpp b/tjp/core/algorithm/list_erase_value_one.hpp new file mode 100755 index 0000000..ee5235b --- /dev/null +++ b/tjp/core/algorithm/list_erase_value_one.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "container_erase_value_one.hpp" + +namespace tjp::core { + +template +bool list_erase_value_one(M &m, K &&k) +{ + return container_erase_value_one(m, std::forward(k)); +} + +} // namespace diff --git a/tjp/core/algorithm/map_erase.hpp b/tjp/core/algorithm/map_erase.hpp new file mode 100755 index 0000000..b6f60e2 --- /dev/null +++ b/tjp/core/algorithm/map_erase.hpp @@ -0,0 +1,24 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto map_erase(T &map, K &&k) +{ + auto i = map.find(std::forward(k)); + if (i != map.end()) + { + map.erase(i); + return true; + } + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/map_erase_get_optional.hpp b/tjp/core/algorithm/map_erase_get_optional.hpp new file mode 100755 index 0000000..dd9d307 --- /dev/null +++ b/tjp/core/algorithm/map_erase_get_optional.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto map_erase_get_optional(T &map, K &&k) +{ + auto i = map.find(std::forward(k)); + if (i != map.end()) + { + auto v = std::make_optional(i->second); + map.erase(i); + return v; + } + + return std::optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/map_erase_if.hpp b/tjp/core/algorithm/map_erase_if.hpp new file mode 100755 index 0000000..0ef7551 --- /dev/null +++ b/tjp/core/algorithm/map_erase_if.hpp @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_erase_if(T &map, F &&f) +{ + int erased = 0; + + auto i = map.begin(); + while (i != map.end()) + { + if (f(*i)) + { + ++erased; + i = map.erase(i); + } + else + ++i; + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/map_erase_if_key.hpp b/tjp/core/algorithm/map_erase_if_key.hpp new file mode 100755 index 0000000..1a26cc3 --- /dev/null +++ b/tjp/core/algorithm/map_erase_if_key.hpp @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_erase_if_key(T &map, F &&f) +{ + int erased = 0; + + auto i = map.begin(); + while (i != map.end()) + { + if (f(i->first)) + { + ++erased; + i = map.erase(i); + } + else + ++i; + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/map_erase_if_value.hpp b/tjp/core/algorithm/map_erase_if_value.hpp new file mode 100755 index 0000000..b749fe6 --- /dev/null +++ b/tjp/core/algorithm/map_erase_if_value.hpp @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_erase_if_value(T &map, F &&f) +{ + int erased = 0; + + auto i = map.begin(); + while (i != map.end()) + { + if (f(i->second)) + { + ++erased; + i = map.erase(i); + } + else + ++i; + } + + return erased; +} + +} // namespace diff --git a/tjp/core/algorithm/map_for_each_value.hpp b/tjp/core/algorithm/map_for_each_value.hpp new file mode 100755 index 0000000..bc0203f --- /dev/null +++ b/tjp/core/algorithm/map_for_each_value.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_for_each_value(T &map, F &&f) +{ + for (auto i=map.begin(); i!=map.end(); ++i) + f(i->second); +} + +} // namespace diff --git a/tjp/core/algorithm/map_has.hpp b/tjp/core/algorithm/map_has.hpp new file mode 100755 index 0000000..933806c --- /dev/null +++ b/tjp/core/algorithm/map_has.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto map_has(const M &m, K &&k) +{ + return m.find(std::forward(k)) != m.end(); +} + +} // namespace diff --git a/tjp/core/algorithm/map_has_key.hpp b/tjp/core/algorithm/map_has_key.hpp new file mode 100755 index 0000000..ba35ab9 --- /dev/null +++ b/tjp/core/algorithm/map_has_key.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "map_has.hpp" + +namespace tjp::core { + +template +bool map_has_key (const M &m, K &&k) +{ + return map_has(m, std::forward(k)); +} + +} // namespace diff --git a/tjp/core/algorithm/map_insert.hpp b/tjp/core/algorithm/map_insert.hpp new file mode 100755 index 0000000..445063c --- /dev/null +++ b/tjp/core/algorithm/map_insert.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto map_insert(M &&m, K &&k, V &&v) +{ + auto [i, inserted] = m.emplace(std::forward(k), std::forward(v)); + + return inserted; +} + +} // namespace diff --git a/tjp/core/algorithm/map_iterator_or_insert.hpp b/tjp/core/algorithm/map_iterator_or_insert.hpp new file mode 100755 index 0000000..f25dcc8 --- /dev/null +++ b/tjp/core/algorithm/map_iterator_or_insert.hpp @@ -0,0 +1,35 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_iterator_insert(M &m, const K &k) +{ + typedef typename M::mapped_type R; + + auto i = m.find(k); + if (i != m.end()) + return i; + + auto [j, inserted] = m.emplace(k, R()); + + return j; +} + +template +auto map_iterator_insert(M &m, const K &k, F &&f) +{ + auto i = m.find(k); + if (i != m.end()) + return i; + + auto [j, inserted] = m.emplace(k, f()); + + return j; +} + +} // namespace diff --git a/tjp/core/algorithm/map_pair.hpp b/tjp/core/algorithm/map_pair.hpp new file mode 100755 index 0000000..90b2341 --- /dev/null +++ b/tjp/core/algorithm/map_pair.hpp @@ -0,0 +1,32 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_pair(const M &m, K &&k) +{ + typedef typename M::value_type *R; + auto i = m.find(std::forward(k)); + if (i != m.end()) + return &*i; + + return (R)nullptr; +} + +template +auto map_pair(M &m, K &&k) +{ + typedef typename M::value_type const *R; + + auto i = m.find(std::forward(k)); + if (i != m.end()) + return &*i; + + return (R)nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/map_set_or_erase_optional.hpp b/tjp/core/algorithm/map_set_or_erase_optional.hpp new file mode 100755 index 0000000..d0f156a --- /dev/null +++ b/tjp/core/algorithm/map_set_or_erase_optional.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "map_erase.hpp" + +namespace tjp::core { + +template +auto map_set_or_erase_optional(M &m, K &&k, V &&v) +{ + if (v) + m[k] = *v; + else + map_erase(m, k); +} + +} // namespace diff --git a/tjp/core/algorithm/map_value.hpp b/tjp/core/algorithm/map_value.hpp new file mode 100755 index 0000000..f53f5d9 --- /dev/null +++ b/tjp/core/algorithm/map_value.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto map_value(M &&m, K &&k) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = m.find(std::forward(k)); + + return + (i != m.end()) ? + &i->second : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_erase.hpp b/tjp/core/algorithm/map_value_erase.hpp new file mode 100755 index 0000000..494f1f9 --- /dev/null +++ b/tjp/core/algorithm/map_value_erase.hpp @@ -0,0 +1,28 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Optional.hpp" + +namespace tjp::core { + +template +auto map_value_erase(M &m, K &&k) +{ + typedef typename M::mapped_type R; + + auto i = m.find(std::forward(k)); + if (i != m.end()) + { + auto result = Optional(std::move(i->second)); + m.erase(i); + + return result; + } + + return Optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_optional.hpp b/tjp/core/algorithm/map_value_optional.hpp new file mode 100755 index 0000000..9748bef --- /dev/null +++ b/tjp/core/algorithm/map_value_optional.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Optional.hpp" + +namespace tjp::core { + +template +auto map_value_optional(M &m, K &&k) +{ + typedef typename M::mapped_type R; + + auto i = m.find(std::forward(k)); + if (i != m.end()) + { + return Optional(std::move(i->second)); + } + + return Optional(); +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_or_default.hpp b/tjp/core/algorithm/map_value_or_default.hpp new file mode 100755 index 0000000..bc1c102 --- /dev/null +++ b/tjp/core/algorithm/map_value_or_default.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +R map_value_or_default(const M &m, K &&k, V &&v) +{ + auto i = m.find(std::forward(k)); + if (i != m.end()) + return i->second; + + return R(v); +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_or_insert.hpp b/tjp/core/algorithm/map_value_or_insert.hpp new file mode 100755 index 0000000..a671a4e --- /dev/null +++ b/tjp/core/algorithm/map_value_or_insert.hpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto &map_value_or_insert(M &m, const K &k, const F &f) +{ + auto i = m.find(k); + if (i != m.end()) + return i->second; + + auto [j, inserted] = m.emplace(k, f()); + + return j->second; +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_or_insert_value.hpp b/tjp/core/algorithm/map_value_or_insert_value.hpp new file mode 100755 index 0000000..8bdfe27 --- /dev/null +++ b/tjp/core/algorithm/map_value_or_insert_value.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto map_value_or_insert_value(M &m, K &&k, V &&v) +{ + auto [i, inserted] = m.emplace(std::forward(k), std::forward(v)); + return &i->second; +} + +} // namespace diff --git a/tjp/core/algorithm/map_value_require.hpp b/tjp/core/algorithm/map_value_require.hpp new file mode 100755 index 0000000..e1396c2 --- /dev/null +++ b/tjp/core/algorithm/map_value_require.hpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../exception/Exception.hpp" + +namespace tjp::core { + +template +auto &map_value_require(M &m, K &&k) +{ + auto i = m.find(std::forward(k)); + if (i == m.end()) + throw Exception { "Map missing key" }; + + return i->second; +} + +} // namespace diff --git a/tjp/core/algorithm/mem_copy.hpp b/tjp/core/algorithm/mem_copy.hpp new file mode 100755 index 0000000..e71ce87 --- /dev/null +++ b/tjp/core/algorithm/mem_copy.hpp @@ -0,0 +1,30 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "small_copy.hpp" +#include + +namespace tjp::core { + +inline +char *mem_copy(char *d, const char *s, size_t size) +{ + if (!maybe_small_copy(d, s, size)) + memcpy(d, s, size); + + return d + size; +} + +inline +size_t mem_copy_(char *d, const char *s, size_t size) +{ + if (!maybe_small_copy(d, s, size)) + memcpy(d, s, size); + + return size; +} + +} // namespace diff --git a/tjp/core/algorithm/mem_copy_asan_safe.hpp b/tjp/core/algorithm/mem_copy_asan_safe.hpp new file mode 100755 index 0000000..bf6b268 --- /dev/null +++ b/tjp/core/algorithm/mem_copy_asan_safe.hpp @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +inline +char *mem_copy_asan_safe(char *d, const char *s, size_t size) +{ + for (auto i=0; i + +namespace tjp::core { + +template +constexpr auto no_throw(F &&f) { + + return [f=std::forward(f)](auto && ...args) noexcept { + try + { + f(std::forward(args)...); + } + catch (...) + { + // + } + }; +} + +} // namespace diff --git a/tjp/core/algorithm/not_zero.hpp b/tjp/core/algorithm/not_zero.hpp new file mode 100755 index 0000000..6a01f73 --- /dev/null +++ b/tjp/core/algorithm/not_zero.hpp @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +constexpr auto not_zero(F &&f) { + return [f](auto &&v) { return f(v) != 0; }; +} + +} // namespace diff --git a/tjp/core/algorithm/numeric_limits.hpp b/tjp/core/algorithm/numeric_limits.hpp new file mode 100755 index 0000000..b4f032e --- /dev/null +++ b/tjp/core/algorithm/numeric_limits.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include "../types/Types.h" + +#pragma once + +namespace tjp::core { + +template +struct numeric_limits_ext {}; + +template<> +struct numeric_limits_ext { + static constexpr s32 random_max = 1 << std::numeric_limits::digits; +}; + +template<> +struct numeric_limits_ext { + static constexpr s64 random_max = 1 << std::numeric_limits::digits; +}; + + +} // namespace diff --git a/tjp/core/algorithm/on_destruct.hpp b/tjp/core/algorithm/on_destruct.hpp new file mode 100755 index 0000000..c0cff66 --- /dev/null +++ b/tjp/core/algorithm/on_destruct.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "ExecuteOnDestruct.hpp" + +namespace tjp::core { + +template +auto on_destruct(F &&f) { + return ExecuteOnDestruct(std::forward(f)); +} + +} // namespace diff --git a/tjp/core/algorithm/one_is.hpp b/tjp/core/algorithm/one_is.hpp new file mode 100755 index 0000000..a627dde --- /dev/null +++ b/tjp/core/algorithm/one_is.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool one_is(const T &l, F &&f) +{ + for (auto &v: l) + if (f(v)) + return true; + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/optional_of_ptr.hpp b/tjp/core/algorithm/optional_of_ptr.hpp new file mode 100755 index 0000000..3680aff --- /dev/null +++ b/tjp/core/algorithm/optional_of_ptr.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto optional_of_ptr(const V *m) +{ + return m ? + Optional(*m) : + Optional{}; +} + +} // namespace diff --git a/tjp/core/algorithm/optional_set_if_empty.hpp b/tjp/core/algorithm/optional_set_if_empty.hpp new file mode 100755 index 0000000..50a69c2 --- /dev/null +++ b/tjp/core/algorithm/optional_set_if_empty.hpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool optional_set_if_empty(V &&m, T &&t) +{ + if (!m.has_value()) + { + m.emplace(std::forward(t)); + return true; + } + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/optional_value.hpp b/tjp/core/algorithm/optional_value.hpp new file mode 100755 index 0000000..bbea3ab --- /dev/null +++ b/tjp/core/algorithm/optional_value.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once +#include + +namespace tjp::core { + +template +auto *optional_value(V &&m) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + return m ? + &*m : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/optional_value_or_default.hpp b/tjp/core/algorithm/optional_value_or_default.hpp new file mode 100755 index 0000000..ebdb418 --- /dev/null +++ b/tjp/core/algorithm/optional_value_or_default.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto optional_value_or_default(M &&m, const V &v) +{ + return m ? + *m : + v; +} + +} // namespace diff --git a/tjp/core/algorithm/remove_const_of_var.hpp b/tjp/core/algorithm/remove_const_of_var.hpp new file mode 100644 index 0000000..c1b143d --- /dev/null +++ b/tjp/core/algorithm/remove_const_of_var.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +T &remove_const_of_var(const T &t) +{ + return const_cast(t); +} + +template +T *remove_const_of_var(const T *t) +{ + return const_cast(t); +} + +} // namespace + diff --git a/tjp/core/algorithm/set_empty.hpp b/tjp/core/algorithm/set_empty.hpp new file mode 100755 index 0000000..a687f7f --- /dev/null +++ b/tjp/core/algorithm/set_empty.hpp @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto set_empty(M &&m) +{ + return m.empty(); +} + +} // namespace diff --git a/tjp/core/algorithm/set_erase.hpp b/tjp/core/algorithm/set_erase.hpp new file mode 100755 index 0000000..cee3d7c --- /dev/null +++ b/tjp/core/algorithm/set_erase.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool set_erase(M &m, K &&k) +{ + auto i = m.find(std::forward(k)); + if (i != m.end()) + { + m.erase(i); + return true; + } + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/set_erase_if_value.hpp b/tjp/core/algorithm/set_erase_if_value.hpp new file mode 100755 index 0000000..d4ea0fa --- /dev/null +++ b/tjp/core/algorithm/set_erase_if_value.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "container_erase_if_imp_use_iterator.hpp" + +namespace tjp::core { + +template +auto set_erase_if_value(T &v, F &&f) +{ + return container_erase_if_imp_use_iterator(v, std::forward(f)); +} + +} // namespace diff --git a/tjp/core/algorithm/set_erase_optional_value.hpp b/tjp/core/algorithm/set_erase_optional_value.hpp new file mode 100755 index 0000000..bbedc7d --- /dev/null +++ b/tjp/core/algorithm/set_erase_optional_value.hpp @@ -0,0 +1,29 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto set_erase_optional_value(T &v, K &&k) +{ + auto i = v.find(std::forward(k)); + + using OV = decltype(std::make_optional(*i)); + + if (i != v.end()) + { + auto ov = std::make_optional(*i); + v.erase(i); + + return ov; + } + + return OV {}; +} + +} // namespace diff --git a/tjp/core/algorithm/set_erase_optional_value_move.hpp b/tjp/core/algorithm/set_erase_optional_value_move.hpp new file mode 100755 index 0000000..6105c31 --- /dev/null +++ b/tjp/core/algorithm/set_erase_optional_value_move.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +#include "remove_const_of_var.hpp" + +namespace tjp::core { + +template +auto set_erase_optional_value_move(T &v, K &&k) +{ + auto i = v.find(std::forward(k)); + + using OV = decltype(std::make_optional(*i)); + + if (i != v.end()) + { + auto ov = std::make_optional(std::move(remove_const_of_var(*i))); + v.erase(i); + + return ov; + } + + return OV {}; +} + +} // namespace diff --git a/tjp/core/algorithm/set_has.hpp b/tjp/core/algorithm/set_has.hpp new file mode 100755 index 0000000..468bb04 --- /dev/null +++ b/tjp/core/algorithm/set_has.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto set_has(const M &m, K &&k) +{ + return m.find(std::forward(k)) != m.end(); +} + +} // namespace diff --git a/tjp/core/algorithm/set_insert.hpp b/tjp/core/algorithm/set_insert.hpp new file mode 100755 index 0000000..5fa7e05 --- /dev/null +++ b/tjp/core/algorithm/set_insert.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "remove_const_of_var.hpp" +#include + +namespace tjp::core { + +template +auto set_insert(M &m, K &&k) +{ + auto i = m.insert(std::forward(k)); + return &*i.first; +} + +} // namespace diff --git a/tjp/core/algorithm/set_insert_mutable.hpp b/tjp/core/algorithm/set_insert_mutable.hpp new file mode 100755 index 0000000..66ec40e --- /dev/null +++ b/tjp/core/algorithm/set_insert_mutable.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "remove_const_of_var.hpp" +#include + +namespace tjp::core { + +template +auto set_insert_mutable(M &m, K &&k) +{ + auto i = m.insert(std::forward(k)); + return remove_const_of_var(&*i.first); +} + +} // namespace diff --git a/tjp/core/algorithm/set_insert_once.hpp b/tjp/core/algorithm/set_insert_once.hpp new file mode 100755 index 0000000..e5d27ad --- /dev/null +++ b/tjp/core/algorithm/set_insert_once.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool set_insert_once(M &m, K &&k) +{ + auto [i, inserted] = m.insert(std::forward(k)); + return inserted; +} + +} // namespace diff --git a/tjp/core/algorithm/set_once.hpp b/tjp/core/algorithm/set_once.hpp new file mode 100755 index 0000000..0822fbb --- /dev/null +++ b/tjp/core/algorithm/set_once.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool set_once(M &m, K &&k) +{ + if (m != k) + { + m = k; + return true; + } + + return false; +} + +bool set_once(bool &v) +{ + return set_once(v, true); +} + +} // namespace diff --git a/tjp/core/algorithm/set_value.hpp b/tjp/core/algorithm/set_value.hpp new file mode 100755 index 0000000..6cbfb77 --- /dev/null +++ b/tjp/core/algorithm/set_value.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "remove_const_of_var.hpp" + +namespace tjp::core { + +template +auto set_value(M &&m, K &&k) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = m.find(std::forward(k)); + return (i != m.end()) ? + &*i : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/set_value_mutable.hpp b/tjp/core/algorithm/set_value_mutable.hpp new file mode 100755 index 0000000..c0e3107 --- /dev/null +++ b/tjp/core/algorithm/set_value_mutable.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "remove_const_of_var.hpp" + +namespace tjp::core { + +template +auto set_value_mutable(M &&m, K &&k) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = m.find(std::forward(k)); + return (i != m.end()) ? + remove_const_of_var(&*i) : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/small_cmp.hpp b/tjp/core/algorithm/small_cmp.hpp new file mode 100755 index 0000000..85a45fa --- /dev/null +++ b/tjp/core/algorithm/small_cmp.hpp @@ -0,0 +1,282 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../types/Types.h" +#include + +namespace tjp::core { + +#define __v1_cmp_l_r(v, l, r) v = *l++ - *r++; if (v != 0) return v > 0 ? 1 : -1; + +inline +int small_cmp_v1(const void *l_, size_t lsize, const void *r_, size_t rsize) +{ + u8 *l = (u8 *)l_; + u8 *r = (u8 *)r_; + + auto size = std::min(lsize, rsize); + + int v; + + auto remainder = size % 8; + switch(remainder) + { + case 7: + __v1_cmp_l_r(v, l, r); + case 6: + __v1_cmp_l_r(v, l, r); + case 5: + __v1_cmp_l_r(v, l, r); + case 4: + __v1_cmp_l_r(v, l, r); + case 3: + __v1_cmp_l_r(v, l, r); + case 2: + __v1_cmp_l_r(v, l, r); + case 1: + __v1_cmp_l_r(v, l, r); + default: + ; + } + + size -= remainder; + while (size > 0) + { + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + + size -= 8; + } + + if (lsize == rsize) + return 0; + return lsize > rsize ? 1 : -1; +} + +inline +int small_cmp_v1a(const void *l_, size_t lsize, const void *r_, size_t rsize) +{ + u8 *l = (u8 *)l_; + u8 *r = (u8 *)r_; + int v; + + auto size = std::min(lsize, rsize); + + auto remainder = size % 4; + switch(remainder) + { + case 3: + __v1_cmp_l_r(v, l, r); + case 2: + __v1_cmp_l_r(v, l, r); + case 1: + __v1_cmp_l_r(v, l, r); + default: + ; + } + + size -= remainder; + while (size > 0) + { + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + __v1_cmp_l_r(v, l, r); + + size -= 4; + } + + if (lsize == rsize) + return 0; + return lsize > rsize ? 1 : -1; +} + +#define __v1_str_cmp_l_r(v, l, r) \ + r_v = *r++; \ + if (r_v == 0) \ + return 1; \ + v = *l++ - r_v; \ + if (v != 0) return v > 0 ? 1 : -1; \ + + +inline +int small_str_cmp_v1a(const void *l_, size_t size, const void *r_) +{ + u8 *l = (u8 *)l_; + u8 *r = (u8 *)r_; + + u8 r_v; + int v; + + auto remainder = size % 4; + switch(remainder) + { + case 3: + __v1_str_cmp_l_r(v, l, r); + case 2: + __v1_str_cmp_l_r(v, l, r); + case 1: + __v1_str_cmp_l_r(v, l, r); + default: + ; + } + + size -= remainder; + while (size > 0) + { + __v1_str_cmp_l_r(v, l, r); + __v1_str_cmp_l_r(v, l, r); + __v1_str_cmp_l_r(v, l, r); + __v1_str_cmp_l_r(v, l, r); + + size -= 4; + } + + if (*r != 0) + return -1; + return 0; +} + +#define __v2_cmp_x_y_l_r(x, y, l, r) x=*l, y=*r; if (x != y) return x > y ? 1 : -1; ++r, ++l; + +inline +int small_cmp_v2(const void *l_, size_t lsize, const void *r_, size_t rsize) +{ + u8 *l = (u8 *)l_; + u8 *r = (u8 *)r_; + u8 x, y; + + auto size = std::min(lsize, rsize); + + auto remainder = size % 8; + switch(remainder) + { + case 7: + __v2_cmp_x_y_l_r(x, y, l, r); + case 6: + __v2_cmp_x_y_l_r(x, y, l, r); + case 5: + __v2_cmp_x_y_l_r(x, y, l, r); + case 4: + __v2_cmp_x_y_l_r(x, y, l, r); + case 3: + __v2_cmp_x_y_l_r(x, y, l, r); + case 2: + __v2_cmp_x_y_l_r(x, y, l, r); + case 1: + __v2_cmp_x_y_l_r(x, y, l, r); + default: + ; + } + + size -= remainder; + while (size > 0) + { + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + __v2_cmp_x_y_l_r(x, y, l, r); + + size -= 8; + } + + if (lsize == rsize) + return 0; + return lsize > rsize ? 1 : -1; +} + +inline +int small_cmp_aligned_v3(const void *l_, size_t lsize, const void *r_, size_t rsize) +{ + auto size = std::min(lsize, rsize); + auto remainder = size % 8; + + s64 v8; + u64 *l8 = (u64 *)l_; + u64 *r8 = (u64 *)r_; + + while (size > remainder) + { + __v1_cmp_l_r(v8, l8, r8); + size -= 8; + } + + u8 *l = (u8 *)l8; + u8 *r = (u8 *)r8; + + int v; + switch(remainder) + { + case 7: + __v1_cmp_l_r(v, l, r); + case 6: + __v1_cmp_l_r(v, l, r); + case 5: + __v1_cmp_l_r(v, l, r); + case 4: + __v1_cmp_l_r(v, l, r); + case 3: + __v1_cmp_l_r(v, l, r); + case 2: + __v1_cmp_l_r(v, l, r); + case 1: + __v1_cmp_l_r(v, l, r); + default: + ; + } + + if (lsize == rsize) + return 0; + return lsize > rsize ? 1 : -1; +} + +inline +auto small_cmp_v3(const void *l, size_t lsize, const void *r, size_t rsize) +{ + if ((u64)l % (alignof(uint64_t)) == 0 && (u64)r % (alignof(uint64_t)) == 0) + return small_cmp_aligned_v3(l, lsize, r, rsize); + return small_cmp_v2(l, lsize, r, rsize); +} + + +inline +auto small_cmp(const void *l, size_t lsize, const void *r, size_t rsize) +{ + return small_cmp_v1a(l, lsize, r, rsize); +} + +inline +auto small_cmp(const void *l, size_t lsize, const void *r) +{ + return small_str_cmp_v1a(l, lsize, r); +} + +inline +int mem_cmp(const void *l, size_t lsize, const void *r, size_t rsize) +{ + auto v = memcmp(l, r, std::min(lsize, rsize)); + if (v != 0) + return v; + + if (lsize == rsize) + return 0; + + return lsize > rsize ? 1 : -1; +} + + +} // namespace diff --git a/tjp/core/algorithm/small_copy.hpp b/tjp/core/algorithm/small_copy.hpp new file mode 100755 index 0000000..073a24d --- /dev/null +++ b/tjp/core/algorithm/small_copy.hpp @@ -0,0 +1,228 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../types/Types.h" + +namespace tjp::core { + +#ifdef NEVER_USE_FOR_POSTERITY +inline +void small_copy_v1(char *d, const char *s, size_t size) +{ + if (size > sizeof(u64)) + { + auto *d_ = (u64 *)d; + auto *s_ = (u64 *)s; + + do + { + *d_++ = *s_++; + size -= sizeof(u64); + } + while (size > sizeof(u64)); + + d = (char *)d_; + s = (char *)s_; + } + + if (size > sizeof(u32)) + { + auto *d_ = (u32 *)d; + auto *s_ = (u32 *)s; + + do + { + *d_++ = *s_++; + size -= sizeof(u32); + } + while (size > sizeof(u32)); + + d = (char *)d_; + s = (char *)s_; + } + + if (size > sizeof(u16)) + { + auto *d_ = (u16 *)d; + auto *s_ = (u16 *)s; + + do + { + *d_++ = *s_++; + size -= sizeof(u16); + } + while (size > sizeof(u16)); + + d = (char *)d_; + s = (char *)s_; + } + + while (size) + { + *d++ = *s++; + size--; + } +} + +inline +void small_copy_v2(char *d, const char *s, size_t size) +{ + switch(size) + { + case 8: + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + case 4: + *d++ = *s++; + *d++ = *s++; + case 2: + *d++ = *s++; + case 1: + *d++ = *s++; + return; + default: + ; + } + + while (size) + { + *d++ = *s++; + size--; + } +} +#endif + +inline +char *small_copy_v3(char *d, const char *s, size_t size) +{ + switch(size) + { + case 8: + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + case 4: + *d++ = *s++; + *d++ = *s++; + case 2: + *d++ = *s++; + case 1: + *d++ = *s++; + return d; + default: + ; + } + + while (size > 0) + { + switch(size) + { + case 4: + *d++ = *s++; + case 3: + *d++ = *s++; + case 2: + *d++ = *s++; + case 1: + *d++ = *s++; + return d; + default: + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + size -= 4; + } + } + + return d; +} + +inline +char *small_copy_v4a(char *d, const char *s, size_t size) +{ + while (size >= 4) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + + size -= 4; + } + + switch (size) + { + case 3: *d++ = *s++; [[fallthrough]]; + case 2: *d++ = *s++; [[fallthrough]]; + case 1: *d++ = *s++; [[fallthrough]]; + default: break; + } + + return d; +} + + +inline +char *small_copy_v4b(char *d, const char *s, size_t size) +{ + while (size >= 8) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + + size -= 8; + } + + while (size >= 4) + { + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + *d++ = *s++; + + size -= 4; + } + + switch (size) + { + case 3: *d++ = *s++; [[fallthrough]]; + case 2: *d++ = *s++; [[fallthrough]]; + case 1: *d++ = *s++; [[fallthrough]]; + default: break; + } + + return d; +} + + +inline +char *small_copy(char *d, const char *s, size_t size) +{ + return small_copy_v4a(d, s, size); +} + +inline +bool maybe_small_copy(char *d, const char *s, size_t size) +{ + if (size > 32) + return false; + + small_copy(d, s, size); + return true; +} + +} // namespace diff --git a/tjp/core/algorithm/starts_with.hpp b/tjp/core/algorithm/starts_with.hpp new file mode 100755 index 0000000..dbe0abc --- /dev/null +++ b/tjp/core/algorithm/starts_with.hpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +bool starts_with (const T &c1, U &&c2) +{ + if (c2.size() > c1.size()) + return false; + + auto c1i = c1.begin(); + auto c2i = c2.begin(); + while (c2i != c2.end()) + { + if (*c1i != *c2i) + return false; + + ++c1i; + ++c2i; + } + + return true; +} + +template +bool starts_with (const T &c1, const char *u2) +{ + return starts_with(c1, std::string_view(u2)); +} + +} // namespace diff --git a/tjp/core/algorithm/starts_with_value.hpp b/tjp/core/algorithm/starts_with_value.hpp new file mode 100755 index 0000000..ecfd10d --- /dev/null +++ b/tjp/core/algorithm/starts_with_value.hpp @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool starts_with_value (const T &c1, U &&v) +{ + if (c1.empty()) + return false; + + return (*c1.begin() == v); +} + +} // namespace diff --git a/tjp/core/algorithm/string_has.hpp b/tjp/core/algorithm/string_has.hpp new file mode 100755 index 0000000..fb6d096 --- /dev/null +++ b/tjp/core/algorithm/string_has.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto string_has(T &v, U &&u) +{ + auto i = v.find(std::forward(u)); + + if (i != T::npos) + return true; + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/tuple_has_value.hpp b/tjp/core/algorithm/tuple_has_value.hpp new file mode 100755 index 0000000..7d4ba5e --- /dev/null +++ b/tjp/core/algorithm/tuple_has_value.hpp @@ -0,0 +1,33 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +bool tuple_has_value(const std::tuple& t, U &&u) { + if constexpr (I == sizeof...(Ts)) + { + // Reached the end of the tuple, and no true values found + return false; + } + else + { + // Check the current element for true + if (std::get(t) == u) + { + return true; + } + else + { + // Recursively check the next element + return tuple_has_value(t, std::forward(u)); + } + } +} + +} // namespace diff --git a/tjp/core/algorithm/unused.hpp b/tjp/core/algorithm/unused.hpp new file mode 100644 index 0000000..157d4fe --- /dev/null +++ b/tjp/core/algorithm/unused.hpp @@ -0,0 +1,11 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { + +template inline void unused(Args&&...) {} + +} // namespace diff --git a/tjp/core/algorithm/update_if_different.hpp b/tjp/core/algorithm/update_if_different.hpp new file mode 100644 index 0000000..07f5dbf --- /dev/null +++ b/tjp/core/algorithm/update_if_different.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +bool update_if_different(T &a, U &&b) +{ + if (a == b) + return false; + + a = b; + return true; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_append.hpp b/tjp/core/algorithm/vector_append.hpp new file mode 100755 index 0000000..473f47a --- /dev/null +++ b/tjp/core/algorithm/vector_append.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +auto &vector_append(T &t, const U &u) +{ + t.insert(t.end(), u.begin(), u.end()); + return t; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_erase_if_value.hpp b/tjp/core/algorithm/vector_erase_if_value.hpp new file mode 100755 index 0000000..838f1f9 --- /dev/null +++ b/tjp/core/algorithm/vector_erase_if_value.hpp @@ -0,0 +1,32 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +size_t vector_erase_if_value(T &&v, F &&f) +{ + if (v.empty()) + return 0; + + auto sizeBefore = v.size(); + + v.erase( + std::remove_if( + v.begin(), v.end(), + std::forward(f) + ), + v.end() + ); + + auto sizeAfter = v.size(); + + return sizeBefore - sizeAfter; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_erase_value_all.hpp b/tjp/core/algorithm/vector_erase_value_all.hpp new file mode 100755 index 0000000..166e323 --- /dev/null +++ b/tjp/core/algorithm/vector_erase_value_all.hpp @@ -0,0 +1,32 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +size_t vector_erase_value_all(T &&v, U &&u) +{ + if (v.empty()) + return 0; + + auto sizeBefore = v.size(); + + v.erase( + std::remove( + v.begin(), v.end(), + std::forward(u) + ), + v.end() + ); + + auto sizeAfter = v.size(); + + return sizeBefore - sizeAfter; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_erase_value_one.hpp b/tjp/core/algorithm/vector_erase_value_one.hpp new file mode 100755 index 0000000..7b183dd --- /dev/null +++ b/tjp/core/algorithm/vector_erase_value_one.hpp @@ -0,0 +1,35 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +size_t vector_erase_value_one(T &&v, U &&u) +{ + auto sizeBefore = v.size(); + + auto i = std::find( + v.begin(), v.end(), + std::forward(u) + ); + + if (i != v.end()) + { + auto last = std::prev(v.end()); + if (i != last) + *i = std::move(*last); + + v.pop_back(); + } + + auto sizeAfter = v.size(); + + return sizeBefore - sizeAfter; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_get_optional_erase_if.hpp b/tjp/core/algorithm/vector_get_optional_erase_if.hpp new file mode 100755 index 0000000..81081ed --- /dev/null +++ b/tjp/core/algorithm/vector_get_optional_erase_if.hpp @@ -0,0 +1,36 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_get_optional_erase_if(T &&v, F &&f) +{ + auto i = std::find_if( + v.begin(), v.end(), + std::forward(f) + ); + + using OV = decltype(std::make_optional(*i)); + + if (i != v.end()) + { + auto ov = std::make_optional(std::move(*i)); + + auto last = std::prev(v.end()); + if (i != last) + *i = std::move(*last); + + v.pop_back(); + return ov; + } + + return OV {}; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_has.hpp b/tjp/core/algorithm/vector_has.hpp new file mode 100755 index 0000000..517e0cb --- /dev/null +++ b/tjp/core/algorithm/vector_has.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_has(T &&v, U &&u) +{ + auto i = std::find( + v.begin(), v.end(), + std::forward(u) + ); + + if (i != v.end()) + return true; + + return false; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_has_if.hpp b/tjp/core/algorithm/vector_has_if.hpp new file mode 100755 index 0000000..09713a2 --- /dev/null +++ b/tjp/core/algorithm/vector_has_if.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "container_has_if.hpp" + +namespace tjp::core { + +template +auto vector_has_if (T &v, U &&u) +{ + return container_has_if(v, std::forward(u)); +} + +} // namespace diff --git a/tjp/core/algorithm/vector_value.hpp b/tjp/core/algorithm/vector_value.hpp new file mode 100755 index 0000000..379a373 --- /dev/null +++ b/tjp/core/algorithm/vector_value.hpp @@ -0,0 +1,28 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_value(T &&v, U &&u) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = std::find( + v.begin(), v.end(), + std::forward(u) + ); + + if (i != v.end()) + return &*i; + + typedef decltype(&*i) R; + return (R)nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_value_at.hpp b/tjp/core/algorithm/vector_value_at.hpp new file mode 100755 index 0000000..3108aa7 --- /dev/null +++ b/tjp/core/algorithm/vector_value_at.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_value_at(T &&v, int index) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + return + (0 <= index && index < v.size()) ? + &v.at(index) : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_value_before_if.hpp b/tjp/core/algorithm/vector_value_before_if.hpp new file mode 100755 index 0000000..dd31c3f --- /dev/null +++ b/tjp/core/algorithm/vector_value_before_if.hpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +auto vector_value_before_if(T &&v, F &&f) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = std::find_if( + v.begin(), v.end(), + std::forward(f) + ); + + return ((i != v.end()) && (i != v.begin()) ? + &*(--i) : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_value_if.hpp b/tjp/core/algorithm/vector_value_if.hpp new file mode 100755 index 0000000..fd648c9 --- /dev/null +++ b/tjp/core/algorithm/vector_value_if.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_value_if(T &&v, F &&f) +{ + static_assert(std::is_lvalue_reference_v, "requires an lvalue"); + + auto i = std::find_if( + begin(std::forward(v)), end(std::forward(v)), + std::forward(f) + ); + + return (i != end(std::forward(v))) ? + &*i : + nullptr; +} + +} // namespace diff --git a/tjp/core/algorithm/vector_value_if_index.hpp b/tjp/core/algorithm/vector_value_if_index.hpp new file mode 100755 index 0000000..64f79d4 --- /dev/null +++ b/tjp/core/algorithm/vector_value_if_index.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto vector_value_if_index(T &&v, F &&f) +{ + auto i = std::find_if( + v.begin(), v.end(), + std::forward(f) + ); + + if (i != v.end()) + return (int)std::distance(v.begin(), i); + + return (int)-1; +} + + +} // namespace diff --git a/tjp/core/algorithm/vector_value_index_if.hpp b/tjp/core/algorithm/vector_value_index_if.hpp new file mode 100755 index 0000000..4ff3017 --- /dev/null +++ b/tjp/core/algorithm/vector_value_index_if.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +Optional vector_value_index_if(T &v, F &&f) +{ + auto i = std::find_if( + v.begin(), v.end(), + std::forward(f) + ); + + if (i != v.end()) + return std::distance(v.begin(), i); + + return {}; +} + +} // namespace diff --git a/tjp/core/assert/debug_assert.cpp b/tjp/core/assert/debug_assert.cpp new file mode 100755 index 0000000..c12d668 --- /dev/null +++ b/tjp/core/assert/debug_assert.cpp @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "debug_assert.h" + +#ifdef ASSERTS +void timprepscius_core_assert_abort() +{ + abort(); +} +#endif diff --git a/tjp/core/assert/debug_assert.h b/tjp/core/assert/debug_assert.h new file mode 100755 index 0000000..6f85904 --- /dev/null +++ b/tjp/core/assert/debug_assert.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" + +#ifdef TJP_CORE_HEADER_ONLY +#include "debug_assert_simple.h" +#else +#include "debug_assert_complex.h" +#endif diff --git a/tjp/core/assert/debug_assert_complex.h b/tjp/core/assert/debug_assert_complex.h new file mode 100755 index 0000000..1be499a --- /dev/null +++ b/tjp/core/assert/debug_assert_complex.h @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include "../system/Debug.h" +#include "../debug/Stack.h" +#include "../log/Log.h" + +#ifdef DEBUG + #ifndef NASSERTS + #define ASSERTS + #endif +#endif + +#ifdef ASSERTS + void timprepscius_core_assert_abort(); + + #define debug_assert(x) \ + if (!(x)) \ + { \ + sLogDebug("errors", tjp::core::getStackString()); \ + sLogDebug("errors", #x << " failed at " << __FILE__ << " line " << __LINE__); \ + timprepscius_core_assert_abort(); \ + } \ + +#else + + #define debug_assert(x) +#endif + +#define debug_assert_reason(x,y) debug_assert(x) diff --git a/tjp/core/assert/debug_assert_simple.h b/tjp/core/assert/debug_assert_simple.h new file mode 100755 index 0000000..ffdd31b --- /dev/null +++ b/tjp/core/assert/debug_assert_simple.h @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include +#include "../system/Debug.h" + +#ifdef DEBUG + #ifndef NASSERTS + #define ASSERTS + #endif +#endif + +#ifdef ASSERTS +#define debug_assert(...) assert(__VA_ARGS__); +#else +#define debug_assert(...) +#endif + +#define release_assert(x,...) if (!(x)) std::abort(); + +#define debug_assert_reason(x,y) debug_assert(x) diff --git a/tjp/core/assert/handle_assert.cpp b/tjp/core/assert/handle_assert.cpp new file mode 100755 index 0000000..77dcdb2 --- /dev/null +++ b/tjp/core/assert/handle_assert.cpp @@ -0,0 +1,35 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif + +#include "../header_only/compile.h" + +#include "debug_assert.h" + +TJP_CORE_HEADER_ONLY_INLINE +bool &get_do_handle_asserts__() +{ + static bool do_handle_asserts = false; + return do_handle_asserts; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool set_do_handle_asserts_(bool v) +{ + auto &r = get_do_handle_asserts__(); + r = v; + + return r; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool get_do_handle_asserts_() +{ + auto &r = get_do_handle_asserts__(); + return r; +} diff --git a/tjp/core/assert/handle_assert.hpp b/tjp/core/assert/handle_assert.hpp new file mode 100755 index 0000000..a4fd478 --- /dev/null +++ b/tjp/core/assert/handle_assert.hpp @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" + +//#ifdef TJP_CORE_HEADER_ONLY +#ifdef TJP_CORE_USE_SIMPLE_ASSERT +#include "handle_assert_simple.hpp" +#else +#include "handle_assert_complex.hpp" +#endif + +#ifdef TJP_CORE_HEADER_ONLY + #include "handle_assert.cpp" +#endif diff --git a/tjp/core/assert/handle_assert_complex.hpp b/tjp/core/assert/handle_assert_complex.hpp new file mode 100755 index 0000000..a349568 --- /dev/null +++ b/tjp/core/assert/handle_assert_complex.hpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "debug_assert.h" +#include "../debug/Stack.h" +#include "../log/Log.h" + +#ifdef ASSERTS + + bool set_do_handle_asserts_(bool); + #define set_do_handle_asserts(x) set_do_handle_asserts_(x) + + bool get_do_handle_asserts_(); + #define get_do_handle_asserts() get_do_handle_asserts_() + + inline + bool do_handle_assert(const char *condition, const char *file, int line, const std::string &stack) { + sLogDebug("errors", stack); + sLogDebug("errors", condition << " failed at " << file << " line " << line); + + if (!get_do_handle_asserts()) + abort(); + + return true; + } + + #define handle_assert(x) if(!(x) && do_handle_assert(#x, __FILE__, __LINE__, tjp::core::getStackString())) + + #define test_assert(x) (!(x) && do_handle_assert(#x, __FILE__, __LINE__, tjp::core::getStackString())) +#else + #define set_do_handle_asserts(x) + #define get_do_handle_asserts() false + + #define handle_assert(x) if(!(x)) + #define test_assert(x) (!(x)) +#endif + diff --git a/tjp/core/assert/handle_assert_simple.hpp b/tjp/core/assert/handle_assert_simple.hpp new file mode 100755 index 0000000..563f459 --- /dev/null +++ b/tjp/core/assert/handle_assert_simple.hpp @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "debug_assert.h" + +#define set_do_handle_asserts(x) +#define get_do_handle_asserts() false + +#define handle_assert(x) if(!(x)) +#define test_assert(x) (!(x)) + diff --git a/tjp/core/assert/release_assert.h b/tjp/core/assert/release_assert.h new file mode 100755 index 0000000..598d070 --- /dev/null +++ b/tjp/core/assert/release_assert.h @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#define ALWAYS_assert_do(e, file, line) \ + ((void)printf ("%s:%d: failed assertion `%s'\n", file, line, e), abort()) + + +#define ALWAYS_assert(e) \ + ((void) ((e) ? ((void)0) : ALWAYS_assert_do (#e, __FILE__, __LINE__))) + +#define release_assert(x) ALWAYS_assert(x) + diff --git a/tjp/core/const_expr/Str+IO.hpp b/tjp/core/const_expr/Str+IO.hpp new file mode 100755 index 0000000..1fa622b --- /dev/null +++ b/tjp/core/const_expr/Str+IO.hpp @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::const_expr { + +template +std::ostream &operator <<(std::ostream &o, const Str &v) +{ + return o << (std::string_view)(v); +} + +inline +std::ostream &operator <<(std::ostream &o, const StrView &v) +{ + return o << (std::string_view)(v); +} + +} // namespace diff --git a/tjp/core/const_expr/Str.hpp b/tjp/core/const_expr/Str.hpp new file mode 100755 index 0000000..47e00f1 --- /dev/null +++ b/tjp/core/const_expr/Str.hpp @@ -0,0 +1,96 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core::const_expr { + +// Note: rename this MutableStrView - or make different types - something +struct StrView +{ + char *v; + size_t len; + + constexpr StrView(char *v_, size_t len_) : + v(v_), len(len_) + {} + + constexpr StrView(const char *v_, size_t len_) : + v(const_cast(v_)), len(len_) + {} + + constexpr StrView(const std::string_view &v_) : + v((char *)v_.data()), len(v_.size()) + {} + + constexpr auto *data() { return v; } + constexpr auto *begin() const { return v; } + constexpr auto *end() const { return begin() + size(); } + constexpr auto *begin() { return v; } + constexpr auto *end() { return begin() + size(); } + constexpr size_t size() { return len; } + constexpr size_t size() const { return len; } + + constexpr void set(const size_t i, const char c) { v[i] = c; } + constexpr char operator[](const size_t i) const { return v[i]; } + + constexpr operator std::string_view() const + { + return std::string_view(v, len); + } +} ; + +template +struct Str { + char v[N]; + + constexpr Str(const char *s) : + v{0} + { + for (auto i=0; i +constexpr bool operator ==(const Str &lhs, const char *rhs) +{ + return (std::string_view)lhs == rhs; +} + +} // namespace + +#include "Str+IO.hpp" diff --git a/tjp/core/const_expr/_tests/Str.cpp b/tjp/core/const_expr/_tests/Str.cpp new file mode 100755 index 0000000..ccca886 --- /dev/null +++ b/tjp/core/const_expr/_tests/Str.cpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include + +namespace tjp::core::const_expr { +namespace { + + +constexpr bool str_is_const_expr() +{ + char source[] = "a> b> c"; + + auto result = StrView(source, 7); + result.set(0, 'q'); + + return result[0] == 'q'; +} + +static_assert(str_is_const_expr(), "str_is_const_expr should be constexpr"); + +} // namespace +} // namespace diff --git a/tjp/core/const_expr/_tests/concat.cpp b/tjp/core/const_expr/_tests/concat.cpp new file mode 100755 index 0000000..32c4d74 --- /dev/null +++ b/tjp/core/const_expr/_tests/concat.cpp @@ -0,0 +1,39 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include + +namespace tjp::core::const_expr { +namespace { + +SCENARIO("core::const_expr::concat") +{ + WHEN("two strings") + { + constexpr std::string_view a("a"); + constexpr std::string_view b("b"); + static_assert(a == "a"); + static_assert(b == "b"); + + constexpr Str<2> ab("ab"); + static_assert((std::string_view)ab == "ab"); + + constexpr auto NULL_CHAR = 1; + constexpr auto abc = concat("ab", "c"); + static_assert(abc.size() == 3+NULL_CHAR); + constexpr Str abcs(abc.data()); + static_assert((std::string_view)abcs == "abc"); + + REQUIRE(ab == "ab"); + REQUIRE(abcs == "abc"); + } + +} + + +} // namespace +} // namespace diff --git a/tjp/core/const_expr/_tests/length.cpp b/tjp/core/const_expr/_tests/length.cpp new file mode 100755 index 0000000..49553ac --- /dev/null +++ b/tjp/core/const_expr/_tests/length.cpp @@ -0,0 +1,24 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include + +namespace tjp::core::const_expr { +namespace { + +SCENARIO("core::const_expr::length") +{ + WHEN("string") + { + static_assert(length("abc") == 3); + } + +} + + +} // namespace +} // namespace diff --git a/tjp/core/const_expr/_tests/remove_char.cpp b/tjp/core/const_expr/_tests/remove_char.cpp new file mode 100644 index 0000000..bdaba30 --- /dev/null +++ b/tjp/core/const_expr/_tests/remove_char.cpp @@ -0,0 +1,99 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +namespace tjp::core::const_expr { +namespace { + +constexpr bool remove_char_constexpr_check() +{ + char source[] = "a_b_c"; + char result[] = {0, 0, 0, 0, 0}; + + remove_char( + StrView(source, 5), + StrView(result, 5), + '_' + ); + + return + result[0] == 'a' && + result[1] == 'b' && + result[2] == 'c'; +} + +constexpr bool remove_second_of_char_2_constexpr_check() +{ + char source[] = "a> b> c"; + char result[] = {0, 0, 0, 0, 0, 0, 0}; + + remove_second_of_char_2( + StrView(source, 7), + StrView(result, 7), + "> " + ); + + return + result[0] == 'a' && + result[1] == '>' && + result[2] == 'b' && + result[3] == '>' && + result[4] == 'c'; +} + +static_assert(remove_char_constexpr_check(), "remove_char should be constexpr"); +static_assert( + remove_second_of_char_2_constexpr_check(), + "remove_second_of_char_2 should be constexpr" +); + +SCENARIO("core::const_expr::remove_char") +{ + WHEN("removing a single character from a string") + { + char source[] = "a_b_c"; + char result[] = {0, 0, 0, 0, 0}; + + remove_char( + StrView(source, 5), + StrView(result, 5), + '_' + ); + + REQUIRE(std::string_view(result, 3) == "abc"); + } + + WHEN("removing the second character of a two-character sequence") + { + char source[] = "a> b> c"; + char result[] = {0, 0, 0, 0, 0, 0, 0}; + + remove_second_of_char_2( + StrView(source, 7), + StrView(result, 7), + "> " + ); + + REQUIRE(std::string_view(result, 5) == "a>b>c"); + } + + WHEN("input is empty") + { + char source[] = ""; + char result[] = {'x'}; + + remove_second_of_char_2( + StrView(source, 0), + StrView(result, 1), + "> " + ); + + REQUIRE(result[0] == 'x'); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/const_expr/concat.hpp b/tjp/core/const_expr/concat.hpp new file mode 100755 index 0000000..eeef029 --- /dev/null +++ b/tjp/core/const_expr/concat.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::const_expr { + +template +constexpr auto concat(const char (&a)[N], const char (&b)[M]) { + std::array result{}; // -1 because we don't need two null terminators + + for (size_t i = 0; i < N - 1; ++i) { + result[i] = a[i]; + } + + for (size_t i = 0; i < M; ++i) { + result[N - 1 + i] = b[i]; + } + + return result; +} + +} // namespace diff --git a/tjp/core/const_expr/count_char.hpp b/tjp/core/const_expr/count_char.hpp new file mode 100755 index 0000000..519d50c --- /dev/null +++ b/tjp/core/const_expr/count_char.hpp @@ -0,0 +1,35 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::const_expr { + +[[nodiscard]] +inline constexpr auto count_char(const StrView &s, const char v) +{ + size_t num = 0; + for (auto &c : s) + { + if (c == v) + ++num; + } + + return num; +} + +[[nodiscard]] +inline constexpr auto count_char(const StrView &s, const char v[2]) +{ + size_t num = 0; + for (size_t i=1; i + +namespace tjp::core::const_expr { + +[[nodiscard]] +inline constexpr auto length(const char *s) +{ + size_t size = 0; + while (*s++) + size++; + + return size; +} + +} // namespace diff --git a/tjp/core/const_expr/remove_char.hpp b/tjp/core/const_expr/remove_char.hpp new file mode 100755 index 0000000..262088d --- /dev/null +++ b/tjp/core/const_expr/remove_char.hpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Str.hpp" + +namespace tjp::core::const_expr { + +[[nodiscard]] +inline constexpr auto remove_char(const StrView &s, StrView result, const char v) +{ + int i = 0; + for (auto &c : s) + { + if (c != v) + result.set(i++, c); + } +} + +[[nodiscard]] +inline constexpr auto remove_second_of_char_2(const StrView &s, StrView result, const char v[2]) +{ + if (result.size() == 0 || s.size() == 0) + return; + + size_t r = 0; + result.set(r++, s[0]); + for (size_t i=1; i("a") == 14795678224343670082U); +static_assert(hash_compile("a") == 2007486030U); +static_assert(hash_compile("a") == 22182U); +static_assert(hash_compile("a") == 80U); +static_assert(hash_compile("ab") == 17973018434836123690U); +static_assert(hash_compile("ab") == 2626114336U); +static_assert(hash_compile("ab") == 46746U); +static_assert(hash_compile("ab") == 228U); +static_assert(hash_compile("abc") == 9059148220514607862U); +static_assert(hash_compile("abc") == 2779386792U); +static_assert(hash_compile("abc") == 28158U); +static_assert(hash_compile("abc") == 144U); +static_assert(hash_compile("abcd") == 11711224204720505282U); +static_assert(hash_compile("abcd") == 3972784484U); +static_assert(hash_compile("abcd") == 62618U); +static_assert(hash_compile("abcd") == 166U); +static_assert(hash_compile("abcde") == 10271438589093974638U); +static_assert(hash_compile("abcde") == 1688475508U); +static_assert(hash_compile("abcde") == 45776U); +static_assert(hash_compile("abcde") == 30U); +static_assert(hash_compile("abcdef") == 15844374392941584856U); +static_assert(hash_compile("abcdef") == 1471257416U); +static_assert(hash_compile("abcdef") == 17304U); +static_assert(hash_compile("abcdef") == 84U); +static_assert(hash_compile("abcdefg") == 1629871225258951438U); +static_assert(hash_compile("abcdefg") == 1553091536U); +static_assert(hash_compile("abcdefg") == 61246U); +static_assert(hash_compile("abcdefg") == 78U); +static_assert(hash_compile("tjp::core::variant::Variant") == 11594898570291287436U); +static_assert(hash_compile("tjp::core::variant::Variant") == 2549889722U); +static_assert(hash_compile("tjp::core::variant::Variant") == 41662U); +static_assert(hash_compile("tjp::core::variant::Variant") == 28U); +static_assert(hash_compile("tjp::core::Str") == 4181101266999643468U); +static_assert(hash_compile("tjp::core::Str") == 4083993560U); +static_assert(hash_compile("tjp::core::Str") == 55404U); +static_assert(hash_compile("tjp::core::Str") == 148U); +//------------------------------- + +} // namespace + diff --git a/tjp/core/const_hash/Hash+zltan.hpp b/tjp/core/const_hash/Hash+zltan.hpp new file mode 100644 index 0000000..d7d0669 --- /dev/null +++ b/tjp/core/const_hash/Hash+zltan.hpp @@ -0,0 +1,123 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::const_hash::zltan { + +using u32 = uint32_t; +using u64 = uint64_t; + +constexpr u64 seed = 0x026f23a; + +constexpr +u64 mix(const u64 h_) { + u64 h = h_; + h ^= h >> 23; + h *= 0x2127599bf4325c37ULL; + h ^= h >> 47; + return h; +} + +constexpr +u64 fasthash64_compiletime(const char *p, const size_t len, const u64 seed) +{ + const u64 m = 0x880355f21e6d1965ULL; + + u64 h = seed ^ (len * m); + u64 v = 0; + + for (size_t i=1; i<=len; ++i) + { + v <<= 8; + v ^= (u64)*p++; + + if ((i % 8) == 0) + { + h ^= mix(v); + h *= m; + v = 0; + } + } + + if ((len % 8) != 0) + { + h ^= mix(v); + h *= m; + } + + return mix(h); +} + +constexpr +u64 fasthash64_compiletime_chunk(const char *p, const size_t len, const u64 seed) +{ + const u64 m = 0x880355f21e6d1965ULL; + + u64 h = seed ^ (len * m); + u64 v = 0; + + const size_t len_8 = len / 8; + + for (size_t i=0; i + +namespace tjp::core::const_hash { + +#ifdef _DEBUG + +static Map, String> hashes; + +void hash_collision_test(size_t width, u64 value, const std::string_view &s) +{ + auto &v = hashes[{width,value}]; + if (v.empty()) + v = s; + + assert(v == s); +} + +#endif + +} // namespace + diff --git a/tjp/core/const_hash/Hash.h b/tjp/core/const_hash/Hash.h new file mode 100644 index 0000000..8ad33f8 --- /dev/null +++ b/tjp/core/const_hash/Hash.h @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../types/Definitions.h" + +namespace tjp::core::const_hash { + +using value = u64; + +} // namespace + +namespace tjp::core { + +using hash_t = const_hash::value; + +} ; diff --git a/tjp/core/const_hash/Hash.hpp b/tjp/core/const_hash/Hash.hpp new file mode 100644 index 0000000..6bf5e34 --- /dev/null +++ b/tjp/core/const_hash/Hash.hpp @@ -0,0 +1,252 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Hash.h" +#include +#include "../debug/Debug.h" +#include "Hash+simple.hpp" +#include "Hash+zltan.hpp" + +namespace tjp::core::const_hash { + +namespace detail = zltan; + +using value = u64; + +constexpr +value version = 0; + +template +constexpr +T hash_label(const T l) +{ + constexpr auto mask = ~T(1); + return (l & mask) | T(version); +} + +template +constexpr +value hash_version(const T h) +{ + return (h & T(1)); +} + +constexpr +size_t hash_strlen(const char *s) +{ + size_t i=0; + + while(s[i]) + ++i; + + return i; +} + +constexpr +size_t hash_strlen(const std::string_view &s) +{ + return s.size(); +} + +static_assert(hash_strlen("abc") == 3); + +constexpr +value hash_compile_(const char *s, const char *e) +{ + return detail::hash_compile_(s, e); +} + +constexpr +value hash_compile_(const char *s) +{ + return hash_compile_(s, s + hash_strlen(s)); +} + +inline +value hash_runtime_(const char *s, const char *e) +{ + return detail::hash_runtime_(s, e); +} + +inline +value hash_runtime_(const char *s) +{ + return hash_runtime_(s, s + hash_strlen(s)); +} + +// ---------- + +template +constexpr +value hash_runtime_(const T &v) +{ + auto *begin = v.data(); + auto *end = begin + v.size(); + + return hash_runtime_((const char *)begin, (const char *)end); +} + +static_assert(hash_strlen(std::string_view("abc")) == 3); + +constexpr +value hash_compile_(const std::string_view &s) +{ + return hash_compile_(s.begin(), s.end()); +} + +inline +value hash_runtime_(const std::string_view &s) +{ + return hash_runtime_(s.begin(), s.end()); +} + +// --------------- + +template +constexpr +T hash_transform(value v) +{ + return (T)v; +} + +template<> +constexpr +u64 hash_transform(value v) +{ + return v; +} + +template<> +constexpr +u32 hash_transform(value h) +{ + auto r = h - (h >> 32); + return (u32)r; +} + +template<> +constexpr +u16 hash_transform(value h64) +{ + auto h = hash_transform(h64); + auto r = h - (h >> 16); + return (u16)r; +} + +template<> +constexpr +u8 hash_transform(value h64) +{ + auto h = hash_transform(h64); + auto r = h - (h >> 8); + return (u8)r; +} + +template +constexpr +T hash_max(T v, T m) +{ + return (m > 0) ? (v % m) : 0; +} + +template +constexpr T hash_compile(const char *s) +{ + return hash_label(hash_transform(hash_compile_(s))); +} + +template +constexpr T hash_compile(const std::string_view &s) +{ + return hash_label(hash_transform(hash_compile_(s))); +} + +template +constexpr T hash_compile(const T max, Args&& ... args) +{ + return + hash_label( + hash_max( + hash_transform(hash_compile_(std::forward(args)...)), + max + ) + ); +} + +// ---- + +static_assert(hash_compile("abcdefghijk") != 0); +static_assert(hash_compile("abcdefghijk") != 0); +static_assert(hash_compile("abcdefghijk") != 0); +static_assert(hash_compile("abcdefghijk") != 0); + +// ----- + +template +T hash_runtime(const char *str) +{ + return hash_label(hash_transform(hash_runtime_(std::string_view(str)))); +} + +template +T hash_runtime(const std::string_view &s) +{ + return hash_label(hash_transform(hash_runtime_(s))); +} + +template +T hash_runtime(const U &v) +{ + return hash_label(hash_transform(hash_runtime_(v))); +} + +template +constexpr T hash_runtime(const T max, Args&& ... args) +{ + return + hash_label( + hash_max( + hash_transform(hash_runtime_(std::forward(args)...)), + max + ) + ); +} + + +#ifdef _DEBUG + +void hash_collision_test(size_t width, u64 value, const std::string_view &s); + +template +void hash_collision_test(T value, const std::string_view &s) +{ + hash_collision_test(sizeof(T), value, s); +} + +#else + +template +void hash_collision_test(T value, const std::string_view &s) +{ +} + +#endif + +// --------- + +} // namespace + +#include "Hash+zltan+expected.inl" + +namespace tjp::core { + +using const_hash::hash_compile; +using const_hash::hash_runtime; +using const_hash::hash_version; + +using const_hash::hash_collision_test; + +} ; diff --git a/tjp/core/const_hash/_tests/Hash.cpp b/tjp/core/const_hash/_tests/Hash.cpp new file mode 100644 index 0000000..d77a50d --- /dev/null +++ b/tjp/core/const_hash/_tests/Hash.cpp @@ -0,0 +1,85 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace tjp::core::const_hash { +namespace { + +constexpr char X[] = "hello there"; + +SCENARIO("core::const_hash") +{ + GIVEN("compile vs runtime") + { + constexpr auto hc = hash_compile(X); + auto hr = hash_runtime(X); + + REQUIRE(hc == hr); + } + + GIVEN("switch") + { + auto h = hash_runtime("there"); + + switch (h) + { + case hash_compile("hello"): + REQUIRE(false); + break; + case hash_compile("there"): + REQUIRE(true); + break; + } ; + + } + + GIVEN("label") + { + bool correct = true; + Vector v { 0 }; + for (auto i=0; i<32768; ++i) + { + v[0] = i; + auto h = hash_runtime(v); + correct = correct && (hash_version(h) == version); + } + + REQUIRE(correct); + } + + GIVEN("max") + { + bool correct = true; + Vector v { 0 }; + for (auto i=1; i<32768; ++i) + { + v[0] = i; + value maxValue = i; + auto h = hash_runtime(maxValue, v); + + correct = correct && (hash_version(h) == version); + correct = correct && (h < maxValue); + + if (!correct) + debug_break(); + } + + REQUIRE(correct); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/const_hash/_tests/HashExpected.cpp b/tjp/core/const_hash/_tests/HashExpected.cpp new file mode 100644 index 0000000..4aba98b --- /dev/null +++ b/tjp/core/const_hash/_tests/HashExpected.cpp @@ -0,0 +1,60 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include +#include +#include +#include + +#include +#include +#include + +#include + +namespace tjp::core::const_hash { +namespace { + +SCENARIO("core::const_hash::expected") +{ + GIVEN("expected") + { + std::ostringstream oss; + + auto produceHash = [&](auto *s) { + auto hu64 = hash_runtime(s); + auto hu32 = hash_runtime(s); + auto hu16 = hash_runtime(s); + auto hu8 = hash_runtime(s); + + oss << "static_assert(hash_compile(\"" << s << "\") == " << hu64 << "U);\n"; + oss << "static_assert(hash_compile(\"" << s << "\") == " << hu32 << "U);\n"; + oss << "static_assert(hash_compile(\"" << s << "\") == " << hu16 << "U);\n"; + oss << "static_assert(hash_compile(\"" << s << "\") == " << (int)hu8 << "U);\n"; + }; + + oss << "//-------------------------------\n"; + oss << "// Expected Hashes\n"; + produceHash("a"); + produceHash("ab"); + produceHash("abc"); + produceHash("abcd"); + produceHash("abcde"); + produceHash("abcdef"); + produceHash("abcdefg"); + + produceHash("tjp::core::variant::Variant"); + produceHash("tjp::core::Str"); + oss << "//-------------------------------\n"; + + std::cout << oss.str() << std::endl; + + REQUIRE(true); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/const_hash/smhasher/CMakeLists.txt b/tjp/core/const_hash/smhasher/CMakeLists.txt new file mode 100644 index 0000000..1e7ef15 --- /dev/null +++ b/tjp/core/const_hash/smhasher/CMakeLists.txt @@ -0,0 +1,44 @@ +project(SMHasher) + +cmake_minimum_required(VERSION 2.4) + +set(CMAKE_BUILD_TYPE Release) + +add_library( + SMHasherSupport + AvalancheTest.cpp + Bitslice.cpp + Bitvec.cpp + CityTest.cpp + City.cpp + crc.cpp + DifferentialTest.cpp + Hashes.cpp + KeysetTest.cpp + lookup3.cpp + md5.cpp + MurmurHash1.cpp + MurmurHash2.cpp + MurmurHash3.cpp + ZLTanP.cpp + Platform.cpp + Random.cpp + sha1.cpp + SpeedTest.cpp + Spooky.cpp + SpookyTest.cpp + Stats.cpp + SuperFastHash.cpp + Types.cpp + PMurHash.c +) + +add_executable( + SMHasher + main.cpp +) + +target_link_libraries( + SMHasher + SMHasherSupport +) diff --git a/tjp/core/const_hash/smhasher/Platform.h b/tjp/core/const_hash/smhasher/Platform.h new file mode 100644 index 0000000..b7006c7 --- /dev/null +++ b/tjp/core/const_hash/smhasher/Platform.h @@ -0,0 +1,94 @@ +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +#pragma once + +#include +#include + +void SetAffinity ( int cpu ); + +//----------------------------------------------------------------------------- +// Microsoft Visual Studio + +#if defined(_MSC_VER) + +#define FORCE_INLINE __forceinline +#define NEVER_INLINE __declspec(noinline) + +#include +#include // Has to be included before intrin.h or VC complains about 'ceil' +#include // for __rdtsc +#include "pstdint.h" + +#define ROTL32(x,y) _rotl(x,y) +#define ROTL64(x,y) _rotl64(x,y) +#define ROTR32(x,y) _rotr(x,y) +#define ROTR64(x,y) _rotr64(x,y) + +#pragma warning(disable : 4127) // "conditional expression is constant" in the if()s for avalanchetest +#pragma warning(disable : 4100) +#pragma warning(disable : 4702) + +#define BIG_CONSTANT(x) (x) + +// RDTSC == Read Time Stamp Counter + +#define rdtsc() __rdtsc() + +//----------------------------------------------------------------------------- +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#define FORCE_INLINE inline __attribute__((always_inline)) +#define NEVER_INLINE __attribute__((noinline)) + +inline uint32_t rotl32 ( uint32_t x, int8_t r ) +{ + return (x << r) | (x >> (32 - r)); +} + +inline uint64_t rotl64 ( uint64_t x, int8_t r ) +{ + return (x << r) | (x >> (64 - r)); +} + +inline uint32_t rotr32 ( uint32_t x, int8_t r ) +{ + return (x >> r) | (x << (32 - r)); +} + +inline uint64_t rotr64 ( uint64_t x, int8_t r ) +{ + return (x >> r) | (x << (64 - r)); +} + +#define ROTL32(x,y) rotl32(x,y) +#define ROTL64(x,y) rotl64(x,y) +#define ROTR32(x,y) rotr32(x,y) +#define ROTR64(x,y) rotr64(x,y) + +#define BIG_CONSTANT(x) (x##LLU) + +inline +uint64_t get_time_ns() { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return static_cast(ts.tv_sec) * 1000000000 + static_cast(ts.tv_nsec); +} + +inline uint64_t rdtsc() +{ + return get_time_ns(); +} + + +#include +#define _stricmp strcasecmp + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- diff --git a/tjp/core/const_hash/smhasher/ZLTanP.cpp b/tjp/core/const_hash/smhasher/ZLTanP.cpp new file mode 100644 index 0000000..5e52f9c --- /dev/null +++ b/tjp/core/const_hash/smhasher/ZLTanP.cpp @@ -0,0 +1,17 @@ + +// get rid of constexpr for that shmasher +#define constexpr + +#include "ZLTanP.h" +#include "ZLTanP.hpp" + +uint64_t ZLTanPHash64 ( const void * key, int len, uint64_t seed ) +{ + return tjp::core::const_hash::zltan::fasthash64_compiletime((char *)key, len, seed); +} + +uint64_t ZLTanPHashChunk64 ( const void * key, int len, uint64_t seed ) +{ + return tjp::core::const_hash::zltan::fasthash64_compiletime_chunk((char *)key, len, seed); +} + diff --git a/tjp/core/const_hash/smhasher/ZLTanP.h b/tjp/core/const_hash/smhasher/ZLTanP.h new file mode 100644 index 0000000..876baec --- /dev/null +++ b/tjp/core/const_hash/smhasher/ZLTanP.h @@ -0,0 +1,46 @@ +//----------------------------------------------------------------------------- +// MurmurHash2 was written by Austin Appleby, and is placed in the public +// domain. The author hereby disclaims copyright to this source code. + +#ifndef _ZLTanP_H_ +#define _ZLTanP_H_ + +//----------------------------------------------------------------------------- +// Platform-specific functions and macros + +// Microsoft Visual Studio + +#if defined(_MSC_VER) && (_MSC_VER < 1600) + +typedef unsigned char uint8_t; +typedef unsigned int uint32_t; +typedef unsigned __int64 uint64_t; + +// Other compilers + +#else // defined(_MSC_VER) + +#include + +#endif // !defined(_MSC_VER) + +//----------------------------------------------------------------------------- + +uint64_t ZLTanPHash64 ( const void * key, int len, uint64_t seed ); +uint64_t ZLTanPHashChunk64 ( const void * key, int len, uint64_t seed ); + +inline void ZLTanPHash64_test ( const void * key, int len, uint32_t seed, void * out ) +{ + *(uint64_t*)out = ZLTanPHash64(key,len,seed); +} + +inline void ZLTanPHashChunk64_test ( const void * key, int len, uint32_t seed, void * out ) +{ + *(uint64_t*)out = ZLTanPHashChunk64(key,len,seed); +} + + +//----------------------------------------------------------------------------- + +#endif // _ZLTanP_H_ + diff --git a/tjp/core/const_hash/smhasher/ZLTanP.hpp b/tjp/core/const_hash/smhasher/ZLTanP.hpp new file mode 120000 index 0000000..1dde236 --- /dev/null +++ b/tjp/core/const_hash/smhasher/ZLTanP.hpp @@ -0,0 +1 @@ +../Hash+zltan.hpp \ No newline at end of file diff --git a/tjp/core/const_hash/smhasher/clone.txt b/tjp/core/const_hash/smhasher/clone.txt new file mode 100644 index 0000000..2a3465d --- /dev/null +++ b/tjp/core/const_hash/smhasher/clone.txt @@ -0,0 +1,19 @@ +git clone https://github.com/aappleby/smhasher + +and then copy all of these files into the src +do the standard + +cd smhasher/src +ln -fs ~/Projects/crown/Core_Zero/core/const_hash/smhasher/* . + +mkdir build +cd build +cmake ../src +make + + +the Platform.h is changed to measure time correctly on the mac + +run with +./SMHasher ZLTanHash64 +./SMHasher ZLTanHashChunk64 diff --git a/tjp/core/const_hash/smhasher/main.cpp b/tjp/core/const_hash/smhasher/main.cpp new file mode 100644 index 0000000..3208455 --- /dev/null +++ b/tjp/core/const_hash/smhasher/main.cpp @@ -0,0 +1,603 @@ +#include "Platform.h" +#include "Hashes.h" +#include "KeysetTest.h" +#include "SpeedTest.h" +#include "AvalancheTest.h" +#include "DifferentialTest.h" +#include "PMurHash.h" +#include "ZLTanP.h" + +#include +#include + +//----------------------------------------------------------------------------- +// Configuration. TODO - move these to command-line flags + +bool g_testAll = false; + +bool g_testSanity = false; +bool g_testSpeed = false; +bool g_testDiff = false; +bool g_testDiffDist = false; +bool g_testAvalanche = false; +bool g_testBIC = false; +bool g_testCyclic = false; +bool g_testTwoBytes = false; +bool g_testSparse = false; +bool g_testPermutation = false; +bool g_testWindow = false; +bool g_testText = false; +bool g_testZeroes = false; +bool g_testSeed = false; + +//----------------------------------------------------------------------------- +// This is the list of all hashes that SMHasher can test. + +struct HashInfo +{ + pfHash hash; + int hashbits; + uint32_t verification; + const char * name; + const char * desc; +}; + +HashInfo g_hashes[] = +{ + { DoNothingHash, 32, 0x00000000, "donothing32", "Do-Nothing function (only valid for measuring call overhead)" }, + { DoNothingHash, 64, 0x00000000, "donothing64", "Do-Nothing function (only valid for measuring call overhead)" }, + { DoNothingHash, 128, 0x00000000, "donothing128", "Do-Nothing function (only valid for measuring call overhead)" }, + + { crc32, 32, 0x3719DB20, "crc32", "CRC-32" }, + + { md5_32, 32, 0xC10C356B, "md5_32a", "MD5, first 32 bits of result" }, + { sha1_32a, 32, 0xF9376EA7, "sha1_32a", "SHA1, first 32 bits of result" }, + + { FNV, 32, 0xE3CBBE91, "FNV", "Fowler-Noll-Vo hash, 32-bit" }, + { Bernstein, 32, 0xBDB4B640, "bernstein", "Bernstein, 32-bit" }, + { lookup3_test, 32, 0x3D83917A, "lookup3", "Bob Jenkins' lookup3" }, + { SuperFastHash, 32, 0x980ACD1D, "superfast", "Paul Hsieh's SuperFastHash" }, + { MurmurOAAT_test, 32, 0x5363BD98, "MurmurOAAT", "Murmur one-at-a-time" }, + { Crap8_test, 32, 0x743E97A1, "Crap8", "Crap8" }, + + { CityHash64_test, 64, 0x25A20825, "City64", "Google CityHash64WithSeed" }, + { CityHash128_test, 128, 0x6531F54E, "City128", "Google CityHash128WithSeed" }, + + { SpookyHash32_test, 32, 0x3F798BBB, "Spooky32", "Bob Jenkins' SpookyHash, 32-bit result" }, + { SpookyHash64_test, 64, 0xA7F955F1, "Spooky64", "Bob Jenkins' SpookyHash, 64-bit result" }, + { SpookyHash128_test, 128, 0x8D263080, "Spooky128", "Bob Jenkins' SpookyHash, 128-bit result" }, + + // MurmurHash2 + + { MurmurHash2_test, 32, 0x27864C1E, "Murmur2", "MurmurHash2 for x86, 32-bit" }, + { MurmurHash2A_test, 32, 0x7FBD4396, "Murmur2A", "MurmurHash2A for x86, 32-bit" }, + { MurmurHash64A_test, 64, 0x1F0D3804, "Murmur2B", "MurmurHash2 for x64, 64-bit" }, + { MurmurHash64B_test, 64, 0xDD537C05, "Murmur2C", "MurmurHash2 for x86, 64-bit" }, + + // MurmurHash3 + + { MurmurHash3_x86_32, 32, 0xB0F57EE3, "Murmur3A", "MurmurHash3 for x86, 32-bit" }, + { MurmurHash3_x86_128, 128, 0xB3ECE62A, "Murmur3C", "MurmurHash3 for x86, 128-bit" }, + { MurmurHash3_x64_128, 128, 0x6384BA69, "Murmur3F", "MurmurHash3 for x64, 128-bit" }, + + { PMurHash32_test, 32, 0xB0F57EE3, "PMurHash32", "Shane Day's portable-ized MurmurHash3 for x86, 32-bit." }, + + // CompiletimeFastHash + { ZLTanPHash64_test, 64, 0x61B121EC, "ZLTanHash64", "ZLTan ZLTan ZLTan" }, + { ZLTanPHashChunk64_test, 64, 0x61B121EC, "ZLTanHashChunk64", "ZLTan ZLTan ZLTan" }, + +}; + +HashInfo * findHash ( const char * name ) +{ + for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) + { + if(_stricmp(name,g_hashes[i].name) == 0) return &g_hashes[i]; + } + + return NULL; +} + +//----------------------------------------------------------------------------- +// Self-test on startup - verify that all installed hashes work correctly. + +void SelfTest ( void ) +{ + bool pass = true; + + for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) + { + HashInfo * info = & g_hashes[i]; + + pass &= VerificationTest(info->hash,info->hashbits,info->verification,false); + } + + if(!pass) + { + printf("Self-test FAILED!\n"); + + for(size_t i = 0; i < sizeof(g_hashes) / sizeof(HashInfo); i++) + { + HashInfo * info = & g_hashes[i]; + + printf("%16s - ",info->name); + pass &= VerificationTest(info->hash,info->hashbits,info->verification,true); + } + + exit(1); + } +} + +//---------------------------------------------------------------------------- + +template < typename hashtype > +void test ( hashfunc hash, HashInfo * info ) +{ + const int hashbits = sizeof(hashtype) * 8; + + printf("-------------------------------------------------------------------------------\n"); + printf("--- Testing %s (%s)\n\n",info->name,info->desc); + + //----------------------------------------------------------------------------- + // Sanity tests + + if(g_testSanity || g_testAll) + { + printf("[[[ Sanity Tests ]]]\n\n"); + + VerificationTest(hash,hashbits,info->verification,true); + SanityTest(hash,hashbits); + AppendedZeroesTest(hash,hashbits); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Speed tests + + if(g_testSpeed || g_testAll) + { + printf("[[[ Speed Tests ]]]\n\n"); + + BulkSpeedTest(info->hash,info->verification); + printf("\n"); + + for(int i = 1; i < 32; i++) + { + double cycles; + + TinySpeedTest(hashfunc(info->hash),sizeof(hashtype),i,info->verification,true,cycles); + } + + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Differential tests + + if(g_testDiff || g_testAll) + { + printf("[[[ Differential Tests ]]]\n\n"); + + bool result = true; + bool dumpCollisions = false; + + result &= DiffTest< Blob<64>, hashtype >(hash,5,1000,dumpCollisions); + result &= DiffTest< Blob<128>, hashtype >(hash,4,1000,dumpCollisions); + result &= DiffTest< Blob<256>, hashtype >(hash,3,1000,dumpCollisions); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Differential-distribution tests + + if(g_testDiffDist /*|| g_testAll*/) + { + printf("[[[ Differential Distribution Tests ]]]\n\n"); + + bool result = true; + + result &= DiffDistTest2(hash); + + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Avalanche tests + + if(g_testAvalanche || g_testAll) + { + printf("[[[ Avalanche Tests ]]]\n\n"); + + bool result = true; + + result &= AvalancheTest< Blob< 32>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 40>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 48>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 56>, hashtype > (hash,300000); + + result &= AvalancheTest< Blob< 64>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 72>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 80>, hashtype > (hash,300000); + result &= AvalancheTest< Blob< 88>, hashtype > (hash,300000); + + result &= AvalancheTest< Blob< 96>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<104>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<112>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<120>, hashtype > (hash,300000); + + result &= AvalancheTest< Blob<128>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<136>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<144>, hashtype > (hash,300000); + result &= AvalancheTest< Blob<152>, hashtype > (hash,300000); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Bit Independence Criteria. Interesting, but doesn't tell us much about + // collision or distribution. + + if(g_testBIC) + { + printf("[[[ Bit Independence Criteria ]]]\n\n"); + + bool result = true; + + //result &= BicTest(hash,2000000); + BicTest3,hashtype>(hash,2000000); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Cyclic' - keys of the form "abcdabcdabcd..." + + if(g_testCyclic || g_testAll) + { + printf("[[[ Keyset 'Cyclic' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + result &= CyclicKeyTest(hash,sizeof(hashtype)+0,8,10000000,drawDiagram); + result &= CyclicKeyTest(hash,sizeof(hashtype)+1,8,10000000,drawDiagram); + result &= CyclicKeyTest(hash,sizeof(hashtype)+2,8,10000000,drawDiagram); + result &= CyclicKeyTest(hash,sizeof(hashtype)+3,8,10000000,drawDiagram); + result &= CyclicKeyTest(hash,sizeof(hashtype)+4,8,10000000,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'TwoBytes' - all keys up to N bytes containing two non-zero bytes + + // This generates some huge keysets, 128-bit tests will take ~1.3 gigs of RAM. + + if(g_testTwoBytes || g_testAll) + { + printf("[[[ Keyset 'TwoBytes' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + for(int i = 4; i <= 20; i += 4) + { + result &= TwoBytesTest2(hash,i,drawDiagram); + } + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Sparse' - keys with all bits 0 except a few + + if(g_testSparse || g_testAll) + { + printf("[[[ Keyset 'Sparse' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + result &= SparseKeyTest< 32,hashtype>(hash,6,true,true,true,drawDiagram); + result &= SparseKeyTest< 40,hashtype>(hash,6,true,true,true,drawDiagram); + result &= SparseKeyTest< 48,hashtype>(hash,5,true,true,true,drawDiagram); + result &= SparseKeyTest< 56,hashtype>(hash,5,true,true,true,drawDiagram); + result &= SparseKeyTest< 64,hashtype>(hash,5,true,true,true,drawDiagram); + result &= SparseKeyTest< 96,hashtype>(hash,4,true,true,true,drawDiagram); + result &= SparseKeyTest< 256,hashtype>(hash,3,true,true,true,drawDiagram); + result &= SparseKeyTest<2048,hashtype>(hash,2,true,true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Permutation' - all possible combinations of a set of blocks + + if(g_testPermutation || g_testAll) + { + { + // This one breaks lookup3, surprisingly + + printf("[[[ Keyset 'Combination Lowbits' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + uint32_t blocks[] = + { + 0x00000000, + + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, + }; + + result &= CombinationKeyTest(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + { + printf("[[[ Keyset 'Combination Highbits' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + uint32_t blocks[] = + { + 0x00000000, + + 0x20000000, 0x40000000, 0x60000000, 0x80000000, 0xA0000000, 0xC0000000, 0xE0000000 + }; + + result &= CombinationKeyTest(hash,8,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + { + printf("[[[ Keyset 'Combination 0x8000000' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + uint32_t blocks[] = + { + 0x00000000, + + 0x80000000, + }; + + result &= CombinationKeyTest(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + { + printf("[[[ Keyset 'Combination 0x0000001' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + uint32_t blocks[] = + { + 0x00000000, + + 0x00000001, + }; + + result &= CombinationKeyTest(hash,20,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + { + printf("[[[ Keyset 'Combination Hi-Lo' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + uint32_t blocks[] = + { + 0x00000000, + + 0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000006, 0x00000007, + + 0x80000000, 0x40000000, 0xC0000000, 0x20000000, 0xA0000000, 0x60000000, 0xE0000000 + }; + + result &= CombinationKeyTest(hash,6,blocks,sizeof(blocks) / sizeof(uint32_t),true,true,drawDiagram); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + } + + //----------------------------------------------------------------------------- + // Keyset 'Window' + + // Skip distribution test for these - they're too easy to distribute well, + // and it generates a _lot_ of testing + + if(g_testWindow || g_testAll) + { + printf("[[[ Keyset 'Window' Tests ]]]\n\n"); + + bool result = true; + bool testCollision = true; + bool testDistribution = false; + bool drawDiagram = false; + + result &= WindowedKeyTest< Blob, hashtype > ( hash, 20, testCollision, testDistribution, drawDiagram ); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Text' + + if(g_testText || g_testAll) + { + printf("[[[ Keyset 'Text' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + const char * alnum = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; + + result &= TextKeyTest( hash, "Foo", alnum,4, "Bar", drawDiagram ); + result &= TextKeyTest( hash, "FooBar", alnum,4, "", drawDiagram ); + result &= TextKeyTest( hash, "", alnum,4, "FooBar", drawDiagram ); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Zeroes' + + if(g_testZeroes || g_testAll) + { + printf("[[[ Keyset 'Zeroes' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + result &= ZeroKeyTest( hash, drawDiagram ); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } + + //----------------------------------------------------------------------------- + // Keyset 'Seed' + + if(g_testSeed || g_testAll) + { + printf("[[[ Keyset 'Seed' Tests ]]]\n\n"); + + bool result = true; + bool drawDiagram = false; + + result &= SeedTest( hash, 1000000, drawDiagram ); + + if(!result) printf("*********FAIL*********\n"); + printf("\n"); + } +} + +//----------------------------------------------------------------------------- + +uint32_t g_inputVCode = 1; +uint32_t g_outputVCode = 1; +uint32_t g_resultVCode = 1; + +HashInfo * g_hashUnderTest = NULL; + +void VerifyHash ( const void * key, int len, uint32_t seed, void * out ) +{ + g_inputVCode = MurmurOAAT(key,len,g_inputVCode); + g_inputVCode = MurmurOAAT(&seed,sizeof(uint32_t),g_inputVCode); + + g_hashUnderTest->hash(key,len,seed,out); + + g_outputVCode = MurmurOAAT(out,g_hashUnderTest->hashbits/8,g_outputVCode); +} + +//----------------------------------------------------------------------------- + +void testHash ( const char * name ) +{ + HashInfo * pInfo = findHash(name); + + if(pInfo == NULL) + { + printf("Invalid hash '%s' specified\n",name); + return; + } + else + { + g_hashUnderTest = pInfo; + + if(pInfo->hashbits == 32) + { + test( VerifyHash, pInfo ); + } + else if(pInfo->hashbits == 64) + { + test( pInfo->hash, pInfo ); + } + else if(pInfo->hashbits == 128) + { + test( pInfo->hash, pInfo ); + } + else if(pInfo->hashbits == 256) + { + test( pInfo->hash, pInfo ); + } + else + { + printf("Invalid hash bit width %d for hash '%s'",pInfo->hashbits,pInfo->name); + } + } +} +//----------------------------------------------------------------------------- + +int main ( int argc, char ** argv ) +{ + const char * hashToTest = "murmur3a"; + + if(argc < 2) + { + printf("(No test hash given on command line, testing Murmur3_x86_32.)\n"); + } + else + { + hashToTest = argv[1]; + } + + // Code runs on the 3rd CPU by default + + SetAffinity((1 << 2)); + + SelfTest(); + + int timeBegin = clock(); + + g_testAll = true; + + //g_testSanity = true; + //g_testSpeed = true; + //g_testAvalanche = true; + //g_testBIC = true; + //g_testCyclic = true; + //g_testTwoBytes = true; + //g_testDiff = true; + //g_testDiffDist = true; + //g_testSparse = true; + //g_testPermutation = true; + //g_testWindow = true; + //g_testZeroes = true; + + testHash(hashToTest); + + //---------- + + int timeEnd = clock(); + + printf("\n"); + printf("Input vcode 0x%08x, Output vcode 0x%08x, Result vcode 0x%08x\n",g_inputVCode,g_outputVCode,g_resultVCode); + printf("Verification value is 0x%08x - Testing took %f seconds\n",g_verify,double(timeEnd-timeBegin)/double(CLOCKS_PER_SEC)); + printf("-------------------------------------------------------------------------------\n"); + return 0; +} diff --git a/tjp/core/containers/Align.h b/tjp/core/containers/Align.h new file mode 100755 index 0000000..2570756 --- /dev/null +++ b/tjp/core/containers/Align.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef __GNUC__ +#define ALIGN( X, __Declaration__ ) __Declaration__ __attribute__((aligned(X))) +#endif + +#ifdef _MSC_VER +#define ALIGN( __Declaration__ ) __pragma( align(push, 4) ) __Declaration__ __pragma( pack(pop)) +#endif diff --git a/tjp/core/containers/Array+IO.hpp b/tjp/core/containers/Array+IO.hpp new file mode 100755 index 0000000..aa94207 --- /dev/null +++ b/tjp/core/containers/Array+IO.hpp @@ -0,0 +1,36 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Array.hpp" +#include "../assert/debug_assert.h" + +namespace std { + +template +void io_r(IO &io, std::array &t) +{ + auto size = io.array_begin(); + debug_assert(size == Size); + + for (auto &v: t) + io.on_vector_value(v); + + io.array_end(); +} + +//template +//void io_w(IO &io, std::array &t) +//{ +// io.array_begin(t.size()); +// debug_assert(size == Size); +// +// for (auto &v: t) +// io.on_vector_value(v); +// +// io.array_end(); +//} + +} // namespace diff --git a/tjp/core/containers/Array.h b/tjp/core/containers/Array.h new file mode 100755 index 0000000..84d1a77 --- /dev/null +++ b/tjp/core/containers/Array.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Array = std::array; + +} // namespace diff --git a/tjp/core/containers/Array.hpp b/tjp/core/containers/Array.hpp new file mode 100755 index 0000000..79ea80a --- /dev/null +++ b/tjp/core/containers/Array.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Array.h" diff --git a/tjp/core/containers/ByF.hpp b/tjp/core/containers/ByF.hpp new file mode 100755 index 0000000..1a31f54 --- /dev/null +++ b/tjp/core/containers/ByF.hpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +struct ByF { + typedef bool is_transparent; + + [[no_unique_address]] + F f; + + bool operator() (const T &lhs, const T &rhs) const + { + return f(lhs) < f(rhs); + } + + template + bool operator() (const T &lhs, const R &rhs) const + { + return f(lhs) < f(rhs); + } + + template + bool operator() (const R &lhs, const T &rhs) const + { + return f(lhs) < f(rhs); + } +} ; + +} diff --git a/tjp/core/containers/ById.hpp b/tjp/core/containers/ById.hpp new file mode 100755 index 0000000..7a597b7 --- /dev/null +++ b/tjp/core/containers/ById.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +struct ById { + typedef bool is_transparent; + + bool operator() (const T &lhs, const T &rhs) const + { + return lhs.id < rhs.id; + } + + template + bool operator() (const T &lhs, const R &rhs) const + { + return lhs.id < rhs; + } + + template + bool operator() (const R &lhs, const T &rhs) const + { + return lhs < rhs.id; + } +} ; + +} diff --git a/tjp/core/containers/ByPtr.hpp b/tjp/core/containers/ByPtr.hpp new file mode 100755 index 0000000..e1cf0b2 --- /dev/null +++ b/tjp/core/containers/ByPtr.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../ptr/Ptr.h" + +namespace tjp::core { + +template +struct ByPtr { + typedef bool is_transparent; + + bool operator() (const StrongPtr &lhs, const StrongPtr &rhs) const + { + return ptr_of(lhs) < ptr_of(rhs); + } + + bool operator() (const StrongPtr &lhs, const T *rhs) const + { + return ptr_of(lhs) < rhs; + } + + bool operator() (const T *lhs, const StrongPtr &rhs) const + { + return lhs < ptr_of(rhs); + } +} ; + +} diff --git a/tjp/core/containers/ByPtrId.hpp b/tjp/core/containers/ByPtrId.hpp new file mode 100755 index 0000000..cc19e8d --- /dev/null +++ b/tjp/core/containers/ByPtrId.hpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +struct ByPtrId { + typedef bool is_transparent; + + bool operator() (const T *lhs, const T *rhs) const + { + debug_assert(lhs); + debug_assert(rhs); + return lhs->id < rhs->id; + } + + template + bool operator() (const T *lhs, const R &rhs) const + { + debug_assert(lhs); + debug_assert(rhs); + + return lhs->id < rhs; + } + + template + bool operator() (const R &lhs, const T *rhs) const + { + debug_assert(lhs); + debug_assert(rhs); + + return lhs < rhs->id; + } +} ; + +} diff --git a/tjp/core/containers/ByStrongPtrId.hpp b/tjp/core/containers/ByStrongPtrId.hpp new file mode 100755 index 0000000..596d8df --- /dev/null +++ b/tjp/core/containers/ByStrongPtrId.hpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +struct ByStrongPtrId { + typedef bool is_transparent; + + bool operator() (const StrongPtr &lhs, const StrongPtr &rhs) const + { + return lhs->id < rhs->id; + } + + + template + bool operator() (const StrongPtr &lhs, const R &rhs) const + { + return lhs->id < rhs; + } + + template + bool operator() (const R &lhs, const StrongPtr &rhs) const + { + return lhs < rhs->id; + } +} ; + +} diff --git a/tjp/core/containers/FilledArray.h b/tjp/core/containers/FilledArray.h new file mode 100755 index 0000000..51969ea --- /dev/null +++ b/tjp/core/containers/FilledArray.h @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +/** + * std list and vector and set are too slow for some reason, need fast allocation, with + */ +template +struct FilledArray; + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/FilledArray.hpp b/tjp/core/containers/FilledArray.hpp new file mode 100755 index 0000000..21b7951 --- /dev/null +++ b/tjp/core/containers/FilledArray.hpp @@ -0,0 +1,66 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "FilledArray.h" +#include "StackArray.hpp" + +#include "../debug/Debug.h" +#include "../assert/debug_assert.h" +#include +#include // memcpy +#include "../threads/TestCollision.h" + +namespace tjp { +namespace core { + +template +struct FilledArray : StackArray +{ + using Super = StackArray; + using iterator = typename Super::iterator; + using const_iterator = typename Super::const_iterator; + + void insert(const T &element) + { + this->push_back(element); + } + + void erase (typename Super::iterator i) + { + if (i == this->end()) + return; + + auto &back = this->back(); + if (i != &back) + *i = std::move(back); + + this->pop_back(); + } + + void erase (const T &element) + { + erase(find(element)); + } + + iterator find (const T &element) + { + // now iterator all except for what used to be the end element + for (auto i=this->begin(); i!=this->end(); ++i) + { + if (*i == element) + { + // the end element was the last element + return i; + } + } + + return this->end(); + } +} ; + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/FilledArrayThreadSafe.h b/tjp/core/containers/FilledArrayThreadSafe.h new file mode 100755 index 0000000..e400b4f --- /dev/null +++ b/tjp/core/containers/FilledArrayThreadSafe.h @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../threads/Lock.h" + +namespace tjp { +namespace core { + +/** + * std list and vector and set are too slow for some reason, need fast allocation, with + */ +template +class FilledArrayThreadSafe; + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/FilledArrayThreadSafe.hpp b/tjp/core/containers/FilledArrayThreadSafe.hpp new file mode 100755 index 0000000..787c189 --- /dev/null +++ b/tjp/core/containers/FilledArrayThreadSafe.hpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "FilledArrayThreadSafe.h" +#include "FilledArray.hpp" + + +namespace tjp { +namespace core { + +/** + * std list and vector and set are too slow for some reason, need fast allocation, with + */ +template +struct FilledArrayThreadSafe : FilledArray +{ + typedef FilledArray Super; + typedef M Mutex; + Mutex m; + + template + FilledArrayThreadSafe(U&& ...u) : + Super(std::forward(u)...) + { + + } +} ; + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/Function.h b/tjp/core/containers/Function.h new file mode 100755 index 0000000..45f2efa --- /dev/null +++ b/tjp/core/containers/Function.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Function = std::function; + +} // namespace diff --git a/tjp/core/containers/Function.hpp b/tjp/core/containers/Function.hpp new file mode 100755 index 0000000..d29e545 --- /dev/null +++ b/tjp/core/containers/Function.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Function.h" diff --git a/tjp/core/containers/InPlaceArray+iterator.inl b/tjp/core/containers/InPlaceArray+iterator.inl new file mode 100755 index 0000000..0870690 --- /dev/null +++ b/tjp/core/containers/InPlaceArray+iterator.inl @@ -0,0 +1,64 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../assert/debug_assert.h" +#include "../assert/handle_assert.hpp" +#include "../algorithm/mem_copy.hpp" + +#include // for memcpy + +namespace tjp::core { + +template +auto rbegin(InPlaceArray &t) +{ + return t.rbegin(); +} + +template +auto rend(InPlaceArray &t) +{ + return t.rend(); +} + +template +auto rbegin(const InPlaceArray &t) +{ + return t.rbegin(); +} + +template +auto rend(const InPlaceArray &t) +{ + return t.rend(); +} + +template +auto begin(InPlaceArray &t) +{ + return t.begin(); +} + +template +auto end(InPlaceArray &t) +{ + return t.end(); +} + +template +auto begin(const InPlaceArray &t) +{ + return t.begin(); +} + +template +auto end(const InPlaceArray &t) +{ + return t.end(); +} + +} // namespace + diff --git a/tjp/core/containers/InPlaceArray.h b/tjp/core/containers/InPlaceArray.h new file mode 100755 index 0000000..df082bf --- /dev/null +++ b/tjp/core/containers/InPlaceArray.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +class InPlaceArray; + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/InPlaceArray.hpp b/tjp/core/containers/InPlaceArray.hpp new file mode 100755 index 0000000..d58d90d --- /dev/null +++ b/tjp/core/containers/InPlaceArray.hpp @@ -0,0 +1,137 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "InPlaceArray.h" +#include "Array.h" + +#include +#include +#include + +#include "../types/Types.h" + +namespace tjp { +namespace core { + +template +class InPlaceArray +{ +public: + static constexpr size_t MaxLength = N; + +private: + using Array = std::array; + using Block = char; + using Size = u32; + + union Static { + Block block; + Array array; + + Static() : block(0) {} + ~Static () {} + } ; + + Static v; + Size length = 0; + + typedef std::allocator Allocator; + Allocator allocator; + +public: + using value_type = typename Array::value_type; + using iterator = typename Array::iterator; + using const_iterator = typename Array::const_iterator; + using pointer = typename Array::pointer; + using reference = typename Array::reference; + using const_reference = typename Array::const_reference; + + inline auto data() { return v.array.data(); } + inline auto data() const { return v.array.data(); } + + inline auto begin() { return v.array.begin(); } + inline auto end () { return v.array.begin() + length; } + + inline auto begin() const { return v.array.begin(); } + inline auto end () const { return v.array.begin() + length; } + + inline auto rbegin() { return v.array.rbegin() + (v.array.size() - length); } + inline auto rend () { return v.array.rend(); } + + inline auto rbegin() const { return v.array.rbegin() + (v.array.size() - length); } + inline auto rend () const { return v.array.rend(); } + + inline const_reference front () const { return v.array.front(); } + inline const_reference back () const { return *(v.array.data() + (length - 1)); } + inline reference front () { return v.array.front(); } + inline reference back () { return *(v.array.data() + (length - 1)); } + +private: + template + void construct(T *t, Args&& ...args) + { + std::allocator_traits::construct(allocator, t, std::forward(args)...); + } + + void destruct(T *t) + { + std::allocator_traits::destroy(allocator, t); + } + +protected: + void shorten_block(size_t length_); + void shorten_items(size_t length_); + void shorten(size_t length_); + void append_block(const T *begin, const T *end); + void append_items(const T *begin, const T *end); + void emplace_items(T *begin, T *end); + +public: + InPlaceArray (); + InPlaceArray(size_t length_, T t=T()); + +// InPlaceArray(InPlaceArray &&rhs); + +// template + InPlaceArray(const InPlaceArray &rhs); + InPlaceArray(const std::initializer_list &rhs); + InPlaceArray(const T *begin, const T *end); + InPlaceArray(const T *begin, size_t size); + +// template + InPlaceArray &operator =(const InPlaceArray &rhs); + InPlaceArray &operator =(const Array &rhs); + ~InPlaceArray (); + + void resize(size_t length_, T t=T()); + void append(const T *begin, const T *end); + void emplace(T *begin, T *end); + + void push_back_(); + void push_back (const T &element); + void push_back (T &&element); + void pop_back (); + + template + T &emplace_back (Args&& ...args); + + const T &at(size_t i) const; + T &at(size_t i); + + const T &operator[] (size_t i) const; + T &operator[] (size_t i); + + size_t size () const; + void clear (); + + bool empty () const; +} ; + +} // namespace utilities +} // namespace + +#include "InPlaceArray.inl" +#include "InPlaceArray+iterator.inl" diff --git a/tjp/core/containers/InPlaceArray.inl b/tjp/core/containers/InPlaceArray.inl new file mode 100755 index 0000000..92b860d --- /dev/null +++ b/tjp/core/containers/InPlaceArray.inl @@ -0,0 +1,333 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../assert/debug_assert.h" +#include "../assert/handle_assert.hpp" +#include "../algorithm/mem_copy.hpp" + +#include "../exception/OutOfBounds.hpp" + +#include // for memcpy + +namespace tjp { +namespace core { + +template +InPlaceArray::InPlaceArray (size_t size, T t) +{ + resize(size, t); +} + +template +InPlaceArray::InPlaceArray () +{ +} + +template +//template +InPlaceArray::InPlaceArray(const InPlaceArray &rhs) +{ + append(rhs.begin(), rhs.end()); +} + +template +//template +InPlaceArray::InPlaceArray(const T *begin, const T *end) +{ + append(begin, end); +} + +template +//template +InPlaceArray::InPlaceArray(const T *data, size_t size) +{ + append(data, data + size); +} + + +//template +//InPlaceArray::InPlaceArray(InPlaceArray &&rhs) +//{ +// append(rhs.begin(), rhs.end()); +//} + +template +//template +InPlaceArray &InPlaceArray::operator =(const InPlaceArray &rhs) +{ + if (this == &rhs) + return *this; + + clear(); + append(rhs.begin(), rhs.end()); + + return *this; +} + +template +//template +InPlaceArray &InPlaceArray::operator =(const Array &rhs) +{ + if (&v.array != &rhs) + v.array = rhs; + + length = N; + + return *this; +} + +template +InPlaceArray::InPlaceArray(const std::initializer_list &rhs) +{ + for (auto &element: rhs) + push_back(element); +} + +template +void InPlaceArray::append_block(const T *begin_, const T *end_) +{ + auto size = (end_ - begin_); + + handle_assert(length + size <= N) { + throw exceptions::OutOfBounds(); + } + + mem_copy((char *)end(), (char *)begin_, size * sizeof(T)); + length += size; +} + +template +void InPlaceArray::append_items(const T *begin_, const T *end_) +{ + for (auto i = begin_; i!=end_; ++i) + push_back(*i); +} + +template +void InPlaceArray::emplace_items(T *begin_, T *end_) +{ + for (auto i = begin_; i!=end_; ++i) + emplace_back(std::move(*i)); +} + +template +void InPlaceArray::append(const T *begin, const T *end) +{ + if constexpr (std::is_trivially_copyable::value) + return append_block(begin, end); + else + return append_items(begin, end); +} + +template +void InPlaceArray::emplace(T *begin, T *end) +{ + if constexpr (std::is_trivially_copyable::value) + return append_block(begin, end); + else + return emplace_items(begin, end); +} + +template +InPlaceArray::~InPlaceArray () +{ + clear(); +} + +template +void InPlaceArray::shorten_items(size_t length_) +{ + while (length > length_) + pop_back(); +} + +template +void InPlaceArray::shorten_block(size_t length_) +{ + if (length > length_) + length = (Size)length_; +} + +template +void InPlaceArray::shorten(size_t length_) +{ + if constexpr (std::is_trivially_destructible::value) + return shorten_block(length_); + else + return shorten_items(length_); +} + +template +void InPlaceArray::resize(size_t length_, T t) +{ + shorten(length_); + + handle_assert(length_ <= N) { + throw exceptions::OutOfBounds(); + } + + if constexpr (std::is_trivially_copyable::value) + { + if (length < length_) + { + auto *data_ = data(); + auto *begin = data_ + length; + auto *end = data_ + length_; + + std::fill(begin, end, t); + length = (Size)length_; + } + } + else + { + while (length < length_) + push_back(t); + } +} + +template +void InPlaceArray::push_back (const T &element) +{ + handle_assert(length < N) { + throw exceptions::OutOfBounds(); + } + + ++length; + + if constexpr (std::is_trivially_copyable::value) + { + back() = element; + } + else + { + construct(&back(), element); + } +} + +template +void InPlaceArray::push_back (T &&element) +{ + handle_assert(length < N) { + throw exceptions::OutOfBounds(); + } + + ++length; + construct(&back(), std::move(element)); +} + +template +void InPlaceArray::pop_back () +{ + debug_assert (length > 0); + + // decrease length + if (length > 0) + { + --length; + destruct(&v.array[length]); + } +} + +template +template +T &InPlaceArray::emplace_back (Args&& ...element) +{ + handle_assert(length < N) { + throw exceptions::OutOfBounds(); + } + + ++length; + auto &t = back(); + construct(&t, std::forward(element)...); + return t; +} + +template +const T &InPlaceArray::at(size_t i) const +{ + return v.array[i]; +} + +template +T &InPlaceArray::at(size_t i) +{ + return v.array[i]; +} + +template +const T &InPlaceArray::operator[] (size_t i) const +{ + return at(i); +} + +template +T &InPlaceArray::operator[] (size_t i) +{ + return at(i); +} + +template +size_t InPlaceArray::size () const +{ + return length; +} + +template +void InPlaceArray::clear () +{ + shorten(0); +} + +template +bool InPlaceArray::empty () const +{ + return length == 0; +} + +template +bool operator <(const InPlaceArray &lhs, const InPlaceArray &rhs) +{ + auto max = std::min(lhs.size(), rhs.size()); + + for (auto i=0; i +bool operator ==(const InPlaceArray &lhs, const InPlaceArray &rhs) +{ + if (lhs.size() != rhs.size()) + return false; + + for (auto i=0; i +bool operator !=(const InPlaceArray &lhs, const InPlaceArray &rhs) +{ + return !(lhs == rhs); +} + +} // namespace utilities +} // namespace + diff --git a/tjp/core/containers/List.h b/tjp/core/containers/List.h new file mode 100755 index 0000000..990e165 --- /dev/null +++ b/tjp/core/containers/List.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using List = std::list; + +} // namespace diff --git a/tjp/core/containers/List.hpp b/tjp/core/containers/List.hpp new file mode 100755 index 0000000..1209ca7 --- /dev/null +++ b/tjp/core/containers/List.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "List.h" diff --git a/tjp/core/containers/Map.h b/tjp/core/containers/Map.h new file mode 100755 index 0000000..9e5f77a --- /dev/null +++ b/tjp/core/containers/Map.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template, typename A=std::allocator>> +using Map = std::map; + +} // namespace diff --git a/tjp/core/containers/Map.hpp b/tjp/core/containers/Map.hpp new file mode 100755 index 0000000..2a9ae46 --- /dev/null +++ b/tjp/core/containers/Map.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Map.h" diff --git a/tjp/core/containers/MemoryArray.h b/tjp/core/containers/MemoryArray.h new file mode 100755 index 0000000..e6ded1d --- /dev/null +++ b/tjp/core/containers/MemoryArray.h @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Vector.h" + +namespace tjp::core { +namespace memory_array { + +template +struct MemoryArrayIterator; + +template +struct MemoryArray; + +} // namespace + +using namespace memory_array; + +} // namespace + diff --git a/tjp/core/containers/MemoryArray.hpp b/tjp/core/containers/MemoryArray.hpp new file mode 100755 index 0000000..f27fcec --- /dev/null +++ b/tjp/core/containers/MemoryArray.hpp @@ -0,0 +1,170 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "MemoryArray.h" +#include "Vector.h" +#include "../assert/debug_assert.h" + +namespace tjp::core { +namespace memory_array { + +template +struct MemoryArrayIterator +{ + char *ptr_; + size_t stride_; + size_t offset_; + + void operator ++() + { + ptr_ += stride_; + } + + T &operator *() + { + return *(T *)(ptr_ + offset_); + } + + bool operator !=(const MemoryArrayIterator &rhs) + { + return ptr_ != rhs.ptr_; + } +} ; + +template +struct MemoryArray +{ + char *begin_; + size_t size_; + size_t stride_; + size_t offset_; + + typedef T value_type; + + MemoryArray(char *begin, size_t size, size_t stride, size_t offset) : + begin_(begin), + size_(size), + stride_(stride), + offset_(offset) + {} + + MemoryArray(const Vector &v) : + begin_((char *)(v.data())), + size_(v.size()), + stride_(sizeof(T)), + offset_(0) + {} + + T &at(size_t index) const + { + char *ptr = (begin_ + stride_*index) + offset_; + return *(T *)ptr; + } + + auto &operator[](size_t index) const + { + return at(index); + } + + auto begin () const + { + return MemoryArrayIterator { begin_, stride_, offset_ }; + } + + auto end () const + { + return MemoryArrayIterator { (begin_ + stride_*size_), stride_, offset_ }; + } + + auto &front () const + { + return at(0); + } + + auto &back () const + { + return at(size()-1); + } + + auto size() const + { + return size_; + } + + bool empty() const + { + return size_ == 0; + } + + template + auto recast() const + { + return MemoryArray { begin_, size_, stride_, offset_ }; + } +} ; + +template +MemoryArray memoryArray() +{ + return MemoryArray { nullptr, 0, 0, 0 }; +} + +template +MemoryArray memoryArray(void *begin, size_t size, size_t stride, size_t offset) +{ + return MemoryArray { (char *)begin, size, stride, offset }; +} + +// ---------------------------------- + +template +MemoryArray memoryArray(const T *begin, size_t size) +{ + static_assert(sizeof(R) <= sizeof(T)); + return memoryArray((void *)begin, size, sizeof(T), 0); +} + +template +MemoryArray memoryArray(const T *begin, size_t size, size_t offset) +{ + static_assert(sizeof(R) <= sizeof(T)); + return memoryArray((void *)begin, size, sizeof(T), offset * sizeof(T)); +} + + +template +MemoryArray memoryArray(const T *begin, size_t size) +{ + return memoryArray(begin, size); +} + + +template +MemoryArray memoryArray(const T *begin, size_t size, size_t offset) +{ + return memoryArray(begin, size, offset); +} + +// ---------------------------------- + +template +MemoryArray memoryArray(const Vector &data) +{ + return memoryArray(data.data(), data.size()); +} + +template +MemoryArray memoryArray(const Vector &data) +{ + return memoryArray(data); +} + +} // namespace + +using namespace memory_array; + +} // namespace + diff --git a/tjp/core/containers/MemorySegment.h b/tjp/core/containers/MemorySegment.h new file mode 100755 index 0000000..4539f1f --- /dev/null +++ b/tjp/core/containers/MemorySegment.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::containers { + +template +struct MemorySegment; + +} // namespace + diff --git a/tjp/core/containers/MemorySegment.hpp b/tjp/core/containers/MemorySegment.hpp new file mode 100755 index 0000000..711748f --- /dev/null +++ b/tjp/core/containers/MemorySegment.hpp @@ -0,0 +1,75 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "MemorySegment.h" +#include + +namespace tjp::core::containers { + +template +struct MemorySegment +{ + using value_type = T; + using size_type = size_t; + + T *data_ = nullptr; + size_t size_ = 0; + + using iterator = T *; + using const_iterator = T *; + + iterator begin() { return data_; } + iterator end() { return data_ + size_; } + + const_iterator begin() const { return data_; } + const_iterator end() const { return data_ + size_; } + + T *data() { return data_; } + const T *data() const { return data_; } + + size_t size() const { return size_; } + + T &operator[](size_t i) + { + return data_[i]; + } + + const T &operator[](size_t i) const + { + return data_[i]; + } +}; + +template +inline +MemorySegment memory_segment(T *t, size_t size) +{ + return MemorySegment { t, size }; +} + +template +inline +MemorySegment memory_segment(T *t, size_t size) +{ + return MemorySegment { (C *)t, size * sizeof(T) / sizeof(C) }; +} + +template +inline +MemorySegment memory_segment_vector(const T &t) +{ + return { (C *)t.data(), t.size() * sizeof(typename T::value_type) / sizeof(C) }; +} + +template +inline +MemorySegment memory_segment_value(const T &t) +{ + return MemorySegment { (C *)&t, sizeof(T) / sizeof(C) }; +} + +} // namespace + diff --git a/tjp/core/containers/MultiContainer.hpp b/tjp/core/containers/MultiContainer.hpp new file mode 100755 index 0000000..fa051d3 --- /dev/null +++ b/tjp/core/containers/MultiContainer.hpp @@ -0,0 +1,232 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray.hpp" +#include "../exception/OutOfBounds.hpp" +#include "../algorithm/vector_erase_if_value.hpp" + +namespace tjp::core { + +template +using MultiContainer_ = StackArray; + +template +struct MultiIterator +{ + using Self = MultiIterator; + using value_type = typename T::value_type; + using reference = typename T::reference; + + I end; + I i; + J j; + bool ended; + + MultiIterator() + { + } + + MultiIterator(I &&end_, I &&i_, J &&j_, bool ended_) : + end(end_), + i(i_), + j(j_), + ended(ended_) + { + validate(); + } + + auto &deref () + { + return *j; + } + + auto &operator *() { return deref(); } + auto &operator ->() { return deref(); } + + void validate() + { + while (!ended && j == (*i)->end()) + { + ++i; + + if (i == end) + ended = true; + else + j = (*i)->begin(); + } + } + + void next() + { + if (ended) + return; + + ++j; + validate(); + } + + auto &operator++(int) + { + next(); + return *this; + } + + auto operator++() + { + auto v = *this; + next(); + return v; + } + + bool operator ==(const Self &rhs) const + { + return + (ended && rhs.ended) || + (i == rhs.i && j == rhs.j); + } + + bool operator !=(const Self &rhs) const + { + return !(*this == rhs); + } +} ; + +template> +struct MultiContainer { + C c; + + using Self = MultiContainer; + using iterator = MultiIterator; + using const_iterator = MultiIterator; + using value_type = typename T::value_type; + using reference = typename T::reference; + + MultiContainer() + {} + + template + MultiContainer(Args ... args) + { + (add(args),...); + } + + template + static auto begin(U &self) + { + auto &c = self.c; + + CI end = c.end(); + CI i = c.begin(); + TI j; + + auto ended = c.empty(); + if (!ended) + { + j = (*i)->begin(); + } + + return MultiIterator( + std::move(end), + std::move(i), + std::move(j), + ended + ); + } + + template + static auto end(U &self) + { + auto &c = self.c; + + CI end = c.end(); + CI i = c.end(); + TI j; + + return MultiIterator( + std::move(end), + std::move(i), + std::move(j), + true + ); + } + + auto begin() + { + return begin(*this); + } + + auto end() + { + return end(*this); + } + + auto begin() const + { + return begin(*this); + } + + auto end() const + { + return end(*this); + } + + void add(T *t) + { + c.push_back(t); + } + + void remove(T *t) + { + auto i = std::find(c.begin(), c.end(), t); + if (i != c.end()) + { + std::swap(*i, c.back()); + c.pop_back(); + } + } + + auto container_size() const + { + return c.size(); + } + + auto size() const + { + size_t size_ = 0; + for (auto *v : c) + size_ += v->size(); + + return size_; + } + + auto empty() const + { + return size() == 0; + } + + auto &at(size_t i) const + { + for (auto *v : c) + { + size_t size_ = v->size(); + if (i < size_) + return v->at(i); + + i -= size_; + } + + debug_assert(false); + throw exceptions::OutOfBounds(); + } + + auto &operator[](size_t i) + { + return at(i); + } +} ; + +} // namespace + diff --git a/tjp/core/containers/Optional+IO.hpp b/tjp/core/containers/Optional+IO.hpp new file mode 100755 index 0000000..472f490 --- /dev/null +++ b/tjp/core/containers/Optional+IO.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Optional.hpp" + +namespace std { + +template +auto logOf(const std::optional &v) +{ + return tjp::core::logOfRef(v ? &*v : nullptr); +} + +} diff --git a/tjp/core/containers/Optional.h b/tjp/core/containers/Optional.h new file mode 100755 index 0000000..9446aad --- /dev/null +++ b/tjp/core/containers/Optional.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Optional = std::optional; + +} // namespace diff --git a/tjp/core/containers/Optional.hpp b/tjp/core/containers/Optional.hpp new file mode 100755 index 0000000..25fd6f4 --- /dev/null +++ b/tjp/core/containers/Optional.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Optional.h" diff --git a/tjp/core/containers/Pack.h b/tjp/core/containers/Pack.h new file mode 100755 index 0000000..0ba2a1e --- /dev/null +++ b/tjp/core/containers/Pack.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef __GNUC__ +#define PACK( __Declaration__ ) __Declaration__ __attribute__((__packed__)) +#endif + +#ifdef _MSC_VER +#define PACK( __Declaration__ ) __pragma( pack(push, 1) ) __Declaration__ __pragma( pack(pop)) +#endif diff --git a/tjp/core/containers/Pair.h b/tjp/core/containers/Pair.h new file mode 100755 index 0000000..80b32ee --- /dev/null +++ b/tjp/core/containers/Pair.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Pair = std::pair; + +} // namespace diff --git a/tjp/core/containers/Pair.hpp b/tjp/core/containers/Pair.hpp new file mode 100755 index 0000000..62230fe --- /dev/null +++ b/tjp/core/containers/Pair.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Pair.h" diff --git a/tjp/core/containers/PtrOnly.h b/tjp/core/containers/PtrOnly.h new file mode 100755 index 0000000..ef0dc10 --- /dev/null +++ b/tjp/core/containers/PtrOnly.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +struct PtrOnly; + +} // namespace diff --git a/tjp/core/containers/PtrOnly.hpp b/tjp/core/containers/PtrOnly.hpp new file mode 100755 index 0000000..39c126c --- /dev/null +++ b/tjp/core/containers/PtrOnly.hpp @@ -0,0 +1,59 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "PtrOrValue.h" + +namespace tjp::core { + +template +struct PtrOnly { + const T *p = nullptr; + + const T *get() const { + return p; + } + + PtrOnly(const T *p_) : + p(p_) + {} + + PtrOnly(const PtrOnly &rhs) : + p(rhs.p) + {} + + PtrOnly(PtrOnly &&rhs) : + p(std::move(rhs.p)) + {} + + auto *operator ->() const + { + return get(); + } + + const T &operator *() const + { + return *get(); + } + + operator const T&() const + { + return *get(); + } +} ; + +template +PtrOnly makePtrOnly(const T *t) +{ + return PtrOnly(t); +} + +template +PtrOnly makePtrOnly(const T &t) +{ + return PtrOnly(t); +} + +} // namespace diff --git a/tjp/core/containers/PtrOrValue.h b/tjp/core/containers/PtrOrValue.h new file mode 100755 index 0000000..a369a75 --- /dev/null +++ b/tjp/core/containers/PtrOrValue.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +struct PtrOrValue; + +} // namespace diff --git a/tjp/core/containers/PtrOrValue.hpp b/tjp/core/containers/PtrOrValue.hpp new file mode 100755 index 0000000..146e2a6 --- /dev/null +++ b/tjp/core/containers/PtrOrValue.hpp @@ -0,0 +1,70 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "PtrOrValue.h" + +namespace tjp::core { + +template +struct PtrOrValue { + Optional v; + const T *p = nullptr; + + const T *get() const { + return v ? + &*v : + p; + } + + PtrOrValue(const T &v_) : + v(v_) {} + + PtrOrValue(T &&v_) : + v(std::move(v_)) {} + + PtrOrValue(const T *p_) : + p(p_) + {} + + PtrOrValue(const PtrOrValue &rhs) : + v(rhs.v), + p(rhs.p) + {} + + PtrOrValue(PtrOrValue &&rhs) : + v(std::move(rhs.v)), + p(std::move(rhs.p)) + {} + + auto *operator ->() const + { + return get(); + } + + const T &operator *() const + { + return *get(); + } + + operator const T&() const + { + return *get(); + } +} ; + +template +PtrOrValue makePtrOrValue(const T *t) +{ + return PtrOrValue(t); +} + +template +PtrOrValue makePtrOrValue(const T &t) +{ + return PtrOrValue(t); +} + +} // namespace diff --git a/tjp/core/containers/Queue.h b/tjp/core/containers/Queue.h new file mode 100755 index 0000000..d069315 --- /dev/null +++ b/tjp/core/containers/Queue.h @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp { +namespace core { + +template +using Queue = std::queue; + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/QueueThreadSafe.hpp b/tjp/core/containers/QueueThreadSafe.hpp new file mode 100755 index 0000000..97c4d36 --- /dev/null +++ b/tjp/core/containers/QueueThreadSafe.hpp @@ -0,0 +1,80 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "List.h" +#include "../threads/Lock.h" + +namespace tjp { +namespace core { + +// this container is used in asio queue operations - +// where the front is always popped and read from the same thread +// this needs to be worked on, maybe a with_front(F &&f) + +template +class QueueThreadSafe +{ +public: + List queue; + mutable MutexType mutex; + +public: + T &front() + { + auto lk = lock_of(mutex); + return queue.front(); + } + + size_t push_back(const T &t) + { + auto lk = lock_of(mutex); + queue.push_back(t); + return queue.size(); + } + + size_t push_back(T &&t) + { + auto lk = lock_of(mutex); + queue.emplace_back(std::move(t)); + return queue.size(); + } + + template + size_t emplace_back(Args&& ...args) + { + auto lk = lock_of(mutex); + queue.emplace_back(std::forward(args)...); + return queue.size(); + } + + size_t pop_front() + { + auto lk = lock_of(mutex); + debug_assert(!queue.empty()); + queue.pop_front(); + return queue.size(); + } + + size_t size() const + { + auto lk = lock_of(mutex); + return queue.size(); + } + + bool empty() const + { + auto lk = lock_of(mutex); + return queue.empty(); + } + + template + auto with(F &&f) { + auto lk = lock_of(mutex); + return f(queue); + } +} ; +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/Reversed.h b/tjp/core/containers/Reversed.h new file mode 100755 index 0000000..7fcfde6 --- /dev/null +++ b/tjp/core/containers/Reversed.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +template +T reversed (T &&t); + +template +struct Reversed; + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/Reversed.hpp b/tjp/core/containers/Reversed.hpp new file mode 100755 index 0000000..bd2c9f3 --- /dev/null +++ b/tjp/core/containers/Reversed.hpp @@ -0,0 +1,67 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Reversed.h" +#include +#include + +namespace tjp { +namespace core { + +template +T reversed (T &&t) +{ + T c(std::move(t)); + for (auto i=0; i +struct Reversed : T +{ + typedef T Super; + typedef T Unreversed; + + template + Reversed(U&& ...u) : Super(u...) + {} + + typedef typename Super::reverse_iterator iterator; + typedef typename Super::iterator reverse_iterator; + typedef typename Super::const_reverse_iterator const_iterator; + typedef typename Super::const_iterator const_reverse_iterator; + + auto begin() { return Super::rbegin(); } + auto begin() const { return Super::rbegin(); } + auto end() { return Super::rend(); } + auto end() const { return Super::rend(); } + + auto rbegin() { return Super::begin(); } + auto rbegin() const { return Super::begin(); } + auto rend() { return Super::end(); } + auto rend() const { return Super::end(); } + + auto &back() { return Super::front(); } + auto &back() const { return Super::front(); } + auto &front() { return Super::back(); } + auto &front() const { return Super::back(); } + + auto &operator[](size_t i) + { + return Super::operator[](Super::size()-1-i); + } + + auto &operator[] (size_t i) const + { + return Super::operator[](Super::size()-1-i); + } +} ; + + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/SafeIteration+IO.h b/tjp/core/containers/SafeIteration+IO.h new file mode 100755 index 0000000..a81418a --- /dev/null +++ b/tjp/core/containers/SafeIteration+IO.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "SafeIteration.h" + +namespace tjp::core { + +template +void io_(IO &io, SafeIteration &t) +{ + io.any((T &)t); +} + +} // namespace diff --git a/tjp/core/containers/SafeIteration.h b/tjp/core/containers/SafeIteration.h new file mode 100755 index 0000000..980cc44 --- /dev/null +++ b/tjp/core/containers/SafeIteration.h @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Vector.h" +#include "FilledArray.h" + +namespace tjp { +namespace core { + +struct SafeIterationException; + +template +class SafeIterator; + +template +using SafeIteratorMutable = + SafeIterator; + +template +using SafeIteratorConst = + SafeIterator; + + +template *, 1>> +class SafeIteration; + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/SafeIteration.hpp b/tjp/core/containers/SafeIteration.hpp new file mode 100755 index 0000000..79b760c --- /dev/null +++ b/tjp/core/containers/SafeIteration.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "SafeIteration_v_all_mutable.hpp" diff --git a/tjp/core/containers/SafeIteration_v_all_mutable.hpp b/tjp/core/containers/SafeIteration_v_all_mutable.hpp new file mode 100755 index 0000000..5f4ae26 --- /dev/null +++ b/tjp/core/containers/SafeIteration_v_all_mutable.hpp @@ -0,0 +1,369 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "SafeIteration.h" + +#include "FilledArrayThreadSafe.hpp" +#include "../exception/Exception.hpp" +#include "../assert/debug_assert.h" +#include "../algorithm/vector_erase_if_value.hpp" + +#include "../threads/Lock.hpp" +#include "../threads/TestMutex.hpp" + +#ifdef SAFE_ITERATION_LOG + #include "../log/Log.h" + #include "../log/LogOf.h" + #define xLogDebugSafeIteration(x) xLogDebug(x) +#else + #define xLogDebugSafeIteration(x) +#endif + +namespace tjp { +namespace core { + +/** +* the only exception the safe iteration templates throw +*/ + +DECLARE_EXCEPTION (SafeIterationException); + +/** +* provides an iterator template which is tightly bound to a safe iteration class +*/ +template +class SafeIterator : public iterator_type +{ +friend class SafeIteration; + +protected: + const SafeIteration *parent; + + bool valid; + +protected: + void invalidate () + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = false; + iterator_type::operator ++(); + } + + void invalidate (iterator_type i) + { + xLogDebugSafeIteration(logOfThis(this)); + + iterator_type::operator =(i); + valid = false; + } + +public: + SafeIterator () : + parent (nullptr) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = false; + } + + SafeIterator (const SafeIteration *parent_, const iterator_type &i) : + iterator_type(i), + parent (parent_) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = true; + parent->addSafeIterator (this); + } + + SafeIterator(const SafeIterator &rhs) : + iterator_type(rhs) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = rhs.valid; + + parent = rhs.parent; + parent->addSafeIterator (this); + } + + SafeIterator &operator=(const SafeIterator &rhs) + { + xLogDebugSafeIteration(logOfThis(this)); + + if (this == &rhs) + return *this; + + if (parent) + parent->removeSafeIterator(this); + + iterator_type::operator=(rhs); + parent = rhs.parent; + valid = rhs.valid; + + if (parent) + parent->addSafeIterator(this); + + return *this; + } + + ~SafeIterator () + { + xLogDebugSafeIteration(logOfThis(this)); + + if (parent) + parent->removeSafeIterator (this); + } + + reference_type operator *() const + { + validate (); + return (reference_type)iterator_type::operator *(); + } + + SafeIterator &operator ++() + { + xLogDebugSafeIteration(logOfThis(this)); + + if (valid) + { + iterator_type::operator ++(); + } + else + { + valid = true; + }; + + return *this; + } + + SafeIterator &operator --() + { + xLogDebugSafeIteration(logOfThis(this)); + + iterator_type::operator --(); + + if (!valid) + { + valid = true; + } + + return *this; + } + + bool isValid () const + { + return valid; + } + + void validate () const + { + if (!valid) + throw SafeIterationException ("invalid iterator dereferenced"); + } +} ; + +template +void safe_iterator_insert(Vector &v, T *t) +{ + v.push_back(t); +} + +template +void safe_iterator_erase(Vector &v, T *t) +{ + v.erase( + std::remove( + v.begin(), v.end(), + t + ), + v.end() + ); +} + +template +void safe_iterator_insert(FilledArray &v, T *t) +{ + v.insert(t); +} + +template +void safe_iterator_erase(FilledArray &v, T *t) +{ + v.erase(t); +} + + +template +class SafeIteration : public T +{ +public: +// static constexpr int FilledArrayInitialSize = 4; + +public: + using container_type = T; + + using T_iterator = typename T::iterator; + using T_const_iterator = T_iterator ; + + using T_reference = typename T::reference; + using T_const_reference = T_reference ; + + using safe_iterator = SafeIteratorMutable; + using safe_const_iterator = safe_iterator; + + using iterator = safe_iterator; + using const_iterator = safe_const_iterator; + + using iterators_container = CM; + //FilledArray; + +protected: + mutable iterators_container iterators; + + void ensureAllIterators (T_const_reference k) + { + ensureAllIterators (this->find(k)); + } + + template + void ensureIteratorSet (const T_iterator &I, Z &set) + { + for (typename Z::iterator i=set.begin(); i!=set.end(); ++i) + { + if ( (*(*i))!=T::end() ) + { + if ( (*(*i)) == I ) + { + (*i)->invalidate (); + } + } + } + } + + void ensureAllIterators (const T_iterator &I) + { + ensureIteratorSet (I, iterators); + } + + template + void clearIteratorSet (Z &set) + { + for (typename Z::iterator i=set.begin(); i!=set.end(); ++i) + { + if ( (*(*i))!= T::end() ) + { + (*i)->invalidate (T::end()); + } + } + } + + void clearAllIterators () + { + clearIteratorSet (iterators); + } + +public: + template + SafeIteration (Args && ...args) : + T(std::forward(args)...) + { + xLogDebugSafeIteration(logOfThis(this)); + } + + SafeIteration (const SafeIteration ©) + { + xLogDebugSafeIteration(logOfThis(this)); + + T::operator =(copy); + } + + ~SafeIteration () + { + debug_assert(iterators.empty()); + } + + SafeIteration &operator =(const SafeIteration ©) + { + xLogDebugSafeIteration(logOfThis(this)); + + T::operator =(copy); + clearAllIterators(); + + return *this; + } + + inline void erase (const T_const_reference &k) + { + xLogDebugSafeIteration(logOfThis(this)); + + ensureAllIterators(k); + T::erase(k); + } + + inline void erase (const T_iterator &i) + { + xLogDebugSafeIteration(logOfThis(this)); + + T_iterator I(i); + ensureAllIterators(i); + T::erase(I); + } + + inline void clear () + { + T::clear(); + clearAllIterators(); + } + + auto begin () + { + xLogDebugSafeIteration(logOfThis(this)); + + return safe_iterator(this, T::begin()); + } + + auto begin () const + { + auto this_ = remove_const_of_var(this); + return this_->begin(); + } + + auto end () + { + xLogDebugSafeIteration(logOfThis(this)); + + return safe_iterator(this, T::end()); + } + + auto end () const + { + auto this_ = remove_const_of_var(this); + return this_->end(); + } + + template + void remove(U &&... u) + { + // use erase not remove + debug_assert(false); + } + +public: + inline void addSafeIterator (safe_iterator *i) const + { + safe_iterator_insert(iterators, i); + } + + inline void removeSafeIterator (safe_iterator *i) const + { + safe_iterator_erase(iterators, i); + } +} ; + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/SafeIteration_v_consts.hpp b/tjp/core/containers/SafeIteration_v_consts.hpp new file mode 100755 index 0000000..b49a4c9 --- /dev/null +++ b/tjp/core/containers/SafeIteration_v_consts.hpp @@ -0,0 +1,364 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "SafeIteration.h" + +#include "FilledArrayThreadSafe.hpp" +#include "../exception/Exception.hpp" +#include "../assert/debug_assert.h" + +#include "../threads/Lock.hpp" +#include "../threads/TestMutex.hpp" + +#ifdef SAFE_ITERATION_LOG + #include "../log/Log.h" + #include "../log/LogOf.h" + #define xLogDebugSafeIteration(x) xLogDebug(x) +#else + #define xLogDebugSafeIteration(x) +#endif + +namespace tjp { +namespace core { + +/** +* the only exception the safe iteration templates throw +*/ + +DECLARE_EXCEPTION (SafeIterationException); + +template class SafeIteration; + +/** +* provides an iterator template which is tightly bound to a safe iteration class +*/ +template +class SafeIterator : public iterator_type +{ +friend class SafeIteration; + +protected: + const SafeIteration *parent; + + bool valid; + +protected: + void invalidate () + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = false; + iterator_type::operator ++(); + } + + void invalidate (iterator_type i) + { + xLogDebugSafeIteration(logOfThis(this)); + + iterator_type::operator =(i); + valid = false; + } + +public: + SafeIterator () : + parent (nullptr) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = false; + } + + SafeIterator (const SafeIteration *parent_, const iterator_type &i) : + iterator_type(i), + parent (parent_) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = true; + parent->addSafeIterator (this); + } + + SafeIterator(const SafeIterator &rhs) : + iterator_type(rhs) + { + xLogDebugSafeIteration(logOfThis(this)); + + valid = rhs.valid; + + parent = rhs.parent; + parent->addSafeIterator (this); + } + + SafeIterator &operator=(const SafeIterator &rhs) + { + xLogDebugSafeIteration(logOfThis(this)); + + if (this == &rhs) + return *this; + + if (parent) + parent->removeSafeIterator(this); + + iterator_type::operator=(rhs); + parent = rhs.parent; + valid = rhs.valid; + + if (parent) + parent->addSafeIterator(this); + + return *this; + } + + ~SafeIterator () + { + xLogDebugSafeIteration(logOfThis(this)); + + if (parent) + parent->removeSafeIterator (this); + } + + reference_type operator *() const + { + validate (); + return (reference_type)iterator_type::operator *(); + } + + SafeIterator &operator ++() + { + xLogDebugSafeIteration(logOfThis(this)); + + if (valid) + { + iterator_type::operator ++(); + } + else + { + valid = true; + }; + + return *this; + } + + SafeIterator &operator --() + { + xLogDebugSafeIteration(logOfThis(this)); + + iterator_type::operator --(); + + if (!valid) + { + valid = true; + } + + return *this; + } + + bool isValid () const + { + return valid; + } + + void validate () const + { + if (!valid) + throw SafeIterationException ("invalid iterator dereferenced"); + } +} ; + +template +class SafeIteration : public T +{ +public: + static constexpr int FilledArrayInitialSize = 4; + +public: + typedef T container_type; + + typedef typename T::iterator T_iterator; + typedef typename T::const_iterator T_const_iterator; + + typedef typename T::reference T_reference; + typedef typename T::const_reference T_const_reference; + + typedef SafeIterator safe_iterator; + typedef SafeIterator safe_const_iterator; + + typedef safe_iterator iterator; + typedef safe_const_iterator const_iterator; + + using iterators_container = FilledArray; + using const_iterators_container = FilledArray; + +protected: + mutable iterators_container iterators; + mutable const_iterators_container const_iterators; + + void ensureAllIterators (T_const_reference k) + { + ensureAllIterators (this->find(k)); + } + + template + void ensureIteratorSet (const T_iterator &I, Z &set) + { + for (typename Z::iterator i=set.begin(); i!=set.end(); ++i) + { + if ( (*(*i))!=T::end() ) + { + if ( (*(*i)) == I ) + { + (*i)->invalidate (); + } + } + } + } + + void ensureAllIterators (const T_iterator &I) + { + ensureIteratorSet (I, iterators); + ensureIteratorSet (I, const_iterators); + } + + template + void clearIteratorSet (Z &set) + { + for (typename Z::iterator i=set.begin(); i!=set.end(); ++i) + { + if ( (*(*i))!= T::end() ) + { + (*i)->invalidate (T::end()); + } + } + } + + void clearAllIterators () + { + clearIteratorSet (iterators); + clearIteratorSet (const_iterators); + } + +public: + template + SafeIteration (Args && ...args) : + T(std::forward(args)...) + { + xLogDebugSafeIteration(logOfThis(this)); + } + + SafeIteration (const SafeIteration ©) + { + xLogDebugSafeIteration(logOfThis(this)); + + T::operator =(copy); + } + + ~SafeIteration () + { + debug_assert(iterators.empty() && const_iterators.empty()); + } + + SafeIteration &operator =(const SafeIteration ©) + { + xLogDebugSafeIteration(logOfThis(this)); + + T::operator =(copy); + clearAllIterators(); + + return *this; + } + +// SafeIteration &operator =(SafeIteration &©) +// { +// xLogDebugSafeIteration(logOfThis(this)); +// +// T::operator =(copy); +// clearAllIterators(); +// +// return *this; +// } + + inline void erase (const T_const_reference &k) + { + xLogDebugSafeIteration(logOfThis(this)); + + ensureAllIterators(k); + T::erase(k); + } + + inline void erase (const T_iterator &i) + { + xLogDebugSafeIteration(logOfThis(this)); + + T_iterator I(i); + ensureAllIterators(i); + T::erase(I); + } + + inline void clear () + { + T::clear(); + clearAllIterators(); + } + + iterator begin () + { + xLogDebugSafeIteration(logOfThis(this)); + + return safe_iterator(this, T::begin()); + } + + const_iterator begin () const + { + xLogDebugSafeIteration(logOfThis(this)); + + return const_iterator(this, T::begin()); + } + + iterator end () + { + xLogDebugSafeIteration(logOfThis(this)); + + return safe_iterator(this, T::end()); + } + + const_iterator end () const + { + xLogDebugSafeIteration(logOfThis(this)); + + return const_iterator(this, T::end()); + } + + template + void remove(U &&... u) + { + // use erase not remove + debug_assert(false); + } + +public: + inline void addSafeIterator (safe_iterator *i) const + { + iterators.insert (i); + } + + inline void addSafeIterator (safe_const_iterator *i) const + { + const_iterators.insert (i); + } + + inline void removeSafeIterator (safe_iterator *i) const + { + iterators.erase (i); + } + + inline void removeSafeIterator (safe_const_iterator *i) const + { + const_iterators.erase (i); + } +} ; + +} // namespace utilities +} // namespace diff --git a/tjp/core/containers/Set.h b/tjp/core/containers/Set.h new file mode 100755 index 0000000..2509084 --- /dev/null +++ b/tjp/core/containers/Set.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Set = std::set; + +template +using SetSortBy = std::set; + +} // namespace diff --git a/tjp/core/containers/Set.hpp b/tjp/core/containers/Set.hpp new file mode 100755 index 0000000..43afffd --- /dev/null +++ b/tjp/core/containers/Set.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Set.h" diff --git a/tjp/core/containers/StackArray+IO.hpp b/tjp/core/containers/StackArray+IO.hpp new file mode 100755 index 0000000..5ee8083 --- /dev/null +++ b/tjp/core/containers/StackArray+IO.hpp @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2+IO.hpp" + +namespace tjp::core { + +using namespace stackarray_v2; + +} // namespace diff --git a/tjp/core/containers/StackArray+hash.hpp b/tjp/core/containers/StackArray+hash.hpp new file mode 100755 index 0000000..5ea5258 --- /dev/null +++ b/tjp/core/containers/StackArray+hash.hpp @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray.hpp" +#include "StackArray_v2+hash.hpp" + +namespace std { + template + struct hash> { + + using A = tjp::core::stackarray_v2::StackArray; + + size_t operator()(const A &a) const { + size_t value = 0; + + hash hasher; + for (auto &v: a) + { + constexpr auto bitsToShift = 8; + // this is dumb, but we want to protect against x,x always going to zero + value = ( + (value << bitsToShift) | + (value >> ((sizeof(value) * 8) - bitsToShift)) + ); + value = value ^ hasher(v); + } + + return value; + } + }; +} diff --git a/tjp/core/containers/StackArray.h b/tjp/core/containers/StackArray.h new file mode 100755 index 0000000..399e5f5 --- /dev/null +++ b/tjp/core/containers/StackArray.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2.h" + +namespace tjp::core { + +using namespace stackarray_v2; + +} // namespace + diff --git a/tjp/core/containers/StackArray.hpp b/tjp/core/containers/StackArray.hpp new file mode 100755 index 0000000..2280b68 --- /dev/null +++ b/tjp/core/containers/StackArray.hpp @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2.hpp" + +namespace tjp::core { + +using namespace stackarray_v2; + +} // namespace diff --git a/tjp/core/containers/StackArray_v2+IO.hpp b/tjp/core/containers/StackArray_v2+IO.hpp new file mode 100755 index 0000000..2d0fc28 --- /dev/null +++ b/tjp/core/containers/StackArray_v2+IO.hpp @@ -0,0 +1,51 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2.hpp" +#include + +#include "../iterators/is_first.hpp" +#include "../string/trim.h" +#include "../string/split.hpp" + +#include "../string/from_string.inl" + +namespace tjp::core::stackarray_v2 { + +template +std::ostream &operator<<(std::ostream &out, const StackArray &a) +{ + std::ostringstream s; + s << "{"; + core::is_first first; + for (auto &id : a) + { + if (!first.check()) + s << ","; + s << id; + } + s << "}"; + + out << s.str(); + return out; +} + +template +std::istream &operator>>(std::istream &in, StackArray &a) +{ + std::string s; + in >> s; + s = core::trim_copy(s, " {}"); + auto parts = core::split(s, ','); + + a.clear(); + for (auto &part : parts) + a.push_back(core::from_string(part)); + + return in; +} + +} // namespace diff --git a/tjp/core/containers/StackArray_v2+hash.hpp b/tjp/core/containers/StackArray_v2+hash.hpp new file mode 100755 index 0000000..4a6d3f5 --- /dev/null +++ b/tjp/core/containers/StackArray_v2+hash.hpp @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2.hpp" + +namespace tjp::core::stackarray_v2 { + + +} // namespace diff --git a/tjp/core/containers/StackArray_v2.h b/tjp/core/containers/StackArray_v2.h new file mode 100755 index 0000000..c23c57c --- /dev/null +++ b/tjp/core/containers/StackArray_v2.h @@ -0,0 +1,18 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../types/Types.h" + +namespace tjp::core::stackarray_v2 { + +/** + * std list and vector and set are too slow for some reason, need fast allocation, with + */ +template +class StackArray; + +} // namespace + diff --git a/tjp/core/containers/StackArray_v2.hpp b/tjp/core/containers/StackArray_v2.hpp new file mode 100755 index 0000000..54fd2d3 --- /dev/null +++ b/tjp/core/containers/StackArray_v2.hpp @@ -0,0 +1,120 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StackArray_v2.h" +#include "InPlaceArray.hpp" +#include "Vector.h" +#include "../debug/Debug.h" +#include "../algorithm/cmp.hpp" + +#include +#include + +namespace tjp::core::stackarray_v2 { + +// this makes random accesses faster, but at a memory pointer +//#define STACK_ARRAY_USE_PTR + +template +class StackArray +{ +public: + using Self = StackArray; + static constexpr size_t Reserved = N; + + using Fixed = InPlaceArray; + using Variable = Vector; + using Ptr = T *; + +private: + std::variant v = Fixed(); + + Fixed &fixed(); + const Fixed &fixed() const; + + Variable &variable(); + const Variable &variable() const; + +#ifdef STACK_ARRAY_USE_PTR + Ptr array; +#endif + +public: + typedef T value_type; + + typedef T *iterator; + typedef const T *const_iterator; + + typedef std::reverse_iterator reverse_iterator; + typedef std::reverse_iterator const_reverse_iterator; + + inline T *data(); + inline const T *data() const; + + inline iterator begin(); + inline const_iterator begin() const; + + inline iterator end (); + inline const_iterator end () const; + + inline reverse_iterator rbegin() { return std::make_reverse_iterator(end()); } + inline const_reverse_iterator rbegin() const { return std::make_reverse_iterator(end()); } + + inline reverse_iterator rend () { return std::make_reverse_iterator(begin()); } + inline const_reverse_iterator rend () const { return std::make_reverse_iterator(begin()); } + + inline T &front () { return *begin(); } + inline T &back () { return *(end() - 1); } + inline const T &front () const { return *begin(); } + inline const T &back () const { return *(end() - 1); } + + void size_to(size_t newSize); + void changed(); + +public: + StackArray (); + StackArray (size_t _allocsize); + + StackArray(const std::initializer_list &rhs); + StackArray(const T *begin, const T *end); + + template + StackArray(const StackArray &rhs); + + template + StackArray &operator =(const StackArray &rhs); + + ~StackArray (); + + void append(const T *begin, const T *end); + void emplace(const T *begin, const T *end); + void resize(size_t length_, T t=T()); + + void push_back (const T &element); + void push_back (T &&element); + void pop_back (); + + template + T &emplace_back (Args&& ...element); + + iterator find (const T &element); + + const T &at(size_t i) const; + T &at(size_t i); + + const T &operator[] (size_t i) const; + T &operator[] (size_t i); + + size_t size () const; + void clear (); + + bool empty () const; + bool on_stack () const; +} ; + +} // namespace + +#include "StackArray_v2.inl" diff --git a/tjp/core/containers/StackArray_v2.inl b/tjp/core/containers/StackArray_v2.inl new file mode 100755 index 0000000..03ca069 --- /dev/null +++ b/tjp/core/containers/StackArray_v2.inl @@ -0,0 +1,411 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "../assert/debug_assert.h" +#include "../algorithm/cmp.hpp" + +#include "../log/Log.h" +#include "../log/LogOf.h" + +namespace tjp::core::stackarray_v2 { + +template +typename StackArray::Fixed &StackArray::fixed () +{ + return std::get(v); +} + +template +typename StackArray::Variable &StackArray::variable () +{ + return std::get(v); +} + +template +const typename StackArray::Fixed &StackArray::fixed () const +{ + return std::get(v); +} + +template +const typename StackArray::Variable &StackArray::variable () const +{ + return std::get(v); +} + +template +StackArray::StackArray () +#ifdef STACK_ARRAY_USE_PTR + : array(fixed().data()) +#endif +{ +} + +template +template +StackArray::StackArray(const StackArray &rhs) : + Self() +{ + append(rhs.begin(), rhs.end()); +} + +template +StackArray::StackArray(const T *begin_, const T *end_) : + Self() +{ + append(begin_, end_); +} + +template +template +StackArray &StackArray::operator =(const StackArray &rhs) +{ + if (this == &rhs) + return *this; + + clear(); + append(rhs.begin(), rhs.end()); + + return *this; +} + +template +StackArray::StackArray(const std::initializer_list &rhs) : + Self() +{ + for (auto &element: rhs) + push_back(element); +} + +template +StackArray::StackArray (size_t size) : + Self() +{ + resize(size); +} + +template +StackArray::~StackArray () +{ +} + +template +T * StackArray::data() +{ +#ifdef STACK_ARRAY_USE_PTR + return array; +#else + return + on_stack() ? + fixed().data() : + variable().data(); +#endif +} + +template +const T * StackArray::data() const +{ +#ifdef STACK_ARRAY_USE_PTR + return array; +#else + return + on_stack() ? + fixed().data() : + variable().data(); +#endif +} + +template +typename StackArray::iterator StackArray::begin() +{ + return data(); +} + +template +typename StackArray::const_iterator StackArray::begin() const +{ + return data(); +} + +template +typename StackArray::iterator StackArray::end () +{ + return data() + size(); +} + +template +typename StackArray::const_iterator StackArray::end () const +{ + return data() + size(); +} + + +template +void StackArray::append(const T *begin, const T *end) +{ + size_to(size() + (end - begin)); + + if (on_stack()) + fixed().append(begin, end); + else + variable().insert(variable().end(), begin, end); + + changed(); +} + +template +void StackArray::emplace(const T *begin, const T *end) +{ + size_to(size() + (end - begin)); + + if (on_stack()) + fixed().emplace(begin, end); + else + variable().emplace(variable().end(), begin, end); + + changed(); +} + +template +void StackArray::resize(size_t length_, T t) +{ + size_to(length_); + + if (on_stack()) + fixed().resize(length_, t); + else + variable().resize(length_, t); + + changed(); +} + +template +void StackArray::size_to(size_t newSize) +{ + if (!on_stack()) + return; + + // why not reserve before each push_back: + + /** + https://en.cppreference.com/w/cpp/container/vector/reserve + + Correctly using reserve() can prevent unnecessary reallocations, but inappropriate uses of reserve() (for instance, calling it before every push_back() call) may actually increase the number of reallocations (by causing the capacity to grow linearly rather than exponentially) and result in increased computational complexity and decreased performance. For example, a function that receives an arbitrary vector by reference and appends elements to it should usually not call reserve() on the vector, since it does not know of the vector's usage characteristics. + + **/ + + if (newSize > N) + { + sLogDebug("core::StackArray::transfer", logVar(newSize) << logVar(N)); + + Variable variable_; + variable_.reserve(newSize); + + auto &fixed_ = fixed(); + for (auto &i: fixed_) + variable_.emplace_back(std::move(i)); + + v = std::move(variable_); + +#ifdef STACK_ARRAY_USE_PTR + array = variable().data(); +#endif + } +} + +template +void StackArray::changed() +{ +#ifdef STACK_ARRAY_USE_PTR + if (!on_stack()) + array = variable().data(); +#endif +} + +template +void StackArray::push_back (const T &element) +{ + size_to(size()+1); + + if (on_stack()) + fixed().push_back(element); + else + variable().push_back(element); + + changed(); +} + +template +void StackArray::push_back (T &&element) +{ + size_to(size()+1); + + if (on_stack()) + fixed().push_back(std::move(element)); + else + variable().push_back(std::move(element)); + + changed(); +} + +template +template +T &StackArray::emplace_back (Args&& ...element) +{ + size_to(size()+1); + + T *r = nullptr; + if (on_stack()) + { + auto &i = fixed().emplace_back(std::forward(element)...); + r = &i; + } + else + { + auto &i = variable().emplace_back(std::forward(element)...); + r = &i; + } + + changed(); + + return *r; +} + +template +void StackArray::pop_back () +{ + if (on_stack()) + fixed().pop_back(); + else + variable().pop_back(); + + changed(); +} + +template +typename StackArray::iterator StackArray::find (const T &element) +{ + // now iterator all except for what used to be the end element + for (iterator i=begin(); i!=end(); ++i) + { + if (*i == element) + { + // the end element was the last element + return i; + } + } + + return end(); +} + +template +const T &StackArray::at(size_t i) const +{ + return data()[i]; +} + +template +T &StackArray::at(size_t i) +{ + return data()[i]; +} + +template +const T &StackArray::operator[] (size_t i) const +{ + return at(i); +} + +template +T &StackArray::operator[] (size_t i) +{ + return at(i); +} + +template +size_t StackArray::size () const +{ + return + on_stack() ? + fixed().size() : + variable().size(); +} + +template +void StackArray::clear () +{ + resize(0); +} + +template +bool StackArray::empty () const +{ + return size() == 0; +} + +template +bool StackArray::on_stack () const +{ + return v.index() == 0; +} + +template +int cmp(const StackArray &lhs, const StackArray &rhs) +{ + auto lhs_size = lhs.size(); + auto rhs_size = rhs.size(); + auto max = std::min(lhs_size, rhs_size); + + auto *l = lhs.data(); + auto *r = rhs.data(); + for (auto i=0; i +bool operator <(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) < 0; +} + +template +bool operator <=(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) <= 0; +} + +template +bool operator >(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) > 0; +} + +template +bool operator >=(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) >= 0; +} + +template +bool operator ==(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) == 0; +} + +template +bool operator !=(const StackArray &lhs, const StackArray &rhs) +{ + return cmp(lhs, rhs) != 0; +} + + + +} // namespace + diff --git a/tjp/core/containers/TransparentLess.hpp b/tjp/core/containers/TransparentLess.hpp new file mode 100755 index 0000000..06b2e70 --- /dev/null +++ b/tjp/core/containers/TransparentLess.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +struct TransparentLess { + using is_transparent = void; + + template + constexpr bool operator()(const T& lhs, const U& rhs) const { + return lhs < rhs; + } +}; + +} // namespace +} // namespace diff --git a/tjp/core/containers/Tuple.h b/tjp/core/containers/Tuple.h new file mode 100755 index 0000000..0687b7a --- /dev/null +++ b/tjp/core/containers/Tuple.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Tuple = std::tuple; + +} // namespace diff --git a/tjp/core/containers/Tuple.hpp b/tjp/core/containers/Tuple.hpp new file mode 100755 index 0000000..6327982 --- /dev/null +++ b/tjp/core/containers/Tuple.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Tuple.h" diff --git a/tjp/core/containers/UnorderedMap.h b/tjp/core/containers/UnorderedMap.h new file mode 100755 index 0000000..83c9786 --- /dev/null +++ b/tjp/core/containers/UnorderedMap.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using UnorderedMap = std::unordered_map; + +} // namespace diff --git a/tjp/core/containers/UnorderedMap.hpp b/tjp/core/containers/UnorderedMap.hpp new file mode 100755 index 0000000..ba18648 --- /dev/null +++ b/tjp/core/containers/UnorderedMap.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "UnorderedMap.h" diff --git a/tjp/core/containers/UnorderedSet.h b/tjp/core/containers/UnorderedSet.h new file mode 100755 index 0000000..f7452b1 --- /dev/null +++ b/tjp/core/containers/UnorderedSet.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using UnorderedSet = std::unordered_set; + +} // namespace diff --git a/tjp/core/containers/UnorderedSet.hpp b/tjp/core/containers/UnorderedSet.hpp new file mode 100755 index 0000000..71081de --- /dev/null +++ b/tjp/core/containers/UnorderedSet.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "UnorderedSet.h" diff --git a/tjp/core/containers/Vector.h b/tjp/core/containers/Vector.h new file mode 100755 index 0000000..95f746d --- /dev/null +++ b/tjp/core/containers/Vector.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +using Vector = std::vector; + +} // namespace diff --git a/tjp/core/containers/Vector.hpp b/tjp/core/containers/Vector.hpp new file mode 100755 index 0000000..3d4932a --- /dev/null +++ b/tjp/core/containers/Vector.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Vector.h" diff --git a/tjp/core/containers/_tests/InPlaceArray.cpp b/tjp/core/containers/_tests/InPlaceArray.cpp new file mode 100755 index 0000000..1c17bc3 --- /dev/null +++ b/tjp/core/containers/_tests/InPlaceArray.cpp @@ -0,0 +1,187 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include +#include + +#include + +#include +#include + +namespace tjp::core::containers { +namespace { + +struct E { + int i; +} ; + +struct Constructable { + static int constructed; + static int copy_constructed; + static int move_constructed; + static int destructed; + + static void clear() { + constructed = + copy_constructed = + move_constructed = + destructed = 0; + } + + int i; + + Constructable(const Constructable &c) + { + i = c.i+1; + copy_constructed++; + } + + Constructable(Constructable &&c) + { + std::swap(i, c.i); + move_constructed++; + } + + Constructable () + { + i = 0; + constructed++; + } + + ~Constructable() + { + destructed++; + } +} ; + +int Constructable::constructed = 0; +int Constructable::copy_constructed = 0; +int Constructable::move_constructed = 0; +int Constructable::destructed = 0; + +SCENARIO("core::containers::InPlace" ) +{ + GIVEN("sizes") + { + using IPA = InPlaceArray; + + sLogTest("debug", + logVar(sizeof(IPA)) + ); + } + + GIVEN("a list with X elements") + { + InPlaceArray a; + + WHEN("add less than N itesm") + { + for (auto i : range(0, 10)) + a.push_back(E{i}); + + REQUIRE(a.size() == 10); + + THEN("arrays elements match") + { + int i=0; + for (auto &v : a) + { + REQUIRE(v.i == i); + i++; + } + } + + WHEN("remove some itesm") + { + for (auto _ : range(0, 5)) + { + unused(_); + a.pop_back(); + } + + REQUIRE(a.size() == 5); + + THEN("arrays elements match") + { + int i=0; + for (auto &v : a) + { + REQUIRE(v.i == i); + i++; + } + } + + WHEN("things are copied") + { + THEN("arrays a elements match") + { + int i=0; + for (auto &v : a) + { + REQUIRE(v.i == i); + i++; + } + } + + auto b = a; + + REQUIRE(b.size() == 5); + + + THEN("arrays elements match") + { + int i=0; + for (auto &v : b) + { + REQUIRE(v.i == i); + i++; + } + } + } + } + } + } + + GIVEN("a list with X unconstructed constructables") + { + { + Constructable::clear(); + + InPlaceArray a; + + REQUIRE(Constructable::constructed == 0); + REQUIRE(Constructable::destructed == 0); + + Constructable c; + a.push_back(std::move(c)); + } + + REQUIRE(Constructable::constructed == 1); + REQUIRE(Constructable::move_constructed == 1); + REQUIRE(Constructable::destructed == 2); + + { + Constructable::clear(); + + InPlaceArray a; + + REQUIRE(Constructable::constructed == 0); + REQUIRE(Constructable::destructed == 0); + + Constructable c; + a.push_back(c); + } + + REQUIRE(Constructable::constructed == 1); + REQUIRE(Constructable::copy_constructed == 1); + REQUIRE(Constructable::destructed == 2); + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/containers/_tests/MultiContainer.cpp b/tjp/core/containers/_tests/MultiContainer.cpp new file mode 100755 index 0000000..aec3d4d --- /dev/null +++ b/tjp/core/containers/_tests/MultiContainer.cpp @@ -0,0 +1,108 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +namespace tjp::core::containers { +namespace { + +SCENARIO("core::containers::MultiContainer") +{ + GIVEN("a multicontainer") + { + using V = Vector; + MultiContainer c; + + V v1, v2, v3; + c.add(&v1); + c.add(&v2); + c.add(&v3); + + REQUIRE(c.size() == 0); + + auto m = 0; + for (auto &_: c) + { + unused(_); + m++; + } + + REQUIRE(m == 0); + + auto v1s = 1; + auto v2s = 7; + auto v3s = 15; + + v1.resize(v1s); + v2.resize(v2s); + v3.resize(v3s); + + auto s = v1s + v2s + v3s; + REQUIRE(c.size() == s); + + m = 0; + for (auto &_: c) + { + unused(_); + m++; + } + + REQUIRE(m == s); + } + + GIVEN("a multicontainer of multicontainer") + { + using V = Vector; + using M = MultiContainer; + using MM = MultiContainer; + M cx0, cx1; + + V v1, v2, v3; + cx0.add(&v1); + cx0.add(&v2); + + cx1.add(&v3); + + MM c(&cx0, &cx1); + + auto size = c.size(); + REQUIRE(size == 0); + + auto m = 0; + for (auto &_: c) + { + unused(_); + m++; + } + + REQUIRE(m == 0); + + auto v1s = 1; + auto v2s = 7; + auto v3s = 15; + + v1.resize(v1s); + v2.resize(v2s); + v3.resize(v3s); + + auto s = v1s + v2s + v3s; + REQUIRE(c.size() == s); + + m = 0; + for (auto &_: c) + { + unused(_); + m++; + } + + REQUIRE(m == s); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/containers/_tests/SafeIteration.cpp b/tjp/core/containers/_tests/SafeIteration.cpp new file mode 100755 index 0000000..a3c997e --- /dev/null +++ b/tjp/core/containers/_tests/SafeIteration.cpp @@ -0,0 +1,114 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include + +#include +#include + +namespace tjp::core::containers { +namespace { + +SCENARIO("core::containers::SafeIteration") +{ + GIVEN("sizes") + { + using LI = List; + using SLI = SafeIteration>; + + using FA = FilledArray; + + sLogTest("debug", + logVar(sizeof(SLI)) + << logVar(sizeof(SLI::container_type)) + << logVar(sizeof(SLI::iterators_container)) + ); + } + GIVEN("a list with X elements") + { + SafeIteration> l; + l.push_back(0); + l.push_back(1); + l.push_back(2); + l.push_back(3); + l.push_back(4); + l.push_back(5); + + WHEN("iterate but my item+1") + { + List r; + + for (auto i : l) + { + r.push_back(i); + + if (i == 3) + { + l.erase(std::find(l.begin(), l.end(), i+1)); + } + } + + REQUIRE(r == List { 0, 1, 2, 3, 5 }); + } + + WHEN("iterate but my item") + { + List r; + + for (auto i : l) + { + r.push_back(i); + + if (i == 3) + { + l.erase(std::find(l.begin(), l.end(), i)); + } + } + + REQUIRE(r == List { 0, 1, 2, 3, 4, 5 }); + } + + WHEN("iterate but remove from front to back") + { + List r; + + for (auto i : l) + { + r.push_back(i); + + if (i == 3) + { + while (!l.empty()) + l.erase(std::find(l.begin(), l.end(), l.front())); + } + } + + REQUIRE(r == List { 0, 1, 2, 3 }); + } + + WHEN("iterate but remove from back to front") + { + List r; + for (auto i : l) + { + r.push_back(i); + if (i == 3) + { + while (!l.empty()) + l.erase(std::find(l.begin(), l.end(), l.back())); + } + } + + REQUIRE(r == List { 0, 1, 2, 3 }); + } + + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/containers/_tests/StackArray_v2.cpp b/tjp/core/containers/_tests/StackArray_v2.cpp new file mode 100755 index 0000000..2c4d88e --- /dev/null +++ b/tjp/core/containers/_tests/StackArray_v2.cpp @@ -0,0 +1,91 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +namespace tjp::core::stackarray_v2 { +namespace { + +struct E { + int i; +} ; + +SCENARIO("core::containers::stackarray_v2" ) +{ + GIVEN("sizes") + { + using SA32 = StackArray; + sLogTest("debug", + logVar(sizeof(SA32)) + << logVar(sizeof(SA32::Fixed)) + << logVar(sizeof(SA32::Variable)) + << logVar(sizeof(SA32::Ptr)) + ); + } + GIVEN("a list with X elements") + { + StackArray a; + + WHEN("add less than N items") + { + for (auto i : range(0, 10)) + a.push_back(E{i}); + + THEN("array is static") + { + REQUIRE(a.on_stack()); + } + + THEN("arrays elements match") + { + int i=0; + for (auto &v : a) + { + REQUIRE(v.i == i); + i++; + } + } + } + + WHEN("add more than N items") + { + for (auto i : range(0, 32)) + a.push_back(E{i}); + + for (auto i : range(32, 128)) + a.push_back(E{i}); + + THEN("array is not static") + { + REQUIRE(!a.on_stack()); + } + + THEN("arrays elements match") + { + int i=0; + for (auto &v : a) + { + REQUIRE(v.i == i); + i++; + } + } + + THEN("item is popped") + { + a.pop_back(); + } + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/debug/Allocations.cpp b/tjp/core/debug/Allocations.cpp new file mode 100755 index 0000000..b977508 --- /dev/null +++ b/tjp/core/debug/Allocations.cpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Allocations.h" + +#include + +namespace tjp::core::debug { + +void Allocations::onAllocation (const type_index &t) +{ + auto l = lock_of(mutex); + allocations[t.name()].count++; +} + +void Allocations::onDeallocation (const type_index &t) +{ + auto l = lock_of(mutex); + allocations[t.name()].count--; +} + +String Allocations::log () +{ + std::ostringstream ss; + for (auto &[id, a]: allocations) + { + if (a.count) + ss << id << ": " << a.count << std::endl; + } + + return ss.str(); +} + +Allocations *Allocations::shared() +{ + static Allocations *allocations = new Allocations(); + return allocations; +} + +} // namespace + diff --git a/tjp/core/debug/Allocations.h b/tjp/core/debug/Allocations.h new file mode 100755 index 0000000..c1d2084 --- /dev/null +++ b/tjp/core/debug/Allocations.h @@ -0,0 +1,58 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Debug.h" +#include +#include "../containers/Map.h" +#include "../string/String.h" +#include "../threads/Lock.hpp" +#include "../algorithm/ExecuteOnDestruct.hpp" +#include "../rtti/RTTI.hpp" + +namespace tjp::core::debug { + +struct Allocations +{ + struct Allocation { + int count = 0; + } ; + + Mutex mutex; + Map allocations; + + void onAllocation (const type_index &t); + void onDeallocation (const type_index &t); + String log (); + + static Allocations *shared(); +} ; + +} // namespace + +#if defined(_DEBUG) + +#define ALLOC_RECORD(x) \ + tjp::core::debug::Allocations::shared()->onAllocation(type_id(*x)) +#define DEALLOC_RECORD(x) \ + tjp::core::debug::Allocations::shared()->onDeallocation(type_id(*x)) + +#define SCOPE_RECORD(x) \ + struct __ALLOC__##x __alloc__ {}; \ + ALLOC_RECORD(&__alloc_); \ + tjp::core::ExecuteOnDestruct __dealloc__([&]() { DEALLOC_RECORD(&__alloc__)); \ + +#define ALLOC_LOG() \ + sLogRelease("alloc", tjp::core::debug::Allocations::shared()->log()) + +#else + +#define ALLOC_RECORD(x) +#define DEALLOC_RECORD(x) +#define SCOPE_RECORD(x) + +#define ALLOC_LOG() + +#endif diff --git a/tjp/core/debug/Allocations.hpp b/tjp/core/debug/Allocations.hpp new file mode 100644 index 0000000..19738ca --- /dev/null +++ b/tjp/core/debug/Allocations.hpp @@ -0,0 +1,25 @@ +// TJP COPYRIGHT HEADER + +#pragma once + +#include "../system/Debug.h" +#include +#include "../containers/Map.h" +#include "../string/String.h" +#include "../threads/Lock.hpp" + +namespace timprepscius::core::debug { + +struct Allocations +{ + Mutex mutex; + Map allocations; + + void onAllocation (const std::type_info &t); + void onDeallocation (const std::type_info &t); + + static Allocations *shared(); +} ; + +} // namespace + diff --git a/tjp/core/debug/CompileTimeSizeOf.h b/tjp/core/debug/CompileTimeSizeOf.h new file mode 100755 index 0000000..89d4d8b --- /dev/null +++ b/tjp/core/debug/CompileTimeSizeOf.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +template +struct CompileTimeSizeOf_ +{ + unsigned char operator()() { return N + 256; } //deliberately causing overflow +}; + +#define COMPILE_TIME_SIZEOF(x) CompileTimeSizeOf_()(); + diff --git a/tjp/core/debug/Debug.h b/tjp/core/debug/Debug.h new file mode 100755 index 0000000..effc8e3 --- /dev/null +++ b/tjp/core/debug/Debug.h @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../system/Debug.h" + +#if defined(_DEBUG) || defined(DEBUG) + #define xDebugLine() { int x = 0; (void)x; } + #define IS_DEBUG() 1 + + #ifndef _DEBUG + #define _DEBUG + #endif + + #ifndef DEBUG + #define DEBUG + #endif + +#else + #define xDebugLine() (void)0; + #define IS_DEBUG() 0 + + #ifndef NDEBUG + #define NDEBUG + #endif +#endif + +#if defined(DEBUG) + #define DEBUG_ONLY(...) __VA_ARGS__ +#else + #define DEBUG_ONLY(...) +#endif diff --git a/tjp/core/debug/RUN_IF.h b/tjp/core/debug/RUN_IF.h new file mode 100755 index 0000000..e9d1678 --- /dev/null +++ b/tjp/core/debug/RUN_IF.h @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#define RUN_IF(x, ...) if constexpr(x){ __VA_ARGS__; } diff --git a/tjp/core/debug/Stack.h b/tjp/core/debug/Stack.h new file mode 100755 index 0000000..112c566 --- /dev/null +++ b/tjp/core/debug/Stack.h @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../system/Debug.h" +#include "../system/System.h" +#include + +namespace tjp::core { + +std::string getStackString(int maxStackDepth=32); + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY + #ifdef SYS_ANDROID + #include "android/Stack.cpp" + #else + #include "glib/Stack.cpp" + #endif +#endif diff --git a/tjp/core/debug/StackUsage.cpp b/tjp/core/debug/StackUsage.cpp new file mode 100755 index 0000000..b65f29d --- /dev/null +++ b/tjp/core/debug/StackUsage.cpp @@ -0,0 +1,99 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "StackUsage.h" +#include +#include +#include + +#include "../system/System.h" + +#ifdef SYS_APPLE + +#include +#include +#include +#include + +#endif + + +namespace tjp { +namespace core { + +#ifndef SYS_ANDROID + +#ifdef SYS_APPLE +void *getStackBase () +{ + return pthread_get_stackaddr_np(pthread_self()); + +/* + uint64_t threadId; + pthread_threadid_np(nullptr, &threadId); + + // Get thread info + mach_msg_type_number_t threadInfoCount = THREAD_BASIC_INFO_COUNT; + thread_basic_info_data_t threadInfo; + if (thread_info((thread_act_t)threadId, THREAD_BASIC_INFO, (thread_info_t)&threadInfo, &threadInfoCount) != KERN_SUCCESS) { + return 0; + } + + // Get the stack base address + void* stackBase = (void*)threadInfo.stack_base; + return stackBase; +*/ +} + +#else + +void *getStackBase() +{ + pthread_attr_t attr; + pthread_getattr_np(pthread_self(), &attr); + + // Get the stack base address + void* stackBase = nullptr; + pthread_attr_getstackaddr(&attr, &stackBase); + + // Clean up thread attributes + pthread_attr_destroy(&attr); + + return stackBase; +} + +#endif + +std::size_t getStackUsage() { + // Define a local variable + int localVariable; + + void* stackBase = getStackBase(); + + // Calculate the current stack pointer (address of localVariable) + std::uintptr_t currentStackPointer = reinterpret_cast(&localVariable); + + // Calculate the stack usage + std::size_t stackUsage = static_cast(reinterpret_cast(stackBase) - currentStackPointer); + + return stackUsage; +} + +#else + +std::size_t getStackUsage() { + + pthread_attr_t attr; + pthread_getattr_np(pthread_self(), &attr); + + size_t size = 0; + pthread_attr_getstacksize(&attr, &size); + + return size; +} + +#endif + +} // namespace +} // namespace diff --git a/tjp/core/debug/StackUsage.h b/tjp/core/debug/StackUsage.h new file mode 100755 index 0000000..1be5288 --- /dev/null +++ b/tjp/core/debug/StackUsage.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +size_t getStackUsage(); + +} // namespace diff --git a/tjp/core/debug/android/Stack.cpp b/tjp/core/debug/android/Stack.cpp new file mode 100755 index 0000000..a67da7a --- /dev/null +++ b/tjp/core/debug/android/Stack.cpp @@ -0,0 +1,81 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif + +#include "../../header_only/compile.h" + +#include "../Stack.h" +#include "../../system/System.h" + +#include +#include +#include +#include + +// https://stackoverflow.com/questions/8115192/android-ndk-getting-the-backtrace +struct BacktraceState +{ + void** current; + void** end; +}; + + +TJP_CORE_HEADER_ONLY_INLINE +static _Unwind_Reason_Code unwindCallback(struct _Unwind_Context* context, void* arg) +{ + BacktraceState* state = static_cast(arg); + uintptr_t pc = _Unwind_GetIP(context); + if (pc) { + if (state->current == state->end) { + return _URC_END_OF_STACK; + } else { + *state->current++ = reinterpret_cast(pc); + } + } + return _URC_NO_REASON; +} + +TJP_CORE_HEADER_ONLY_INLINE +size_t captureBacktrace(void** buffer, size_t max) +{ + BacktraceState state = {buffer, buffer + max}; + _Unwind_Backtrace(unwindCallback, &state); + + return state.current - buffer; +} + +TJP_CORE_HEADER_ONLY_INLINE +void dumpBacktrace(std::ostream& os, void** buffer, size_t count) +{ + for (size_t idx = 0; idx < count; ++idx) { + const void* addr = buffer[idx]; + const char* symbol = ""; + + Dl_info info; + if (dladdr(addr, &info) && info.dli_sname) { + symbol = info.dli_sname; + } + + os << " #" << std::setw(2) << idx << ": " << addr << " " << symbol << "\n"; + } +} + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +std::string getStackString(int maxStackDepth) +{ + auto buffer = (void **)alloca(sizeof(void *) * maxStackDepth); + auto count = captureBacktrace(buffer, maxStackDepth); + + std::ostringstream oss; + dumpBacktrace(oss, buffer, count); + + return oss.str(); +} + +} // namespace diff --git a/tjp/core/debug/debug_break.h b/tjp/core/debug/debug_break.h new file mode 100755 index 0000000..dda8c7f --- /dev/null +++ b/tjp/core/debug/debug_break.h @@ -0,0 +1,24 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../system/Debug.h" + +#include "../system/System.h" + +namespace tjp::core { + +#ifdef _DEBUG +inline void debug_break() +{ +#ifdef SYS_APPLE + __asm__("brk #0"); +#endif +} +#else +inline void debug_break() {}; +#endif + +} // namespace diff --git a/tjp/core/debug/glib/Stack.cpp b/tjp/core/debug/glib/Stack.cpp new file mode 100755 index 0000000..6c65d55 --- /dev/null +++ b/tjp/core/debug/glib/Stack.cpp @@ -0,0 +1,43 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif + +#include "../../header_only/compile.h" + +#include "../Stack.h" +#include "../../system/System.h" + +#include +#include + +namespace tjp { +namespace core { + +TJP_CORE_HEADER_ONLY_INLINE +std::string getStackString(int maxStackDepth) +{ + void* trace[64]; + if (maxStackDepth > 64) maxStackDepth = 64; + + char** messages = NULL; + int trace_size = 0; + + std::ostringstream out; + + trace_size = backtrace( trace, maxStackDepth ); + messages = backtrace_symbols( trace, trace_size ); + for( int i = 2; i < trace_size; ++i ) { + out << "\t" << messages[i] << std::endl; + } + + free (messages); + + return out.str(); +} + +} // namespace +} // namespace diff --git a/tjp/core/exception/Exception+IO.hpp b/tjp/core/exception/Exception+IO.hpp new file mode 100755 index 0000000..2f8e6de --- /dev/null +++ b/tjp/core/exception/Exception+IO.hpp @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Exception.hpp" + +namespace tjp::core { + +template +void io_(IO &io, Exception &v) +{ + io.object( + "what", v.what() + ); +} + +} // namespace diff --git a/tjp/core/exception/Exception.cpp b/tjp/core/exception/Exception.cpp new file mode 100755 index 0000000..51d5410 --- /dev/null +++ b/tjp/core/exception/Exception.cpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Exception.hpp" +#include + +namespace tjp::core { + +std::ostream &operator <<(std::ostream &out, const tjp::core::Exception &e) +{ + return out << "Exception: " << e.what(); +} + +} // namespace + diff --git a/tjp/core/exception/Exception.h b/tjp/core/exception/Exception.h new file mode 100755 index 0000000..227c791 --- /dev/null +++ b/tjp/core/exception/Exception.h @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +#define DECLARE_EXCEPTION_HEADER(e) class e; + +namespace tjp::core { + +class Exception; + +std::ostream &operator <<(std::ostream &, const tjp::core::Exception &e); + +} // namespace + + + diff --git a/tjp/core/exception/Exception.hpp b/tjp/core/exception/Exception.hpp new file mode 100755 index 0000000..f35ddf1 --- /dev/null +++ b/tjp/core/exception/Exception.hpp @@ -0,0 +1,71 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Exception.h" +#include "../string/String.hpp" +#include "../string/StringView.hpp" +#include + +#define TJP_EXCEPTION_BASE ::tjp::core::Exception + +#define DECLARE_EXCEPTION_BASE(e,k) \ + struct e : k \ + { \ + typedef k Super; \ + e(const value_type &what) : Super(what) { } \ + e() { } \ + } ;\ + +#define DECLARE_EXCEPTION_BASE_MSG(e,k,msg) \ + struct e : k \ + { \ + typedef k Super; \ + e(const value_type &what) : Super(what) { } \ + e() : Super(msg) { } \ + } ;\ + +#define DECLARE_EXCEPTION_BASE_MSG_PREFIX(e,k,msg) \ + struct e : k \ + { \ + static constexpr ::tjp::core::StringView Prefix = msg; \ + typedef k Super; \ + e(const value_type &what) : Super(msg ": " + what) { } \ + e() : Super(msg) { } \ + } ;\ + +#define DECLARE_EXCEPTION_BASE_MSG_PREFIX_ARGS(e,k,msg,...) \ + struct e : k \ + { \ + static constexpr ::tjp::core::StringView Prefix = msg; \ + typedef k Super; \ + e(const value_type &what) : Super(msg ": " + what, __VA_ARGS__) { } \ + e() : Super(msg, __VA_ARGS__) { } \ + } ;\ + + +#define DECLARE_EXCEPTION(e) DECLARE_EXCEPTION_BASE(e, TJP_EXCEPTION_BASE) +#define DECLARE_EXCEPTION_MESSAGE(e, msg) DECLARE_EXCEPTION_BASE_MSG(e,TJP_EXCEPTION_BASE, msg) + +namespace tjp::core { + +class Exception +{ +public: + using value_type = String; + +private: + value_type _what; + +public: + Exception (const value_type &what) : _what(what) { } + Exception () { } + virtual ~Exception () { } + + const value_type &what() const throw() { return _what; } + value_type &what() throw() { return _what; } +} ; + +} // namespace diff --git a/tjp/core/exception/NotImplemented.h b/tjp/core/exception/NotImplemented.h new file mode 100755 index 0000000..7682a1e --- /dev/null +++ b/tjp/core/exception/NotImplemented.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_HEADER(NotImplemented); + +} // namespace + + diff --git a/tjp/core/exception/NotImplemented.hpp b/tjp/core/exception/NotImplemented.hpp new file mode 100755 index 0000000..609eeb0 --- /dev/null +++ b/tjp/core/exception/NotImplemented.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "NotImplemented.h" +#include "Exception.hpp" + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_MESSAGE(NotImplemented, "Not implemented") + +} // namespace + + diff --git a/tjp/core/exception/NullPointer.h b/tjp/core/exception/NullPointer.h new file mode 100755 index 0000000..f01f987 --- /dev/null +++ b/tjp/core/exception/NullPointer.h @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Exception.h" + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_HEADER(NullPointer); + +} // namespace + + diff --git a/tjp/core/exception/NullPointer.hpp b/tjp/core/exception/NullPointer.hpp new file mode 100755 index 0000000..fe508aa --- /dev/null +++ b/tjp/core/exception/NullPointer.hpp @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "NullPointer.h" + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_MESSAGE(NullPointer, "Null pointer") + +} // namespace + + diff --git a/tjp/core/exception/OutOfBounds.h b/tjp/core/exception/OutOfBounds.h new file mode 100755 index 0000000..4c81b37 --- /dev/null +++ b/tjp/core/exception/OutOfBounds.h @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Exception.h" + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_HEADER(OutOfBounds); + +} // namespace + + diff --git a/tjp/core/exception/OutOfBounds.hpp b/tjp/core/exception/OutOfBounds.hpp new file mode 100755 index 0000000..4999e12 --- /dev/null +++ b/tjp/core/exception/OutOfBounds.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "OutOfBounds.h" +#include "Exception.hpp" + +namespace tjp::core::exceptions { + +DECLARE_EXCEPTION_MESSAGE(OutOfBounds, "Not implemented") + +} // namespace + + diff --git a/tjp/core/exception/debug_throw.h b/tjp/core/exception/debug_throw.h new file mode 100755 index 0000000..8afebfd --- /dev/null +++ b/tjp/core/exception/debug_throw.h @@ -0,0 +1,41 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../log/Log.h" +#include "../debug/Debug.h" +#include "../debug/Stack.h" + +#include + +#ifdef _DEBUG + +#define debug_throw(...) { \ + try { throw __VA_ARGS__; } \ + catch (tjp::core::Exception &e) \ + { \ + sLogDebug("exceptions", e << ": " << core::getStackString()); \ + throw; \ + } \ + catch (std::runtime_error &e) \ + { \ + sLogDebug("exceptions", e.what() << ": " << core::getStackString()); \ + throw; \ + } \ + catch (...) \ + { \ + sLogDebug("exceptions", core::getStackString()); \ + throw; \ + } \ +} \ + +#else + +#define debug_throw(...) throw __VA_ARGS__ + +#endif + +#define throw_debug(...) debug_throw(__VA_ARGS__) + diff --git a/tjp/core/header_only/compile.h b/tjp/core/header_only/compile.h new file mode 100755 index 0000000..00250ce --- /dev/null +++ b/tjp/core/header_only/compile.h @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef TJP_CORE_HEADER_ONLY + #define TJP_CORE_HEADER_ONLY_INLINE inline + #define TJP_CORE_HEADER_ONLY_COMPILE +#else + #define TJP_CORE_HEADER_ONLY_INLINE +#endif diff --git a/tjp/core/io/memstream.h b/tjp/core/io/memstream.h new file mode 100755 index 0000000..e351ad9 --- /dev/null +++ b/tjp/core/io/memstream.h @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::io { + +struct imembuf; +struct imemstream; + +struct omembuf; +struct omemstream; + +} diff --git a/tjp/core/io/memstream.hpp b/tjp/core/io/memstream.hpp new file mode 100755 index 0000000..4136edc --- /dev/null +++ b/tjp/core/io/memstream.hpp @@ -0,0 +1,110 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "memstream.h" + +#include +#include +#include + +namespace tjp::core::io { + +// https://stackoverflow.com/questions/13059091/creating-an-input-stream-from-constant-memory/13059195#13059195 +struct imembuf: std::streambuf +{ + imembuf(char const* base, size_t size) { + char* p(const_cast(base)); + this->setg(p, p, p + size); + } +}; + +struct imemstream: virtual imembuf, std::istream +{ + imemstream(char const* base, size_t size) + : imembuf(base, size) + , std::istream(static_cast(this)) { + } + + imemstream(const std::string_view &s) + : imembuf(s.data(), s.size()) + , std::istream(static_cast(this)) { + } + +}; + +struct omembuf: std::streambuf { + std::vector &v; + size_t offset = 0; + omembuf(std::vector &v_) : v(v_) { + + } + + // ------------------------ OUTPUT FUNCTIONS ------------------------ + + int_type overflow ( int_type c) override + { + if (c != EOF) v.push_back(static_cast(c)); + offset = v.size(); + return c; + } + + std::streamsize xsputn ( const char* s, std::streamsize num) override + { + auto written = num; + while(num && offset < v.size()) + { + v[offset++] = *s++; + num--; + } + + v.insert(v.end(), s, s+num); + offset += num; + + return written; + } + + pos_type seekpos( + pos_type pos, + std::ios_base::openmode which = std::ios_base::in | std::ios_base::out + ) override + { + if (pos > v.size()) + return pos_type(-1); + + offset = pos; + return pos; + } + + pos_type seekoff( + off_type off, std::ios_base::seekdir dir, + std::ios_base::openmode which = std::ios_base::in | std::ios_base::out + ) override + { + if (off < 0 && -off > offset) + return pos_type(-1); + + return seekpos(offset + off); + } +}; + +struct omemstream: virtual omembuf, std::ostream { + omemstream(std::vector &v_) + : omembuf(v_) + , std::ostream(static_cast(this)) { + } +}; + +struct omemstream_: virtual omembuf, std::ostream { + std::vector data; + + omemstream_() + : omembuf(data) + , std::ostream(static_cast(this)) { + } +}; + +} // namespace + diff --git a/tjp/core/iterators/_tests/enumerate.cpp b/tjp/core/iterators/_tests/enumerate.cpp new file mode 100755 index 0000000..fe6e03d --- /dev/null +++ b/tjp/core/iterators/_tests/enumerate.cpp @@ -0,0 +1,105 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "../../testing/catch.hpp" +#include "../enumerate.hpp" + +#include "../../containers/Vector.hpp" +#include "../../containers/List.hpp" + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::enumerate") +{ + GIVEN("a vector") + { + fail_on_copy_vector l; + l.resize(42, 1); + + WHEN("iterating") + { + size_t last = 0; + for (auto [e, v]: enumerate(l)) + { + last = e; + REQUIRE(v == 1); + } + + auto expected = l.size() - 1; + REQUIRE(last == expected); + } + + WHEN("iterating and setting") + { + size_t last = 0; + for (auto [e, v]: enumerate(l)) + { + v = (int)e; + } + + for (auto [e, v]: enumerate(l)) + { + last = e; + REQUIRE(v == (int)e); + } + + auto expected = l.size() - 1; + REQUIRE(last == expected); + } + + WHEN("iterating const") + { + const auto &lc = l; + size_t last = 0; + for (auto [e, v]: enumerate(lc)) + { + last = e; + REQUIRE(v == 1); + } + + auto expected = l.size() - 1; + REQUIRE(last == expected); + } + + WHEN("iterating value") + { + const auto &lc = l; + size_t last = 0; + for (auto [e, v]: enumerate_value(lc)) + { + last = e; + REQUIRE(v == 1); + } + + auto expected = l.size() - 1; + REQUIRE(last == expected); + } + } + + GIVEN("a list") + { + List l; + l.resize(42, 1); + + WHEN("iterating to X") + { + size_t last = 0; + for (auto [e, v]: enumerate(l)) + { + last = e; + REQUIRE(v == 1); + } + + auto expected = l.size() - 1; + REQUIRE(last == expected); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/fail_on_copy_vector.hpp b/tjp/core/iterators/_tests/fail_on_copy_vector.hpp new file mode 100755 index 0000000..87b9fb4 --- /dev/null +++ b/tjp/core/iterators/_tests/fail_on_copy_vector.hpp @@ -0,0 +1,31 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +namespace tjp::core { + +template +struct fail_on_copy_vector : Vector { + + fail_on_copy_vector(const fail_on_copy_vector &) { + REQUIRE(false); + } + + fail_on_copy_vector(fail_on_copy_vector &&) { + REQUIRE(false); + } + + fail_on_copy_vector(std::initializer_list &&v) : + Vector(v) + {} + + fail_on_copy_vector() {} +} ; + +} // namespace diff --git a/tjp/core/iterators/_tests/is_first.cpp b/tjp/core/iterators/_tests/is_first.cpp new file mode 100755 index 0000000..c3d464d --- /dev/null +++ b/tjp/core/iterators/_tests/is_first.cpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::is_first") +{ + GIVEN("a vector") + { + fail_on_copy_vector l; + l.resize(42, 1); + int expected = 10; + l[0] = expected; + + WHEN("iterating to X") + { + int value = 0; + is_first first; + for (auto &v: l) + { + if (first) + value = v; + } + + REQUIRE(value == expected); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/no_first.cpp b/tjp/core/iterators/_tests/no_first.cpp new file mode 100755 index 0000000..d0aff51 --- /dev/null +++ b/tjp/core/iterators/_tests/no_first.cpp @@ -0,0 +1,76 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::no_first") +{ + GIVEN("a vector") + { + fail_on_copy_vector l; + l.resize(42, 1); + l.front() = 10; + l.back() = 100; + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto v: no_first(l)) + sum += v; + + auto expected = 100 + 40; + REQUIRE(sum == expected); + } + } + + GIVEN("a list") + { + List l; + l.resize(42, 1); + l.front() = 10; + l.back() = 100; + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto v: no_first(l)) + sum += v; + + auto expected = 100 + 40; + REQUIRE(sum == expected); + } + } + + GIVEN("an empty list") + { + List l; + + WHEN("iterating") + { + size_t sum = 0; + size_t count = 0; + for (auto v: no_first(l)) + { + sum += v; + ++count; + } + + REQUIRE(sum == 0); + REQUIRE(count == 0); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/no_last.cpp b/tjp/core/iterators/_tests/no_last.cpp new file mode 100755 index 0000000..14633ff --- /dev/null +++ b/tjp/core/iterators/_tests/no_last.cpp @@ -0,0 +1,76 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::no_last") +{ + GIVEN("a vector") + { + fail_on_copy_vector l; + l.resize(42, 1); + l.front() = 10; + l.back() = 100; + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto v: no_last(l)) + sum += v; + + auto expected = 10 + 40; + REQUIRE(sum == expected); + } + } + + GIVEN("a list") + { + List l; + l.resize(42, 1); + l.front() = 10; + l.back() = 100; + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto v: no_last(l)) + sum += v; + + auto expected = 10 + 40; + REQUIRE(sum == expected); + } + } + + GIVEN("an empty list") + { + List l; + + WHEN("iterating") + { + size_t sum = 0; + size_t count = 0; + for (auto v: no_last(l)) + { + sum += v; + ++count; + } + + REQUIRE(sum == 0); + REQUIRE(count == 0); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/range.cpp b/tjp/core/iterators/_tests/range.cpp new file mode 100755 index 0000000..f5cef3b --- /dev/null +++ b/tjp/core/iterators/_tests/range.cpp @@ -0,0 +1,61 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::range") +{ + GIVEN("a range") + { + WHEN("iterating to X") + { + auto X = 100; + auto j = 0; + for (auto i: range(X)) + { + unused(i); + j++; + } + + REQUIRE(j == X); + } + + WHEN("iterating X to Y") + { + auto X = 50, Y = 100; + auto j = 0; + for (auto i: range(X, Y)) + { + unused(i); + j++; + } + + REQUIRE(j == (Y-X)); + } + + WHEN("iterating Y to X") + { + auto X = 50, Y = 100; + auto j = 0; + for (auto i: range(Y, X, -1)) + { + unused(i); + j++; + } + + REQUIRE(j == (Y-X)); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/range_with.cpp b/tjp/core/iterators/_tests/range_with.cpp new file mode 100755 index 0000000..99bf97b --- /dev/null +++ b/tjp/core/iterators/_tests/range_with.cpp @@ -0,0 +1,57 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include +#include +#include + +#include "fail_on_copy_vector.hpp" + +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::range_with") +{ + fail_on_copy_vector l; + l.resize(42); + for (auto [i, v]: enumerate(l)) + v = (int)i; + + GIVEN("a range") + { + WHEN("iterating first 5") + { + auto X = 5; + auto j = 0; + for (auto i: range_with(l, X)) + { + unused(i); + j += i; + } + + REQUIRE(j == (0+1+2+3+4)); + } + + WHEN("iterating next 5") + { + auto X = 5; + auto j = 0; + for (auto i: range_with(l, X, X)) + { + unused(i); + j += i; + } + + REQUIRE(j == (5+6+7+8+9)); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/reverse.cpp b/tjp/core/iterators/_tests/reverse.cpp new file mode 100755 index 0000000..daa9355 --- /dev/null +++ b/tjp/core/iterators/_tests/reverse.cpp @@ -0,0 +1,43 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include +#include + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::reverse") +{ + GIVEN("a vector") + { + fail_on_copy_vector l; + l.resize(42, 1); + int expected = 10; + l.back() = expected; + + WHEN("iterating to X") + { + int value = 0; + is_first first; + for (auto &v: reverse(l)) + { + if (first) + value = v; + } + + REQUIRE(value == expected); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/safe_next.cpp b/tjp/core/iterators/_tests/safe_next.cpp new file mode 100755 index 0000000..2cdb0df --- /dev/null +++ b/tjp/core/iterators/_tests/safe_next.cpp @@ -0,0 +1,85 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::safe_next") +{ + GIVEN("a list") + { + List l; + l.resize(42, 1); + + WHEN("iterating to X") + { + auto v = 0; + for (auto i: safe_next(l)) + v += *i; + + REQUIRE(v == 42); + } + + WHEN("iterating to X") + { + auto v = 0; + auto e = -1; + for (auto i: safe_next(l)) + { + ++e; + v += *i; + + if (e % 2 == 0) + { + l.erase(i); + } + } + + REQUIRE(v == 42); + } + + WHEN("iterating to X with vaue") + { + auto v = 0; + for (auto x: safe_next_value(l)) + v += x; + + REQUIRE(v == 42); + } + + WHEN("iterating to X with value") + { + auto v = 0; + auto e = -1; + auto i = l.begin(); + for (auto &x: safe_next_value(l)) + { + auto n = i; + n++; + + ++e; + v += x; + + if (e % 2 == 0) + { + l.erase(i); + } + + i = n; + } + + REQUIRE(v == 42); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/transform_with.cpp b/tjp/core/iterators/_tests/transform_with.cpp new file mode 100755 index 0000000..91e7a88 --- /dev/null +++ b/tjp/core/iterators/_tests/transform_with.cpp @@ -0,0 +1,75 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "../../testing/catch.hpp" +#include "../transform_with.hpp" +#include "../enumerate.hpp" + +#include "../../containers/Vector.hpp" +#include "../../containers/List.hpp" + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::transform_with") +{ + GIVEN("a vector") + { + fail_on_copy_vector l = { 1, 3, 5, 7, 9 }; + auto make_even = [](auto &v) { return v + 1; }; + + WHEN("transform_with") + { + for (auto v: transform_with(l, make_even)) + { + auto is_even = (v % 2) == 0; + REQUIRE(is_even); + } + } + + WHEN("transform_with with enumerate") + { + for (auto [e, v]: enumerate_value(transform_with(l, make_even))) + { + auto is_even = (v % 2) == 0; + REQUIRE(is_even); + } + } + + WHEN("transform_with reference") + { + auto make_even = [](auto &v) -> int & { v+=1; return v; }; + + for (auto v: transform_with(l, make_even)) + { + auto is_even = (v % 2) == 0; + REQUIRE(is_even); + } + } + + WHEN("transform_with reference enumerate") + { + auto make_even = [](auto &v) -> int & { ++v; return v; }; + + for (auto [e, v]: enumerate(transform_with(l, make_even))) + { + auto is_even = (v % 2) == 0; + REQUIRE(is_even); + + v = e; + } + + for (auto [e, v]: enumerate_value(transform_with(l, make_even))) + { + REQUIRE(v == e+1); + } + + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/iterators/_tests/zip.cpp b/tjp/core/iterators/_tests/zip.cpp new file mode 100755 index 0000000..3a7b66d --- /dev/null +++ b/tjp/core/iterators/_tests/zip.cpp @@ -0,0 +1,96 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include +#include + +#include "fail_on_copy_vector.hpp" + +namespace tjp::core { +namespace { + +SCENARIO("core::iterators::zip") +{ + constexpr size_t size = 42; + GIVEN("two vector") + { + fail_on_copy_vector l; + fail_on_copy_vector r; + l.resize(size); + r.resize(size); + + for (auto [lv, rv]: zip(l, r)) + { + lv = 1; + rv = 1; + } + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto [lv, rv]: zip(l, r)) + sum += lv + rv; + + auto expected = size * 2; + REQUIRE(sum == expected); + } + } + + GIVEN("three vector") + { + fail_on_copy_vector l; + fail_on_copy_vector r; + fail_on_copy_vector u; + l.resize(size); + r.resize(size); + u.resize(size); + + for (auto [lv, rv, uv]: zip(l, r, u)) + { + lv = 1; + rv = 1; + uv = 1; + } + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto [lv, rv, uv]: zip(l, r, u)) + sum += lv + rv + uv; + + auto expected = size * 3; + REQUIRE(sum == expected); + } + } + GIVEN("two list") + { + List l; + List r; + l.resize(size); + r.resize(size); + + for (auto [lv, rv]: zip(l, r)) + { + lv = 1; + rv = 1; + } + + WHEN("iterating to X") + { + size_t sum = 0; + for (auto [lv, rv]: zip(l, r)) + sum += lv + rv; + + auto expected = size * 2; + REQUIRE(sum == expected); + } + } +} + + +} // namespace +} // namespace diff --git a/tjp/core/iterators/enumerate.hpp b/tjp/core/iterators/enumerate.hpp new file mode 100755 index 0000000..0789178 --- /dev/null +++ b/tjp/core/iterators/enumerate.hpp @@ -0,0 +1,88 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::iterators { + +template +struct enumerate_wrapper { + T iterable; +}; + +template +struct enumerate_iterator +{ + size_t i; + I iter; + + bool operator != (const enumerate_iterator & other) const + { + return iter != other.iter; + } + + void operator ++ () + { + ++i; + ++iter; + } + auto operator * () const + { + return std::tuple(i, *iter); + } +}; + +template +auto begin (enumerate_wrapper w) +{ + return enumerate_iterator { 0, begin(w.iterable) }; +} + +template +auto end (enumerate_wrapper w) +{ + return enumerate_iterator { 0, end(w.iterable) }; +} + +template ())), + typename = decltype(end(std::declval()))> +constexpr auto enumerate_ref(T && iterable) +{ + using V = decltype(*std::declval()); + using R = V &; + + return enumerate_wrapper { std::forward(iterable) }; +} + +template ())), + typename = decltype(end(std::declval()))> +constexpr auto enumerate_value(T && iterable) +{ + using V = decltype(*std::declval()); + + return enumerate_wrapper { std::forward(iterable) }; +} + + +// TODO: the default c++ iteration is by value but here we have by ref, should it be by value? + +template +constexpr auto enumerate(T && iterable) +{ + return enumerate_ref(std::forward(iterable)); +} + +} // namespace + +namespace tjp::core { + +using iterators::enumerate; +using iterators::enumerate_ref; +using iterators::enumerate_value; + +} // namespace diff --git a/tjp/core/iterators/is_first.hpp b/tjp/core/iterators/is_first.hpp new file mode 100755 index 0000000..e665af4 --- /dev/null +++ b/tjp/core/iterators/is_first.hpp @@ -0,0 +1,39 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::iterators { + +struct is_first +{ + bool v = true; + + bool check () + { + auto r = v; + v = false; + return r; + } + + operator bool() + { + return check(); + } + + bool operator()() + { + return check(); + } + +} ; + +} // namespace + +namespace tjp::core { + +using iterators::is_first; + +} // namespace + diff --git a/tjp/core/iterators/macro_min_max.h b/tjp/core/iterators/macro_min_max.h new file mode 100755 index 0000000..27e0dfe --- /dev/null +++ b/tjp/core/iterators/macro_min_max.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +#define macro_min(a,b) ((ab)?a:b) + +} // namespace utilities +} // namespace diff --git a/tjp/core/iterators/no_first.hpp b/tjp/core/iterators/no_first.hpp new file mode 100755 index 0000000..a8766af --- /dev/null +++ b/tjp/core/iterators/no_first.hpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::iterators { + +template +struct no_first_wrapper +{ + T iterable; +}; + +template +auto begin (no_first_wrapper w) +{ + auto b = std::begin(w.iterable); + auto e = std::end(w.iterable); + return (b == e) ? e : std::next(b); +} + +template +auto end (no_first_wrapper w) +{ + return end(w.iterable); +} + +template +no_first_wrapper no_first (T&& iterable) +{ + return { std::forward(iterable) }; +} + +} // namespace + +namespace tjp::core { + +using iterators::no_first; + +} // namespace + diff --git a/tjp/core/iterators/no_last.hpp b/tjp/core/iterators/no_last.hpp new file mode 100755 index 0000000..af9a852 --- /dev/null +++ b/tjp/core/iterators/no_last.hpp @@ -0,0 +1,42 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::iterators { + +template +struct no_last_wrapper +{ + T iterable; +}; + +template +auto begin (no_last_wrapper w) +{ + return begin(w.iterable); +} + +template +auto end (no_last_wrapper w) +{ + auto b = std::begin(w.iterable); + auto e = std::end(w.iterable); + return (b == e) ? e : std::prev(e); +} + +template +no_last_wrapper no_last (T&& iterable) +{ + return { std::forward(iterable) }; +} + +} // namespace + + +namespace tjp::core { + +using iterators::no_last; + +} // namespace diff --git a/tjp/core/iterators/range.hpp b/tjp/core/iterators/range.hpp new file mode 100755 index 0000000..190ba52 --- /dev/null +++ b/tjp/core/iterators/range.hpp @@ -0,0 +1,85 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include "macro_min_max.h" + +namespace tjp::core::iterators { + +template +class range { + public: + class iterator { + friend class range; + public: + T operator *() const { return i_; } + + const iterator &operator ++() { + int inc = inc_; + + while(inc > 0) { + ++i_; + --inc; + } + + while(inc < 0) { + --i_; + ++inc; + } + + return *this; + } + + iterator operator ++(int) + { + iterator copy(*this); + ++(*this); + return copy; + } + + bool operator ==(const iterator &other) const { return i_ == other.i_; } + bool operator !=(const iterator &other) const { return i_ != other.i_; } + + protected: + iterator(T start, int inc) : i_ (start), inc_(inc) { } + iterator(T start) : i_ (start), inc_(1) { } + + private: + int inc_; + T i_; + }; + + iterator begin() const { return begin_; } + iterator end() const { return end_; } + + range(T end) : + begin_(macro_min(T(0), end)), + end_(end) + {} + + range(T begin, T end) : + begin_(macro_min(begin, end)), + end_(end) + {} + + range(T begin, T end, int inc) : + begin_(inc > 0 ? macro_min(begin,end) : macro_max(begin,end), inc), + end_(end) + {} + +private: + iterator begin_; + iterator end_; +}; + +} // namespace + +namespace tjp::core { + +using iterators::range; + +} // namespace + diff --git a/tjp/core/iterators/range_with.hpp b/tjp/core/iterators/range_with.hpp new file mode 100755 index 0000000..5a17991 --- /dev/null +++ b/tjp/core/iterators/range_with.hpp @@ -0,0 +1,70 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::iterators { + +template +struct range_over +{ + T begin_; + T end_; + + T begin() { return begin_; } + T end() { return end_; } +} ; + +template +auto range_with(T begin, T end) +{ + return range_over { begin, end }; +} + + + +template +auto range_with(T &t) +{ + return range_over { t.begin(), t.end() }; +} + +template +auto range_with(const T &t) +{ + return range_over { t.begin(), t.end() }; +} + +template +auto range_with(T &t, size_t num) +{ + return range_over { t.begin(), t.begin() + num }; +} + +template +auto range_with(const T &t, size_t num) +{ + return range_over { t.begin(), t.begin() + num }; +} + +template +auto range_with(T &t, size_t from, size_t num) +{ + return range_over { t.begin() + from, t.begin() + from + num }; +} + +template +auto range_with(const T &t, size_t from, size_t num) +{ + return range_over { t.begin() + from, t.begin() + from + num }; +} + +} // namespace + +namespace tjp::core { + +using iterators::range_with; + +} // namespace + diff --git a/tjp/core/iterators/reverse.hpp b/tjp/core/iterators/reverse.hpp new file mode 100755 index 0000000..20f8fbb --- /dev/null +++ b/tjp/core/iterators/reverse.hpp @@ -0,0 +1,30 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::iterators { + +template +struct reversion_wrapper { T iterable; }; + +template +auto begin (reversion_wrapper w) { return rbegin(w.iterable); } + +template +auto end (reversion_wrapper w) { return rend(w.iterable); } + +template +reversion_wrapper reverse (T&& iterable) { return { std::forward(iterable) }; } + +} // namespace + +namespace tjp::core { + +using iterators::reverse; + +} // namespace + diff --git a/tjp/core/iterators/safe_next.hpp b/tjp/core/iterators/safe_next.hpp new file mode 100755 index 0000000..a63ff39 --- /dev/null +++ b/tjp/core/iterators/safe_next.hpp @@ -0,0 +1,89 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +template ())), + typename = decltype(std::end(std::declval()))> +constexpr auto safe_next(T && iterable) +{ + struct iterator + { + TI iter; + TI end; + TI next; + + iterator(TI iter_, TI end_) : + iter(iter_), + next(iter_), + end(end_) + { + if (next != end) + ++next; + } + + bool operator != (const iterator & other) const { return iter != other.iter; } + void operator ++ () + { + iter = next; + if (next != end) + ++next; + } + + const TI &operator * () const { return iter; } + TI &operator * () { return iter; } + }; + struct iterable_wrapper + { + T &iterable; + auto begin() { return iterator(std::begin(iterable), std::end(iterable)); } + auto end() { return iterator(std::end(iterable), std::end(iterable)); } + }; + return iterable_wrapper{ std::forward(iterable) }; +} + +template ())), + typename = decltype(std::end(std::declval()))> +constexpr auto safe_next_value(T && iterable) +{ + struct iterator + { + TI iter; + TI end; + TI next; + + iterator(TI iter_, TI end_) : + iter(iter_), + next(iter_), + end(end_) + { + if (next != end) + ++next; + } + + bool operator != (const iterator & other) const { return iter != other.iter; } + void operator ++ () + { + iter = next; + if (next != end) + ++next; + } + + auto &operator * () const { return *iter; } + auto &operator * () { return *iter; } + }; + struct iterable_wrapper + { + T &iterable; + auto begin() { return iterator(std::begin(iterable), std::end(iterable)); } + auto end() { return iterator(std::end(iterable), std::end(iterable)); } + }; + return iterable_wrapper{ std::forward(iterable) }; +} + diff --git a/tjp/core/iterators/safe_next_with.hpp b/tjp/core/iterators/safe_next_with.hpp new file mode 100755 index 0000000..114bcf2 --- /dev/null +++ b/tjp/core/iterators/safe_next_with.hpp @@ -0,0 +1,87 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +template ())), + typename = decltype(std::end(std::declval()))> +constexpr auto safe_next_with(T && iterable, TI iter) +{ + struct iterator + { + TI iter; + TI end; + TI next; + + iterator(TI iter_, TI end_) : + iter(iter_), + next(iter_), + end(end_) + { + if (next != end) + ++next; + } + + bool operator != (const iterator & other) const { return iter != other.iter; } + void operator ++ () + { + iter = next; + if (next != end) + ++next; + } + + const TI &operator * () const { return iter; } + TI &operator * () { return iter; } + + bool operator !=(const TI &rhs) + { + return iter != rhs; + } + }; + + return iterator{ iter, iterable.end() }; +} + +template ())), + typename = decltype(std::end(std::declval()))> +constexpr auto safe_next_with_value(T && iterable, TI iter) +{ + struct iterator + { + TI iter; + TI end; + TI next; + + iterator(TI iter_, TI end_) : + iter(iter_), + next(iter_), + end(end_) + { + if (next != end) + ++next; + } + + bool operator != (const iterator & other) const { return iter != other.iter; } + void operator ++ () + { + iter = next; + if (next != end) + ++next; + } + + auto &operator * () const { return *iter; } + auto &operator * () { return *iter; } + + bool operator !=(const TI &rhs) + { + return iter != rhs; + } + }; + + return iterator{ iter, iterable.end() }; +} diff --git a/tjp/core/iterators/transform_with.hpp b/tjp/core/iterators/transform_with.hpp new file mode 100755 index 0000000..8bd5ad1 --- /dev/null +++ b/tjp/core/iterators/transform_with.hpp @@ -0,0 +1,67 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp { +namespace core { +namespace iterators { + +template ())) +> +struct transform_with_iterator : I +{ + typedef I Super; + F f; + using R = decltype(std::declval()(*std::declval())); + + transform_with_iterator(Super i, F &f_) : + Super(i), + f(f_) + {} + + R operator *() const + { + return f(Super::operator*()); + } +} ; + +template +struct transform_with_wrapper { + T iterable; + F f; +}; + + +template +auto begin (transform_with_wrapper w) +{ + return transform_with_iterator(begin(w.iterable), w.f); +} + +template +auto end (transform_with_wrapper w) +{ + return transform_with_iterator(end(w.iterable), w.f); +} + +template +transform_with_wrapper transform_with (T&& iterable, F &&f) +{ + return { std::forward(iterable), std::forward(f) }; +} + +} // namespace + +using iterators::transform_with; +using iterators::transform_with_wrapper; +using iterators::transform_with_iterator; + +} // namespace +} // namespace + diff --git a/tjp/core/iterators/zip.hpp b/tjp/core/iterators/zip.hpp new file mode 100755 index 0000000..4101102 --- /dev/null +++ b/tjp/core/iterators/zip.hpp @@ -0,0 +1,151 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::iterators { +namespace zip_detail { + +template +using select_access_type_for = std::conditional_t< + std::is_same_v::iterator> || + std::is_same_v::const_iterator>, + typename Iter::value_type, + typename Iter::reference +>; + + +template +auto any_match_impl(std::tuple const & lhs, + std::tuple const & rhs, + std::index_sequence) -> bool +{ + auto result = false; + result = (... | (std::get(lhs) == std::get(rhs))); + return result; +} + + +template +auto any_match(std::tuple const & lhs, std::tuple const & rhs) + -> bool +{ + return any_match_impl(lhs, rhs, std::index_sequence_for{}); +} + + + +template +class zip_iterator +{ +public: + + using value_type = std::tuple< + select_access_type_for... + >; + + zip_iterator() = delete; + + zip_iterator(Iters && ... iters) + : m_iters {std::forward(iters)...} + { + } + + auto operator++() -> zip_iterator& + { + std::apply( + [](auto && ... args) { + ( + (++args), + ... + ); + }, + m_iters + ); + return *this; + } + + auto operator++(int) -> zip_iterator + { + auto tmp = *this; + ++*this; + return tmp; + } + + auto operator!=(zip_iterator const & other) + { + return !(*this == other); + } + + auto operator==(zip_iterator const & other) + { + return any_match(m_iters, other.m_iters); + } + + auto operator*() -> value_type + { + return std::apply([](auto && ... args){ + return value_type(*args...); + }, m_iters); + } + +private: + std::tuple m_iters; +}; + + +/* std::decay needed because T is a reference, and is not a complete type */ +template +using select_iterator_for = std::conditional_t< + std::is_const_v>, + typename std::decay_t::const_iterator, + typename std::decay_t::iterator>; + + + +template +class zipper +{ +public: + using zip_type = zip_iterator ...>; + + template + zipper(Args && ... args) + : m_args{std::forward(args)...} + { + } + + auto begin() -> zip_type + { + return std::apply([](auto && ... args){ + return zip_type(std::begin(args)...); + }, m_args); + } + auto end() -> zip_type + { + return std::apply([](auto && ... args){ + return zip_type(std::end(args)...); + }, m_args); + } + +private: + std::tuple m_args; + +}; + + +template +auto zip(T && ... t) +{ + return zipper{std::forward(t)...}; +} + +} // namespace zip_detail +} // namespace + +namespace tjp::core { + +using iterators::zip_detail::zip; + +} // namespace diff --git a/tjp/core/log/Color.cpp b/tjp/core/log/Color.cpp new file mode 100755 index 0000000..0c877ee --- /dev/null +++ b/tjp/core/log/Color.cpp @@ -0,0 +1,68 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined(TJP_CORE_HEADER_ONLY) + #pragma once +#endif + +#include +#include "Color.hpp" + +namespace tjp::core::log::detail { + +TJP_CORE_HEADER_ONLY_INLINE +bool isColorAvailable(std::ostream &o) +{ + return o.iword(SupportsColorFlag::id()); +} + +TJP_CORE_HEADER_ONLY_INLINE +std::ostream &operator <<(std::ostream &o, const Color &color) +{ + if (isColorAvailable(o)) + o << color.value; + + return o; +} + + +template<> +TJP_CORE_HEADER_ONLY_INLINE +std::ostream &operator <<(std::ostream &o, const Colored &s) +{ + if (!s.v) + return o; + + if (!isColorAvailable(o)) + return o << s.v; + + auto sum = 0; + for (auto i=0; i<128; ++i) + { + if (s.v[i] == 0) + break; + sum += s.v[i]; + } + + auto code = sum % 128 + 1; + + o + << "\033[38;5;" << code << "m" + << s.v + << "\033[0m"; + + return o; +} + +TJP_CORE_HEADER_ONLY_INLINE +std::ostream &operator <<(std::ostream &o, const ColoredStory &v) +{ + if (v.story) + o << "[" << color(v.story) << "] "; + return o; +} + + +} // namespace + diff --git a/tjp/core/log/Color.hpp b/tjp/core/log/Color.hpp new file mode 100755 index 0000000..388148b --- /dev/null +++ b/tjp/core/log/Color.hpp @@ -0,0 +1,95 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" +#include + +namespace tjp::core::log::detail { + +struct ColoredStory +{ + const char *story; +} ; + +template +struct Colored +{ + const T &v; +} ; + +template +struct SupportsColorFlag_ +{ + static inline int id_ = -1; +} ; + +struct SupportsColorFlag : SupportsColorFlag_ +{ + static int id() + { + if (id_ < 0) + id_ = std::ios_base::xalloc(); + + return id_; + } +} ; + +template +Colored color(const T &v) { return { v }; } + +std::ostream &operator <<(std::ostream &o, const ColoredStory &v); + +template +std::ostream &operator <<(std::ostream &o, const Colored &); + +template<> +std::ostream &operator <<(std::ostream &o, const Colored &); + +// -------------------------------------- + + +#define xLogColorStory(story) tjp::core::log::detail::ColoredStory { story } + +struct Color +{ + const char *value; + + Color(const char *value_) : + value(value_) + {} +}; + +std::ostream &operator <<(std::ostream &o, const Color &color); + +} // namespace + +namespace tjp::core::log { + +using detail::Color; +using detail::color; + +//the following are UBUNTU/LINUX, and MacOS ONLY terminal color codes. +const Color RESET ="\033[0m"; +const Color BLACK = "\033[30m"; +const Color RED = "\033[31m"; +const Color GREEN = "\033[32m"; +const Color YELLOW = "\033[33m"; +const Color BLUE = "\033[34m"; +const Color MAGENTA = "\033[35m"; +const Color CYAN = "\033[36m"; +const Color WHITE = "\033[37m"; +const Color BOLDBLACK = "\033[1m\033[30m"; +const Color BOLDRED = "\033[1m\033[31m"; +const Color BOLDGREEN = "\033[1m\033[32m"; +const Color BOLDYELLOW = "\033[1m\033[33m"; +const Color BOLDBLUE = "\033[1m\033[34m"; +const Color BOLDMAGENTA = "\033[1m\033[35m"; +const Color BOLDCYAN = "\033[1m\033[36m"; +const Color BOLDWHITE = "\033[1m\033[37m"; + +} + +#include "Color.inl" diff --git a/tjp/core/log/Color.inl b/tjp/core/log/Color.inl new file mode 100755 index 0000000..a4098cb --- /dev/null +++ b/tjp/core/log/Color.inl @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Log.h" + +#include + +namespace tjp::core::log::detail { + +template +std::ostream &operator <<(std::ostream &o, const Colored &v) +{ + std::ostringstream s; + s << v.v; + o << color(s.str().c_str()); + + return o; +} + +} // namespace diff --git a/tjp/core/log/Detail.cpp b/tjp/core/log/Detail.cpp new file mode 100755 index 0000000..60d4621 --- /dev/null +++ b/tjp/core/log/Detail.cpp @@ -0,0 +1,244 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined(TJP_CORE_HEADER_ONLY) + #pragma once +#endif + +#include "Detail.hpp" + +#include "Util.inl" +#include "../io/memstream.hpp" +#include "../algorithm/set_has.hpp" +#include "../algorithm/unused.hpp" +#include "../string/as_string_view.hpp" + +#include +#include + +namespace tjp::core::log::detail { + +TJP_CORE_HEADER_ONLY_INLINE +bool operator==(const Story &lhs, const Story &rhs) +{ + return + lhs.hash == rhs.hash && + lhs.name == rhs.name; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool operator<(const Story &lhs, const Story &rhs) +{ + if (lhs.hash == rhs.hash) + return lhs.name < rhs.name; + + return lhs.hash < rhs.hash; +} + +TJP_CORE_HEADER_ONLY_INLINE +Manager::Manager() : + file(this), + termSupportsColor(detectIfColorIsAvailable()) +{ +} + +TJP_CORE_HEADER_ONLY_INLINE +Manager &getManager() +{ + static Manager manager; + return manager; +} + +TJP_CORE_HEADER_ONLY_INLINE +void Stories::clear() +{ + all = false; + names.clear(); + activated.clear(); +} + +TJP_CORE_HEADER_ONLY_INLINE +void Stories::activate(const Story &s) +{ + if (s.name == "*") + { + all = true; + return; + } + + if (!set_has(activated, s)) + { + names.push_back(String(s.name)); + + Story s_ = s; + s_.name = names.back(); + activated.insert (s_); + } +} + +TJP_CORE_HEADER_ONLY_INLINE +bool Stories::isActivated (const Story &s) +{ + return all || set_has(activated, s); +} + +// --------------- + +struct File::I { + std::ofstream file; +} ; + +TJP_CORE_HEADER_ONLY_INLINE +File::File(Manager *manager_) : + manager(manager_) +{ + i = new I(); +} + +TJP_CORE_HEADER_ONLY_INLINE +File::~File() +{ + delete i; +} + +TJP_CORE_HEADER_ONLY_INLINE +Settings &File::getSettings() +{ + return manager->settings; +} + +TJP_CORE_HEADER_ONLY_INLINE +void File::start() +{ + if (i->file.is_open()) + i->file.close(); + + auto &settings = getSettings(); + + i->file.open( + settings.LogFileName, + settings.AppendToLogFile ? + std::ios::app : + std::ios::out + ); +} + +TJP_CORE_HEADER_ONLY_INLINE +void File::write(const StringView &s) +{ + if (!i->file) + return; + + sizeWritten += s.size(); + i->file << s; + i->file.flush(); + + checkRotate(); +} + +TJP_CORE_HEADER_ONLY_INLINE +void File::checkRotate() +{ + auto &settings = getSettings(); + + if (settings.RotateSize != 0 && sizeWritten > settings.RotateSize) + rotate(); +} + +TJP_CORE_HEADER_ONLY_INLINE +void File::rotate() +{ + char data[256]; + GetTimeStamp(data, std::size(data), '_'); + rotateTo(getSettings().LogFileName + "." + data); +} + +TJP_CORE_HEADER_ONLY_INLINE +void File::rotateTo(const std::string_view &name_) +{ + i->file.close(); + + auto name = std::string(name_); + remove(name.c_str()); + rename(getSettings().LogFileName.c_str(), name.c_str()); + + sizeWritten = 0; + start(); +} + +// ------- + +TJP_CORE_HEADER_ONLY_INLINE +void Manager::writeToConsole (const StringView &s) +{ + auto lock = std::lock_guard(mutex); + + char data[256]; + core::io::omemstream_ out; + out << "XD " << __GetLogStamp__(data, termSupportsColor) << s; + + auto externalConsolePrint = external.console; + if (externalConsolePrint) + return externalConsolePrint(core::as_string_view(out.data)); + + fwrite((void *)out.data.data(), 1, out.data.size(), stdout); +} + +TJP_CORE_HEADER_ONLY_INLINE +void Manager::writeToDebugger (const StringView &s) +{ + auto lock = std::lock_guard(mutex); + + char data[256]; + unused(data); + + auto externalDebuggerPrint = external.debugger; + if (externalDebuggerPrint) + { +#ifdef SYS_ANDROID + core::io::omemstream_ out_; + out_ << __GetLogStamp__(data, false) << s; + auto out = as_string_view(out_.data); +#else + auto &out = s; +#endif + externalDebuggerPrint(out); + } + + #ifdef WIN32 + OutputDebugString (__GetLogStamp__(data, false)); + OutputDebugString (s.c_str()); + #endif +} + +TJP_CORE_HEADER_ONLY_INLINE +void Manager::writeToLog (const StringView &s) +{ + auto externalLogPrint = external.log; + bool willWrite = externalLogPrint || settings.LogToFileActivated; + if (willWrite) + { + char data[256]; + core::io::omemstream_ out; + out << __GetLogStamp__(data, false) << s; + auto outs = as_string_view(out.data); + + if (externalLogPrint) + externalLogPrint(outs); + + if (settings.LogToFileActivated) + file.write(outs); + + #ifdef USE_OSX_LOG + // Define a custom log category + static os_log_t os_log_ = os_log_create("com.timprepscius.crown", "std"); + + // Log a message with default log level + os_log(os_log_, "%s", s.c_str()); + #endif + } +} + +} // namespace + diff --git a/tjp/core/log/Detail.h b/tjp/core/log/Detail.h new file mode 100755 index 0000000..1754f96 --- /dev/null +++ b/tjp/core/log/Detail.h @@ -0,0 +1,10 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core::log::detail { + +} // namespace + diff --git a/tjp/core/log/Detail.hpp b/tjp/core/log/Detail.hpp new file mode 100755 index 0000000..1557d4b --- /dev/null +++ b/tjp/core/log/Detail.hpp @@ -0,0 +1,126 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" + +#include "../string/String.hpp" +#include "../string/StringView.hpp" +#include "../types/Types.h" + +#include "../containers/List.hpp" +#include "../containers/Set.hpp" + +#include "../const_hash/Hash.hpp" + +#include + +namespace tjp::core::log::detail { + +struct Manager; + +struct Story +{ + using Hash = u32; + Hash hash; + StringView name; + + constexpr Story(const char *s) : + hash(hash_compile(s)), + name(s) + {} +} ; + +struct Settings +{ + String LogFileName = "log.txt"; + bool AppendToLogFile = false; + bool LogToFileActivated = false; + bool LogToDebuggerActivated = false; + bool LogToConsoleActivated = true; + bool LogInExecutableDirectory = false; + + // zero for never rotate + u64 RotateSize = 10 * (1024 * 1024); +} ; + +typedef void (*TimPrepsciusCoreLogExternalPrintPtr)(const StringView &); + + +struct External +{ + TimPrepsciusCoreLogExternalPrintPtr debugger = nullptr; + TimPrepsciusCoreLogExternalPrintPtr log = nullptr; + TimPrepsciusCoreLogExternalPrintPtr console = nullptr; +} ; + +struct Stories +{ + bool all = false; + + Set activated; + List names; + + void clear(); + void activate(const Story &s); + bool isActivated (const Story &s); +} ; + +struct File +{ + struct I; + + Manager *manager; + Settings &getSettings(); + + File (Manager *); + ~File(); + + I *i; + u64 sizeWritten = 0; + + void start(); + void write(const StringView &s); + + void checkRotate(); + void rotate(); + void rotateTo(const std::string_view &name); +} ; + +struct Manager +{ + using Mutex = std::mutex; + Mutex mutex; + + External external; + Settings settings; + Stories stories; + File file; + + bool termSupportsColor = false; + + Manager(); + + void start(); + void rotate(); + void rotateTo(const StringView &); + + void writeToLog(const StringView &); + void writeToDebugger(const StringView &); + void writeToConsole(const StringView &); + + template + auto with_lock(F &&f) + { + std::lock_guard lock(mutex); + f(*this); + } +} ; + +Manager &getManager(); + +std::string methodName(const char *prettyFunction); + +} // namespace diff --git a/tjp/core/log/Log+Precision.h b/tjp/core/log/Log+Precision.h new file mode 100755 index 0000000..c8bb625 --- /dev/null +++ b/tjp/core/log/Log+Precision.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +/** + * Debug and Error logging utility methods and macros used throughout + * the application + */ + +#include + +#define LOG_PRECISION(x) std::fixed << std::setprecision(x) diff --git a/tjp/core/log/Log.cpp b/tjp/core/log/Log.cpp new file mode 100755 index 0000000..14b274f --- /dev/null +++ b/tjp/core/log/Log.cpp @@ -0,0 +1,171 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined(TJP_CORE_HEADER_ONLY) + #pragma once +#endif + +#include "Log.h" +#include + +#include "../system/System.h" + +#if defined(SYS_IOS) || defined(SYS_MAC) + // #define USE_OSX_LOG +#endif + +#if defined(USE_OSX_LOG) + #include +#endif + +namespace tjp::core::log { + +TJP_CORE_HEADER_ONLY_INLINE +void ActivateStory (const Story &s) +{ + getManager().stories.activate(s); +} + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalDebugPrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + getManager().with_lock([&](auto &manager) { + manager.external.debugger = f; + }); +} + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalLogPrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + getManager().with_lock([&](auto &manager) { + manager.external.log = f; + }); +} + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalConsolePrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + getManager().with_lock([&](auto &manager) { + manager.external.console = f; + }); +} + +// ------------------------------ + +TJP_CORE_HEADER_ONLY_INLINE +void Start () +{ + getManager().with_lock([&](auto &manager) { + if (manager.settings.LogToFileActivated) + manager.file.start(); + }); +} + +TJP_CORE_HEADER_ONLY_INLINE +void RotateTo(const std::string_view &fileName) +{ + getManager().with_lock([&](auto &manager) { + if (manager.settings.LogToFileActivated) + manager.file.rotateTo(fileName); + }); +} + +TJP_CORE_HEADER_ONLY_INLINE +void Rotate() +{ + getManager().with_lock([&](auto &manager) { + if (manager.settings.LogToFileActivated) + manager.file.rotate(); + }); +} + +TJP_CORE_HEADER_ONLY_INLINE +void ActivateStory_(const Story &s) +{ + getManager().with_lock([&](auto &manager) { + manager.stories.activate(s); + }); +} + +//--------------------------------------------------- + +TJP_CORE_HEADER_ONLY_INLINE +void ActivateStories (const std::string &filename) +{ + std::ifstream in(filename.c_str()); + + if (!in) + return; + + while (!in.eof()) + { + char line[80]; + in.getline(line, 80); + line[79]='\0'; + + for (int i=0;i<80; i++) + { + if (line[i] == '\r' || line[i]=='\n' || line[i]=='#' || line[i] =='\0') + { + line[i] = '\0'; + break; + } + } + + if (line[0] == 0) + continue; + + xLogActivateStory(line); + } +} + +// --- + +TJP_CORE_HEADER_ONLY_INLINE +void Initialize (const Settings &settings_) +{ + getManager().with_lock([&](auto &manager) { + manager.settings = settings_; + }); + + Start(); +} + + +TJP_CORE_HEADER_ONLY_INLINE +void Initialize (const std::string &fileName) +{ + getManager().with_lock([&](auto &manager) { + auto &settings = manager.settings; + + settings.LogFileName = fileName; + settings.LogToFileActivated = !fileName.empty(); + settings.LogToConsoleActivated = !settings.LogToFileActivated; + settings.LogToDebuggerActivated = false; + + settings.LogInExecutableDirectory = false; + }); + + Start(); +} + +} // namespace + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalDebuggerPrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + tjp::core::log::setExternalDebugPrint(f); +} + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalLogPrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + tjp::core::log::setExternalLogPrint(f); +} + +TJP_CORE_HEADER_ONLY_INLINE +void setExternalConsolePrint(TimPrepsciusCoreLogExternalPrintPtr f) +{ + tjp::core::log::setExternalConsolePrint(f); +} diff --git a/tjp/core/log/Log.h b/tjp/core/log/Log.h new file mode 100755 index 0000000..87eaeee --- /dev/null +++ b/tjp/core/log/Log.h @@ -0,0 +1,242 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" + +#include "../debug/Debug.h" +#include "Detail.hpp" +#include "Color.hpp" + +#include "../io/memstream.hpp" +#include "../string/as_string_view.hpp" + +typedef void (*TimPrepsciusCoreLogExternalPrintPtr)(const std::string_view &); +void setExternalDebugPrint(TimPrepsciusCoreLogExternalPrintPtr f); +void setExternalLogPrint(TimPrepsciusCoreLogExternalPrintPtr f); +void setExternalConsolePrint(TimPrepsciusCoreLogExternalPrintPtr f); + +namespace tjp::core::log { + +using detail::Settings; +using detail::Story; +using detail::getManager; + +#define xLogManager() tjp::core::log::getManager() + +void Initialize(const std::string &fileName = {}); +void Initialize(const Settings &); +#define xLogInitialize(...) tjp::core::log::Initialize(__VA_ARGS__) + +/** + * the functions actually write strings + */ +void WriteToLog (const std::string &); +void WriteToDebugger (const std::string &); +void WriteToConsole (const std::string &); + +/** + * functions to turn on/off logs and query their state + */ + +void ActivateStory (const Story &s); +void RotateTo (const std::string_view &rotateTo); +void Rotate (); +void Start(); +void Stop (); + +void ActivateStories (const std::string &fileName); + +//----------------------------------------------------------------------------- + +#if defined(_DEBUG) || defined(DEBUG) + #ifndef LOG_DEBUG + #define LOG_DEBUG + #endif +#else + #ifndef LOG_DEBUG +// #define LOG_DEBUG + #endif +#endif + +#define LOG_RELEASE +#define LOG_ERROR + +#ifdef TESTING + #define LOG_TEST +#endif + +#if defined(LOG_DEBUG) || defined(LOG_RELEASE) +#define xLogActivateStories(s) tjp::core::log::ActivateStories(s) + +#define xLogActivateStory(s) \ + tjp::core::log::ActivateStory(s); \ + sLogRelease(s, "logging activated") + +#define xLogStart() tjp::core::log::Start() +#define xLogStop() tjp::core::log::Stop() +#else +#define xLogActivateStories(s) +#define xLogActivateStory(x) +#define xLogStoryActivated(x) +#define xLogStart(x) +#define xLogStop(x) +#endif + +//----------------------------------------------------------------------------- + +#define xLogDebugStreamName "Debug" +#define xLogReleaseStreamName "Release" +#define xLogErrorStreamName "Error" +#define xLogSettings tjp::core::log::Settings::global + + +// ------------------------------------ + +#define xLogMethodName(x) tjp::core::log::detail::methodName(x) + +// ------------------------------------ + +#define xLogNoStory "_" +#define xLogAllStories "*" + +// ------------------------------------ + +#ifdef LOG_DEBUG + #define xFormatDebugger(p,n,story,...) __FILE__ << "(" << __LINE__ << ") : " << xLogColorStory(story) << n << " " << __VA_ARGS__ << std::endl +#else + #define xFormatDebugger(p,n,story,...) story << n << " " << __VA_ARGS__ << std::endl +#endif + +#define xFormatLog(p,n,story,...) "[" << story << "] " << n << " " << __VA_ARGS__ << std::endl +#define xFormatConsole(p,n,story,...) xLogColorStory(story) << n << " " << __VA_ARGS__ << std::endl + +#define xLogTo(useColor, where, ...) \ +{ \ + ::tjp::core::io::omemstream_ _out; \ + if (useColor) \ + _out.iword(::tjp::core::log::detail::SupportsColorFlag::id()) = 1; \ + _out << __VA_ARGS__; \ + where(::tjp::core::as_string_view(_out.data)); \ +} + +#define _xLog__(manager, n_,condition,story,...) \ +{ \ + if (condition) \ + { \ + auto n = xLogMethodName(n_); \ + if (manager.settings.LogToDebuggerActivated) \ + xLogTo(false, manager.writeToDebugger, xFormatDebugger(xLogDebugStreamName,n,story,__VA_ARGS__)) \ + if (manager.settings.LogToFileActivated) \ + xLogTo(false, manager.writeToLog, xFormatLog(xLogDebugStreamName,n,story,__VA_ARGS__)); \ + if (manager.settings.LogToConsoleActivated) \ + xLogTo(manager.termSupportsColor, manager.writeToConsole, xFormatConsole(xLogDebugStreamName,n,story,__VA_ARGS__)); \ + } \ +} + +#define _xLog_(n_,condition,story,...) \ +{ \ + auto &manager = xLogManager(); \ + _xLog__(manager, n_,condition,story, __VA_ARGS__); \ +} \ + +#define _xLog(n_,condition,story,...) \ +{ \ + auto &manager = xLogManager(); \ + if (manager.stories.isActivated(story)) \ + _xLog__(manager, n_,condition,story, __VA_ARGS__); \ +} \ + +// -------------------------------------- + +#define _xLogDebug(condition,story,...) _xLog(__PRETTY_FUNCTION__,condition,story,__VA_ARGS__) +#define _xLogTest(condition,story,...) _xLog(__PRETTY_FUNCTION__,condition,story,__VA_ARGS__) + +#ifdef _DEBUG + #define LOG_USE_FUNCTION_NAMES +#else +// #define LOG_USE_FUNCTION_NAMES +#endif + +#ifdef LOG_USE_FUNCTION_NAMES + #define _xLogRelease(condition,story,...) _xLog(__PRETTY_FUNCTION__,condition,story,__VA_ARGS__) + #define _xLogError(condition,story,...) _xLog_(__PRETTY_FUNCTION__,condition,story,__VA_ARGS__) +#else + #define _xLogRelease(condition,story,...) _xLog(nullptr,condition,story,__VA_ARGS__) + #define _xLogError(condition,story,...) _xLog_(nullptr,condition,story,__VA_ARGS__) +#endif + +// -------------------------------------- + +#ifdef LOG_DEBUG + #define xLogDebug(...) _xLogDebug(true,xLogNoStory,__VA_ARGS__) + #define xLogDebugIf(condition,...) _xLogDebug(condition,xLogNoStory,__VA_ARGS__) + + #define sLogDebug(story,...) _xLogDebug(true,story,__VA_ARGS__) + #define sLogDebugIf(condition,story,...) _xLogDebug(condition,story,__VA_ARGS__) + + #define fLogDebug(x) xLogDebug(x) + + #define LOG_DEBUG_ONLY(...) __VA_ARGS__ +#else + #define xLogDebug(...) + #define xLogDebugIf(...) + #define sLogDebug(...) + #define sLogDebugIf(...) + #define fLogDebug(...) + + #define LOG_DEBUG_ONLY(...) +#endif + +#ifdef LOG_RELEASE + #define xLogRelease(...) _xLogRelease(true,xLogNoStory,__VA_ARGS__) + #define xLogReleaseIf(condition,...) _xLogRelease(condition,xLogNoStory,__VA_ARGS__) + + #define sLogRelease(story,...) _xLogRelease(true,story,__VA_ARGS__) + #define sLogReleaseIf(condition,story,...) _xLogRelease(condition,story,__VA_ARGS__) +#else + #define xLogRelease(...) + #define xLogReleaseIf(...) + #define sLogRelease(...) + #define sLogReleaseIf(...) +#endif + +#ifdef LOG_TEST + #define xLogTest(x) _xLogTest(true,xLogNoStory,x) + #define xLogTestIf(condition,x) _xLogTest(condition,xLogNoStory,x) + + #define sLogTest(story,x) _xLogTest(true,story,x) + #define sLogTestIf(condition,story,x) _xLogTest(condition,story,x) +#else + #define xLogTest(...) + #define xLogTestIf(...) + #define sLogTest(...) + #define sLogTestIf(...) +#endif + +#ifdef LOG_ERROR + #define xLogError(...) _xLogError(true,xLogNoStory,__VA_ARGS__) + #define sLogError(story,...) _xLogError(true,story,__VA_ARGS__) + #define sLogErrorIf(condition,story,...) _xLogError(condition,story,__VA_ARGS__) +#else + #define xLogError(...) + #define sLogError(...) + #define sLogErrorIf(...) +#endif + +// -------------------------------------- + +#define nLogDebug(...) +#define nLogRelease(...) +#define nLogError(...) + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY_COMPILE + #include "Detail.cpp" + #include "Color.cpp" + #include "Log.cpp" +#endif + diff --git a/tjp/core/log/LogOf.h b/tjp/core/log/LogOf.h new file mode 100755 index 0000000..c040160 --- /dev/null +++ b/tjp/core/log/LogOf.h @@ -0,0 +1,192 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../type_traits/is_iterable.hpp" +#include +#include +#include "demangle.h" + +#include "../types/Types+IO.h" + +namespace tjp::core { + +template +struct LogOf +{ + const T &t; + explicit LogOf(const T &t_) : t(t_) {} + + std::ostream &operator()(std::ostream &o) const + { + return o << t; + } +} ; + +template +struct LogOfV +{ + T t; + explicit LogOfV(T t_) : t(t_) {} + + std::ostream &operator()(std::ostream &o) const + { + return o << t; + } +} ; + +template +auto logOfV(T t) { return LogOfV(t); } + +template +std::ostream &operator <<(std::ostream &o, const LogOf &v) +{ + return v(o); +} + +template +std::ostream &operator <<(std::ostream &o, const LogOfV &v) +{ + return v(o); +} + +template::value, T>::type* = nullptr> +auto logOf(const T &t); + +template::value, T>::type* = nullptr> +auto logOf(const T &t); + + +inline +auto logOf(const std::string &t) { return t; } + +inline +auto logOf(bool v) { return v ? "true" : "false"; } + +template +auto logOf(const std::pair &t) { + std::ostringstream o; + o << "(" << logOf(t.first) << "," << logOf(t.second) << ")"; + return o.str(); +} + +template::value, T>::type*> +auto logOf(const T &t) { return LogOf(t); } + +template::value, T>::type*> +auto logOf(const T &t) { + std::ostringstream o; + o << "["; + auto first = true; + for (auto v : t) + { + if (!first) + { + o << ","; + } + + o << logOf(v); + first = false; + } + o << "]"; + + return o.str(); +} + +inline +auto logOf(const std::string_view &v) +{ + return v; +} + +template +struct NullOrValue +{ + const T *t; + explicit NullOrValue(const T *t_) : t(t_) {} +} ; + +template +std::ostream &operator <<(std::ostream &o, const NullOrValue &v) +{ + if (v.t) + return o << logOf(*v.t); + + return o << "null"; +} + +template +auto logOfRef(T *t) +{ + return NullOrValue(t); +} + +template +struct NullOrPtrValue +{ + const T *t; + explicit NullOrPtrValue(const T *t_) : t(t_) {} +} ; + +template +std::ostream &operator <<(std::ostream &o, const NullOrPtrValue &v) +{ + if (v.t) + return o << "[" << v.t << "] " << logOf(*v.t); + + return o << "null"; +} + +template +auto logPtrValue(T *t) +{ + return NullOrPtrValue(t); +} + +template +auto logPtr(T *t) +{ + return t; +} + +template +struct SpaceBefore +{ + const T &t; +} ; + +template +std::ostream &operator <<(std::ostream &o, const SpaceBefore &v) +{ + return o << " " << logOf(v.t); +} + +template +SpaceBefore _logOf(const T &t) +{ + return SpaceBefore { t }; +} + +template +auto logOfDispatch(T &&t) +{ + return logOf(std::forward(t)); +} + +template +auto logOfDispatchV(T t) +{ + return logOfV(t); +} + +#define logOfThis(x) "[" << tjp::core::logPtr(x) << "] " +#define logVar(x) #x << " " << tjp::core::logOfDispatch(x) << " " +#define logVarV(x) #x << " " << tjp::core::logOfDispatchV(x) << " " +#define logType(x) #x << " " << tjp::core::type_id().name() << " " +#define logLabel(l) l << " " +#define logLabelVar(l, x) l << " " << tjp::core::logOfDispatch(x) << " " +#define logLabelVarV(l, x) l << " " << tjp::core::logOfDispatchV(x) << " " + +} // namespace diff --git a/tjp/core/log/Util.inl b/tjp/core/log/Util.inl new file mode 100755 index 0000000..f5c97fd --- /dev/null +++ b/tjp/core/log/Util.inl @@ -0,0 +1,170 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include +#include +#include + +#include "../algorithm/set_has.hpp" +#include "../algorithm/is_in.hpp" + +namespace tjp::core::log::detail { + +TJP_CORE_HEADER_ONLY_INLINE +long timeSinceEpochMillisec() +{ + using namespace std::chrono; + return duration_cast(system_clock::now().time_since_epoch()).count() % 1000000; +} + + + +TJP_CORE_HEADER_ONLY_INLINE +bool detectIfColorIsAvailable() +{ + // is the stdout redirected, if so no color + if (getenv("FORCE_COLOR")) + return true; + + if (!isatty(fileno(stdout))) + return false; + + const char* term = getenv("TERM"); + if (!term) + return false; + + // Some terminals support color + std::string_view term_(term); + if (term_ == "dumb") + return false; + + return true; +} + +using ThreadID = uint64_t; +ThreadID getCurrentThreadID(); + +TJP_CORE_HEADER_ONLY_INLINE +ThreadID getCurrentThreadID () +{ +#ifdef WIN32 + return GetCurrentThreadId(); +#else + return (ThreadID)pthread_self(); +#endif +} + + +TJP_CORE_HEADER_ONLY_INLINE +char * GetTimeStamp (char *data, int size, char marker=0) +{ +#ifdef WIN32 + __time64_t ltime; + _time64( <ime ); + + char *timestr = _ctime64(<ime); +// auto threadID = getCurrentThreadID(); + +#else + std::time_t t = std::time(nullptr); + char timestr[128]; + std::strftime(timestr, size, "%Y%m%d_%H:%M:%S", std::localtime(&t)); +// auto threadID = getCurrentThreadID(); +#endif + + snprintf (data, size, "%s.%06ld", timestr, timeSinceEpochMillisec()); + + if (marker) + for (auto *c=data; *c; ++c) + if (*c == ':' || *c == '.') + *c = marker; + + return data; +} + +TJP_CORE_HEADER_ONLY_INLINE +char * __GetLogStamp__ (char *data, bool colorize) +{ + char timeStamp[128]; + GetTimeStamp(timeStamp, std::size(timeStamp)); + + auto threadID = getCurrentThreadID(); + auto dataSize = 256; + + if (colorize) + { + // all of the threadIDs are divisible by 128, so we use 127 + auto color = (int)threadID % 127 + 1; + #if defined(SYS_LINUX) || defined(SYS_ANDROID) + snprintf (data, dataSize, "%s \033[38;5;%dm%lx\033[0m | ", timeStamp, color, threadID); + #else + snprintf (data, dataSize, "%s \033[38;5;%dm%llx\033[0m | ", timeStamp, color, threadID); + #endif + } + else + { + #if defined(SYS_LINUX) || defined(SYS_ANDROID) + snprintf (data, dataSize, "%s %lx | ", timeStamp, threadID); + #else + snprintf (data, dataSize, "%s %llx | ", timeStamp, threadID); + #endif + } + + return data; +} + +TJP_CORE_HEADER_ONLY_INLINE +std::string methodName(const char *prettyFunction_) +{ + if (!prettyFunction_) + return "[]"; + + std::string_view prettyFunction(prettyFunction_); + auto end = prettyFunction.find('('); + if (end == std::string_view::npos) + end = 0; + auto begin = end; + + auto stack = 0; + decltype(begin) skipEnd = 0; + decltype(begin) skipBegin = 0; + for (begin = end; begin > 0; begin--) + { + if (prettyFunction[begin] == '>') + { + if (stack == 0) + skipEnd = begin; + stack++; + } + if (prettyFunction[begin] == '<') + { + stack--; + if (stack == 0) + skipBegin = begin; + } + + if (prettyFunction[begin] == ' ' && stack == 0) + break; + } + + while (begin < end && is_in(prettyFunction[begin], ' ', '&', '*')) + begin = begin+1; + + std::string part; + + if (skipBegin != skipEnd) + part = std::string(prettyFunction.substr(begin,skipBegin-begin+1)) + std::string(prettyFunction.substr(skipEnd, end-skipEnd)); + else + part = prettyFunction.substr(begin,end-begin); + + if (part.size() > 30) + return part.substr(part.size() - 30); + + return part; +} + +} // namespace diff --git a/tjp/core/log/_tests/LogOf.cpp b/tjp/core/log/_tests/LogOf.cpp new file mode 100755 index 0000000..d3a577f --- /dev/null +++ b/tjp/core/log/_tests/LogOf.cpp @@ -0,0 +1,96 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include +#include +#include +#include + +namespace tjp::core::log { +namespace { + +struct S { + int i = 0; +}; + +std::ostream &operator <<(std::ostream &o, const S &s) +{ + return o << "S: " << s.i; +} + +SCENARIO("core::log::LogOf") +{ + GIVEN("a struct") + { + S x { 42 }; + + WHEN("serialize with logOf") + { + std::ostringstream s; + s << logOf(x); + String str = s.str(); + + REQUIRE(str == "S: 42"); + } + } + + GIVEN("a vector") + { + Vector x = { 1, 2, 3, 4 }; + + WHEN("serialize with logOf") + { + std::ostringstream s; + s << logOf(x); + String str = s.str(); + + REQUIRE(str == "[1,2,3,4]"); + } + } + + GIVEN("a map") + { + std::map x = { {1,1}, {2,2}, {3,3}, {4,4} }; + + WHEN("serialize with logOf") + { + std::ostringstream s; + s << logOf(x); + String str = s.str(); + + REQUIRE(str == "[(1,1),(2,2),(3,3),(4,4)]"); + } + } + + GIVEN("an optional") + { + std::optional x; + + WHEN("serialize with logOf") + { + std::ostringstream s; + s << logOf(x); + String str = s.str(); + + REQUIRE(str == "null"); + } + + WHEN("serialize value with logOf") + { + x = 1; + + std::ostringstream s; + s << logOf(x); + String str = s.str(); + + REQUIRE(str == "1"); + } + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/log/demangle.cpp b/tjp/core/log/demangle.cpp new file mode 100755 index 0000000..9032287 --- /dev/null +++ b/tjp/core/log/demangle.cpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +namespace tjp::core { + +char * demangle(const char *mangled) +{ + int status; + char * demangled = abi::__cxa_demangle(mangled,0,0,&status); + return demangled; +} + +} // namespace diff --git a/tjp/core/log/demangle.h b/tjp/core/log/demangle.h new file mode 100755 index 0000000..53ebd8f --- /dev/null +++ b/tjp/core/log/demangle.h @@ -0,0 +1,11 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +char *demangle(const char *mangled); + +} // namespace diff --git a/tjp/core/math/Float16.h b/tjp/core/math/Float16.h new file mode 100644 index 0000000..de39960 --- /dev/null +++ b/tjp/core/math/Float16.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +struct Float16; + +Float16& set(Float16 &lhs, float rhs); + +} // namespace diff --git a/tjp/core/math/Float16.hpp b/tjp/core/math/Float16.hpp new file mode 100644 index 0000000..5b4672d --- /dev/null +++ b/tjp/core/math/Float16.hpp @@ -0,0 +1,74 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../types/Types.h" +#include "Float16.h" + +namespace tjp::core { + +struct Float16 +{ + using V = u16; + V v; + + struct Bits { V v; }; + + constexpr explicit Float16(Bits bits) : + v(bits.v) + { + } + + constexpr Float16() : + v(0) + {} + + constexpr Float16(const Float16 &rhs) : + v(rhs.v) + {} + + constexpr Float16(float rhs) : + v(convert(rhs)) + { + } + + constexpr Float16(double rhs) : + v(convert((float)rhs)) + { + } + + static constexpr V convert(float rhs); + static constexpr float convert(V rhs); + + static constexpr Float16 max(); + static constexpr Float16 min__(); + static constexpr Float16 negative_max(); + + auto ordered() const + { + u16 sign = v >> 15; + if (sign == 0) + return v | 0x8000; + else + return ~v; + } + + operator float() const; + operator double() const; + + Float16 &operator =(float rhs) + { + return set(*this, rhs); + } + + Float16 &operator =(double rhs) + { + return set(*this, rhs); + } +} ; + +} // namespace + +#include "Float16.inl" diff --git a/tjp/core/math/Float16.inl b/tjp/core/math/Float16.inl new file mode 100644 index 0000000..2d65ffa --- /dev/null +++ b/tjp/core/math/Float16.inl @@ -0,0 +1,186 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +inline +Float16::operator float() const +{ + return convert(v); +} + +inline +Float16::operator double() const +{ + return (float)*this; +} + +inline +bool operator <(const Float16 &lhs, const Float16 &rhs) +{ + return lhs.ordered() < rhs.ordered(); +} + +inline +bool operator >(const Float16 &lhs, const Float16 &rhs) +{ + return lhs.ordered() > rhs.ordered(); +} + +inline +bool operator ==(const Float16 &lhs, const Float16 &rhs) +{ + return lhs.v == rhs.v; +} + +inline +bool operator !=(const Float16 &lhs, const Float16 &rhs) +{ + return lhs.v != rhs.v; +} + +// --- + +inline +constexpr Float16 Float16::max() +{ + return Float16(Float16::Bits { .v = 0x7BFF }); +} + +inline +constexpr Float16 Float16::negative_max() +{ + return Float16(Float16::Bits { .v = 0xFBFF }); +} + +inline +constexpr Float16 Float16::min__() +{ + return Float16(Float16::Bits { .v = 0x0400 }); +} + +// --- + +union Float16_Float32Bits { + float f; + uint32_t u; +}; + +inline +constexpr float Float16::convert(V v) +{ + uint16_t hv = v; + uint16_t sign = (hv >> 15) & 0x1; + uint16_t exp = (hv >> 10) & 0x1F; + uint16_t frac = hv & 0x3FF; + + uint32_t sign32 = sign << 31; + uint32_t exp32 = 0, frac32 = 0; + + if (exp == 0) { + if (frac == 0) { + // Zero + exp32 = 0; + frac32 = 0; + } else { + // Subnormal: normalize + int e = -14; // unbiased exponent for half subnormals + uint32_t f = frac; + while ((f & 0x400) == 0) { + f <<= 1; + e--; + } + f &= 0x3FF; + exp32 = (e + 127) << 23; + frac32 = f << 13; + } + } + else if (exp == 0x1F) { + // Inf or NaN + exp32 = 0xFF << 23; + if (frac == 0) { + // Inf + frac32 = 0; + } else { + // NaN – preserve payload, set quiet NaN bit + frac32 = (frac << 13) | 0x400000; + } + } + else { + // Normalized + int e = exp - 15 + 127; + exp32 = (uint32_t)e << 23; + frac32 = (uint32_t)frac << 13; + } + + auto u = sign32 | exp32 | frac32; + Float16_Float32Bits result { .u = u }; + return result.f; +} + +inline +constexpr Float16::V Float16::convert(float rhs) +{ + Float16_Float32Bits result { .f = rhs }; + uint32_t bits = result.u; + + uint32_t sign = (bits >> 31) & 0x1; + int32_t exp = (bits >> 23) & 0xFF; + uint32_t frac = bits & 0x7FFFFF; + + uint16_t sign16 = sign << 15; + uint16_t exp16 = 0; + uint16_t frac16 = 0; + + if (exp == 0) { + // Zero or subnormal in float + exp16 = 0; + frac16 = 0; // Flush subnormals to zero + } + else if (exp == 0xFF) { + // Inf or NaN + exp16 = 0x1F; + frac16 = frac ? 0x200 : 0; // Preserve a quiet NaN bit + } + else { + // Normalized float + int newExp = exp - 127 + 15; + if (newExp >= 0x1F) { + // Overflow → Inf + exp16 = 0x1F; + frac16 = 0; + } + else if (newExp <= 0) { + // Underflow → subnormal or zero + if (newExp < -10) { + exp16 = 0; + frac16 = 0; + } + else { + // Subnormal half + uint32_t mant = (frac | 0x800000) >> (1 - newExp); + frac16 = mant >> 13; + exp16 = 0; + } + } + else { + exp16 = newExp; + frac16 = frac >> 13; + } + } + + Float16::V v = sign16 | (exp16 << 10) | frac16; + return v; +} + +inline +Float16& set(Float16 &lhs, float rhs) +{ + lhs.v = Float16::convert(rhs); + return lhs; +} + +} // namespace diff --git a/tjp/core/math/_tests/Float16.cpp b/tjp/core/math/_tests/Float16.cpp new file mode 100755 index 0000000..71d700a --- /dev/null +++ b/tjp/core/math/_tests/Float16.cpp @@ -0,0 +1,113 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include + +namespace tjp::core { +namespace { + +float randomFloat() { + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_int_distribution dist; + + uint32_t bits = dist(gen); + float value; + std::memcpy(&value, &bits, sizeof(value)); + return value; +} + +float randomFloatInRange(float l, float r) { + static std::random_device rd; + static std::mt19937 gen(rd()); + static std::uniform_real_distribution dist(l, r); + + return dist(gen); +} + +SCENARIO("core::math::Float16") +{ + GIVEN("nothing") + { + WHEN("tested all floats") + { + bool all_passed = true; + + auto testCount = 100000; + for (auto i=0; i r16_max || a < r16_min; + all_passed = all_passed && was_out_of_range; + } + else + { + auto relative_epsilon = 0.001f; // relative tolerance + auto absolute_epsilon = 0.001f; // absolute tolerance + auto d = std::abs(b - a); + auto epsilon = std::max(relative_epsilon * std::abs(a), absolute_epsilon); + all_passed = all_passed && (d < epsilon); + + if (!all_passed) + REQUIRE(false); + } + + if (!all_passed) + REQUIRE(false); + } + + REQUIRE(all_passed); + } + + WHEN("tested valid float16s") + { + bool all_passed = true; + auto testCount = 100000; + for (auto i=0; i +#include + +#include +#include + +//#include "std/CustomControlBlock.h" + +namespace tjp { +namespace core { + +namespace memory { +namespace test_compile { + +struct A +{ + int i; + + ~A () + { + i = 2; + } +} ; + +struct B +{ + static int allocations; + int x = 5; + B () { + allocations++; + } + ~B () { + allocations--; + } +}; + +int B::allocations = 0; + +int num_c_deallocations = 0; +int num_c_destroys = 0; + +struct C +{ + int x= 5; + + ~C () + { + num_c_destroys++; + x = 2; + } +} ; + + +void on_deallocate(C *p) +{ + num_c_deallocations++; +} + +struct CustomDeleter : StrongThis +{ + int called = 0; + + template + void deallocate(T *t) + { + called++; + delete t; + } +} ; + +SCENARIO("core::ptr") +{ + GIVEN("a ptr to normal") + { + WHEN("a ptr is created normal") + { + B::allocations = 0; + + auto ptr = strong(); + REQUIRE(B::allocations == 1); + ptr = nullptr; + + REQUIRE(B::allocations == 0); + } + + } + + GIVEN("a ptr") + { + WHEN("a ptr is created normal") + { + num_c_deallocations = num_c_destroys = 0; + + auto ptr = strong(); + ptr = nullptr; + + REQUIRE(num_c_deallocations == 1); + REQUIRE(num_c_destroys == 1); + } + + WHEN("a ptr is created with a custom deleter") + { + CustomDeleter deleter; + + num_c_deallocations = num_c_destroys = 0; + + auto ptr = strong_with_delete( + new C(), [&](C *t) { deleter.deallocate(t); } + ); + ptr = nullptr; + + REQUIRE(num_c_deallocations == 1); + REQUIRE(num_c_destroys == 1); + REQUIRE(deleter.called == 1); + } + } + + GIVEN("a ptr with a custom deleter") + { + CustomDeleter deleter; + + WHEN("create a pointer") + { + auto a = strong_with_delete( + new A(), [&](A *t) { deleter.deallocate(t); } + ); + + WHEN("transfer the pointer elsewherez") + { + auto b = a; + a = nullptr; + + WHEN("nullify the pointer") + { + b = nullptr; + + REQUIRE(deleter.called == 1); + } + } + } + } +} + +} // namespace +} // namespace + +} // namespace +} // namespace diff --git a/tjp/core/ptr/std/CustomControlBlock.h b/tjp/core/ptr/std/CustomControlBlock.h new file mode 100755 index 0000000..8831f1e --- /dev/null +++ b/tjp/core/ptr/std/CustomControlBlock.h @@ -0,0 +1,63 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::ptr::using_std { + +template +class CustomControlBlock1 + : public std::__shared_weak_count +{ + std::__compressed_pair, _Alloc> __data_; +public: + _LIBCPP_INLINE_VISIBILITY + CustomControlBlock1(_Tp __p, _Dp __d, _Alloc __a) + : __data_(std::__compressed_pair<_Tp, _Dp>(__p, _VSTD::move(__d)), _VSTD::move(__a)) {} + +#ifndef _LIBCPP_NO_RTTI + virtual const void* __get_deleter(const std::type_info&) const _NOEXCEPT; +#endif + +private: + virtual void __on_zero_shared() _NOEXCEPT; + virtual void __on_zero_shared_weak() _NOEXCEPT; +}; + +#ifndef _LIBCPP_NO_RTTI + +template +const void* +CustomControlBlock1<_Tp, _Dp, _Alloc>::__get_deleter(const std::type_info& __t) const _NOEXCEPT +{ + return __t == typeid(_Dp) ? _VSTD::addressof(__data_.first().second()) : nullptr; +} + +#endif // _LIBCPP_NO_RTTI + +template +void +CustomControlBlock1<_Tp, _Dp, _Alloc>::__on_zero_shared() _NOEXCEPT +{ + __data_.first().second()(__data_.first().first()); + __data_.first().second().~_Dp(); +} + +template +void +CustomControlBlock1<_Tp, _Dp, _Alloc>::__on_zero_shared_weak() _NOEXCEPT +{ + typedef typename std::__allocator_traits_rebind<_Alloc, CustomControlBlock1>::type _Al; + typedef std::allocator_traits<_Al> _ATraits; + typedef std::pointer_traits _PTraits; + + _Al __a(__data_.second()); + __data_.second().~_Alloc(); +// __a.deallocate(_PTraits::pointer_to(*this), 1); +} + +} // namespace + diff --git a/tjp/core/ptr/std/Ptr+Debug.h b/tjp/core/ptr/std/Ptr+Debug.h new file mode 100755 index 0000000..6c56ce4 --- /dev/null +++ b/tjp/core/ptr/std/Ptr+Debug.h @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef DEBUG + #define MEMORY_PTR_DEBUG_TYPE +#endif + +#define MEMORY_PTR_DEBUG_ALLOCATIONS +#define LOG_MEMORY_PTR diff --git a/tjp/core/ptr/std/Ptr+GCC.h b/tjp/core/ptr/std/Ptr+GCC.h new file mode 100755 index 0000000..7987779 --- /dev/null +++ b/tjp/core/ptr/std/Ptr+GCC.h @@ -0,0 +1,129 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core::ptr::using_std { + +template +class StrongPtrAllocator +{ +public: + typedef A Allocator; + typedef size_t size_type; + typedef std::ptrdiff_t difference_type; + typedef T* pointer; + typedef const T* const_pointer; + typedef T& reference; + typedef const T& const_reference; + typedef T value_type; + +public: + template struct rebind { + typedef StrongPtrAllocator< + _Tp1, + typename A::template rebind<_Tp1>::other + > other; + }; + + Allocator allocator; + +public: + StrongPtrAllocator() {} + StrongPtrAllocator (const StrongPtrAllocator &) {} + ~StrongPtrAllocator () {} + + template + StrongPtrAllocator (const _Up &) { } + + T *allocate (size_t size) + { + return allocator.allocate(size); + } + + void deallocate(T *t, size_t size) + { + return allocator.deallocate(t, size); + } + + void construct(pointer __p) + { + return allocator.construct(__p); + } + + template + void construct(U* p, Args&&... args) + { + allocator.construct(p, std::forward(args)...); + } + + void destroy(pointer p) + { + deallocate_detail(p); + allocator.destroy(p); + } + + template + void destroy(U* p) + { + deallocate_detail(p); + allocator.destroy(p); + } +} ; + +template +auto strong_no_deallocate(Args && ...args) +{ + return std::make_shared( + std::forward(args)... + ); +} + +template +auto strong_with_deallocate(Args && ...args) +{ + return std::allocate_shared( + StrongPtrAllocator>(), + std::forward(args)... + ); +} + +template +auto strong(Args && ...args) +{ + if constexpr (type_has_deallocate::value) { + return strong_with_deallocate( + std::forward(args)... + ); + } + else + { + return strong_no_deallocate( + std::forward(args)... + ); + } +} + +template +auto strong_with_delete(T *ptr, F &&f) +{ + return std::shared_ptr( + ptr, + makeDeleterWithFunction(std::move(f)) + ); +} + +template +auto strong_with_allocator(Allocator allocator, Args&& ...args) +{ + return std::allocate_shared( + StrongPtrAllocator { allocator }, + std::forward(args)... + ); +} + +} // namespace + diff --git a/tjp/core/ptr/std/Ptr+IO.h b/tjp/core/ptr/std/Ptr+IO.h new file mode 100755 index 0000000..a672ee1 --- /dev/null +++ b/tjp/core/ptr/std/Ptr+IO.h @@ -0,0 +1,34 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace std { + +template +void io_ptr_allocate(IO &io, shared_ptr &ptr) +{ + io.allocate(ptr); +} + +template +void io_ptr_allocate_default(IO &io, shared_ptr &ptr) +{ + ptr = tjp::core::ptr::using_std::strong(); +} + +template +void io_w(IO &io, const shared_ptr &r) +{ + io.any(tjp::core::ptr::using_std::ptr_of(r)); +} + +template +void io_r(IO &io, shared_ptr &t) +{ + auto p = io.template pointer(t); + io.any(p); +} + +} // namespace diff --git a/tjp/core/ptr/std/Ptr+LLVM.h b/tjp/core/ptr/std/Ptr+LLVM.h new file mode 100755 index 0000000..4e97cb9 --- /dev/null +++ b/tjp/core/ptr/std/Ptr+LLVM.h @@ -0,0 +1,78 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + + +namespace tjp::core::ptr::using_std { + +template +auto strong_no_deallocate(Args && ...args) +{ + return std::make_shared( + std::forward(args)... + ); +} + +template +auto strong_with_deallocate(Args && ...args) +{ + return std::shared_ptr( + new T(std::forward(args)...), + makeDeleter() + ); +} + +template +auto strong(Args && ...args) +{ + if constexpr (type_has_deallocate::value) { + return strong_with_deallocate( + std::forward(args)... + ); + } + else + { + return strong_no_deallocate( + std::forward(args)... + ); + } +} + +template +auto strong_with_delete(T *ptr, F &&f) +{ + return std::shared_ptr( + ptr, + makeDeleterWithFunction(std::move(f)) + ); +} + +template +auto strong_with_allocator(Allocator allocator, Args && ...args) +{ + auto ptr = allocator.allocate(1); + allocator.construct(ptr, std::forward(args)...); + + auto f = makeDeleterWithAllocator(allocator); + typedef decltype(f) F; + + typedef T *Tp; + typedef std::__shared_ptr_pointer TControlBlock; + using ControlBlockAllocator = typename Allocator::template rebind::other; + + #ifdef _DEBUG + auto controlBlockSize = sizeof(TControlBlock); + (void)controlBlockSize; + #endif + + ControlBlockAllocator controlBlockAllocator; + auto ctrl = controlBlockAllocator.allocate(1); + controlBlockAllocator.construct(ctrl, ptr, f, allocator); + + return std::shared_ptr::__create_with_control_block(ptr, ctrl); +} + +} // namespace + diff --git a/tjp/core/ptr/std/Ptr+Log.h b/tjp/core/ptr/std/Ptr+Log.h new file mode 100755 index 0000000..aa4ea55 --- /dev/null +++ b/tjp/core/ptr/std/Ptr+Log.h @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../../log/LogOf.h" +#include "Ptr.h" + +namespace std { + +template +auto logOf(const std::shared_ptr &v) +{ + return tjp::core::logPtrValue(tjp::core::ptr::using_std::ptr_of(v)); +} + +template +auto logOf(const std::weak_ptr &v) +{ + return tjp::core::logPtrValue(tjp::core::ptr::using_std::ptr_of(tjp::core::ptr::using_std::strong(v))); +} + +template +T *logPtr(const std::shared_ptr &v) +{ + return tjp::core::ptr::using_std::ptr_of(v); +} + +template +T *logPtr(const std::weak_ptr &v) +{ + return tjp::core::ptr::using_std::ptr_of(strong(v)); +} + + +} // namespace + diff --git a/tjp/core/ptr/std/Ptr.h b/tjp/core/ptr/std/Ptr.h new file mode 100755 index 0000000..4570411 --- /dev/null +++ b/tjp/core/ptr/std/Ptr.h @@ -0,0 +1,140 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +#include "../../debug/Debug.h" + +template +struct type_has_deallocate : std::false_type {}; + +template +struct type_has_deallocate< + T, + std::void_t< + decltype( + on_deallocate( + std::declval() + ) + ) + > +> : std::true_type {}; + +template +void on_deallocate(T *t) +{ +} + +template +void deallocate_detail(T *t) +{ + on_deallocate(t); +} + +namespace tjp::core::ptr::using_std { + +template +auto makeDeleter() +{ + return [](T *p) { + deallocate_detail(p); + delete p; + } ; +} + +template +auto makeDeleterWithFunction(F &&f) +{ + return [f](T *p) { + deallocate_detail(p); + f(p); + } ; +} + +template +auto makeDeleterWithAllocator(A a) +{ + return [a](T *p) { + deallocate_detail(p); + + auto &a_ = const_cast(a); + a_.destroy(p); + a_.deallocate(p, 1); + } ; +} + +template +using StrongPtr = std::shared_ptr; + +template +using WeakPtr = std::weak_ptr; + +template +using StrongThis = std::enable_shared_from_this; + +template +auto strong_ptr_dynamic_cast(const V &v) +{ + return std::dynamic_pointer_cast(v); +} + +template +auto strong_ptr_cast(const V &v) +{ + return std::static_pointer_cast(v); +} + +template +auto weak_this(T *t) +{ + return t->weak_from_this(); +} + +template +auto strong_this(T *t) +{ + return std::static_pointer_cast(t ? t->weak_from_this().lock() : std::shared_ptr()); +} + +template +auto strong(const WeakPtr &t) +{ + return t.lock(); +} + +template +auto weak(const StrongPtr &t) +{ + return std::weak_ptr(t); +} + + +template +auto strong_thread(const T &t) +{ + return t; +} + +template +auto ptr_of(const StrongPtr &t) +{ + return t.get(); +} + +template +auto ref_this(T *t) +{ + return strong_this(t); +} + +} // namespace + +#ifdef _GLIBCXX_MEMORY + #include "Ptr+GCC.h" +#else + #include "Ptr+LLVM.h" +#endif diff --git a/tjp/core/ptr/strong_emplace.hpp b/tjp/core/ptr/strong_emplace.hpp new file mode 100755 index 0000000..5cffcc5 --- /dev/null +++ b/tjp/core/ptr/strong_emplace.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +StrongPtr &strong_emplace(StrongPtr &t, Args&& ...args) +{ + return t = strong(std::forward(args)...); +} + +template +StrongPtr &strong_emplace(StrongPtr &t) +{ + return t = strong(); +} + +} // namespace + diff --git a/tjp/core/ptr/strong_init.hpp b/tjp/core/ptr/strong_init.hpp new file mode 100755 index 0000000..1866086 --- /dev/null +++ b/tjp/core/ptr/strong_init.hpp @@ -0,0 +1,22 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +struct InitRequired {}; + +template +auto strong_init(Args && ...args) +{ + auto v = strong(InitRequired{}, std::forward(args)...); + v->init(v); + return v; +} + +} // namespace +} // namespace + diff --git a/tjp/core/ptr/strong_of.hpp b/tjp/core/ptr/strong_of.hpp new file mode 100755 index 0000000..d0ad726 --- /dev/null +++ b/tjp/core/ptr/strong_of.hpp @@ -0,0 +1,24 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +auto strong_of_value(const T &t) +{ + return strong(t); +} + +template +auto strong_of(T &&t) +{ + return strong>(std::forward(t)); +} + +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr+Debug.h b/tjp/core/ptr/using_info/Ptr+Debug.h new file mode 100755 index 0000000..023c3c9 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr+Debug.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../../system/Debug.h" + +#ifdef DEBUG + #define MEMORY_PTR_DEBUG_TYPE +#endif + +//#define MEMORY_PTR_DEBUG_ALLOCATIONS +//#define LOG_MEMORY_PTR diff --git a/tjp/core/ptr/using_info/Ptr+IO.h b/tjp/core/ptr/using_info/Ptr+IO.h new file mode 100755 index 0000000..51075d5 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr+IO.h @@ -0,0 +1,55 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +template +void io_ptr_allocate(IO &io, StrongPtr &ptr) +{ + io.allocate(ptr); +} + +template +void io_ptr_allocate_default(IO &io, StrongPtr &ptr) +{ + ptr = strong(); +} + +template +void io_json_w(IO &io, const StrongPtr &r) +{ + io.any((T *)r); +} + +template +void io_json_r(IO &io, StrongPtr &t) +{ + auto p = io.template pointer(t); + io.any(p); +} + +template +void io_bin_w(IO &io, const StrongPtr &r) +{ + io.any((T *)r); +} + +template +void io_bin_r(IO &io, StrongPtr &r) +{ + auto p = io.template pointer(r); + io.any(p); +} + +} // namespace +} // namespace +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/ptr/using_info/Ptr+Log.cpp b/tjp/core/ptr/using_info/Ptr+Log.cpp new file mode 100755 index 0000000..b81a35b --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr+Log.cpp @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Ptr+Log.h" + +namespace tjp { +namespace core { + + +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr+Log.h b/tjp/core/ptr/using_info/Ptr+Log.h new file mode 100755 index 0000000..a81ad13 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr+Log.h @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../../log/LogOf.h" +#include "Ptr.h" + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +template +std::ostream &operator <<(std::ostream &o, const StrongPtr &v) +{ + return o << logOf(v.ptr()); +} + +} // namespace +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr+Logging.cpp b/tjp/core/ptr/using_info/Ptr+Logging.cpp new file mode 100755 index 0000000..4588d51 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr+Logging.cpp @@ -0,0 +1,46 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Ptr.hpp" + +#include +#include +#include + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +std::string Debug::getInfoFor (K k) +{ + return "not implemented"; +} + +std::string setToString(const std::set &ids) +{ + std::ostringstream oss; + + oss << " ["; + for (auto &id: ids) + { + oss << id << " "; + } + oss << "] "; + + return oss.str(); +} + +void Debug::print () +{ + std::cout << "SmartPtr printDebug " << std::endl;; +} + +} // namespace +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr.cpp b/tjp/core/ptr/using_info/Ptr.cpp new file mode 100755 index 0000000..8893451 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr.cpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Ptr.hpp" + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { + +namespace detail { + +Mutex &Object::mutex() +{ + static Mutex v; + return v; +} + +} // namespace detail + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr.h b/tjp/core/ptr/using_info/Ptr.h new file mode 100755 index 0000000..3f57324 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr.h @@ -0,0 +1,95 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Ptr+Debug.h" + +#include "../../threads/Lock.h" +#include + +template +void onStrongPtrDelete(T *t); + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +class Catalog; + +template +class StrongPtr; + +template +class WeakPtr; + +template +class StrongThis; + +class Debug; + +} // namespace detail + +template +using StrongPtr = detail::StrongPtr; + +template +using WeakPtr = detail::WeakPtr; + +template +using StrongThis = detail::StrongThis; + +using Catalog = detail::Catalog; + +// ------------------------------------------------ + +template +size_t refCount (T *k); + +template +StrongPtr strong (Args&& ...); + +template +StrongPtr strong_any (T *); + +template +StrongPtr strong (const StrongPtr &t); + +template +WeakPtr weak (const StrongPtr &t); + +template +StrongPtr strong (const WeakPtr &t); + +template +StrongPtr strong_this (T *that); + +template +StrongPtr ref_this(T *that); + +template +WeakPtr weak_this (T *that); + +template +StrongPtr strong_thread(const StrongPtr &t); + +template +StrongPtr strong_thread_this(T *t); + +template +StrongPtr strong_thread (const WeakPtr &t); + +template +T *ptr_of(const StrongPtr &t); + +template +StrongPtr strong_ptr_cast(const StrongPtr &t); + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_info/Ptr.hpp b/tjp/core/ptr/using_info/Ptr.hpp new file mode 100755 index 0000000..0078406 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr.hpp @@ -0,0 +1,315 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Ptr.h" + +#include +#include +#include + +#include "../../threads/Lock.hpp" +#include "../../containers/FilledArray.hpp" +#include "../../assert/debug_assert.h" +#include "../../rtti/RTTI.hpp" + +#include + +#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS +#include +#endif + +template +void onStrongPtrDelete(T *t); + +template +void deallocate(T *t); + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +typedef core::Mutex Mutex; +typedef core::Mutex::Lock Lock; + +typedef void *K; +typedef void *W; + +struct NotCataloged {}; +struct Cataloged {}; + +struct WeakRef; + +struct Object +{ + typedef detail::Lock Lock; + static Mutex &mutex(); + + template + Object(T *p, bool allocated); + + std::atomic count = 0; + K p; + bool allocated; + bool threaded = false; + + StrongPtr *weak = nullptr; + + template + T *ptr(); + + void mark_threaded (); + + void ref (void *that); + + template + T *unref_no_lock (void *that); + + template + T *unref_lock (void *that); + + template + void unref (void *that); + + StrongPtr get_weak(); + + #ifdef MEMORY_PTR_DEBUG_TYPE + const char *typeName; + #endif + + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + Mutex idsMutex; + std::set ids; + #endif +} ; + +class Debug +{ +public: + static std::string getInfoFor (K k); + static void print (); +}; + +template +class StrongPtr; + +class WeakRef +{ +private: + friend class Object; + Object *object = nullptr; + bool threaded = false; + + WeakRef &operator = (const WeakRef &rhs) = delete; + WeakRef (const WeakRef &w) = delete; + + void ref(Object *object); + void unref(); + + void mark_threaded(); + +public: + WeakRef(Object *object_); + ~WeakRef(); + + template + StrongPtr ptr(); +} ; + +template +class WeakPtr; + +template +class StrongPtr { + +public: + typedef T value_type; + typedef T element_type; + typedef T *pointer_type; + +private: + detail::Object *object = nullptr; + + template + void check_compatible_u() const + { + debug_assert(static_cast((T *)0) == 0); + } + + StrongPtr *mutable_this() const; + void ref (detail::Object *object_); + void unref (); + void swap (detail::Object *&lhs, void *lhs_, detail::Object *&rhs, void *rhs_); + +public: + detail::Object *&accessObject() const; + +public: + ~StrongPtr (); + + StrongPtr (); + + StrongPtr (const detail::Object *object_); + + // ------------------------- + + StrongPtr(StrongPtr &&rhs); + StrongPtr(const StrongPtr &rhs); + + // ------------------------- + + template + StrongPtr(const StrongPtr &rhs) + { + check_compatible_u(); + ref(rhs.accessObject()); + } + + template + StrongPtr(StrongPtr &&rhs) + { + check_compatible_u(); + swap(object, (void *)this, rhs.accessObject(), (void *)&rhs); + } + + // ------------------------- + + StrongPtr &operator =(const StrongPtr &rhs); + StrongPtr &operator =(StrongPtr &&rhs); + + // ------------------------- + + operator bool() const; + bool operator !() const; + + // ------------------------- + + template + StrongPtr cast() const + { + check_compatible_u(); + + if (!object) + return {}; + + auto *t = object->ptr(); + auto *u = dynamic_cast(t); + debug_assert((void *)u == (void *)t || u == nullptr); + + if (u) + { + return StrongPtr(object); + } + + return StrongPtr(); + } + + T *ptr() const; + + operator T *() const; + T &operator *() const; + T *operator -> () const; + + bool operator == (const T *_t) const; + bool operator == (const StrongPtr &_t) const; + bool operator != (const StrongPtr &_t) const; + bool operator <(const StrongPtr &rhs) const; + + WeakPtr weak() const; + + void mark_threaded(); +}; + +template +class WeakPtr +{ +private: + StrongPtr t; + +protected: + +public: + WeakPtr (); + WeakPtr (const StrongPtr &rhs); + WeakPtr (const WeakPtr &rhs); + WeakPtr (WeakPtr &&rhs); + + WeakPtr &operator =(const WeakPtr &rhs); + WeakPtr &operator =(WeakPtr &&rhs); + + StrongPtr ptr() const; +} ; + +template +class StrongThis +{ + StrongThis(const StrongThis &rhs) = delete; + void operator =(const StrongThis &rhs) = delete; + +protected: + Object strong_tracker; + +public: + StrongThis(); + + Object *get_strong_this() { + return &strong_tracker; + } +} ; + +template +class has_strong_this +{ + typedef char one; + struct two { char x[2]; }; + + template static one test( decltype(&C::get_strong_this) ) ; + template static two test(...); + +public: + enum { value = sizeof(test(0)) == sizeof(char) }; +}; + +template +Object *object_from_this(T *t) +{ + return t->get_strong_this(); +} + +template::value, T>::type* = nullptr> +Object *object_for(T *t) +{ + return new Object(t, true); +} + +template::value, T>::type* = nullptr> +Object *object_for(T *t) +{ + return object_from_this(t); +} + +} // namespace detail + +template +using StrongPtr = detail::StrongPtr; + +template +using WeakPtr = detail::WeakPtr; + +template +using StrongThis = detail::StrongThis; + +using Catalog = detail::Catalog; + +} // namespace +} // namespace +} // namespace + +} // namespace + +#include "Ptr.inl" + diff --git a/tjp/core/ptr/using_info/Ptr.inl b/tjp/core/ptr/using_info/Ptr.inl new file mode 100755 index 0000000..75a3e73 --- /dev/null +++ b/tjp/core/ptr/using_info/Ptr.inl @@ -0,0 +1,545 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef LOG_MEMORY_PTR +#include "../../log/Log.h" +#include "../../log/LogOf.h" +#define LogDebugStrongPtr(x) xLogDebug(x) +#else +#define LogDebugStrongPtr(x) +#endif + +template +void onStrongPtrDelete(T *t) {} + +template +void deallocate(T *t) +{ + delete t; +} + +namespace tjp { +namespace core { +namespace ptr { +namespace using_info { +namespace detail { + +// ---------------------------------------------------------------- + +template +StrongThis::StrongThis () : + strong_tracker(static_cast(this), false) +{} + +// ---------------------------------------------------------------- + +inline +void Object::mark_threaded() +{ + threaded = true; + get_weak()->mark_threaded(); +} + +template +Object::Object(T *p_, bool allocated_) : + p(p_), + allocated(allocated_) +{ + #ifdef MEMORY_PTR_DEBUG_TYPE + typeName = type_id().name(); + #endif +} + +template +T *Object::ptr() +{ + return reinterpret_cast(p); +} + +inline +void Object::ref (void *that) +{ + ++count; + + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + { + auto l = lock_of(idsMutex); + ids.insert(that); + } + #endif +} + +template +T *Object::unref_no_lock (void *that) +{ + T *t = nullptr; + { + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + { + auto l = lock_of(idsMutex); + ids.erase(that); + } + #endif + + if (--count == 0) + { + if (weak) + { + weak->ptr()->unref(); + delete weak; + weak = nullptr; + } + + t = ptr(); + p = nullptr; + if (allocated) + delete this; + } + } + + return t; +} + + +template +T *Object::unref_lock (void *that) +{ + Object::Lock l(Object::mutex()); + + return unref_no_lock(that); +} + +template +void Object::unref (void *that) +{ + T *t = nullptr; + if (threaded) + t = unref_lock(that); + else + t = unref_no_lock(that); + + if (t) + { + onStrongPtrDelete(t); + deallocate(t); + } +} + +inline +StrongPtr Object::get_weak() +{ + if (!weak) + weak = new StrongPtr(strong(this)); + + return *weak; +} + +// ---------------------------------------------------------------- + +inline +void WeakRef::ref(Object *object_) +{ + unref(); + object = object_; +} + +inline +void WeakRef::unref() +{ + object = nullptr; +} + +inline +WeakRef::WeakRef(Object *object_) +{ + ref(object_); +} + +inline +WeakRef::~WeakRef() +{ + unref(); +} + +template +StrongPtr WeakRef::ptr() +{ + if (threaded) + { + detail::Object::Lock l(detail::Object::mutex()); + return StrongPtr(object); + } + + return StrongPtr(object); +} + +inline +void WeakRef::mark_threaded() +{ + threaded = true; +} + +// ---------------------------------------------------------------- + +template +StrongPtr *StrongPtr::mutable_this() const +{ + return const_cast *>(this); +} + + +template +detail::Object *&StrongPtr::accessObject() const +{ + return mutable_this()->object; +} + +template +void StrongPtr::ref (Object *object_) +{ + debug_assert(object == nullptr); + object = object_; + + if (object) + { + object->ref(this); + } +} + +template +void StrongPtr::unref () +{ + if (object) + { + object->unref(this); + } + + object = nullptr; +} + +template +void StrongPtr::swap(detail::Object *&lhs, void *lhs_, detail::Object *&rhs, void *rhs_) +{ + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + { + if (lhs) + { + Lock ll(lhs->idsMutex); + lhs->ids.erase(lhs_); + lhs->ids.insert(rhs_); + } + + if (rhs) + { + Lock lr(rhs->idsMutex); + rhs->ids.erase(rhs_); + rhs->ids.insert(lhs_); + } + } + #endif + + std::swap(lhs, rhs); +} + +template +StrongPtr::~StrongPtr () +{ + unref(); +} + +template +StrongPtr::StrongPtr () +{ + ref(nullptr); +} + +template +StrongPtr::StrongPtr (const Object *object_) +{ + ref(const_cast(object_)); +} + +template +StrongPtr::StrongPtr(StrongPtr &&rhs) +{ + swap(object, this, rhs.object, &rhs); +} + +template +StrongPtr::StrongPtr(const StrongPtr &rhs) +{ + ref(rhs.object); +} + +// ------------------------- + +template +StrongPtr &StrongPtr::operator =(const StrongPtr &rhs) +{ + if (rhs.object == object) + return *this; + + unref(); + ref(rhs.object); + + return *this; +} + +template +StrongPtr &StrongPtr::operator =(StrongPtr &&rhs) +{ + std::swap(object, rhs.object); + return *this; +} + +template +StrongPtr::operator bool() const +{ + return object != nullptr; +} + +template +bool StrongPtr::operator !() const +{ + return object == nullptr; +} + + +template +T *StrongPtr::ptr() const +{ + if (!object) + return nullptr; + + return object->ptr(); +} + +template +StrongPtr::operator T *() const +{ + return ptr(); +} + +template +T &StrongPtr::operator *() const +{ + return *ptr(); +} + +template +T *StrongPtr::operator -> () const +{ + return ptr(); +} + +template +bool StrongPtr::operator == (const T *_t) const +{ + return ptr() == _t; +} + +template +bool StrongPtr::operator == (const StrongPtr &rhs) const +{ + return ptr() == rhs.ptr(); +} + +template +bool StrongPtr::operator != (const StrongPtr &rhs) const +{ + return ptr() != rhs.ptr(); +} + +template +bool StrongPtr::operator <(const StrongPtr &rhs) const +{ + return ptr() < rhs.ptr(); +} + +template +WeakPtr StrongPtr::weak() const +{ + return object ? WeakPtr(object->get_weak()) : WeakPtr(); +} + +template +void StrongPtr::mark_threaded() +{ + if (object) + { + object->mark_threaded(); + } +} + + +// ------------- + + +template +WeakPtr::WeakPtr () +{ +} + +template +WeakPtr::WeakPtr (const StrongPtr &rhs) : t(rhs) +{ +} + +template +WeakPtr::WeakPtr (const WeakPtr &rhs) : t(rhs.t) +{ +} + +template +WeakPtr::WeakPtr (WeakPtr &&rhs) : t(std::move(rhs.t)) +{ +} + +template +WeakPtr &WeakPtr::operator =(const WeakPtr &rhs) +{ + t = rhs.t; + return *this; +} + +template +WeakPtr &WeakPtr::operator =(WeakPtr &&rhs) +{ + t = std::move(rhs.t); + return *this; +} + +template +StrongPtr WeakPtr::ptr() const +{ + return t ? t->ptr() : StrongPtr(); +} + +// ------------------------------------------------------- + +template +size_t ref_count_of(T *t) +{ + auto o = object_from_this(t); + return o->count; +} + + +} // namespace detail + +template +size_t refCount(T *t) +{ + return detail::ref_count_of(t); +} + +template +StrongPtr strong_ (Args&& ... args) +{ + auto t = new T(std::forward(args)...); + + return StrongPtr( + detail::object_for(t) + ); +} + +template +StrongPtr strong (Args&& ... args) +{ + return strong_(std::forward(args)...); +} + +template +StrongPtr strong (const StrongPtr &t) +{ + return t; +} + +template +WeakPtr weak (const StrongPtr &t) +{ + return t.weak(); +} + + +template +StrongPtr strong(const WeakPtr &t) +{ + return t.ptr(); +} + +template +StrongPtr strong_this (T *that) +{ + return StrongPtr( + detail::object_from_this(that) + ); +} + +template +StrongPtr ref_this(T *that) +{ + auto *object = detail::object_from_this(that); + if (object->count == 0) + return {}; + + return StrongPtr(object); +} + +template +WeakPtr weak_this (T *that) +{ + return detail::object_from_this(that)->get_weak(); +} + +template +StrongPtr strong_thread(const StrongPtr &t) +{ + detail::Object::Lock l(detail::Object::mutex()); + auto v = strong(t); + v.mark_threaded(); + + return v; +} + + +template +StrongPtr strong_thread(const WeakPtr &t) +{ + detail::Object::Lock l(detail::Object::mutex()); + auto v = strong(t); + v.mark_threaded(); + return v; +} + + +template +StrongPtr strong_thread_this(T *t) +{ + detail::Object::Lock l(detail::Object::mutex()); + auto v = strong_this(t); + v.mark_threaded(); + return v; +} + +template +T *ptr_of(const StrongPtr &t) +{ + return t.ptr(); +} + +template +StrongPtr strong_ptr_cast(const StrongPtr &t) +{ + return t.template cast(); +} + +} // namespace +} // namespace +} // namespace + +} // namespace + diff --git a/tjp/core/ptr/using_info/_tests/Ptr.cpp b/tjp/core/ptr/using_info/_tests/Ptr.cpp new file mode 100755 index 0000000..beeaab0 --- /dev/null +++ b/tjp/core/ptr/using_info/_tests/Ptr.cpp @@ -0,0 +1,65 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +namespace tjp::core::ptr::using_info { +namespace { + +struct Deletable : StrongThis { + size_t &flag; + Deletable(size_t &flag_) : flag(flag_) + {} + ~Deletable() + { flag++; } +} ; + + +SCENARIO("core::ptr::using_info::custom_ptr_to_info") +{ + size_t deleteFlag = 0; + GIVEN("ptr") + { + + auto *v = new Deletable(deleteFlag); + auto p1 = strong_this(v); + + WHEN("referenced only once") + { + REQUIRE(refCount(v) == 1); + } + + WHEN("referenced") + { + auto p2 = p1; + + THEN("references is 2") + { + REQUIRE(refCount(v) == 2); + } + } + + WHEN("referenced and removed") + { + { + auto p2 = p1; + } + + THEN("references is 1") + { + REQUIRE(refCount(v) == 1); + } + } + + WHEN("item is deleted") + { + p1 = {}; + REQUIRE(deleteFlag == 1); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/ptr/using_maps/Ptr+Debug.h b/tjp/core/ptr/using_maps/Ptr+Debug.h new file mode 100755 index 0000000..023c3c9 --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr+Debug.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../../system/Debug.h" + +#ifdef DEBUG + #define MEMORY_PTR_DEBUG_TYPE +#endif + +//#define MEMORY_PTR_DEBUG_ALLOCATIONS +//#define LOG_MEMORY_PTR diff --git a/tjp/core/ptr/using_maps/Ptr+IO.h b/tjp/core/ptr/using_maps/Ptr+IO.h new file mode 100755 index 0000000..b66c792 --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr+IO.h @@ -0,0 +1,41 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +template +void io_json_w(IO &io, const StrongPtr &r) +{ + io.any((T *)r); +} + +template +void io_json_r(IO &io, StrongPtr &t) +{ + auto p = io.template pointer(t); + io.any(p); +} + +template +void io_bin_w(IO &io, const StrongPtr &r) +{ + io.any((T *)r); +} + +template +void io_bin_r(IO &io, StrongPtr &r) +{ + auto p = io.template pointer(r); + io.any(p); +} + +} // namespace +} // namespace +} // namespace +} // namespace diff --git a/tjp/core/ptr/using_maps/Ptr+Log.h b/tjp/core/ptr/using_maps/Ptr+Log.h new file mode 100755 index 0000000..7faf109 --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr+Log.h @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../../log/LogOf.h" +#include "Ptr.h" + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +template +std::ostream &operator <<(std::ostream &o, const StrongPtr &v) +{ + return o << logOf(ptr_of(v)); +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_maps/Ptr+Logging.cpp b/tjp/core/ptr/using_maps/Ptr+Logging.cpp new file mode 100755 index 0000000..84497f5 --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr+Logging.cpp @@ -0,0 +1,70 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Ptr.hpp" + +#include +#include +#include + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +std::string SmartPtrBase::getInfoFor (K k) +{ + auto l = lock_of(m()); + std::ostringstream ss; + auto &items_ = items(); + auto i = items_.find(k); + if (i != items_.end()) + { + ss << i->second.count; + } + else + ss << "0"; + + return ss.str(); +} + +std::string setToString(const std::set &ids) +{ + std::ostringstream oss; + + oss << " ["; + for (auto &id: ids) + { + oss << id << " "; + } + oss << "] "; + + return oss.str(); +} + +void SmartPtrBase::printDebug () +{ + std::cout << "SmartPtr printDebug " << std::endl;; + + auto l = lock_of(m()); + for (auto &i : items()) + { + std::cout << "\t" << i.first << "\t" << i.second.count + #ifdef MEMORY_PTR_DEBUG_TYPE + << "\t" << i.second.typeName + #endif + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + << setToString(i.second.ids) + #endif + ; + + std::cout << std::endl; + } +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_maps/Ptr.cpp b/tjp/core/ptr/using_maps/Ptr.cpp new file mode 100755 index 0000000..127752a --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr.cpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Ptr.hpp" + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +SmartPtrStatics::Items &SmartPtrStatics::items() +{ + static Items *items_ = new Items(); + return *items_; +} + +SmartPtrStatics::Weaks &SmartPtrStatics::weaks() +{ + static Weaks *weaks_ = new Weaks(); + return *weaks_; +} + +Mutex &SmartPtrStatics::m() +{ + static Mutex *m_ = new Mutex(); + return *m_; +} + +// ------------------------------------------------ + + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_maps/Ptr.h b/tjp/core/ptr/using_maps/Ptr.h new file mode 100755 index 0000000..90d259a --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr.h @@ -0,0 +1,61 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Ptr+Debug.h" + +template +void onStrongPtrDelete(T *t); + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +struct SmartPtrStatics; + +class SmartPtrBase; + +template +class StrongPtr; + +template +class WeakRef; + +template +class WeakPtr; + +template +class StrongPtr; + +template +StrongPtr strong (T *t); + +template +StrongPtr strong (const StrongPtr &t); + +template +WeakPtr weak (const StrongPtr &t); + +template +StrongPtr strong_this (T *that); + +template +StrongPtr ref_this(T *that); + +template +WeakPtr weak_this (T *that); + +template +auto ptr_of(const StrongPtr &t) +{ + return t.get(); +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_maps/Ptr.hpp b/tjp/core/ptr/using_maps/Ptr.hpp new file mode 100755 index 0000000..38fb7a0 --- /dev/null +++ b/tjp/core/ptr/using_maps/Ptr.hpp @@ -0,0 +1,598 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Ptr.h" + +#include +#include + +#include "../../threads/Lock.hpp" +#include "../../containers/FilledArray.hpp" +#include "../../assert/debug_assert.h" +#include "../../rtti/RTTI.hpp" + +#include + +#ifdef LOG_MEMORY_PTR +#include "../../log/Log.h" +#include "../../log/LogOf.h" +#define LogDebugStrongPtr(x) xLogDebug(x) +#else +#define LogDebugStrongPtr(x) +#endif + +#ifdef MEMORY_PTR_DEBUG_ALLOCATIONS +#include +#endif + +template +void onStrongPtrDelete(T *t) {} + +template +void deallocate(T *t) +{ + delete t; +} + +namespace tjp { +namespace core { +namespace ptr { +namespace using_maps { + +struct SmartPtrStatics +{ + typedef void *K; + typedef int V; + typedef void *W; + + struct Item + { + size_t count; + + #ifdef MEMORY_PTR_DEBUG_TYPE + const char *typeName; + #endif + + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + std::set ids; + #endif + } ; + +// typedef std::map Items; + typedef std::unordered_map Items; + +// typedef std::vector WeakList; + struct WeakList { + bool valid = false; + FilledArray values; + } ; +// typedef FilledArray WeakList; + +// typedef std::map Weaks; + typedef std::unordered_map Weaks; + + static Items &items(); + static Weaks &weaks(); + static Mutex &m(); +} ; + +class SmartPtrBase : public SmartPtrStatics +{ + +public: + static size_t refCount (K k) + { + auto l = lock_of(m()); + auto &items_ = items(); + if (items_.find(k) != items_.end()) + return items_[k].count; + + return 0; + } + + static std::string getInfoFor (K k); + static void printDebug (); +}; + +template +class StrongPtr; + +template +class WeakRef : public SmartPtrBase +{ +private: + WeakList *l = nullptr; + T *t; + + void ref () + { + if (t != 0) + { + auto lock = lock_of(m()); + + auto &weaks_ = weaks(); + + auto i = weaks_.find(t); + if (i == weaks_.end()) + { + auto &w = weaks_[t]; + l = &w; + + auto &items_ = items(); + w.valid = items_.find(t) != items_.end(); + } + else + { + l = &i->second; + } + + l->values.push_back(this); + } + } + + void unref () + { + if (t != 0) + { + auto lock = lock_of(m()); + + auto i = std::find(l->values.begin(), l->values.end(), this); + if (i != l->values.end()) + l->values.erase(i); + } + } + + void validate () + { + debug_assert(l->valid); + } + + WeakRef &operator = (const WeakRef &rhs); + WeakRef (const WeakRef &w) = delete; + +public: + WeakRef(const T *_t) : + t(const_cast(_t)) + { + ref(); + } + + ~WeakRef() + { + unref(); + } + + static void validate_nolock (T *t) + { + if (t != 0) + { + auto &weaks_ = weaks(); + auto l = weaks_.find(t); + if (l == weaks_.end()) + return; + + l->second.valid = true; + } + } + static void validate (T *t) + { + if (!t) + return; + + auto lock = lock_of(m()); + return validate_nolock(t); + } + + static void nullify_nolock (T *t) + { + if (!t) + return; + + auto &weaks_ = weaks(); + auto l = weaks_.find(t); + if (l == weaks_.end()) + return; + + for (auto &i : l->second.values) + ((WeakRef *)i)->t = 0; + + weaks_.erase(l); + } + + static void nullify (T *t) + { + if (!t) + return; + + auto lock = lock_of(m()); + return nullify(t); + } + + StrongPtr ptr() + { + auto lock = lock_of(m()); + if (t) + validate(); + + return StrongPtr(t); + } +} ; + +template +class WeakPtr; + +template +class StrongPtr : public SmartPtrBase { + +public: + typedef T value_type; + typedef T element_type; + typedef T *pointer_type; + +private: + T *t = nullptr; + +public: + ~StrongPtr () + { + set(nullptr); + } + + // ------------------------- + + StrongPtr () + { + } + + StrongPtr (const T *_t) + { + set(_t); + } + + // ------------------------- + + StrongPtr(StrongPtr &&rhs) + { + swap(std::move(rhs)); + } + + StrongPtr(const StrongPtr &rhs) + { + set(rhs); + } + + // ------------------------- + + template + StrongPtr(const StrongPtr &rhs) + { + set(rhs); + } + + template + StrongPtr(StrongPtr &&rhs) + { + swap(std::move(rhs)); + } + + // ------------------------- + + StrongPtr &operator =(const StrongPtr &rhs) + { + set(rhs); + return *this; + } + + StrongPtr &operator =(StrongPtr &&rhs) + { + swap(std::move(rhs)); + return *this; + } + + // ------------------------- + + operator bool() const + { + return t != nullptr; + } + + bool operator !() const + { + return t == nullptr; + } + + template + StrongPtr cast() const + { + auto *u = dynamic_cast(t); + debug_assert((void *)u == (void *)t || u == nullptr); + return StrongPtr(u); + } + + template + U *&move () const + { + debug_assert(static_cast(static_cast(t))==t); + return (U *&)t; + } + + T *ptr() const + { + return t; + } + + T *get() const + { + return t; + } + + operator T *() const + { + return t; + } + + T &operator *() const + { + return *t; + } + + T *operator -> () const + { + return t; + } + + bool operator == (const T *_t) const + { + return t == _t; + } + + bool operator == (const StrongPtr &_t) const + { + return t == _t.t; + } + + bool operator != (const StrongPtr &_t) const + { + return t != _t.t; + } + + bool operator <(const StrongPtr &rhs) const + { + return t < rhs.t; + } + + WeakPtr weak() const + { + auto l = lock_of(m()); + return WeakPtr(t ? new WeakRef(t) : nullptr); + } + +private: + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + void on_swap_no_lock(T *l, T *r, void *lp, void *rp) + { + if (l == r) + return; + + auto &items_ = items(); + + if (l != 0) + { + auto i = items_.find(l); + i->second.ids.erase(lp); + i->second.ids.insert(rp); + } + + if (r != 0) + { + auto i = items_.find(r); + i->second.ids.erase(rp); + i->second.ids.insert(lp); + } + } + #else + void on_swap_no_lock(T *l, T *r, void *lp, void *rp) {} + #endif + + T *set_return_deferred_delete_no_lock(const T *_t) + { + if (t == _t) + return nullptr; + + T *deferredDelete = nullptr; + auto &items_ = items(); + + if (t != 0) + { + LogDebugStrongPtr(logOfThis(this) << type_id().name() << ": this" << logOfThis(this) << " -> " << t << " #" << getInfoFor(t) << "--"); + + auto i = items_.find(t); + + debug_assert(i != items_.end()); + i->second.count--; + + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + i->second.ids.erase((void *)this); + #endif + + if (i->second.count == 0) + { + items_.erase (i); + deferredDelete = t; + WeakRef::nullify_nolock(deferredDelete); + } + } + + t = const_cast(_t); + + if (t != 0) + { + auto i = items_.find(t); + if (items_.find(t) != items_.end()) + { + i->second.count++; + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + i->second.ids.insert((void*)this); + #endif + } + else + { + items_.insert(std::pair( + t, + { + 1 + #ifdef MEMORY_PTR_DEBUG_TYPE + , type_id().name() + #endif + #ifdef MEMORY_PTR_DEBUG_ALLOCATIONS + , { (void*)this } + #endif + } + )); + WeakRef::validate_nolock(t); + } + + LogDebugStrongPtr(logOfThis(this) << type_id().name() << ": this" << logOfThis(this) << " -> " << t << " #" << getInfoFor(t)); + } + + return deferredDelete; + } + + void set(const T *t_) + { + T *deferredDelete = nullptr; + { + auto l = lock_of(m()); + deferredDelete = set_return_deferred_delete_no_lock(t_); + } + + do_delete(deferredDelete); + } + + template + void set(const StrongPtr &rhs) + { + T *deferredDelete = nullptr; + { + auto l = lock_of(m()); + deferredDelete = set_return_deferred_delete_no_lock(ptr_of(rhs)); + } + + do_delete(deferredDelete); + } + + + template + void swap(StrongPtr &&rhs) + { + auto l = lock_of(m()); + on_swap_no_lock(t, rhs.template move(), this, &rhs); + std::swap(t, rhs.template move()); + } + + void do_delete(T *t) + { + if (t) + { + LogDebugStrongPtr(logOfThis(this) << type_id().name() << ":" << t << " # deferredDelete"); + + onStrongPtrDelete(t); + deallocate(t); + } + } +}; + +template +class WeakPtr +{ +private: + StrongPtr > t; + +protected: + +public: + WeakPtr () {} + WeakPtr (WeakRef *rhs) : t(rhs) {} + WeakPtr (const WeakPtr &rhs) : t(rhs.t) {} + WeakPtr (WeakPtr &&rhs) : t(std::move(rhs.t)) {} + + WeakPtr &operator =(const WeakPtr &rhs) + { + t = rhs.t; + return *this; + } + + WeakPtr &operator =(WeakPtr &&rhs) + { + t = std::move(rhs.t); + return *this; + } + + StrongPtr ptr() const + { + return t ? t->ptr() : nullptr; + } +} ; + +// ------------------------------------------------ + + +template +size_t refCount (T *that) +{ + return SmartPtrBase::refCount(that); +} + +template +StrongPtr strong (T *t) +{ + return StrongPtr(t); +} + +template +StrongPtr strong (const StrongPtr &t) +{ + return t; +} + +template +WeakPtr weak (const StrongPtr &t) +{ + return t.weak(); +} + +template +StrongPtr strong_this (T *that) +{ + debug_assert(refCount(that) > 0); + auto s = strong(that); + return s; +} + +template +StrongPtr ref_this(T *that) +{ + auto l = lock_of(SmartPtrBase::m()); + if (refCount(that) > 0) + return strong(that); + + return nullptr; +} + +template +WeakPtr weak_this (T *that) +{ +// auto s = strong_this(that); +// return s.weak(); + + return WeakPtr(new WeakRef(that)); +} + +} // namespace +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/ptr/using_maps/_tests/Ptr.cpp b/tjp/core/ptr/using_maps/_tests/Ptr.cpp new file mode 100755 index 0000000..948c715 --- /dev/null +++ b/tjp/core/ptr/using_maps/_tests/Ptr.cpp @@ -0,0 +1,68 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +namespace tjp::core::ptr::using_maps { +namespace { + +//SmartPtrBase::Items SmartPtrBase::items; +//SmartPtrBase::Weaks SmartPtrBase::weaks; +//Mutex SmartPtrBase::m; + +struct Deletable { + size_t &flag; + Deletable(size_t &flag_) : flag(flag_) {} + ~Deletable() { flag++; } +} ; + + +SCENARIO("core::ptr::using_maps::custom_ptr") +{ + size_t deleteFlag = 0; + GIVEN("ptr") + { + + auto *v = new Deletable(deleteFlag); + auto p1 = strong(v); + + WHEN("referenced only once") + { + REQUIRE(refCount(v) == 1); + } + + WHEN("referenced") + { + auto p2 = p1; + + THEN("references is 2") + { + REQUIRE(refCount(v) == 2); + } + } + + WHEN("referenced and removed") + { + { + auto p2 = p1; + } + + THEN("references is 1") + { + REQUIRE(refCount(v) == 1); + } + } + + WHEN("item is deleted") + { + p1 = (Deletable *)nullptr; + REQUIRE(refCount(v) == 0); + REQUIRE(deleteFlag == 1); + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/rtti/RTTI+custom.hpp b/tjp/core/rtti/RTTI+custom.hpp new file mode 100755 index 0000000..f77760c --- /dev/null +++ b/tjp/core/rtti/RTTI+custom.hpp @@ -0,0 +1,165 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "TypeName.hpp" +#include "../types/Definitions.h" +#include "../const_hash/Hash.hpp" + +#include +#include + + +namespace tjp::core::rtti { + +using type_index_v = u32; + +struct type_index { + type_index_v v; + const char *name() const { return "[name]"; } +} ; + +inline +constexpr bool operator <(const type_index &lhs, const type_index &rhs) +{ + return lhs.v < rhs.v; +} + +inline +constexpr bool operator ==(const type_index &lhs, const type_index &rhs) +{ + return lhs.v == rhs.v; +} + +inline +constexpr bool operator !=(const type_index &lhs, const type_index &rhs) +{ + return lhs.v != rhs.v; +} + +#define ENABLE_RTTI_CLASS \ +tjp::core::rtti::type_index _static_type_id_() const { return tjp::core::rtti::type_id(*this); } + +#define ENABLE_RTTI_GET_BASE \ +virtual tjp::core::rtti::type_index _type_() { return _static_type_id_(); } + +#define ENABLE_RTTI_GET_OVERRIDE(BASE) \ +tjp::core::rtti::type_index _type_() override { return _static_type_id_(); } + +#define ENABLE_RTTI_IS_BASE \ +virtual bool _is_(tjp::core::rtti::type_index v) { return _static_type_id_() == v; } + +#define ENABLE_RTTI_IS_OVERRIDE(BASE) \ +bool _is_(tjp::core::rtti::type_index v) override { \ + return _static_type_id_() == v || BASE::_is_(v); \ +} \ + +#define ENABLE_RTTI_BASE \ + ENABLE_RTTI_CLASS \ + ENABLE_RTTI_GET_BASE \ + ENABLE_RTTI_IS_BASE \ + +#define ENABLE_RTTI(BASE) \ + ENABLE_RTTI_CLASS \ + ENABLE_RTTI_GET_OVERRIDE(BASE) \ + ENABLE_RTTI_IS_OVERRIDE(BASE) \ + + +#define RTTI_TYPE_FOR_STRING(x) tjp::core::hash_compile(x) + +template +constexpr auto type_id_name() +{ + return type_name(); +} + +constexpr +type_index type_id_using(const std::string_view &s) +{ + auto v = RTTI_TYPE_FOR_STRING(s); + return { v }; +} + +template +constexpr type_index type_id() +{ + constexpr auto name = type_id_name(); + constexpr auto v = RTTI_TYPE_FOR_STRING(name); + return {v}; +} + +template +type_index type_id(const T &t) +{ + return type_id(); +} + + +template +using pushback_t = decltype(std::declval()._is_(type_index{})); + +template > +struct has_rtti_method : std::false_type{}; + +template +struct has_rtti_method>>: + std::true_type{}; + +//template +//struct has_rtti_method: public std::false_type {}; +// +//template +//struct has_rtti_method> : public std::true_type {}; + +template::value, T>::type* = nullptr> +constexpr bool is_type(T *t, const type_index type) +{ + return type_id() == type; +} + +template::value, T>::type* = nullptr> +bool is_type(T *t, const type_index type) +{ + if (type_id() == type) + return true; + + return t && t->_is_(type); +} + + +template +bool is_type(U *u) +{ + return is_type(u, type_id()); +} + +template +T *static_cast_ptr(U *u) +{ + return static_cast(u); +} + +template::value, U>::type* = nullptr> +constexpr T *dynamic_cast_ptr(U *u) +{ + if constexpr(type_id() == type_id()) + return u; + + return nullptr; +} + +template::value, U>::type* = nullptr> +T *dynamic_cast_ptr(U *u) +{ + if constexpr(type_id() == type_id()) + return u; + + if (is_type(u)) + return static_cast(u); + + return nullptr; +} + +} // namespace diff --git a/tjp/core/rtti/RTTI+std.hpp b/tjp/core/rtti/RTTI+std.hpp new file mode 100755 index 0000000..37f7de4 --- /dev/null +++ b/tjp/core/rtti/RTTI+std.hpp @@ -0,0 +1,48 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { +namespace rtti { + +#define ENABLE_RTTI_BASE +#define ENABLE_RTTI(BASE) + +using type_index = std::type_index; + +template +type_index type_id(const T &t) +{ + return typeid(T); +} + +template +type_index type_id() +{ + return typeid(T); +} + +template +bool is_type(U *u) +{ + return dynamic_cast(u) != nullptr; +} + +template +T *static_cast_ptr(U *u) +{ + return static_cast(u); +} + +template +T *dynamic_cast_ptr(U *u) +{ + return dynamic_cast(u); +} + +} // namespace +} // namespace diff --git a/tjp/core/rtti/RTTI.cpp b/tjp/core/rtti/RTTI.cpp new file mode 100755 index 0000000..d0cdf86 --- /dev/null +++ b/tjp/core/rtti/RTTI.cpp @@ -0,0 +1,162 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "RTTI.hpp" +#include +#include + +#include +#include + +namespace tjp::core::rtti { +namespace { + +struct A { + ENABLE_RTTI_BASE; + +} ; + +struct B : A { + ENABLE_RTTI(A); +} ; + +struct C_different_base { + ENABLE_RTTI_BASE; +} ; + +//struct D_no_inherit_shouldn_t_compile { +// ENABLE_RTTI(A); +//} ; + +struct E : A { + ENABLE_RTTI(A); +} ; + +struct B_A : B { + ENABLE_RTTI(B); +} ; + +struct X0 {}; +struct X1 {}; + +SCENARIO("core::rtti") +{ + GIVEN("some structures") + { + A a_; + B b_; + C_different_base c_; +// D_no_inherit d_; + B_A b_a_; + + auto *a = &a_; + unused(a); + + auto *b = &b_; + unused(a); + + auto *c = &c_; + unused(c); + +// auto *d = &d_; + + auto *b_a = &b_a_; + + static_assert(has_rtti_method::value == false); + static_assert(has_rtti_method::value == true); + + sLogTest("testing", + logVar(type_id().v) + << logVar(type_id().v) + << logVar(type_id().v) +// << logVar(type_id().v) + << logVar(type_id().v) + << logVar(type_id().v) + ); + + sLogTest("testing", + logVar(has_rtti_method::value) + << logVar(has_rtti_method::value) + << logVar(has_rtti_method::value) + << logVar(has_rtti_method::value) +// << logVar(has_rtti_method::value) + << logVar(has_rtti_method::value) + << logVar(has_rtti_method::value) + ); + + { + auto cast_a = dynamic_cast_ptr(b); + auto cast_b = dynamic_cast_ptr(cast_a); + REQUIRE(cast_b == b); + } + + { + auto cast_a = dynamic_cast_ptr(b); + auto cast_e = dynamic_cast_ptr(cast_a); + REQUIRE(cast_e == nullptr); + } + + { + auto cast_a = dynamic_cast_ptr(b_a); + auto cast_b = dynamic_cast_ptr(cast_a); + REQUIRE(cast_b == b_a); + auto cast_b_a = dynamic_cast_ptr(cast_a); + REQUIRE(cast_b_a == b_a); + + auto cast_b_a_2 = dynamic_cast_ptr(cast_b); + REQUIRE(cast_b_a_2 == b_a); + } + + + } + + GIVEN("some datatypes") + { + int i_; + char c_; + float f_; + + X0 x0_; + X1 x1_; + + auto *i = &i_; + auto *c = &c_; + unused(c); + + auto *f = &f_; + + auto *x0 = &x0_; + auto *x1 = &x1_; + unused(x1); + + { + auto x = dynamic_cast_ptr(i); + REQUIRE(x == nullptr); + + auto y = dynamic_cast_ptr(i); + REQUIRE(y == i); + } + + { + auto x = dynamic_cast_ptr(f); + REQUIRE(x == nullptr); + + auto y = dynamic_cast_ptr(f); + REQUIRE(y == f); + } + + { + auto x = dynamic_cast_ptr(x0); + REQUIRE(x == nullptr); + + auto y = dynamic_cast_ptr(x0); + REQUIRE(y == x0); + } + + + } +} + +} // namespace +} // namespace diff --git a/tjp/core/rtti/RTTI.hpp b/tjp/core/rtti/RTTI.hpp new file mode 100755 index 0000000..b752d1c --- /dev/null +++ b/tjp/core/rtti/RTTI.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef __GXX_RTTI + #include "RTTI+std.hpp" +#else + #include "RTTI+custom.hpp" +#endif + +namespace tjp::core { + +using rtti::static_cast_ptr; +using rtti::dynamic_cast_ptr; +using rtti::type_id; +using rtti::type_index; + +} // namespace diff --git a/tjp/core/rtti/TypeName+custom.hpp b/tjp/core/rtti/TypeName+custom.hpp new file mode 100755 index 0000000..626ed42 --- /dev/null +++ b/tjp/core/rtti/TypeName+custom.hpp @@ -0,0 +1,139 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +#include "../const_expr/Str.hpp" +#include "../const_expr/count_char.hpp" +#include "../const_expr/remove_char.hpp" +#include "../const_expr/length.hpp" + +namespace tjp::core::rtti { + +// basis: +// https://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template/59522794#59522794 +// https://stackoverflow.com/posts/59522794/revisions + +namespace impl +{ + using const_expr::Str; + using const_expr::StrView; + + template + constexpr const auto &RawTypeName_() + { + #ifdef _MSC_VER + return __FUNCSIG__; + #else + return __PRETTY_FUNCTION__; + #endif + } + + template + constexpr const auto RawTypeName() + { + constexpr auto &s = RawTypeName_(); + constexpr auto n = const_expr::length(s); + + return Str(s); + } + + struct RawTypeNameFormat + { + std::size_t leading_junk = 0, trailing_junk = 0; + }; + + // Returns `false` on failure. + inline constexpr bool GetRawTypeNameFormat(RawTypeNameFormat *format) + { + const auto &str = RawTypeName_(); + const auto length = const_expr::length(str); + + for (std::size_t i = 0;; i++) + { + if (str[i] == 'i' && str[i+1] == 'n' && str[i+2] == 't') + { + if (format) + { + format->leading_junk = i; + format->trailing_junk = length-i-3; // `3` is the length of "int" + } + return true; + } + } + return false; + } + + inline static constexpr RawTypeNameFormat format = + []{ + static_assert(GetRawTypeNameFormat(nullptr), "Unable to figure out how to generate type names on this compiler."); + RawTypeNameFormat format; + GetRawTypeNameFormat(&format); + return format; + }(); + +} // namespace + +template +[[nodiscard]] constexpr auto type_name_() +{ + constexpr std::size_t length = + const_expr::length(impl::RawTypeName_()) + - impl::format.leading_junk + - impl::format.trailing_junk; + + constexpr const auto &name = impl::RawTypeName_(); + + return std::string_view { + &name[impl::format.leading_junk], + length + }; +} + +template +[[nodiscard]] constexpr auto type_name_custom(const T *) +{ + return type_name_(); +} + +template +[[nodiscard]] constexpr auto type_name_dispatch(const T *t) +{ + return type_name_custom(t); +} + +template +[[nodiscard]] constexpr auto type_name() +{ + constexpr auto name = type_name_dispatch((T *)nullptr); + + // on some compilers, there is weirdness at the end of template names + constexpr auto numSpaces = const_expr::count_char(name, "> "); + constexpr int size = name.size() - numSpaces; + + const_expr::Str result; + const_expr::remove_second_of_char_2(name, result, "> "); + + return result; +} + +template <> +[[nodiscard]] constexpr auto type_name() +{ + return type_name_(); +} + +template +[[nodiscard]] constexpr auto type_unique_label_stringview() +{ + return type_name_dispatch((T *)nullptr); +} + + +} // namespace + + diff --git a/tjp/core/rtti/TypeName.hpp b/tjp/core/rtti/TypeName.hpp new file mode 100755 index 0000000..d9be469 --- /dev/null +++ b/tjp/core/rtti/TypeName.hpp @@ -0,0 +1,38 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef __GXX_RTTI + #include "TypeName+custom.hpp" +// #include "TypeName+std.hpp" +#else + #include "TypeName+custom.hpp" +#endif + +namespace tjp::core { + +using rtti::type_name; +using rtti::type_unique_label_stringview; + + +} // namespace + +#define TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, replace_with) \ +[[nodiscard]] constexpr auto type_name_custom(const type_to_replace *) \ +{ \ + return std::string_view(replace_with); \ +} \ + +#define TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME(type_to_replace) \ + TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, #type_to_replace) + +#define TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME_WITH(type_to_replace, replace_with) \ +namespace tjp::core::rtti { \ + template<> \ + TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME_WITH(type_to_replace, replace_with) \ +} \ + +#define TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(type_to_replace) \ + TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME_WITH(type_to_replace, #type_to_replace) diff --git a/tjp/core/rtti/_tests/All.cxx b/tjp/core/rtti/_tests/All.cxx new file mode 100755 index 0000000..2c81e0c --- /dev/null +++ b/tjp/core/rtti/_tests/All.cxx @@ -0,0 +1,382 @@ +// https://godbolt.org/ +// to test compilers + +#include +#include +#include + +namespace tjp::core::const_expr { + +struct StrView { + char *v; + size_t len; + + constexpr StrView(char *v_, size_t len_) : + v(v_), len(len_) + {} + + constexpr StrView(const char *v_, size_t len_) : + v(const_cast(v_)), len(len_) + {} + + constexpr StrView(const std::string_view &v_) : + v((char *)v_.data()), len(v_.size()) + {} + + constexpr auto *data() { return v; } + constexpr auto *begin() const { return v; } + constexpr auto *end() const { return begin() + size(); } + constexpr auto *begin() { return v; } + constexpr auto *end() { return begin() + size(); } + constexpr size_t size() { return len; } + constexpr const size_t size() const { return len; } + + constexpr void set(const size_t i, const char c) { v[i] = c; } + constexpr char operator[](const size_t i) const { return v[i]; } + + constexpr operator std::string_view() const + { + return std::string_view(v, len); + } +} ; + +template +struct Str { + char v[N]; + + constexpr Str(const char *s) : + v{0} + { + for (auto i=0; i +constexpr bool operator ==(const Str &lhs, const char *rhs) +{ + return (std::string_view)lhs == rhs; +} + +} // namespace + +#include + +namespace tjp::core::const_expr { + +template +std::ostream &operator <<(std::ostream &o, const Str &v) +{ + return o << (std::string_view)(v); +} + +inline +std::ostream &operator <<(std::ostream &o, const StrView &v) +{ + return o << (std::string_view)(v); +} + +} // namespace + + +namespace tjp::core::const_expr { + +[[nodiscard]] +inline constexpr auto count_char(const StrView &s, const char v) +{ + size_t num = 0; + for (auto &c : s) + { + if (c == v) + ++num; + } + + return num; +} + +[[nodiscard]] +inline constexpr auto count_char(const StrView &s, const char v[2]) +{ + size_t num = 0; + for (auto i=0; i + +namespace tjp::core::rtti { + +// https://stackoverflow.com/questions/1055452/c-get-name-of-type-in-template/59522794#59522794 +// https://stackoverflow.com/posts/59522794/revisions + +namespace impl +{ + using const_expr::Str; + using const_expr::StrView; + + template + constexpr const auto &RawTypeName_() + { + #ifdef _MSC_VER + return __FUNCSIG__; + #else + return __PRETTY_FUNCTION__; + #endif + } + + template + constexpr const auto RawTypeName() + { + constexpr auto &s = RawTypeName_(); + constexpr auto n = const_expr::length(s); + + return Str(s); + } + + struct RawTypeNameFormat + { + std::size_t leading_junk = 0, trailing_junk = 0; + }; + + // Returns `false` on failure. + inline constexpr bool GetRawTypeNameFormat(RawTypeNameFormat *format) + { + const auto &str = RawTypeName_(); + const auto length = const_expr::length(str); + + for (std::size_t i = 0;; i++) + { + if (str[i] == 'i' && str[i+1] == 'n' && str[i+2] == 't') + { + if (format) + { + format->leading_junk = i; + format->trailing_junk = length-i-3; // `3` is the length of "int" + } + return true; + } + } + return false; + } + + inline static constexpr RawTypeNameFormat format = + []{ + static_assert(GetRawTypeNameFormat(nullptr), "Unable to figure out how to generate type names on this compiler."); + RawTypeNameFormat format; + GetRawTypeNameFormat(&format); + return format; + }(); + +} // namespace + +template +[[nodiscard]] constexpr auto type_name_() +{ + constexpr std::size_t length = + const_expr::length(impl::RawTypeName_()) + - impl::format.leading_junk + - impl::format.trailing_junk; + + constexpr const auto &name = impl::RawTypeName_(); + + return std::string_view { + &name[impl::format.leading_junk], + length + }; +} + +template +[[nodiscard]] constexpr auto type_name_custom(const T *) +{ + return type_name_(); +} + +template +[[nodiscard]] constexpr auto type_name_dispatch(const T *t) +{ + return type_name_custom(t); +} + +template +[[nodiscard]] constexpr auto type_name() +{ + constexpr auto name = type_name_dispatch((T *)nullptr); + constexpr auto numSpaces = const_expr::count_char(name, "> "); + constexpr int size = name.size() - numSpaces; + + const_expr::Str result; + const_expr::remove_char(name, result, "> "); + + return result; +} + +template <> +[[nodiscard]] constexpr auto type_name() +{ + return type_name_(); +} + +} // namespace + +// ------------------------------------------- +// ------------------------------------------- +// ------------------------------------------- +// ------------------------------------------- + + +namespace tjp::core::rtti { + +[[nodiscard]] inline constexpr auto type_id_for(const std::string_view &s) +{ + int type = 0; + for (auto &c : s) + type += (int)c; + + return type; +} +template +[[nodiscard]] inline constexpr auto type_id_for(const std::array &s) +{ + int type = 0; + for (auto &c: s) + type += (int)c; + + return type; +} + +template +[[nodiscard]] constexpr auto type_id() +{ + constexpr auto name = type_name(); + return type_id_for(name); +} + +} // namespace + +#include +#include + +namespace tjp::core::rtti { + +struct Y; + +template +struct X {}; + +using XY = X; + +template +struct XX {}; + +using XXY = XX>; + +template +struct XXX {}; + +using XXXY = XXX>>; + +using MXY = std::map, XXY>; +using SMX = std::shared_ptr; + +inline void run() +{ + std::cout << "before" << std::endl; + std::cout << "[" << impl::RawTypeName() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "[" <() << "]" << std::endl; + std::cout << "after" << std::endl; +} + +} // namespcae + +int main(int argc, char *arv[]) +{ + tjp::core::rtti::run(); +} diff --git a/tjp/core/rtti/_tests/TypeName.cpp b/tjp/core/rtti/_tests/TypeName.cpp new file mode 100755 index 0000000..10c2cae --- /dev/null +++ b/tjp/core/rtti/_tests/TypeName.cpp @@ -0,0 +1,77 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include +#include + +#include + +namespace tjp::core::rtti { +namespace { + +struct A { + ENABLE_RTTI_BASE; + +} ; + +struct B : A { + ENABLE_RTTI(A); +} ; + +struct C_different_base { + ENABLE_RTTI_BASE; +} ; + +//struct D_no_inherit_shouldn_t_compile { +// ENABLE_RTTI(A); +//} ; + +struct E : A { + ENABLE_RTTI(A); +} ; + +struct B_A : B { + ENABLE_RTTI(B); +} ; + +struct X0 {}; +struct X1 {}; + +template +struct Z {}; + +TIMPREPSCIUS_CORE_RTTI_REPLACE_LOCAL_TYPENAME(Z); + +SCENARIO("core::rtti::type_name") +{ + GIVEN("some structures") + { + sLogDebug("testing", + logVar(type_name()) + << logVar(type_name()) + << logVar(type_name()) +// << logVar(type_id().v) + << logVar(type_name()) + << logVar(type_name()) + << logVar(type_name()) + << logVar(type_name()) + << logVar(type_name()) + << logVar(type_name()) + << logVar(type_name>()) + << logVar(type_name>()) + << logVar(type_name()) + ); + + static_assert(type_name() == "tjp::core::Str"); + static_assert(type_name>() == "Z"); + static_assert(!(type_name>() == "Z")); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/sfinae/_tests/if_or.cpp b/tjp/core/sfinae/_tests/if_or.cpp new file mode 100755 index 0000000..8feef1a --- /dev/null +++ b/tjp/core/sfinae/_tests/if_or.cpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +#include + +namespace tjp::core::sfinae { +namespace { + +SCENARIO("core::sfinae::if_or") +{ + static_assert( + std::is_same_v::type, int> + ); + + static_assert( + std::is_same_v::type, float> + ); +} + + +} // namespace +} // namespace diff --git a/tjp/core/sfinae/if_or.hpp b/tjp/core/sfinae/if_or.hpp new file mode 100644 index 0000000..212848d --- /dev/null +++ b/tjp/core/sfinae/if_or.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { +namespace sfinae { + +template +struct if_or { typedef U type; }; + +template +struct if_or { typedef T type; }; + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/string/Dictionary.h b/tjp/core/string/Dictionary.h new file mode 100644 index 0000000..7c88262 --- /dev/null +++ b/tjp/core/string/Dictionary.h @@ -0,0 +1,90 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include +#include + +#include "../threads/Lock.hpp" +#include "../ptr/Ptr.hpp" + +namespace tjp { +namespace core { +namespace string_dictionary { + +struct Instance; +struct Entry; +struct Dictionary; + +struct Reference +{ + StrongPtr entry; + + operator const std::string &() const; + operator const std::string_view () const; +} ; + +struct Entry +{ + StrongPtr container; + const std::string value; + + Entry(const StrongPtr &container, std::string &&string); + + ~Entry (); +} ; + +bool operator ==(const Reference &lhs, const Reference &rhs); +bool operator ==(const Reference &lhs, const std::string &r); +bool operator ==(const Reference &lhs, const std::string_view &r); +bool operator ==(const Reference &lhs, const char *r); + +bool operator ==(const std::string &l, const Reference &rhs); +bool operator ==(const std::string_view &l, const Reference &rhs); +bool operator ==(const char *l, const Reference &rhs); + +bool operator !=(const Reference &lhs, const Reference &rhs); +bool operator !=(const Reference &lhs, const std::string &r); +bool operator !=(const Reference &lhs, const std::string_view &r); +bool operator !=(const Reference &lhs, const char *r); + +bool operator !=(const std::string &l, const Reference &rhs); +bool operator !=(const std::string_view &l, const Reference &rhs); +bool operator !=(const char *l, const Reference &rhs); + +bool operator <(const Reference &lhs, const Reference &rhs); +bool operator <(const Reference &lhs, const std::string &r); +bool operator <(const Reference &lhs, const std::string_view &r); +bool operator <(const Reference &lhs, const char *r); + +bool operator <(const std::string &l, const Reference &rhs); +bool operator <(const std::string_view &l, const Reference &rhs); +bool operator <(const char *l, const Reference &rhs); + +// ---- + +struct Dictionary : StrongThis +{ + Mutex mutex; + std::map> entries; + + void remove(Entry *entry); + + Reference get(const std::string_view &value); + Reference get(const std::string &value); + Reference get(std::string &&value); + Reference get(const char *value); +} ; + +} // namespace + +using StringDictionary = string_dictionary::Dictionary; +using StringRef = string_dictionary::Reference; + +} // namespace +} // namespace + +#include "Dictionary.inl" diff --git a/tjp/core/string/Dictionary.inl b/tjp/core/string/Dictionary.inl new file mode 100644 index 0000000..0a3224c --- /dev/null +++ b/tjp/core/string/Dictionary.inl @@ -0,0 +1,233 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { +namespace string_dictionary { + +// ---- + +inline +Entry::Entry(const StrongPtr &container_, std::string &&value_) : + container(container_), + value(std::move(value_)) +{ +} + +inline +Entry::~Entry () +{ + if (container) + container->remove(this); +} + +// ---- + +inline +Reference::operator const std::string &() const +{ + return entry->value; +} + +inline +Reference::operator const std::string_view () const +{ + return entry->value; +} + +inline +bool operator ==(const Reference &lhs, const Reference &rhs) +{ + return (const std::string &)lhs == (const std::string &)rhs; +} + +inline +bool operator ==(const Reference &lhs, const std::string &r) +{ + return (const std::string &)lhs == r; +} + +inline +bool operator ==(const Reference &lhs, const std::string_view &r) +{ + return (const std::string &)lhs == r; +} + +inline +bool operator ==(const Reference &lhs, const char *r) +{ + return (const std::string &)lhs == r; +} + +inline +bool operator ==(const std::string &l, const Reference &rhs) +{ + return l == (const std::string &)rhs; +} + +inline +bool operator ==(const std::string_view &l, const Reference &rhs) +{ + return l == (const std::string &)rhs; +} + +inline +bool operator ==(const char *l, const Reference &rhs) +{ + return l == (const std::string &)rhs; +} + + + +inline +bool operator !=(const Reference &lhs, const Reference &rhs) +{ + return (const std::string &)lhs != (const std::string &)rhs; +} + +inline +bool operator !=(const Reference &lhs, const std::string &r) +{ + return (const std::string &)lhs != r; +} + +inline +bool operator !=(const Reference &lhs, const std::string_view &r) +{ + return (const std::string &)lhs != r; +} + +inline +bool operator !=(const Reference &lhs, const char *r) +{ + return (const std::string &)lhs != r; +} + +inline +bool operator !=(const std::string &l, const Reference &rhs) +{ + return l != (const std::string &)rhs; +} + +inline +bool operator !=(const std::string_view &l, const Reference &rhs) +{ + return l != (const std::string &)rhs; +} + +inline +bool operator !=(const char *l, const Reference &rhs) +{ + return l != (const std::string &)rhs; +} + + + +inline +bool operator <(const Reference &lhs, const Reference &rhs) +{ + return (const std::string &)lhs < (const std::string &)rhs; +} + +inline +bool operator <(const Reference &lhs, const std::string &r) +{ + return (const std::string &)lhs < r; +} + +inline +bool operator <(const Reference &lhs, const std::string_view &r) +{ + return (const std::string &)lhs < r; +} + +inline +bool operator <(const Reference &lhs, const char *r) +{ + return (const std::string &)lhs < r; +} + +inline +bool operator <(const std::string &l, const Reference &rhs) +{ + return l < (const std::string &)rhs; +} + +inline +bool operator <(const std::string_view &l, const Reference &rhs) +{ + return l < (const std::string &)rhs; +} + +inline +bool operator <(const char *l, const Reference &rhs) +{ + return l < (const std::string &)rhs; +} + + +// ---- + +inline +void Dictionary::remove(Entry *entry) +{ + auto i = entries.find(entry->value); + if (i != entries.end()) + entries.erase(i); +} + +inline +Reference Dictionary::get(const std::string_view &value) +{ + auto i = entries.find(value); + if (i != entries.end()) + return { strong(i->second) }; + + auto entry = strong(Entry { strong_this(this), std::string(value) }); + entries.emplace(entry->value, entry); + return { std::move(entry) }; +} + +inline +Reference Dictionary::get(const std::string &value) +{ + auto i = entries.find(value); + if (i != entries.end()) + return { strong(i->second) }; + + auto entry = strong(strong_this(this), std::string(value)); + entries.emplace(entry->value, entry); + return { std::move(entry) }; +} + +inline +Reference Dictionary::get(std::string &&value) +{ + auto i = entries.find(value); + if (i != entries.end()) + return { strong(i->second) }; + + auto entry = strong(strong_this(this), std::move(value)); + entries.emplace(entry->value, entry); + return { std::move(entry) }; +} + +inline +Reference Dictionary::get(const char *value) +{ + auto i = entries.find(value); + if (i != entries.end()) + return { strong(i->second) }; + + auto entry = strong(strong_this(this), std::string(value)); + entries.emplace(entry->value, entry); + return { std::move(entry) }; +} + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/string/Str+IO.h b/tjp/core/string/Str+IO.h new file mode 100755 index 0000000..11ffb32 --- /dev/null +++ b/tjp/core/string/Str+IO.h @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Str.h" +#include +#include "from_string.h" + +namespace tjp::core::str { + +#ifdef TJP_STR_USE_TEMPLATES + + template + void io_(IO &io, TJP_STR &v) + { + io.intrinsic_string(v); + } + +#else + template + void io_(IO &io, TJP_STR &v) + { + io.intrinsic_string(v); + } +#endif + +TJP_STR_TEMPLATE +TJP_STR_INLINE +std::ostream &operator <<(std::ostream &o, const TJP_STR &v); + + +TJP_STR_TEMPLATE +TJP_STR_INLINE +void from_string(str::TJP_STR &v, const std::string_view &s); + +} // namespace + +#include "Str+IO.inl" diff --git a/tjp/core/string/Str+IO.inl b/tjp/core/string/Str+IO.inl new file mode 100755 index 0000000..d7b33e7 --- /dev/null +++ b/tjp/core/string/Str+IO.inl @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Str+IO.h" +#include "Str.hpp" +#include "from_string.h" + +namespace tjp::core::str { + +TJP_STR_TEMPLATE +TJP_STR_INLINE +std::ostream &operator <<(std::ostream &o, const TJP_STR &v) +{ + return o << (std::string_view)v; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +void from_string(str::TJP_STR &v, const std::string_view &s) +{ + v = s; +} + +} // namespace + diff --git a/tjp/core/string/Str.cpp b/tjp/core/string/Str.cpp new file mode 100644 index 0000000..6d54b7a --- /dev/null +++ b/tjp/core/string/Str.cpp @@ -0,0 +1,10 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "Str.hpp" + +#ifndef TJP_STR_INLINE +#define TJP_STR_INLINE +#include "Str.inl" +#endif diff --git a/tjp/core/string/Str.h b/tjp/core/string/Str.h new file mode 100755 index 0000000..8017210 --- /dev/null +++ b/tjp/core/string/Str.h @@ -0,0 +1,150 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" + +#include "../rtti/TypeName+custom.hpp" + +namespace tjp::core { +namespace str { + +#define TJP_STR_INLINE inline + +#define TJP_STR_USE_TEMPLATES +#ifdef TJP_STR_USE_TEMPLATES + constexpr int Str_DefaultN = 48; + + template + struct Str; + + #define TJP_STR_TEMPLATE template + #define TJP_STR_TEMPLATE2 template + + #define TJP_STR_TEMPLATE12 template + #define CONST_TEMPLATE_N1 N1 + + #define TJP_STR Str + #define TJP_STR2 Str + #define TJP_STR_TYPENAME typename TJP_STR + + #define TJP_STR_DEFAULT Str +#else + struct Str; + + #define TJP_STR_TEMPLATE + #define TJP_STR_TEMPLATE12 + #define TJP_STR_TEMPLATE2 + #define CONST_TEMPLATE_N1 48 + + #define TJP_STR Str + #define TJP_STR2 Str + #define TJP_STR_TYPENAME TJP_STR + + #define TJP_STR_DEFAULT Str +#endif + + +TJP_STR_TEMPLATE12 +bool operator ==(const TJP_STR &lhs, const TJP_STR2 &rhs); + +TJP_STR_TEMPLATE +bool operator ==(const TJP_STR &lhs, const String &r); + +TJP_STR_TEMPLATE +bool operator ==(const TJP_STR &lhs, const StringView &r); + +TJP_STR_TEMPLATE +bool operator ==(const TJP_STR &lhs, const char *r); + +TJP_STR_TEMPLATE +bool operator ==(const String &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator ==(const StringView &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator ==(const char *l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE12 +bool operator !=(const TJP_STR &lhs, const TJP_STR2 &rhs); + +TJP_STR_TEMPLATE +bool operator !=(const TJP_STR &lhs, const String &r); + +TJP_STR_TEMPLATE +bool operator !=(const TJP_STR &lhs, const StringView &r); + +TJP_STR_TEMPLATE +bool operator !=(const TJP_STR &lhs, const char *r); + +TJP_STR_TEMPLATE +bool operator !=(const String &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator !=(const StringView &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator !=(const char *l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE12 +bool operator <(const TJP_STR &lhs, const TJP_STR2 &rhs); + +TJP_STR_TEMPLATE +bool operator <(const TJP_STR &lhs, const String &r); + +TJP_STR_TEMPLATE +bool operator <(const TJP_STR &lhs, const StringView &r); + +TJP_STR_TEMPLATE +bool operator <(const TJP_STR &lhs, const char *r); + +TJP_STR_TEMPLATE +bool operator <(const String &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator <(const StringView &l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +bool operator <(const char *l, const TJP_STR &rhs); + +TJP_STR_TEMPLATE12 +TJP_STR operator+(const TJP_STR &lhs, const TJP_STR2 &rhs); + +TJP_STR_TEMPLATE +TJP_STR operator+(const String &lhs, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +TJP_STR operator+(const StringView &lhs, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +TJP_STR operator+(const char *lhs, const TJP_STR &rhs); + +TJP_STR_TEMPLATE +TJP_STR operator+(const TJP_STR &lhs, const String &rhs); + +TJP_STR_TEMPLATE +TJP_STR operator+(const TJP_STR &lhs, const StringView &rhs); + +TJP_STR_DEFAULT operator+(const char *lhs, const StringView &rhs); + +} // namespace + +#ifdef TJP_STR_USE_TEMPLATES + template + using StrN = str::TJP_STR; + + using Str = StrN; + using Str = Str; +#else + using Str = str::TJP_STR; + using Str = Str; +#endif + +} // namespace + +TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(tjp::core::Str); + diff --git a/tjp/core/string/Str.hpp b/tjp/core/string/Str.hpp new file mode 100755 index 0000000..d4d1e30 --- /dev/null +++ b/tjp/core/string/Str.hpp @@ -0,0 +1,58 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Str.h" +#include "../containers/StackArray.hpp" + +namespace tjp::core::str { + +TJP_STR_TEMPLATE +struct Str +{ + static constexpr int N = CONST_TEMPLATE_N1; + using Internal = StackArray; + using value_type = typename Internal::value_type; + using const_iterator_ = typename Internal::const_iterator; + + Internal string; + + Str(); + Str(size_t size, char initializer); + Str(const String &rhs); + Str(const StringView &rhs); + Str(const char *rhs); + Str(const char *begin, const char *end); + Str(const StringView &v0, const StringView &v1); + + TJP_STR_TEMPLATE2 + Str(const TJP_STR2 &rhs); + + explicit Str(const Vector &v); + + operator const StringView () const; + bool empty() const; + + void clear(); + + const value_type *data() const; + const_iterator_ begin() const; + const_iterator_ end() const; + size_t size () const; + + char front() const; + char back() const; + + + const char *c_str() const; + const char *c_str(); + String toString() const; +} ; + +} // namespace + +#ifdef TJP_STR_INLINE +#include "Str.inl" +#endif diff --git a/tjp/core/string/Str.inl b/tjp/core/string/Str.inl new file mode 100644 index 0000000..a14ccff --- /dev/null +++ b/tjp/core/string/Str.inl @@ -0,0 +1,464 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Str.hpp" +#include "../algorithm/small_cmp.hpp" + +#include + +namespace tjp { +namespace core { +namespace str { + +typedef StringView compare_type; + +TJP_STR_INLINE +auto cmp (const compare_type &l, const compare_type &r) +{ + return small_cmp(l.data(), l.size(), r.data(), r.size()); +} + +TJP_STR_INLINE +auto cmp (const compare_type &l, const char *r) +{ + return small_cmp(l.data(), l.size(), r); +} + +TJP_STR_INLINE +auto cmp (const char *l, const compare_type &r) +{ + return -cmp(r, l); +} + +TJP_STR_TEMPLATE12 +TJP_STR_INLINE +auto cmp(const TJP_STR &lhs, const TJP_STR2 &rhs) +{ + return small_cmp(lhs.data(), lhs.size(), rhs.data(), rhs.size()); +} + +TJP_STR_INLINE +auto add(const compare_type &l, const compare_type &r) +{ + return Str(l, r); +} + + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR::Str() +{ + +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR::Str(size_t size, char c) +{ + for (auto i=0; i &rhs) : + string(rhs.data(), rhs.data() + rhs.size()) +{ +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR::Str(const StringView &rhs) : + string(rhs.data(), rhs.data() + rhs.size()) +{ +} + +TJP_STR_TEMPLATE +TJP_STR_TEMPLATE2 +TJP_STR_INLINE +TJP_STR::Str(const TJP_STR2 &rhs) : + string(rhs.string) +{ +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR::Str(const char *begin, const char *end) : + string(begin, end) +{ +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR::Str(const char *rhs) +{ + debug_assert(rhs); + if (!rhs) + return; + + auto MAX = 16384; + for (auto i=0; i(this)->c_str(); +} + +TJP_STR_INLINE +bool operator ==(const compare_type &lhs, const char *rhs) +{ + return cmp(lhs, rhs) == 0; +} + + +TJP_STR_INLINE +bool operator ==(const char *lhs, const compare_type &rhs) +{ + return rhs == lhs; +} + +TJP_STR_INLINE +bool operator !=(const compare_type &lhs, const char *rhs) +{ + return !(lhs == rhs); +} + +TJP_STR_INLINE +bool operator !=(const char *lhs, const compare_type &rhs) +{ + return !(lhs == rhs); +} + +TJP_STR_INLINE +bool operator <(const compare_type &lhs, const char *rhs) +{ + return cmp(lhs, rhs) < 0; +} + + +TJP_STR_INLINE +bool operator <(const char *lhs, const compare_type &rhs) +{ + return cmp(lhs, rhs) < 0; +} + + + + + + +TJP_STR_TEMPLATE12 +TJP_STR_INLINE +bool operator ==(const TJP_STR &lhs, const TJP_STR2 &rhs) +{ + return cmp(lhs, rhs) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const TJP_STR &lhs, const String &r) +{ + return cmp((const compare_type &)lhs, compare_type(r)) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const TJP_STR &lhs, const StringView &r) +{ + return cmp((const compare_type &)lhs, r) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const TJP_STR &lhs, const char *r) +{ + return cmp((const compare_type &)lhs, r) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const String &l, const TJP_STR &rhs) +{ + return cmp(compare_type(l), (const compare_type &)rhs) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const StringView &l, const TJP_STR &rhs) +{ + return cmp(l, (const compare_type &)rhs) == 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator ==(const char *l, const TJP_STR &rhs) +{ + return cmp(l, (const compare_type &)rhs) == 0; +} + + + +TJP_STR_TEMPLATE12 +TJP_STR_INLINE +bool operator !=(const TJP_STR &lhs, const TJP_STR2 &rhs) +{ + return cmp(lhs, rhs) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const TJP_STR &lhs, const String &r) +{ + return cmp((const compare_type &)lhs, compare_type(r)) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const TJP_STR &lhs, const StringView &r) +{ + return cmp((const compare_type &)lhs, r) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const TJP_STR &lhs, const char *r) +{ + return cmp((const compare_type &)lhs, r) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const String &l, const TJP_STR &rhs) +{ + return cmp(compare_type(l), (const compare_type &)rhs) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const StringView &l, const TJP_STR &rhs) +{ + return cmp(compare_type(l), (const compare_type &)rhs) != 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator !=(const char *l, const TJP_STR &rhs) +{ + return cmp(l, (const compare_type &)rhs) != 0; +} + + +TJP_STR_TEMPLATE12 +TJP_STR_INLINE +bool operator <(const TJP_STR &lhs, const TJP_STR2 &rhs) +{ + return cmp(lhs, rhs) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const TJP_STR &lhs, const String &r) +{ + return cmp((const compare_type &)lhs, compare_type(r)) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const TJP_STR &lhs, const StringView &r) +{ + return cmp((const compare_type &)lhs, r) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const TJP_STR &lhs, const char *r) +{ + return cmp((const compare_type &)lhs, r) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const String &l, const TJP_STR &rhs) +{ + return cmp(compare_type(l), (const compare_type &)rhs) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const StringView &l, const TJP_STR &rhs) +{ + return cmp(l, (const compare_type &)rhs) < 0; +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +bool operator <(const char *l, const TJP_STR &rhs) +{ + return cmp(l, (const compare_type &)rhs) < 0; +} + +TJP_STR_TEMPLATE12 +TJP_STR_INLINE +TJP_STR operator+(const TJP_STR &lhs, const TJP_STR2 &rhs) +{ + return add(lhs, rhs); +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const String &lhs, const TJP_STR &rhs) +{ + return add(lhs, rhs); +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const StringView &lhs, const TJP_STR &rhs) +{ + return add(lhs, rhs); +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const char *lhs, const TJP_STR &rhs) +{ + return add(lhs, rhs); +} + + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const TJP_STR &lhs, const String &rhs) +{ + return add(lhs, rhs); +} + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const TJP_STR &lhs, const StringView &rhs) +{ + return add(lhs, rhs); +} + + +TJP_STR_TEMPLATE +TJP_STR_INLINE +TJP_STR operator+(const TJP_STR &lhs, const char *rhs) +{ + return add(lhs, rhs); +} + + + +} // namespace +} // namespace +} // namespace + diff --git a/tjp/core/string/String.h b/tjp/core/string/String.h new file mode 100755 index 0000000..541478b --- /dev/null +++ b/tjp/core/string/String.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +// TODO: this header should be String+RTTI.hpp, and String_.h should be String.h + +#include "String_.h" + +#include "../rtti/TypeName.hpp" + +TIMPREPSCIUS_CORE_RTTI_REPLACE_TYPENAME(tjp::core::String); diff --git a/tjp/core/string/String.hpp b/tjp/core/string/String.hpp new file mode 100755 index 0000000..f3fd7f3 --- /dev/null +++ b/tjp/core/string/String.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" diff --git a/tjp/core/string/StringView+concat.hpp b/tjp/core/string/StringView+concat.hpp new file mode 100755 index 0000000..9c69dd9 --- /dev/null +++ b/tjp/core/string/StringView+concat.hpp @@ -0,0 +1,81 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" + +namespace tjp::core { + +template +size_t concat_size(const StringView &s) +{ + return s.size(); +} + +template +size_t concat_size(const StringView &s, Args && ...args) +{ + return concat_size(s) + concat_size(args...); +} + +template +void concat_ (String &s, const StringView &v) +{ + s.insert(s.end(), v.begin(), v.end()); +} + +template +void concat_ (String &s, const StringView &v, Args && ...args) +{ + s.insert(s.end(), v.begin(), v.end()); + concat_(s, std::forward(args)...); +} + +template +String concat (Args && ...args) +{ + String s; + s.reserve(concat_size(args...)); + concat_(s, std::forward(args)...); + + return s; +} + +} // namespace + +namespace std { + +inline +std::string operator +(const std::string &lhs, const std::string_view &rhs) +{ + return tjp::core::concat(lhs, rhs); +} + +inline +std::string operator +(const std::string_view &lhs, const std::string &rhs) +{ + return tjp::core::concat(lhs, rhs); +} + +inline +std::string operator +(const std::string_view &lhs, const std::string_view &rhs) +{ + return tjp::core::concat(lhs, rhs); +} + +inline +std::string operator +(const char *lhs, const std::string_view &rhs) +{ + return tjp::core::concat(lhs, rhs); +} + +inline +std::string operator +(const std::string_view &lhs, const char *rhs) +{ + return tjp::core::concat(lhs, rhs); +} + +} // namespace diff --git a/tjp/core/string/StringView+less.hpp b/tjp/core/string/StringView+less.hpp new file mode 100755 index 0000000..fb3c81f --- /dev/null +++ b/tjp/core/string/StringView+less.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" + +namespace tjp::core { + +inline +bool operator <(const String &lhs, const StringView &rhs) +{ + return (StringView)lhs < rhs; +} + +inline +bool operator <(const StringView &lhs, const String &rhs) +{ + return lhs < (StringView)rhs; +} + + +} // namespace diff --git a/tjp/core/string/StringView.h b/tjp/core/string/StringView.h new file mode 100755 index 0000000..abc3be7 --- /dev/null +++ b/tjp/core/string/StringView.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +using StringView = std::string_view; + +} // namespace diff --git a/tjp/core/string/StringView.hpp b/tjp/core/string/StringView.hpp new file mode 100755 index 0000000..c9cedef --- /dev/null +++ b/tjp/core/string/StringView.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "StringView.h" diff --git a/tjp/core/string/String_.h b/tjp/core/string/String_.h new file mode 100755 index 0000000..9dcb134 --- /dev/null +++ b/tjp/core/string/String_.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +using String = std::string; + +} // namespace diff --git a/tjp/core/string/ToString.hpp b/tjp/core/string/ToString.hpp new file mode 100644 index 0000000..a915165 --- /dev/null +++ b/tjp/core/string/ToString.hpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.hpp" +#include "StringView.hpp" + +#include + +namespace tjp::core { + +struct ToString +{ + struct End_ {}; + static constexpr End_ End{}; + + std::stringstream o; + + template + ToString &operator <<(T &&t) + { + o << t; + return *this; + } + + operator String() + { + return o.str(); + } +} ; + +inline +String operator <<(std::stringstream &o, ToString::End_) +{ + return o.str(); +} + +} // namespace diff --git a/tjp/core/string/Tokenizer.h b/tjp/core/string/Tokenizer.h new file mode 100644 index 0000000..b1c972e --- /dev/null +++ b/tjp/core/string/Tokenizer.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp { +namespace core { + +struct TokenVector; +struct TokenStringView; + +template +class Tokenizer; + +} // namespace +} // namespace diff --git a/tjp/core/string/Tokenizer.hpp b/tjp/core/string/Tokenizer.hpp new file mode 100644 index 0000000..29d6216 --- /dev/null +++ b/tjp/core/string/Tokenizer.hpp @@ -0,0 +1,132 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "Tokenizer.h" +#include +#include +#include "str_find.h" + +namespace tjp { +namespace core { + +struct TokenVector +{ + typedef std::vector Tokens; + Tokens tokens; + + TokenVector(const std::string &_del) : + tokens(255, false) + { + const unsigned char *begin = (const unsigned char *)_del.c_str(); + const unsigned char *end = begin + _del.size(); + for (const unsigned char *c=begin; c!=end;++c) + tokens[*c] = true; + } + + size_t find(const unsigned char *s, size_t left, char &t, size_t size) const + { + return str_find(s, tokens.data(), left, t, size); + } +} ; + +struct TokenStringView +{ + typedef std::string_view Tokens; + Tokens tokens; + + TokenStringView(const std::string_view &_del) : + tokens(_del) + { + } + + size_t find(const unsigned char *s, size_t left, char &t, size_t size) const + { + return str_find(s, tokens, left, t, size); + } +} ; + +template +class Tokenizer +{ +public: + typedef token_type Tokens; + typedef size_t index; + +protected: + const unsigned char *s; + const Tokens *tokens; + + index size; + index left; + index right; + char t; + +public: + + Tokenizer (const char *_s, index _size, const token_type &tokens_) : + s((const unsigned char *)_s), + left(0), + tokens(&tokens_), + size(_size) + { + right = tokens->find(s, left, t, size); + } + + Tokenizer () : + s(nullptr), + tokens(nullptr), + left(0), + right(0), + size(0) + { + + } + + bool next (string &_s, char &_t) + { + index _left,_size; + + bool result = next(_left, _size, _t); + if (result) + _s = string((const char *)s+_left, _size); + + return result; + } + + bool next (index &_left, index &_size, char &_t) + { + if (left != -1) + { + _t = t; + + if (right == -1) + { + _left = left; + _size = size - left; + left = right; + } + else + { + _left = left; + _size = right-left; + + left = right + 1; + if (left < size) + right = tokens->find(s, left, t, size); + else + left = -1; + } + + return true; + } + + return false; + } +} ; + + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/Dictionary.cpp b/tjp/core/string/_tests/Dictionary.cpp new file mode 100644 index 0000000..58ad19f --- /dev/null +++ b/tjp/core/string/_tests/Dictionary.cpp @@ -0,0 +1,41 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include + +namespace tjp::core::string_dictionary { +namespace { + +SCENARIO("core::string::string_dictionary") +{ + GIVEN("a dictionary") + { + auto dictionary = strong(); + auto hi_cstr = "hi"; + auto hi_str = std::string("hi"); + auto hi_str_view = std::string_view(hi_str); + + auto hi0 = dictionary->get(hi_cstr); + auto hi1 = dictionary->get(hi_str); + auto hi2 = dictionary->get(hi_str_view); + + REQUIRE(hi2 == hi1); + REQUIRE(hi0 == hi1); + REQUIRE(hi0 == hi_cstr); + REQUIRE(hi0 == hi_str); + REQUIRE(hi0 == hi_str_view); + + REQUIRE(hi0.entry == hi1.entry); + REQUIRE(hi1.entry == hi2.entry); + + auto bye = dictionary->get("bye"); + + REQUIRE(hi0 != "bye"); + REQUIRE(hi0 != bye); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/Str.cpp b/tjp/core/string/_tests/Str.cpp new file mode 100755 index 0000000..de3d1c7 --- /dev/null +++ b/tjp/core/string/_tests/Str.cpp @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include + +#include +#include + +namespace tjp::core { +namespace { + +struct AB { + Str a, b; +}; + +SCENARIO("core::string::str") +{ + GIVEN("sizeof") + { + Str a; + + sLogTest("testing", logVar(sizeof(Str)) << logVar(sizeof(Str::Internal)) << logVar(sizeof(a)) << logVar(sizeof(AB))); + } + + GIVEN("a const string") + { + Str one("1"); + Str one_again("1"); + Str two("2"); + + StrN<12> small("S"); + Str bigger = small; + + std::string v; + for (auto i=0;i<256;++i) + v += "a"; + + Str longString(v); + + REQUIRE(one == one); + REQUIRE(one == "1"); + REQUIRE(one != "2"); + REQUIRE(one != two); + REQUIRE(one == one_again); + REQUIRE(longString == longString); + REQUIRE(longString != one); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/cmp_case.cpp b/tjp/core/string/_tests/cmp_case.cpp new file mode 100755 index 0000000..6d18c62 --- /dev/null +++ b/tjp/core/string/_tests/cmp_case.cpp @@ -0,0 +1,59 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace tjp::core { +namespace { + +int positivenegativeone(int v) +{ + return v > 0 ? 1 : (v<0) ? -1 : 0; +} + +SCENARIO("core::string::cmp_case") +{ + GIVEN("a const string") + { + Vector strings { + "one", + "two", + "onewithmore", + "three", + "thre", + "" + } ; + + for (auto &l: strings) + { + for (auto &r: strings) + { + auto a = positivenegativeone(strcasecmp(l.c_str(), r.c_str())); + auto b = positivenegativeone(strncasecmp(l.c_str(), l.size(), r.c_str(), r.size())); + auto c = positivenegativeone(cmp_case(l, r)); + + REQUIRE(a == b); + REQUIRE(b == c); + } + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/join.cpp b/tjp/core/string/_tests/join.cpp new file mode 100755 index 0000000..0d8684c --- /dev/null +++ b/tjp/core/string/_tests/join.cpp @@ -0,0 +1,53 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::string::join") +{ + GIVEN("string") + { + String s = join_values( + ',', + Vector{"a", "b", "c", "d"} + ); + + REQUIRE(s == "a,b,c,d"); + } + + GIVEN("strings") + { + String s = join_values( + ',', + Vector{"a", "b", "c", "d"}, + Vector{"e", "f", "g", "h"} + ); + + REQUIRE(s == "a,b,c,d,e,f,g,h"); + } + + GIVEN("string and integers") + { + String s = join_values( + ',', + Vector{"a", "b", "c", "d"}, + Vector{0, 1, 2, 3} + ); + + REQUIRE(s == "a,b,c,d,0,1,2,3"); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/replace.cpp b/tjp/core/string/_tests/replace.cpp new file mode 100755 index 0000000..b14b2ac --- /dev/null +++ b/tjp/core/string/_tests/replace.cpp @@ -0,0 +1,58 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include + +#include +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::string::replace") +{ + GIVEN("string") + { + String s = "abc"; + + WHEN("begin") + { + auto replaced = replace(s, "a", "xyz"); + REQUIRE(replaced == true); + + REQUIRE(s == "xyzbc"); + } + + WHEN("end") + { + bool replaced = replace(s, "c", "xyz"); + REQUIRE(replaced == true); + + REQUIRE(s == "abxyz"); + } + + WHEN("middle") + { + bool replaced = replace(s, "b", "xyz"); + REQUIRE(replaced == true); + + REQUIRE(s == "axyzc"); + } + + WHEN("missing") + { + bool replaced = replace(s, "d", "xyz"); + REQUIRE(replaced == false); + + REQUIRE(s == "abc"); + } + } + + +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/split_once.cpp b/tjp/core/string/_tests/split_once.cpp new file mode 100755 index 0000000..098de27 --- /dev/null +++ b/tjp/core/string/_tests/split_once.cpp @@ -0,0 +1,48 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::string::split_once") +{ + GIVEN("strings") + { + Vector> strings { + { "asdf:1234", ":", true, "asdf", "1234" }, + { ":asdf1234", ":", true, "", "asdf1234" }, + { "asdf1234:", ":", true, "asdf1234", "" }, + { "asdf1234", ":", false, "", "" }, + { ":asdf:1234", ":", true, "", "asdf:1234" }, + { "asdf::1234", ":", true, "asdf", ":1234" }, + } ; + + for (auto &ss : strings) + { + auto &[s, c, has_value, l, r] = ss; + + auto split = split_once(s, c); + REQUIRE(split.has_value() == has_value); + + if (has_value) + { + auto &[lv, rv] = *split; + REQUIRE(lv == l); + REQUIRE(rv == r); + } + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/strncasecmp.cpp b/tjp/core/string/_tests/strncasecmp.cpp new file mode 100755 index 0000000..d687faf --- /dev/null +++ b/tjp/core/string/_tests/strncasecmp.cpp @@ -0,0 +1,50 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace tjp::core { +namespace { + +int positivenegativeone(int v) +{ + return v > 0 ? 1 : (v<0) ? -1 : 0; +} + + +SCENARIO("core::string::strncasecmp") +{ + GIVEN("a const string") + { + Vector strings { + "one", + "two", + "three", + "" + } ; + + for (auto &l: strings) + { + for (auto &r: strings) + { + auto a = positivenegativeone(strcasecmp(l.c_str(), r.c_str())); + auto b = positivenegativeone(strncasecmp(l.c_str(), l.size(), r.c_str(), r.size())); + + REQUIRE(a == b); + } + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/strncmp.cpp b/tjp/core/string/_tests/strncmp.cpp new file mode 100755 index 0000000..1939cdf --- /dev/null +++ b/tjp/core/string/_tests/strncmp.cpp @@ -0,0 +1,50 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include +#include +#include + +#include + +#include +#include + +#include + +namespace tjp::core { +namespace { + +int positivenegativeone(int v) +{ + return v > 0 ? 1 : (v<0) ? -1 : 0; +} + + +SCENARIO("core::string::strncmp") +{ + GIVEN("a const string") + { + Vector strings { + "one", + "two", + "three", + "" + } ; + + for (auto &l: strings) + { + for (auto &r: strings) + { + auto a = positivenegativeone(strcmp(l.c_str(), r.c_str())); + auto b = positivenegativeone(strncmp(l.c_str(), l.size(), r.c_str(), r.size())); + + REQUIRE(a == b); + } + } + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/_tests/trim.cpp b/tjp/core/string/_tests/trim.cpp new file mode 100755 index 0000000..754bd2c --- /dev/null +++ b/tjp/core/string/_tests/trim.cpp @@ -0,0 +1,57 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include + +#include + +#include +#include + +namespace tjp::core { +namespace { + +SCENARIO("core::string::trim") +{ + GIVEN("string") + { + String s = "abc"; + + auto trimmed_left = trim_left_copy(s, "a"); + auto trimmed_right = trim_right_copy(s, "c"); + auto trimmed = trim_copy(s, "ac"); + + REQUIRE(trimmed_left == "bc"); + REQUIRE(trimmed_right == "ab"); + REQUIRE(trimmed == "b"); + } + + GIVEN("string view") + { + String s_ = "abc"; + StringView s = s_; + + auto trimmed_left = trim_left_copy(s, "a"); + auto trimmed_right = trim_right_copy(s, "c"); + auto trimmed = trim_copy(s, "ac"); + + REQUIRE(trimmed_left == "bc"); + REQUIRE(trimmed_right == "ab"); + REQUIRE(trimmed == "b"); + } + + GIVEN("string view from string on stack") + { + auto trimmed_left = trim_left_copy(String("abc"), "a"); + auto trimmed_right = trim_right_copy(String("abc"), "c"); + auto trimmed = trim_copy(String("abc"), "ac"); + + REQUIRE(trimmed_left == "bc"); + REQUIRE(trimmed_right == "ab"); + REQUIRE(trimmed == "b"); + } +} + +} // namespace +} // namespace diff --git a/tjp/core/string/as_string.hpp b/tjp/core/string/as_string.hpp new file mode 100755 index 0000000..463d0c4 --- /dev/null +++ b/tjp/core/string/as_string.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" + +namespace tjp::core { + +template +String as_string(const T &s) +{ + return String((char *)s.data(), s.size() * sizeof(s.front())); +} + +template<> +inline +String as_string(const String &s) +{ + return s; +} + + +} // namespace diff --git a/tjp/core/string/as_string_view.hpp b/tjp/core/string/as_string_view.hpp new file mode 100755 index 0000000..9874957 --- /dev/null +++ b/tjp/core/string/as_string_view.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" + +namespace tjp::core { + +template +StringView as_string_view(const T &s) +{ + return StringView((char *)s.data(), s.size() * sizeof(s.front())); +} + +} // namespace diff --git a/tjp/core/string/as_vector.hpp b/tjp/core/string/as_vector.hpp new file mode 100755 index 0000000..a7ee523 --- /dev/null +++ b/tjp/core/string/as_vector.hpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" +#include "../containers/Vector.h" + +namespace tjp::core { + +template +Vector as_vector(const U &s) +{ + return Vector((T *)s.data(), (T *)(s.data() + s.size())); +} + +template +Vector as_vector(const String &s) +{ + return Vector((T *)s.data(), (T *)(s.data() + s.size())); +} + +template +Vector as_vector(const StringView &s) +{ + return Vector((T *)s.data(), (T *)(s.data() + s.size())); +} + +template +Vector as_vector(const char *s) +{ + return as_vector(StringView(s)); +} + +} // namespace diff --git a/tjp/core/string/auto_to_string.hpp b/tjp/core/string/auto_to_string.hpp new file mode 100644 index 0000000..3065f19 --- /dev/null +++ b/tjp/core/string/auto_to_string.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "ToString.hpp" + +// this is questionable + +namespace std { + +template +auto operator <<(const std::string &s, T &&t) +{ + return tjp::core::ToString() << s << std::forward(t); +} + +template +auto operator <<(const std::string_view &s, T &&t) +{ + return tjp::core::ToString() << s << std::forward(t); +} + +} // namespace diff --git a/tjp/core/string/cmp.cpp b/tjp/core/string/cmp.cpp new file mode 100755 index 0000000..015b424 --- /dev/null +++ b/tjp/core/string/cmp.cpp @@ -0,0 +1,50 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif +#include "../header_only/compile.h" + +#include "cmp.hpp" +#include "strncmp.h" + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +int cmp(const String &l, const String &r) +{ + return strncmp(l.c_str(), l.size(), r.c_str(), r.size()); +} + +TJP_CORE_HEADER_ONLY_INLINE +bool less(const String &l, const String &r) +{ + return l < r; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool equal(const String &l, String &r) +{ + return l == r; +} + +TJP_CORE_HEADER_ONLY_INLINE +int cmp(const StringView &l, const StringView &r) +{ + return strncmp(l.data(), l.size(), r.data(), r.size()); +} + +TJP_CORE_HEADER_ONLY_INLINE +bool less(const StringView &l, const StringView &r) +{ + return l < r; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool equal(const StringView &l, const StringView &r) +{ + return l == r; +} + +} // namespace diff --git a/tjp/core/string/cmp.hpp b/tjp/core/string/cmp.hpp new file mode 100755 index 0000000..cf517f2 --- /dev/null +++ b/tjp/core/string/cmp.hpp @@ -0,0 +1,20 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" + +namespace tjp::core { + +int cmp(const String &l, const String &r); +bool less(const String &l, const String &r); +bool equal(const String &l, const String &r); + +int cmp(const StringView &l, const StringView &r); +bool less(const StringView &l, const StringView &r); +bool equal(const StringView &l, const StringView &r); + +} // namespace diff --git a/tjp/core/string/cmp_case.cpp b/tjp/core/string/cmp_case.cpp new file mode 100755 index 0000000..f51fa95 --- /dev/null +++ b/tjp/core/string/cmp_case.cpp @@ -0,0 +1,52 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif +#include "../header_only/compile.h" + +#include "cmp_case.hpp" +#include "strncasecmp.h" + + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +int cmp_case(const String &l, const String &r) +{ + return strncasecmp(l.c_str(), l.size(), r.c_str(), r.size()); +} + +TJP_CORE_HEADER_ONLY_INLINE +bool less_case(const String &l, const String &r) +{ + return cmp_case(l,r) < 0; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool equal_case(const String &l, const String &r) +{ + return cmp_case(l,r) == 0; +} + +TJP_CORE_HEADER_ONLY_INLINE +int cmp_case(const StringView &l, const StringView &r) +{ + return strncasecmp(l.data(), l.size(), r.data(), r.size()); +} + +TJP_CORE_HEADER_ONLY_INLINE +bool less_case(const StringView &l, const StringView &r) +{ + return cmp_case(l, r) < 0; +} + +TJP_CORE_HEADER_ONLY_INLINE +bool equal_case(const StringView &l, const StringView &r) +{ + return cmp_case(l,r) == 0; +} + +} // namespace diff --git a/tjp/core/string/cmp_case.hpp b/tjp/core/string/cmp_case.hpp new file mode 100755 index 0000000..e8a13b9 --- /dev/null +++ b/tjp/core/string/cmp_case.hpp @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" + +namespace tjp::core { + +int cmp_case(const String &l, const String &r); +int cmp_case(const StringView &l, const StringView &r); + +bool less_case(const String &l, const String &r); +bool less_case(const StringView &l, const StringView &r); + +bool equal_case(const String &l, const String &r); +bool equal_case(const StringView &l, const StringView &r); + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY + #include "cmp_case.cpp" +#endif diff --git a/tjp/core/string/ends_with.hpp b/tjp/core/string/ends_with.hpp new file mode 100755 index 0000000..c636fec --- /dev/null +++ b/tjp/core/string/ends_with.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../algorithm/ends_with.hpp" diff --git a/tjp/core/string/find_after.hpp b/tjp/core/string/find_after.hpp new file mode 100755 index 0000000..e46d2c0 --- /dev/null +++ b/tjp/core/string/find_after.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Optional.hpp" + +#include "StringView.hpp" + +namespace tjp::core::string { + +inline +Optional find_after(const StringView &s, const StringView &find, StringView::pos pos=0) +{ + if (pos + find.size() > s.size()) + return {}; + + auto f = s.find(find, pos); + if (f == s.npos) + return {}; + + return f + find.size(); +} + +} // namespace diff --git a/tjp/core/string/find_if.hpp b/tjp/core/string/find_if.hpp new file mode 100755 index 0000000..f214993 --- /dev/null +++ b/tjp/core/string/find_if.hpp @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Optional.hpp" + +#include "StringView.hpp" + +namespace tjp::core::string { + +inline +Optional find_if(const StringView &s, const StringView &find, size_t pos=0) +{ + auto f = s.find(find, pos); + if (f == s.npos) + return {}; + + return f; +} + +} // namespace diff --git a/tjp/core/string/from_string.cpp b/tjp/core/string/from_string.cpp new file mode 100755 index 0000000..b4bd4c0 --- /dev/null +++ b/tjp/core/string/from_string.cpp @@ -0,0 +1,69 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif + +#include "../header_only/compile.h" + +#include "from_string.hpp" +#include +#include + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +void from_string(std::string_view &v, const std::string_view &s) +{ + v = s; +} + +TJP_CORE_HEADER_ONLY_INLINE +void from_string(std::string &v, const std::string_view &s) +{ + v = s; +} + +TJP_CORE_HEADER_ONLY_INLINE +void from_string(bool &v, const std::string_view &s) +{ + v = (s == "true"); +} + + +TJP_CORE_HEADER_ONLY_INLINE +int naive_atoi(const std::string_view &s) +{ + // Taken from http://tinodidriksen.com/uploads/code/cpp/speed-string-to-int.cpp + + int x = 0; + bool neg = false; + auto *p = s.data(); + auto *e = p + s.size(); + + if (p < e && *p == '-') { + neg = true; + ++p; + } + + while (p < e && *p >= '0' && *p <= '9') { + x = (x*10) + (*p - '0'); + ++p; + } + + if (neg) { + x = -x; + } + return x; +} + +TJP_CORE_HEADER_ONLY_INLINE +void from_string(int &v, const std::string_view &s) +{ + v = naive_atoi(s); +} + + +} // namespace diff --git a/tjp/core/string/from_string.h b/tjp/core/string/from_string.h new file mode 100755 index 0000000..602cca4 --- /dev/null +++ b/tjp/core/string/from_string.h @@ -0,0 +1,25 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +void from_string(T &t, const std::string_view &s); + +template +T from_string(const std::string_view &s); + +template +T from_string(const std::string_view &s, const T &defaultValue); + +void from_string(std::string_view &v, const std::string_view &s); +void from_string(std::string &, const std::string_view &s); +void from_string(bool &v, const std::string_view &s); +void from_string(int &v, const std::string_view &s); + +} // namespace diff --git a/tjp/core/string/from_string.hpp b/tjp/core/string/from_string.hpp new file mode 100755 index 0000000..615e54e --- /dev/null +++ b/tjp/core/string/from_string.hpp @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../header_only/compile.h" + +#include "from_string.h" +#include "from_string.inl" + +#ifdef TJP_CORE_HEADER_ONLY + #include "from_string.cpp" +#endif diff --git a/tjp/core/string/from_string.inl b/tjp/core/string/from_string.inl new file mode 100755 index 0000000..62910e7 --- /dev/null +++ b/tjp/core/string/from_string.inl @@ -0,0 +1,44 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "from_string.h" +#include "../io/memstream.hpp" + +namespace tjp::core { + +template +void from_string(T &t, const std::string_view &s) +{ + io::imemstream in(s.data(), s.size()); + in >> t; +} + +template +T from_string(const std::string_view &s, const T &defaultValue) +{ + T t = defaultValue; + from_string(t, s); + return t; +} + +template +T from_string(const std::string_view &s) +{ + T t; + from_string(t, s); + return t; +} + +template +T from_string_using(const U &s) +{ + T t; + io::imemstream in(s.data(), s.size()); + in >> t; + return t; +} + +} // namespace diff --git a/tjp/core/string/has.hpp b/tjp/core/string/has.hpp new file mode 100755 index 0000000..e832ff0 --- /dev/null +++ b/tjp/core/string/has.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../algorithm/has_sequence.hpp" +#include "StringView.hpp" + +namespace tjp::core { + +bool has(const StringView &lhs, const StringView &rhs) +{ + return has_sequence(lhs, rhs); +} + +} // namespace diff --git a/tjp/core/string/has_prefix.hpp b/tjp/core/string/has_prefix.hpp new file mode 100755 index 0000000..a043beb --- /dev/null +++ b/tjp/core/string/has_prefix.hpp @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "starts_with.hpp" + +namespace tjp::core { + +inline +bool has_prefix(const std::string_view &s, const std::string_view &prefix) +{ + return starts_with(s, prefix); +} + +} // namespace diff --git a/tjp/core/string/join.hpp b/tjp/core/string/join.hpp new file mode 100755 index 0000000..044c94b --- /dev/null +++ b/tjp/core/string/join.hpp @@ -0,0 +1,72 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../iterators/is_first.hpp" +#include "to_string.hpp" +#include + +namespace tjp::core { + +template +void join_(std::string &result, is_first &first, const V &delimiter, const T & sv) +{ + for (auto &s : sv) + { + if (!first.check()) + result += delimiter; + + result.insert(result.end(), s.begin(), s.end()); + } +} + +template +void join_(std::string &result, is_first &first, const V &delimiter, const U &u, const T & sv) +{ + for (auto &s_ : sv) + { + auto s = u(s_); + if (!first.check()) + result += delimiter; + + result.insert(result.end(), s.begin(), s.end()); + } +} + +template +std::string join(const V &delimiter, T&& ... t) +{ + std::string result; + is_first first; + + ((join_(result, first, delimiter, t)),...) ; + + return result; +} + +template +std::string join_values(const V &delimiter, T&& ... t) +{ + std::string result; + is_first first; + + auto u = [](auto &v) { return to_string(v); }; + ((join_(result, first, delimiter, u, t)),...) ; + + return result; +} + +template +std::string join_with(const V &delimiter, U &&u, T&& ... t) +{ + std::string result; + is_first first; + + ((join_(result, first, delimiter, u, t)),...) ; + + return result; +} + +} // namespace diff --git a/tjp/core/string/replace.cpp b/tjp/core/string/replace.cpp new file mode 100755 index 0000000..a2c750e --- /dev/null +++ b/tjp/core/string/replace.cpp @@ -0,0 +1,37 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined(TJP_CORE_HEADER_ONLY) + #pragma once +#endif +#include "../header_only/compile.h" + +#include "replace.h" +#include + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +bool replace(String& str, const StringView& from, const StringView& to) +{ + size_t start_pos = str.find(from); + if(start_pos == std::string::npos) + return false; + str.replace(start_pos, from.length(), to); + return true; +} + +TJP_CORE_HEADER_ONLY_INLINE +void replaceAll(String& str, const StringView& from, const StringView& to) +{ + if(from.empty()) + return; + size_t start_pos = 0; + while((start_pos = str.find(from, start_pos)) != std::string::npos) { + str.replace(start_pos, from.length(), to); + start_pos += to.length(); // In case 'to' contains 'from', like replacing 'x' with 'yx' + } +} + +} // namespace diff --git a/tjp/core/string/replace.h b/tjp/core/string/replace.h new file mode 100755 index 0000000..67d26d8 --- /dev/null +++ b/tjp/core/string/replace.h @@ -0,0 +1,19 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.hpp" +#include "StringView.hpp" + +namespace tjp::core { + +bool replace(String & str, const StringView& from, const StringView& to); +void replaceAll(String& str, const StringView& from, const StringView& to); + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY + #include "replace.cpp" +#endif diff --git a/tjp/core/string/replaced.cpp b/tjp/core/string/replaced.cpp new file mode 100755 index 0000000..322b0c4 --- /dev/null +++ b/tjp/core/string/replaced.cpp @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "replace.h" +#include "replaced.h" +#include + +namespace tjp::core { + +String replacedFirst(const StringView & str, const StringView& from, const StringView& to) { + auto s = String(str); + replace(s, from, to); + return s; +} + +String replaced(const StringView & str, const StringView& from, const StringView& to) { + auto s = String(str); + replaceAll(s, from, to); + return s; +} + +} // namespace diff --git a/tjp/core/string/replaced.h b/tjp/core/string/replaced.h new file mode 100755 index 0000000..c7bd61c --- /dev/null +++ b/tjp/core/string/replaced.h @@ -0,0 +1,15 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.hpp" +#include "StringView.hpp" + +namespace tjp::core { + +String replaceFirst(const StringView & str, const StringView& from, const StringView& to); +String replaced(const StringView & str, const StringView& from, const StringView& to); + +} // namespace diff --git a/tjp/core/string/split.hpp b/tjp/core/string/split.hpp new file mode 100755 index 0000000..768c0a3 --- /dev/null +++ b/tjp/core/string/split.hpp @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +template +std::vector split(const T &s, const T &delimiter); + +} // namespace + +#include "split.inl" diff --git a/tjp/core/string/split.inl b/tjp/core/string/split.inl new file mode 100755 index 0000000..a4446ff --- /dev/null +++ b/tjp/core/string/split.inl @@ -0,0 +1,49 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +namespace tjp::core { + +template +std::vector split(const T &s, const T &delimiter) +{ + std::vector result; + + size_t last = 0; size_t next = 0; + while ((next = s.find(delimiter, last)) != T::npos) + { + if (last < next) + result.push_back(s.substr(last, next-last)); + + last = next + std::max(delimiter.size(), (size_t)1); + } + + if (last < s.size()) + result.push_back(s.substr(last)); + + return result; +} + +template +std::vector split(const T &s, char delimiter) +{ + std::vector result; + + size_t last = 0; size_t next = 0; + while ((next = s.find(delimiter, last)) != T::npos) + { + if (last < next) + result.push_back(s.substr(last, next-last)); + + last = next + 1; + } + + if (last < s.size()) + result.push_back(s.substr(last)); + + return result; +} + +} // namespace diff --git a/tjp/core/string/split_once.hpp b/tjp/core/string/split_once.hpp new file mode 100755 index 0000000..b837d0c --- /dev/null +++ b/tjp/core/string/split_once.hpp @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Tuple.hpp" +#include "../containers/Optional.hpp" +#include "StringView.hpp" + +namespace tjp::core { + +template +Optional> split_once(const T &s, const StringView &delimiter) +{ + auto v = s.find(delimiter); + if (v == s.npos) + return {}; + + return Tuple { + s.substr(0, v), + s.substr(v+delimiter.size()) + }; +} + +} // namespace diff --git a/tjp/core/string/starts_with.hpp b/tjp/core/string/starts_with.hpp new file mode 100755 index 0000000..4b1e7ea --- /dev/null +++ b/tjp/core/string/starts_with.hpp @@ -0,0 +1,7 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../algorithm/starts_with.hpp" diff --git a/tjp/core/string/str_find.cpp b/tjp/core/string/str_find.cpp new file mode 100755 index 0000000..05d9725 --- /dev/null +++ b/tjp/core/string/str_find.cpp @@ -0,0 +1,62 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "str_find.h" +#include + +namespace tjp::core { + +size_t str_find(const char *s, char del, size_t offset) +{ + const char *result = strchr(s+offset, del); + if (result == NULL) + return -1; + return (size_t)(result - s); +} + +size_t str_find(const unsigned char *s, const unsigned char *tokens, size_t offset, char &t, size_t size) +{ + t = 0; + + bool found = false; + const unsigned char *r = (const unsigned char *)s+offset; + const unsigned char *e = s + size; + for (;r < e && *r!=0; r++) + { + if (*(tokens + *r)) + { + t = *r; + found = true; + break; + } + } + + if (!found) + return -1; + + return (int)(r - s); +} + +size_t str_find(const unsigned char *s, const std::string_view &tokens, size_t offset, char &t, size_t size) +{ + t = 0; + + const unsigned char *r = (const unsigned char *)s+offset; + const unsigned char *e = s + size; + for (;r < e && *r!=0; r++) + { + for (auto &t_ : tokens) + { + if (t_ == *r) + { + t = t_; + return (int)(r - s); + } + } + } + + return -1; +} + +} // namespace diff --git a/tjp/core/string/str_find.h b/tjp/core/string/str_find.h new file mode 100755 index 0000000..01e56ab --- /dev/null +++ b/tjp/core/string/str_find.h @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +size_t str_find(const char *s, char del, size_t offset=0); +size_t str_find(const unsigned char *s, const unsigned char *tokens, size_t offset, char &t, size_t size); +size_t str_find(const unsigned char *s, const std::string_view &tokens, size_t offset, char &t, size_t size); + + +} // namespace diff --git a/tjp/core/string/strncasecmp.cpp b/tjp/core/string/strncasecmp.cpp new file mode 100755 index 0000000..0fe56dc --- /dev/null +++ b/tjp/core/string/strncasecmp.cpp @@ -0,0 +1,32 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TJP_CORE_HEADER_ONLY + #pragma once +#endif +#include "../header_only/compile.h" + +#include "strncasecmp.h" + +#include +#include + +namespace tjp::core { + +TJP_CORE_HEADER_ONLY_INLINE +int strncasecmp(const char *l, size_t ls, const char *r, size_t rs) +{ + auto v = ::strncasecmp(l, r, std::min(ls, rs)); + if (v != 0) + return v; + + if (ls > rs) + return 1; + if (ls < rs) + return -1; + + return 0; +} + +} // namespace diff --git a/tjp/core/string/strncasecmp.h b/tjp/core/string/strncasecmp.h new file mode 100755 index 0000000..d706e35 --- /dev/null +++ b/tjp/core/string/strncasecmp.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +int strncasecmp(const char *l, size_t ls, const char *r, size_t rs); + +} // namespace + +#ifdef TJP_CORE_HEADER_ONLY + #include "strncasecmp.cpp" +#endif diff --git a/tjp/core/string/strncmp.cpp b/tjp/core/string/strncmp.cpp new file mode 100755 index 0000000..9d12990 --- /dev/null +++ b/tjp/core/string/strncmp.cpp @@ -0,0 +1,28 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "strncmp.h" + +#include +#include + +#include + +namespace tjp::core { + +int strncmp(const char *l, size_t ls, const char *r, size_t rs) +{ + auto v = ::strncmp(l, r, std::min(ls, rs)); + if (v != 0) + return v; + + if (ls > rs) + return 1; + if (ls < rs) + return -1; + + return 0; +} + +} // namespace diff --git a/tjp/core/string/strncmp.h b/tjp/core/string/strncmp.h new file mode 100755 index 0000000..6523ac5 --- /dev/null +++ b/tjp/core/string/strncmp.h @@ -0,0 +1,13 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace tjp::core { + +int strncmp(const char *l, size_t ls, const char *r, size_t rs); + +} // namespace diff --git a/tjp/core/string/sxprintf.h b/tjp/core/string/sxprintf.h new file mode 100755 index 0000000..ac6450d --- /dev/null +++ b/tjp/core/string/sxprintf.h @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include +#include + +namespace tjp::core { + +template +void sxprintf(T &t, const char *format, Args &&... args) +{ + static_assert(std::is_array::value, "T must be an array"); + static_assert(std::is_same::type, char>::value, "T must be an array of char"); + + snprintf(t, std::size(t), format, std::forward(args)...); +} + +} // namespace diff --git a/tjp/core/string/to_lower.hpp b/tjp/core/string/to_lower.hpp new file mode 100755 index 0000000..a64420a --- /dev/null +++ b/tjp/core/string/to_lower.hpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.h" +#include "StringView.h" +#include + +namespace tjp::core { + +inline +String to_lower(const StringView &s_) +{ + String s(s_); + + std::transform( + s.begin(), s.end(), s.begin(), + [](unsigned char c){ return std::tolower(c); } + ); + + return s; +} + +} // namespace + diff --git a/tjp/core/string/to_string.h b/tjp/core/string/to_string.h new file mode 100755 index 0000000..b1b8b94 --- /dev/null +++ b/tjp/core/string/to_string.h @@ -0,0 +1,23 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include + +namespace std { + +inline +std::string to_string(const std::string_view &s); + +} + +namespace tjp { +namespace core { + +template +std::string to_string(const T &t); + +} // namespace +} // namespace diff --git a/tjp/core/string/to_string.hpp b/tjp/core/string/to_string.hpp new file mode 100755 index 0000000..b165cc2 --- /dev/null +++ b/tjp/core/string/to_string.hpp @@ -0,0 +1,40 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "to_string.h" +#include +#include + +namespace std { + +inline +std::string to_string(const std::string_view &s) +{ + return std::string(s.data(), s.size()); +} + +} // namespace + +namespace tjp { +namespace core { + +template +std::string to_string(const T &t) +{ + std::ostringstream s; + s << t; + return s.str(); +} + +inline +std::string to_string(const std::string_view &s) +{ + return std::to_string(s); +} + + +} // namespace +} // namespace diff --git a/tjp/core/string/trim.h b/tjp/core/string/trim.h new file mode 100755 index 0000000..8c2eb8b --- /dev/null +++ b/tjp/core/string/trim.h @@ -0,0 +1,32 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "String.hpp" +#include "StringView.hpp" + +namespace tjp::core { + +template +T trim_right_copy( + const T &s, + const StringView &delimiters = " \f\n\r\t\v" +); + +template +T trim_left_copy( + const T &s, + const StringView &delimiters = " \f\n\r\t\v" +); + +template +T trim_copy( + const T &s, + const StringView & delimiters = " \f\n\r\t\v" +); + +} // namespace + +#include "trim.inl" diff --git a/tjp/core/string/trim.inl b/tjp/core/string/trim.inl new file mode 100755 index 0000000..55a9182 --- /dev/null +++ b/tjp/core/string/trim.inl @@ -0,0 +1,49 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "trim.h" + +namespace tjp::core { + +template +T trim_right_copy( + const T &s, + const StringView &delimiters) +{ + if (s.empty()) + return {}; + + return s.substr( 0, s.find_last_not_of( delimiters ) + 1 ); +} + +template +T trim_left_copy( + const T &s, + const StringView &delimiters) +{ + if (s.empty()) + return {}; + + return s.substr( s.find_first_not_of( delimiters ) ); +} + +template +T trim_copy( + const T &s, + const StringView &delimiters) +{ + if (s.empty()) + return {}; + + return + trim_left_copy( + trim_right_copy(s, delimiters), + delimiters + ); +} + + +} // namespace diff --git a/tjp/core/string/unprefix.hpp b/tjp/core/string/unprefix.hpp new file mode 100755 index 0000000..4f7b4e0 --- /dev/null +++ b/tjp/core/string/unprefix.hpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "../containers/Optional.hpp" +#include "starts_with.hpp" + +namespace tjp::core { + +inline +Optional unprefix(const std::string_view &s, const std::string_view &prefix) +{ + if (starts_with(s, prefix)) + return s.substr(prefix.size()); + + return {}; +} + +} // namespace diff --git a/tjp/core/system/Debug.h b/tjp/core/system/Debug.h new file mode 100644 index 0000000..f8c231a --- /dev/null +++ b/tjp/core/system/Debug.h @@ -0,0 +1,17 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef _DEBUG + #ifndef DEBUG + #define DEBUG + #endif +#endif + +#ifdef DEBUG + #ifndef _DEBUG + #define _DEBUG + #endif +#endif diff --git a/tjp/core/system/DisableWarningsAllPop.h b/tjp/core/system/DisableWarningsAllPop.h new file mode 100644 index 0000000..1b2a37c --- /dev/null +++ b/tjp/core/system/DisableWarningsAllPop.h @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined COMPILER_LLVM +#pragma GCC diagnostic pop +#endif + +#if defined COMPILER_GCC +#pragma GCC diagnostic pop +#endif + diff --git a/tjp/core/system/DisableWarningsAllPush.h b/tjp/core/system/DisableWarningsAllPush.h new file mode 100644 index 0000000..e8de932 --- /dev/null +++ b/tjp/core/system/DisableWarningsAllPush.h @@ -0,0 +1,16 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "System.h" + +#if defined COMPILER_LLVM +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Weverything" +#endif + +#if defined COMPILER_GCC +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-variable" +#endif + diff --git a/tjp/core/system/DisableWarningsPop.h b/tjp/core/system/DisableWarningsPop.h new file mode 100644 index 0000000..f30f218 --- /dev/null +++ b/tjp/core/system/DisableWarningsPop.h @@ -0,0 +1,14 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined __GNUC__ +#pragma GCC diagnostic pop + +#elif defined __SUNPRO_CC +# pragma enable_warn + +#elif defined _MSC_VER +# pragma warning(pop) + +#endif diff --git a/tjp/core/system/DisableWarningsPush.h b/tjp/core/system/DisableWarningsPush.h new file mode 100644 index 0000000..090b40a --- /dev/null +++ b/tjp/core/system/DisableWarningsPush.h @@ -0,0 +1,28 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#if defined __GNUC__ +#pragma GCC diagnostic push +//#pragma GCC diagnostic ignored "-Wcomma" +//#pragma GCC diagnostic ignored "-Wdocumentation" +//#pragma GCC diagnostic ignored "-Wshorten-64-to-32" +#pragma GCC diagnostic ignored "-Wdeprecated-declarations" +//#pragma GCC diagnostic ignored "-W#pragma-messages" + +#pragma clang diagnostic ignored "-Wcomma" +#pragma clang diagnostic ignored "-Wdocumentation" +#pragma clang diagnostic ignored "-Wshorten-64-to-32" +#pragma clang diagnostic ignored "-Wdeprecated-declarations" +#pragma clang diagnostic ignored "-W#pragma-messages" +#pragma clang diagnostic ignored "-Wdocumentation" + +#elif defined __SUNPRO_CC +# pragma disable_warn + +#elif defined _MSC_VER +//# pragma warning(push, 0) +# pragma warning(push) +# pragma warning(disable : 4800) +//# pragma warning(disable : ...) +#endif diff --git a/tjp/core/system/Optimization.h b/tjp/core/system/Optimization.h new file mode 100644 index 0000000..2232258 --- /dev/null +++ b/tjp/core/system/Optimization.h @@ -0,0 +1,26 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "System.h" + +#ifdef COMPILER_LLVM + #define LLVM_NO_OPTIMIZATION_FUNCTION __attribute__ ((optnone)) +#else + #define LLVM_NO_OPTIMIZATION_FUNCTION +#endif + +#ifdef COMPILER_GCC + #define GCC_NO_OPTIMIZATION_BLOCK_BEGIN \ + #pragma GCC push_options \ + #pragma GCC optimize ("O0") \ + + #define GCC_NO_OPTIMIZATION_BLOCK_END \ + #pragma GCC pop_options +#else + #define GCC_NO_OPTIMIZATION_BLOCK_BEGIN + #define GCC_NO_OPTIMIZATION_BLOCK_END +#endif + diff --git a/tjp/core/system/System.h b/tjp/core/system/System.h new file mode 100644 index 0000000..6ddb9d3 --- /dev/null +++ b/tjp/core/system/System.h @@ -0,0 +1,54 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#if !defined(SYS_LINUX) && !defined(SYS_WINDOWS) && !defined(SYS_IOS) && !defined(SYS_ANDROID) + +#ifdef __llvm__ + #define COMPILER_LLVM +#elif defined __GNUC__ + #define COMPILER_GCC +#endif + +#ifdef _WIN32 + //define something for Windows (32-bit and 64-bit, this part is common) + #ifdef _WIN64 + #define SYS_WINDOWS + //define something for Windows (64-bit only) + #else + #define SYS_WINDOWS + //define something for Windows (32-bit only) + #endif +#elif __APPLE__ + #define SYS_APPLE + + #include "TargetConditionals.h" + #if TARGET_IPHONE_SIMULATOR + #define SYS_IOS + #define SYS_IOS_SIMULATOR + // iOS Simulator + #elif TARGET_OS_IPHONE + #define SYS_IOS + // iOS device + #elif TARGET_OS_MAC + #define SYS_MAC + // Other kinds of Mac OS + #else + # error "Unknown Apple platform" + #endif +#elif __linux__ + #define SYS_LINUX + // linux +#elif __unix__ // all unices not caught above + #define SYS_LINUX + // Unix +#elif defined(_POSIX_VERSION) + #define SYS_LINUX + // POSIX +#else +# error "Unknown system" +#endif + +#endif diff --git a/tjp/core/testing/Defines.h b/tjp/core/testing/Defines.h new file mode 100644 index 0000000..498a1df --- /dev/null +++ b/tjp/core/testing/Defines.h @@ -0,0 +1,11 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "NO_WHEN.h" +#include "TESTING_ONLY.h" +#include "TEST_SIGNAL.h" +#include "wait_until.h" + diff --git a/tjp/core/testing/NO_WHEN.h b/tjp/core/testing/NO_WHEN.h new file mode 100644 index 0000000..96b39ef --- /dev/null +++ b/tjp/core/testing/NO_WHEN.h @@ -0,0 +1,11 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#define NO_WHEN(x) if (false) +#define NO_GIVEN(x) if (false) +#define NO_THEN(x) if (false) +#define NO_SCENARIO(...) static void no_scenario##__COUNTER__ () + diff --git a/tjp/core/testing/TESTING_ONLY.h b/tjp/core/testing/TESTING_ONLY.h new file mode 100644 index 0000000..a3e2948 --- /dev/null +++ b/tjp/core/testing/TESTING_ONLY.h @@ -0,0 +1,12 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef TESTING + #define TESTING_ONLY(...) __VA_ARGS__ +#else + #define TESTING_ONLY(...) +#endif + diff --git a/tjp/core/testing/TEST_SIGNAL.cpp b/tjp/core/testing/TEST_SIGNAL.cpp new file mode 100644 index 0000000..d95d414 --- /dev/null +++ b/tjp/core/testing/TEST_SIGNAL.cpp @@ -0,0 +1,182 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#define TESTING +#include "TEST_SIGNAL.h" + +#include +#include + +#include "../threads/Lock.h" +#include "../timer/Timer.hpp" + +#include "../log/Log.h" +#include "../log/LogOf.h" +#include "../algorithm/starts_with.hpp" +#include "../algorithm/ends_with.hpp" +#include "../assert/debug_assert.h" + + +namespace tjp::core { + +void TestSignal::clear () +{ + auto l = lock_of(mutex); + clear_no_lock(); +} + +void TestSignal::clear_no_lock () +{ + events.clear(); + cleared = true; +} + +std::ostream &TestSignal::print (std::ostream &s) +{ + auto l = lock_of(mutex); + return print_no_lock(s); +} + +std::ostream &TestSignal::print_no_lock (std::ostream &s) +{ + s << "TSE: test events\n"; + for (auto &e : events) + { + s << "TSE: \t" << e.object << "\t" << e.message << std::endl; + } + + return s; +} + +std::ostream &TestSignal::print_clear (std::ostream &s) +{ + auto l = lock_of(mutex); + auto &r = print_no_lock(s); + clear_no_lock(); + + return r; +} + + +void TestSignal::append (Event &&e) +{ + xLogDebug("TESTING_EVENT " << logVar(e.object) << logVar(e.message)); + + auto l = lock_of(mutex); + events.emplace_back(std::move(e)); + signal.notify_all(); +} + +TestSignal::Events::iterator TestSignal::find(const Event &e, Events::iterator i) +{ + if (i == events.end()) + i = events.begin(); + else + ++i; + + bool hasStar = false; + std::string_view search; + if (ends_with(e.message, STAR)) + { + search = { e.message.c_str(), e.message.length() - STAR.length() }; + hasStar = true; + } + + for (; i!=events.end(); ++i) + { + auto &event = *i; + if (e.object == nullptr || e.object == event.object) + { + + if (hasStar) + { + if (starts_with(event.message, search)) + return i; + } + else + if (e.message == event.message) + { + return i; + } + } + } + + return events.end(); +} + +bool TestSignal::waitFor(const Event &e, double time, std::function &&f) +{ + Timer t; + auto l = lock_of(mutex); + auto i = events.end(); + while (t.elapsed() < time) + { + if (cleared) + { + i = events.end(); + cleared = false; + } + + i = find(e, i); + if (i != events.end()) + { + f(i); + return true; + } + else + { + i--; + } + + signal.wait_for(l, std::chrono::milliseconds(int(1000 * time))); + } + + return false; +} + +bool TestSignal::waitForNot(const Event &e, double time, double settleTime) +{ + Timer t; + Timer settleTimer; + auto i = events.end(); + + auto l = lock_of(mutex); + cleared = false; + while (t.elapsed() < time && settleTimer.elapsed() < settleTime) + { + debug_assert(!cleared); + + auto j = find(e, i); + + if (j != events.end()) + { + i = j; + settleTimer.restart(); + } + + auto remainingTime = time - t.elapsed(); + auto waitTime = std::min(remainingTime, settleTime); + signal.wait_for(l, std::chrono::milliseconds(int(1000 * waitTime))); + } + + return t.elapsed() < time; +} + +bool TestSignal::waitFor(const Event &e, double time) +{ + return waitFor(e, time, [](auto &i){}); +} + +bool TestSignal::waitForErase(const Event &e, double time) +{ + return waitFor(e, time, [this](auto &i){ events.erase(i); }); +} + +bool TestSignal::waitForClear(const Event &e, double time) +{ + return waitFor(e, time, [this](auto &i){ events.clear(); }); +} + +} // namespace + diff --git a/tjp/core/testing/TEST_SIGNAL.h b/tjp/core/testing/TEST_SIGNAL.h new file mode 100644 index 0000000..bb2847e --- /dev/null +++ b/tjp/core/testing/TEST_SIGNAL.h @@ -0,0 +1,163 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#ifdef TESTING + +#include "../threads/Lock.hpp" +#include "../timer/Timer.hpp" +#include + +#include +#include + +namespace tjp { +namespace core { + +struct TestSignal +{ + core::Event::Mutex mutex; + core::Event signal; + bool cleared = false; + + struct Event { + void *object; + std::string message; + } ; + + typedef std::list Events; + Events events; + +public: + void clear (); + void clear_no_lock (); + void append (Event &&e); + + const std::string STAR = "*"; + Events::iterator find(const Event &e, Events::iterator i); + + bool waitFor(const Event &e, double time, std::function &&f); + bool waitForNot(const Event &e, double time, double settleTime); + bool waitFor(const Event &e, double time); + bool waitForErase(const Event &e, double time); + bool waitForClear(const Event &e, double time); + + std::ostream &print (std::ostream &s); + std::ostream &print_no_lock (std::ostream &s); + std::ostream &print_clear (std::ostream &s); +} ; + + +template +struct TestSignalSingleton +{ + static TestSignal *singleton; + + static TestSignal *getInstance () + { + if (!singleton) + singleton = new TestSignal(); + + return singleton; + } +} ; + +template +TestSignal *TestSignalSingleton::singleton = nullptr; + + +// ------- + + +template +void process_test_event_string_args(S &s, T &t) +{ + s << t; +} + +template +void process_test_event_string_args(S &s, T &&t, X&&...x) +{ + s << t << ","; + process_test_event_string_args(s, x...); +} + +template +std::string process_test_event_string(T&& ...t) +{ + std::ostringstream s; + process_test_event_string_args(s, t...); + return s.str(); +} + +template +void process_test_event_clear() +{ + TestSignalSingleton::getInstance()->clear (); +} + +template +S &process_test_event_print(S &stream) +{ + return TestSignalSingleton::getInstance()->print (stream); +} + +template +S &process_test_event_print_clear(S &stream) +{ + return TestSignalSingleton::getInstance()->print_clear (stream); +} + +template +void process_test_event(void *v, T&&...t) +{ + TestSignalSingleton::getInstance()->append (TestSignal::Event{ v, process_test_event_string(t...) }); +} + +template +bool wait_test_event(double time, void *v, T&&...t) +{ + return TestSignalSingleton::getInstance()->waitFor(TestSignal::Event{ v, process_test_event_string(t...) }, time); +} + +template +bool wait_test_event_clear(double time, void *v, T&&...t) +{ + return TestSignalSingleton::getInstance()->waitForClear(TestSignal::Event{ v, process_test_event_string(t...) }, time); +} + +template +bool wait_test_event_erase(double time, void *v, T&&...t) +{ + return TestSignalSingleton::getInstance()->waitForErase(TestSignal::Event{ v, process_test_event_string(t...) }, time); +} + +template +bool wait_test_event_settle(double time, double settle, void *v, T&&...t) +{ + return TestSignalSingleton::getInstance()->waitForNot(TestSignal::Event{ v, process_test_event_string(t...) }, time, settle); +} + +} // namespace +} // namespace + +#define TEST_SIGNAL_CLEAR() tjp::core::process_test_event_clear() +#define TEST_SIGNAL_PRINT(stream) tjp::core::process_test_event_print(stream) +#define TEST_SIGNAL_PRINT_CLEAR(stream) tjp::core::process_test_event_print_clear(stream) +#define TEST_SIGNAL(v,...) tjp::core::process_test_event(v,__VA_ARGS__) +#define TEST_WAIT(delay, v, ...) tjp::core::wait_test_event(delay, v, __VA_ARGS__) +#define TEST_WAIT_CLEAR(delay, v, ...) tjp::core::wait_test_event_clear(delay, v, __VA_ARGS__) +#define TEST_WAIT_ERASE(delay, v, ...) tjp::core::wait_test_event_erase(delay, v, __VA_ARGS__) +#define TEST_WAIT_SETTLE(delay, settle, v, ...) tjp::core::wait_test_event_settle(delay, settle, v, __VA_ARGS__) + +#else + +#define TEST_SIGNAL_CLEAR(...) +#define TEST_SIGNAL(...) +#define TEST_WAIT(...) true +#define TEST_WAIT_ERASE(...) true +#define TEST_WAIT_CLEAR(...) true + +#endif diff --git a/tjp/core/testing/THEN_REQUIRE.h b/tjp/core/testing/THEN_REQUIRE.h new file mode 100644 index 0000000..39c1d91 --- /dev/null +++ b/tjp/core/testing/THEN_REQUIRE.h @@ -0,0 +1,8 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#define THEN_REQUIRE(x, ...) THEN(x) { REQUIRE(__VA_ARGS__); } + diff --git a/tjp/core/testing/_tests/TEST_SIGNAL.cpp b/tjp/core/testing/_tests/TEST_SIGNAL.cpp new file mode 100644 index 0000000..a1e5836 --- /dev/null +++ b/tjp/core/testing/_tests/TEST_SIGNAL.cpp @@ -0,0 +1,59 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#ifdef TESTS_WHICH_REQUIRE_LIB + +#define TESTING +#include +#include +#include + +SCENARIO("test signaling", "[core::future]" ) +{ + GIVEN("a signal") + { + TEST_SIGNAL_CLEAR(); + TEST_SIGNAL((void *)1, "hello"); + + WHEN("testing exactly") + { + REQUIRE(TEST_WAIT(1.0, (void *)1, "hello")); + } + + WHEN("testing any same message") + { + REQUIRE(TEST_WAIT(1.0, nullptr, "hello")); + } + + WHEN("testing any message same object") + { + REQUIRE(TEST_WAIT(1.0, (void *)1, "*")); + } + + WHEN("testing any object wrong message") + { + REQUIRE(!TEST_WAIT(0.1, nullptr, "goodbye")); + } + + WHEN("testing any message wrong object") + { + REQUIRE(!TEST_WAIT(0.1, (void *)2, "*")); + } + + WHEN("testing any message and then not") + { + REQUIRE(TEST_WAIT_ERASE(0.1, (void *)nullptr, "hello")); + REQUIRE(!TEST_WAIT_ERASE(0.1, (void *)nullptr, "hello")); + } + + WHEN("testing any message and then not") + { + REQUIRE(TEST_WAIT_CLEAR(0.1, (void *)nullptr, "hello")); + REQUIRE(!TEST_WAIT_ERASE(0.1, (void *)nullptr, "hello")); + } + + } +} + +#endif diff --git a/tjp/core/testing/catch.cpp b/tjp/core/testing/catch.cpp new file mode 100644 index 0000000..b351a48 --- /dev/null +++ b/tjp/core/testing/catch.cpp @@ -0,0 +1,27 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#include "catch2.hpp" + +#include +#include + +int CATCH2_REPEAT_TEST_QUANTITY = 1; + +namespace tjp::core::testing { + +void cleanup(int) +{ + kill(0, SIGKILL); // Kill all processes in the group +} + +void setup_kill_childprocesses_on_exit() +{ + signal(SIGHUP, cleanup); // Handle Xcode stop signal + signal(SIGTERM, cleanup); // Handle Xcode stop signal + setpgid(0, 0); // Set this process as the leader of a new process group +} + +} + diff --git a/tjp/core/testing/catch.hpp b/tjp/core/testing/catch.hpp new file mode 100644 index 0000000..e0f1137 --- /dev/null +++ b/tjp/core/testing/catch.hpp @@ -0,0 +1,21 @@ +// License: Modified MIT (NON-AI) +// See the LICENSE file in the root directory for license information. +// Copyright 2025 Timothy Prepscius + +#pragma once + +#include "catch2.hpp" +#include "../string/to_string.hpp" + +extern int CATCH2_REPEAT_TEST_QUANTITY; + +#define REPEAT_TEST() \ + for (auto i=0; i +# if TARGET_OS_OSX == 1 +# define CATCH_PLATFORM_MAC +# elif TARGET_OS_IPHONE == 1 +# define CATCH_PLATFORM_IPHONE +# endif + +#elif defined(linux) || defined(__linux) || defined(__linux__) +# define CATCH_PLATFORM_LINUX + +#elif defined(WIN32) || defined(__WIN32__) || defined(_WIN32) || defined(_MSC_VER) || defined(__MINGW32__) +# define CATCH_PLATFORM_WINDOWS +#endif + +// end catch_platform.h + +#ifdef CATCH_IMPL +# ifndef CLARA_CONFIG_MAIN +# define CLARA_CONFIG_MAIN_NOT_DEFINED +# define CLARA_CONFIG_MAIN +# endif +#endif + +// start catch_user_interfaces.h + +namespace Catch { + unsigned int rngSeed(); +} + +// end catch_user_interfaces.h +// start catch_tag_alias_autoregistrar.h + +// start catch_common.h + +// start catch_compiler_capabilities.h + +// Detect a number of compiler features - by compiler +// The following features are defined: +// +// CATCH_CONFIG_COUNTER : is the __COUNTER__ macro supported? +// CATCH_CONFIG_WINDOWS_SEH : is Windows SEH supported? +// CATCH_CONFIG_POSIX_SIGNALS : are POSIX signals supported? +// CATCH_CONFIG_DISABLE_EXCEPTIONS : Are exceptions enabled? +// **************** +// Note to maintainers: if new toggles are added please document them +// in configuration.md, too +// **************** + +// In general each macro has a _NO_ form +// (e.g. CATCH_CONFIG_NO_POSIX_SIGNALS) which disables the feature. +// Many features, at point of detection, define an _INTERNAL_ macro, so they +// can be combined, en-mass, with the _NO_ forms later. + +#ifdef __cplusplus + +# if (__cplusplus >= 201402L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201402L) +# define CATCH_CPP14_OR_GREATER +# endif + +# if (__cplusplus >= 201703L) || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L) +# define CATCH_CPP17_OR_GREATER +# endif + +#endif + +#if defined(__cpp_lib_uncaught_exceptions) +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +// We have to avoid both ICC and Clang, because they try to mask themselves +// as gcc, and we want only GCC in this block +#if defined(__GNUC__) && !defined(__clang__) && !defined(__ICC) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "GCC diagnostic pop" ) + +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) + +#endif + +#if defined(__clang__) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic push" ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION _Pragma( "clang diagnostic pop" ) + +// As of this writing, IBM XL's implementation of __builtin_constant_p has a bug +// which results in calls to destructors being emitted for each temporary, +// without a matching initialization. In practice, this can result in something +// like `std::string::~string` being called on an uninitialized value. +// +// For example, this code will likely segfault under IBM XL: +// ``` +// REQUIRE(std::string("12") + "34" == "1234") +// ``` +// +// Therefore, `CATCH_INTERNAL_IGNORE_BUT_WARN` is not implemented. +# if !defined(__ibmxl__) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) (void)__builtin_constant_p(__VA_ARGS__) /* NOLINT(cppcoreguidelines-pro-type-vararg, hicpp-vararg) */ +# endif + +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wexit-time-destructors\"" ) \ + _Pragma( "clang diagnostic ignored \"-Wglobal-constructors\"") + +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wparentheses\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-variable\"" ) + +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wgnu-zero-variadic-macro-arguments\"" ) + +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS \ + _Pragma( "clang diagnostic ignored \"-Wunused-template\"" ) + +#endif // __clang__ + +//////////////////////////////////////////////////////////////////////////////// +// Assume that non-Windows platforms support posix signals by default +#if !defined(CATCH_PLATFORM_WINDOWS) + #define CATCH_INTERNAL_CONFIG_POSIX_SIGNALS +#endif + +//////////////////////////////////////////////////////////////////////////////// +// We know some environments not to support full POSIX signals +#if defined(__CYGWIN__) || defined(__QNX__) || defined(__EMSCRIPTEN__) || defined(__DJGPP__) + #define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +#endif + +#ifdef __OS400__ +# define CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS +# define CATCH_CONFIG_COLOUR_NONE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Android somehow still does not support std::to_string +#if defined(__ANDROID__) +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING +# define CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Not all Windows environments support SEH properly +#if defined(__MINGW32__) +# define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH +#endif + +//////////////////////////////////////////////////////////////////////////////// +// PS4 +#if defined(__ORBIS__) +# define CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE +#endif + +//////////////////////////////////////////////////////////////////////////////// +// Cygwin +#ifdef __CYGWIN__ + +// Required for some versions of Cygwin to declare gettimeofday +// see: http://stackoverflow.com/questions/36901803/gettimeofday-not-declared-in-this-scope-cygwin +# define _BSD_SOURCE +// some versions of cygwin (most) do not support std::to_string. Use the libstd check. +// https://gcc.gnu.org/onlinedocs/gcc-4.8.2/libstdc++/api/a01053_source.html line 2812-2813 +# if !((__cplusplus >= 201103L) && defined(_GLIBCXX_USE_C99) \ + && !defined(_GLIBCXX_HAVE_BROKEN_VSWPRINTF)) + +# define CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING + +# endif +#endif // __CYGWIN__ + +//////////////////////////////////////////////////////////////////////////////// +// Visual C++ +#if defined(_MSC_VER) + +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION __pragma( warning(push) ) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION __pragma( warning(pop) ) + +# if _MSC_VER >= 1900 // Visual Studio 2015 or newer +# define CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +# endif + +// Universal Windows platform does not support SEH +// Or console colours (or console at all...) +# if defined(WINAPI_FAMILY) && (WINAPI_FAMILY == WINAPI_FAMILY_APP) +# define CATCH_CONFIG_COLOUR_NONE +# else +# define CATCH_INTERNAL_CONFIG_WINDOWS_SEH +# endif + +// MSVC traditional preprocessor needs some workaround for __VA_ARGS__ +// _MSVC_TRADITIONAL == 0 means new conformant preprocessor +// _MSVC_TRADITIONAL == 1 means old traditional non-conformant preprocessor +# if !defined(__clang__) // Handle Clang masquerading for msvc +# if !defined(_MSVC_TRADITIONAL) || (defined(_MSVC_TRADITIONAL) && _MSVC_TRADITIONAL) +# define CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +# endif // MSVC_TRADITIONAL +# endif // __clang__ + +#endif // _MSC_VER + +#if defined(_REENTRANT) || defined(_MSC_VER) +// Enable async processing, as -pthread is specified or no additional linking is required +# define CATCH_INTERNAL_CONFIG_USE_ASYNC +#endif // _MSC_VER + +//////////////////////////////////////////////////////////////////////////////// +// Check if we are compiled with -fno-exceptions or equivalent +#if defined(__EXCEPTIONS) || defined(__cpp_exceptions) || defined(_CPPUNWIND) +# define CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED +#endif + +//////////////////////////////////////////////////////////////////////////////// +// DJGPP +#ifdef __DJGPP__ +# define CATCH_INTERNAL_CONFIG_NO_WCHAR +#endif // __DJGPP__ + +//////////////////////////////////////////////////////////////////////////////// +// Embarcadero C++Build +#if defined(__BORLANDC__) + #define CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// Use of __COUNTER__ is suppressed during code analysis in +// CLion/AppCode 2017.2.x and former, because __COUNTER__ is not properly +// handled by it. +// Otherwise all supported compilers support COUNTER macro, +// but user still might want to turn it off +#if ( !defined(__JETBRAINS_IDE__) || __JETBRAINS_IDE__ >= 20170300L ) + #define CATCH_INTERNAL_CONFIG_COUNTER +#endif + +//////////////////////////////////////////////////////////////////////////////// + +// RTX is a special version of Windows that is real time. +// This means that it is detected as Windows, but does not provide +// the same set of capabilities as real Windows does. +#if defined(UNDER_RTSS) || defined(RTX64_BUILD) + #define CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH + #define CATCH_INTERNAL_CONFIG_NO_ASYNC + #define CATCH_CONFIG_COLOUR_NONE +#endif + +#if !defined(_GLIBCXX_USE_C99_MATH_TR1) +#define CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Various stdlib support checks that require __has_include +#if defined(__has_include) + // Check if string_view is available and usable + #if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW + #endif + + // Check if optional is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # define CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if byte is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # include + # if __cpp_lib_byte > 0 + # define CATCH_INTERNAL_CONFIG_CPP17_BYTE + # endif + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) + + // Check if variant is available and usable + # if __has_include() && defined(CATCH_CPP17_OR_GREATER) + # if defined(__clang__) && (__clang_major__ < 8) + // work around clang bug with libstdc++ https://bugs.llvm.org/show_bug.cgi?id=31852 + // fix should be in clang 8, workaround in libstdc++ 8.2 + # include + # if defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # define CATCH_CONFIG_NO_CPP17_VARIANT + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__GLIBCXX__) && defined(_GLIBCXX_RELEASE) && (_GLIBCXX_RELEASE < 9) + # else + # define CATCH_INTERNAL_CONFIG_CPP17_VARIANT + # endif // defined(__clang__) && (__clang_major__ < 8) + # endif // __has_include() && defined(CATCH_CPP17_OR_GREATER) +#endif // defined(__has_include) + +#if defined(CATCH_INTERNAL_CONFIG_COUNTER) && !defined(CATCH_CONFIG_NO_COUNTER) && !defined(CATCH_CONFIG_COUNTER) +# define CATCH_CONFIG_COUNTER +#endif +#if defined(CATCH_INTERNAL_CONFIG_WINDOWS_SEH) && !defined(CATCH_CONFIG_NO_WINDOWS_SEH) && !defined(CATCH_CONFIG_WINDOWS_SEH) && !defined(CATCH_INTERNAL_CONFIG_NO_WINDOWS_SEH) +# define CATCH_CONFIG_WINDOWS_SEH +#endif +// This is set by default, because we assume that unix compilers are posix-signal-compatible by default. +#if defined(CATCH_INTERNAL_CONFIG_POSIX_SIGNALS) && !defined(CATCH_INTERNAL_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_NO_POSIX_SIGNALS) && !defined(CATCH_CONFIG_POSIX_SIGNALS) +# define CATCH_CONFIG_POSIX_SIGNALS +#endif +// This is set by default, because we assume that compilers with no wchar_t support are just rare exceptions. +#if !defined(CATCH_INTERNAL_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_NO_WCHAR) && !defined(CATCH_CONFIG_WCHAR) +# define CATCH_CONFIG_WCHAR +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_NO_CPP11_TO_STRING) && !defined(CATCH_CONFIG_CPP11_TO_STRING) +# define CATCH_CONFIG_CPP11_TO_STRING +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_NO_CPP17_OPTIONAL) && !defined(CATCH_CONFIG_CPP17_OPTIONAL) +# define CATCH_CONFIG_CPP17_OPTIONAL +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_NO_CPP17_UNCAUGHT_EXCEPTIONS) && !defined(CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS) +# define CATCH_CONFIG_CPP17_UNCAUGHT_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_NO_CPP17_STRING_VIEW) && !defined(CATCH_CONFIG_CPP17_STRING_VIEW) +# define CATCH_CONFIG_CPP17_STRING_VIEW +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_VARIANT) && !defined(CATCH_CONFIG_NO_CPP17_VARIANT) && !defined(CATCH_CONFIG_CPP17_VARIANT) +# define CATCH_CONFIG_CPP17_VARIANT +#endif + +#if defined(CATCH_INTERNAL_CONFIG_CPP17_BYTE) && !defined(CATCH_CONFIG_NO_CPP17_BYTE) && !defined(CATCH_CONFIG_CPP17_BYTE) +# define CATCH_CONFIG_CPP17_BYTE +#endif + +#if defined(CATCH_CONFIG_EXPERIMENTAL_REDIRECT) +# define CATCH_INTERNAL_CONFIG_NEW_CAPTURE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_NEW_CAPTURE) && !defined(CATCH_INTERNAL_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NO_NEW_CAPTURE) && !defined(CATCH_CONFIG_NEW_CAPTURE) +# define CATCH_CONFIG_NEW_CAPTURE +#endif + +#if !defined(CATCH_INTERNAL_CONFIG_EXCEPTIONS_ENABLED) && !defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +# define CATCH_CONFIG_DISABLE_EXCEPTIONS +#endif + +#if defined(CATCH_INTERNAL_CONFIG_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_NO_POLYFILL_ISNAN) && !defined(CATCH_CONFIG_POLYFILL_ISNAN) +# define CATCH_CONFIG_POLYFILL_ISNAN +#endif + +#if defined(CATCH_INTERNAL_CONFIG_USE_ASYNC) && !defined(CATCH_INTERNAL_CONFIG_NO_ASYNC) && !defined(CATCH_CONFIG_NO_USE_ASYNC) && !defined(CATCH_CONFIG_USE_ASYNC) +# define CATCH_CONFIG_USE_ASYNC +#endif + +#if defined(CATCH_INTERNAL_CONFIG_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_NO_ANDROID_LOGWRITE) && !defined(CATCH_CONFIG_ANDROID_LOGWRITE) +# define CATCH_CONFIG_ANDROID_LOGWRITE +#endif + +#if defined(CATCH_INTERNAL_CONFIG_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_NO_GLOBAL_NEXTAFTER) && !defined(CATCH_CONFIG_GLOBAL_NEXTAFTER) +# define CATCH_CONFIG_GLOBAL_NEXTAFTER +#endif + +// Even if we do not think the compiler has that warning, we still have +// to provide a macro that can be used by the code. +#if !defined(CATCH_INTERNAL_START_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_START_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION) +# define CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_PARENTHESES_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_WARNINGS +#endif +#if !defined(CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_ZERO_VARIADIC_WARNINGS +#endif + +// The goal of this macro is to avoid evaluation of the arguments, but +// still have the compiler warn on problems inside... +#if !defined(CATCH_INTERNAL_IGNORE_BUT_WARN) +# define CATCH_INTERNAL_IGNORE_BUT_WARN(...) +#endif + +#if defined(__APPLE__) && defined(__apple_build_version__) && (__clang_major__ < 10) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#elif defined(__clang__) && (__clang_major__ < 5) +# undef CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if !defined(CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS) +# define CATCH_INTERNAL_SUPPRESS_UNUSED_TEMPLATE_WARNINGS +#endif + +#if defined(CATCH_CONFIG_DISABLE_EXCEPTIONS) +#define CATCH_TRY if ((true)) +#define CATCH_CATCH_ALL if ((false)) +#define CATCH_CATCH_ANON(type) if ((false)) +#else +#define CATCH_TRY try +#define CATCH_CATCH_ALL catch (...) +#define CATCH_CATCH_ANON(type) catch (type) +#endif + +#if defined(CATCH_INTERNAL_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_NO_TRADITIONAL_MSVC_PREPROCESSOR) && !defined(CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR) +#define CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#endif + +// end catch_compiler_capabilities.h +#define INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) name##line +#define INTERNAL_CATCH_UNIQUE_NAME_LINE( name, line ) INTERNAL_CATCH_UNIQUE_NAME_LINE2( name, line ) +#ifdef CATCH_CONFIG_COUNTER +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __COUNTER__ ) +#else +# define INTERNAL_CATCH_UNIQUE_NAME( name ) INTERNAL_CATCH_UNIQUE_NAME_LINE( name, __LINE__ ) +#endif + +#include +#include +#include + +// We need a dummy global operator<< so we can bring it into Catch namespace later +struct Catch_global_namespace_dummy {}; +std::ostream& operator<<(std::ostream&, Catch_global_namespace_dummy); + +namespace Catch { + + struct CaseSensitive { enum Choice { + Yes, + No + }; }; + + class NonCopyable { + NonCopyable( NonCopyable const& ) = delete; + NonCopyable( NonCopyable && ) = delete; + NonCopyable& operator = ( NonCopyable const& ) = delete; + NonCopyable& operator = ( NonCopyable && ) = delete; + + protected: + NonCopyable(); + virtual ~NonCopyable(); + }; + + struct SourceLineInfo { + + SourceLineInfo() = delete; + SourceLineInfo( char const* _file, std::size_t _line ) noexcept + : file( _file ), + line( _line ) + {} + + SourceLineInfo( SourceLineInfo const& other ) = default; + SourceLineInfo& operator = ( SourceLineInfo const& ) = default; + SourceLineInfo( SourceLineInfo&& ) noexcept = default; + SourceLineInfo& operator = ( SourceLineInfo&& ) noexcept = default; + + bool empty() const noexcept { return file[0] == '\0'; } + bool operator == ( SourceLineInfo const& other ) const noexcept; + bool operator < ( SourceLineInfo const& other ) const noexcept; + + char const* file; + std::size_t line; + }; + + std::ostream& operator << ( std::ostream& os, SourceLineInfo const& info ); + + // Bring in operator<< from global namespace into Catch namespace + // This is necessary because the overload of operator<< above makes + // lookup stop at namespace Catch + using ::operator<<; + + // Use this in variadic streaming macros to allow + // >> +StreamEndStop + // as well as + // >> stuff +StreamEndStop + struct StreamEndStop { + std::string operator+() const; + }; + template + T const& operator + ( T const& value, StreamEndStop ) { + return value; + } +} + +#define CATCH_INTERNAL_LINEINFO \ + ::Catch::SourceLineInfo( __FILE__, static_cast( __LINE__ ) ) + +// end catch_common.h +namespace Catch { + + struct RegistrarForTagAliases { + RegistrarForTagAliases( char const* alias, char const* tag, SourceLineInfo const& lineInfo ); + }; + +} // end namespace Catch + +#define CATCH_REGISTER_TAG_ALIAS( alias, spec ) \ + CATCH_INTERNAL_START_WARNINGS_SUPPRESSION \ + CATCH_INTERNAL_SUPPRESS_GLOBALS_WARNINGS \ + namespace{ Catch::RegistrarForTagAliases INTERNAL_CATCH_UNIQUE_NAME( AutoRegisterTagAlias )( alias, spec, CATCH_INTERNAL_LINEINFO ); } \ + CATCH_INTERNAL_STOP_WARNINGS_SUPPRESSION + +// end catch_tag_alias_autoregistrar.h +// start catch_test_registry.h + +// start catch_interfaces_testcase.h + +#include + +namespace Catch { + + class TestSpec; + + struct ITestInvoker { + virtual void invoke () const = 0; + virtual ~ITestInvoker(); + }; + + class TestCase; + struct IConfig; + + struct ITestCaseRegistry { + virtual ~ITestCaseRegistry(); + virtual std::vector const& getAllTests() const = 0; + virtual std::vector const& getAllTestsSorted( IConfig const& config ) const = 0; + }; + + bool isThrowSafe( TestCase const& testCase, IConfig const& config ); + bool matchTest( TestCase const& testCase, TestSpec const& testSpec, IConfig const& config ); + std::vector filterTests( std::vector const& testCases, TestSpec const& testSpec, IConfig const& config ); + std::vector const& getAllTestCasesSorted( IConfig const& config ); + +} + +// end catch_interfaces_testcase.h +// start catch_stringref.h + +#include +#include +#include +#include + +namespace Catch { + + /// A non-owning string class (similar to the forthcoming std::string_view) + /// Note that, because a StringRef may be a substring of another string, + /// it may not be null terminated. + class StringRef { + public: + using size_type = std::size_t; + using const_iterator = const char*; + + private: + static constexpr char const* const s_empty = ""; + + char const* m_start = s_empty; + size_type m_size = 0; + + public: // construction + constexpr StringRef() noexcept = default; + + StringRef( char const* rawChars ) noexcept; + + constexpr StringRef( char const* rawChars, size_type size ) noexcept + : m_start( rawChars ), + m_size( size ) + {} + + StringRef( std::string const& stdString ) noexcept + : m_start( stdString.c_str() ), + m_size( stdString.size() ) + {} + + explicit operator std::string() const { + return std::string(m_start, m_size); + } + + public: // operators + auto operator == ( StringRef const& other ) const noexcept -> bool; + auto operator != (StringRef const& other) const noexcept -> bool { + return !(*this == other); + } + + auto operator[] ( size_type index ) const noexcept -> char { + assert(index < m_size); + return m_start[index]; + } + + public: // named queries + constexpr auto empty() const noexcept -> bool { + return m_size == 0; + } + constexpr auto size() const noexcept -> size_type { + return m_size; + } + + // Returns the current start pointer. If the StringRef is not + // null-terminated, throws std::domain_exception + auto c_str() const -> char const*; + + public: // substrings and searches + // Returns a substring of [start, start + length). + // If start + length > size(), then the substring is [start, size()). + // If start > size(), then the substring is empty. + auto substr( size_type start, size_type length ) const noexcept -> StringRef; + + // Returns the current start pointer. May not be null-terminated. + auto data() const noexcept -> char const*; + + constexpr auto isNullTerminated() const noexcept -> bool { + return m_start[m_size] == '\0'; + } + + public: // iterators + constexpr const_iterator begin() const { return m_start; } + constexpr const_iterator end() const { return m_start + m_size; } + }; + + auto operator += ( std::string& lhs, StringRef const& sr ) -> std::string&; + auto operator << ( std::ostream& os, StringRef const& sr ) -> std::ostream&; + + constexpr auto operator "" _sr( char const* rawChars, std::size_t size ) noexcept -> StringRef { + return StringRef( rawChars, size ); + } +} // namespace Catch + +constexpr auto operator "" _catch_sr( char const* rawChars, std::size_t size ) noexcept -> Catch::StringRef { + return Catch::StringRef( rawChars, size ); +} + +// end catch_stringref.h +// start catch_preprocessor.hpp + + +#define CATCH_RECURSION_LEVEL0(...) __VA_ARGS__ +#define CATCH_RECURSION_LEVEL1(...) CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(CATCH_RECURSION_LEVEL0(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL2(...) CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(CATCH_RECURSION_LEVEL1(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL3(...) CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(CATCH_RECURSION_LEVEL2(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL4(...) CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(CATCH_RECURSION_LEVEL3(__VA_ARGS__))) +#define CATCH_RECURSION_LEVEL5(...) CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(CATCH_RECURSION_LEVEL4(__VA_ARGS__))) + +#ifdef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_EXPAND_VARGS(...) __VA_ARGS__ +// MSVC needs more evaluations +#define CATCH_RECURSION_LEVEL6(...) CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(CATCH_RECURSION_LEVEL5(__VA_ARGS__))) +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL6(CATCH_RECURSION_LEVEL6(__VA_ARGS__)) +#else +#define CATCH_RECURSE(...) CATCH_RECURSION_LEVEL5(__VA_ARGS__) +#endif + +#define CATCH_REC_END(...) +#define CATCH_REC_OUT + +#define CATCH_EMPTY() +#define CATCH_DEFER(id) id CATCH_EMPTY() + +#define CATCH_REC_GET_END2() 0, CATCH_REC_END +#define CATCH_REC_GET_END1(...) CATCH_REC_GET_END2 +#define CATCH_REC_GET_END(...) CATCH_REC_GET_END1 +#define CATCH_REC_NEXT0(test, next, ...) next CATCH_REC_OUT +#define CATCH_REC_NEXT1(test, next) CATCH_DEFER ( CATCH_REC_NEXT0 ) ( test, next, 0) +#define CATCH_REC_NEXT(test, next) CATCH_REC_NEXT1(CATCH_REC_GET_END test, next) + +#define CATCH_REC_LIST0(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1(f, x, peek, ...) , f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0) ) ( f, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2(f, x, peek, ...) f(x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1) ) ( f, peek, __VA_ARGS__ ) + +#define CATCH_REC_LIST0_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST1_UD(f, userdata, x, peek, ...) , f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST0_UD) ) ( f, userdata, peek, __VA_ARGS__ ) +#define CATCH_REC_LIST2_UD(f, userdata, x, peek, ...) f(userdata, x) CATCH_DEFER ( CATCH_REC_NEXT(peek, CATCH_REC_LIST1_UD) ) ( f, userdata, peek, __VA_ARGS__ ) + +// Applies the function macro `f` to each of the remaining parameters, inserts commas between the results, +// and passes userdata as the first parameter to each invocation, +// e.g. CATCH_REC_LIST_UD(f, x, a, b, c) evaluates to f(x, a), f(x, b), f(x, c) +#define CATCH_REC_LIST_UD(f, userdata, ...) CATCH_RECURSE(CATCH_REC_LIST2_UD(f, userdata, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define CATCH_REC_LIST(f, ...) CATCH_RECURSE(CATCH_REC_LIST2(f, __VA_ARGS__, ()()(), ()()(), ()()(), 0)) + +#define INTERNAL_CATCH_EXPAND1(param) INTERNAL_CATCH_EXPAND2(param) +#define INTERNAL_CATCH_EXPAND2(...) INTERNAL_CATCH_NO## __VA_ARGS__ +#define INTERNAL_CATCH_DEF(...) INTERNAL_CATCH_DEF __VA_ARGS__ +#define INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE(...) INTERNAL_CATCH_STRINGIZE2(__VA_ARGS__) +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_STRINGIZE2(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) +#else +// MSVC is adding extra space and needs another indirection to expand INTERNAL_CATCH_NOINTERNAL_CATCH_DEF +#define INTERNAL_CATCH_STRINGIZE2(...) INTERNAL_CATCH_STRINGIZE3(__VA_ARGS__) +#define INTERNAL_CATCH_STRINGIZE3(...) #__VA_ARGS__ +#define INTERNAL_CATCH_STRINGIZE_WITHOUT_PARENS(param) (INTERNAL_CATCH_STRINGIZE(INTERNAL_CATCH_REMOVE_PARENS(param)) + 1) +#endif + +#define INTERNAL_CATCH_MAKE_NAMESPACE2(...) ns_##__VA_ARGS__ +#define INTERNAL_CATCH_MAKE_NAMESPACE(name) INTERNAL_CATCH_MAKE_NAMESPACE2(name) + +#define INTERNAL_CATCH_REMOVE_PARENS(...) INTERNAL_CATCH_EXPAND1(INTERNAL_CATCH_DEF __VA_ARGS__) + +#ifndef CATCH_CONFIG_TRADITIONAL_MSVC_PREPROCESSOR +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) decltype(get_wrapper()) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__)) +#else +#define INTERNAL_CATCH_MAKE_TYPE_LIST2(...) INTERNAL_CATCH_EXPAND_VARGS(decltype(get_wrapper())) +#define INTERNAL_CATCH_MAKE_TYPE_LIST(...) INTERNAL_CATCH_EXPAND_VARGS(INTERNAL_CATCH_MAKE_TYPE_LIST2(INTERNAL_CATCH_REMOVE_PARENS(__VA_ARGS__))) +#endif + +#define INTERNAL_CATCH_MAKE_TYPE_LISTS_FROM_TYPES(...)\ + CATCH_REC_LIST(INTERNAL_CATCH_MAKE_TYPE_LIST,__VA_ARGS__) + +#define INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_0) INTERNAL_CATCH_REMOVE_PARENS(_0) +#define INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_0, _1) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_1_ARG(_1) +#define INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_0, _1, _2) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_2_ARG(_1, _2) +#define INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_0, _1, _2, _3) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_3_ARG(_1, _2, _3) +#define INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_0, _1, _2, _3, _4) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_4_ARG(_1, _2, _3, _4) +#define INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_0, _1, _2, _3, _4, _5) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_5_ARG(_1, _2, _3, _4, _5) +#define INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_0, _1, _2, _3, _4, _5, _6) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_6_ARG(_1, _2, _3, _4, _5, _6) +#define INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_0, _1, _2, _3, _4, _5, _6, _7) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_7_ARG(_1, _2, _3, _4, _5, _6, _7) +#define INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_8_ARG(_1, _2, _3, _4, _5, _6, _7, _8) +#define INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_9_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9) +#define INTERNAL_CATCH_REMOVE_PARENS_11_ARG(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10) INTERNAL_CATCH_REMOVE_PARENS(_0), INTERNAL_CATCH_REMOVE_PARENS_10_ARG(_1, _2, _3, _4, _5, _6, _7, _8, _9, _10) + +#define INTERNAL_CATCH_VA_NARGS_IMPL(_0, _1, _2, _3, _4, _5, _6, _7, _8, _9, _10, N, ...) N + +#define INTERNAL_CATCH_TYPE_GEN\ + template struct TypeList {};\ + template\ + constexpr auto get_wrapper() noexcept -> TypeList { return {}; }\ + template class...> struct TemplateTypeList{};\ + template class...Cs>\ + constexpr auto get_wrapper() noexcept -> TemplateTypeList { return {}; }\ + template\ + struct append;\ + template\ + struct rewrap;\ + template class, typename...>\ + struct create;\ + template class, typename>\ + struct convert;\ + \ + template \ + struct append { using type = T; };\ + template< template class L1, typename...E1, template class L2, typename...E2, typename...Rest>\ + struct append, L2, Rest...> { using type = typename append, Rest...>::type; };\ + template< template class L1, typename...E1, typename...Rest>\ + struct append, TypeList, Rest...> { using type = L1; };\ + \ + template< template class Container, template class List, typename...elems>\ + struct rewrap, List> { using type = TypeList>; };\ + template< template class Container, template class List, class...Elems, typename...Elements>\ + struct rewrap, List, Elements...> { using type = typename append>, typename rewrap, Elements...>::type>::type; };\ + \ + template