diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 833ec336..849882e7 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -38,7 +38,9 @@ jobs: cmake_args: "-DCMAKE_CXX_FLAGS=-m64" - os: windows-latest arch: x86 - cmake_args: "-G \"Visual Studio 17 2022\" -A Win32" + # /arch:IA32 means these are builds without SIMD, due to really bad compiler ICEs + # see https://github.com/Langulus/SIMD/issues/22 for more info and updates on the situation + cmake_args: "-G \"Visual Studio 17 2022\" -A Win32 -DCMAKE_CXX_FLAGS=\"/arch:IA32\"" - os: windows-latest arch: x64 cmake_args: "-G \"Visual Studio 17 2022\" -A x64" diff --git a/CMakeLists.txt b/CMakeLists.txt index e020cdda..7ef6b684 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -5,21 +5,17 @@ project(LangulusAnyness HOMEPAGE_URL https://langulus.com ) -# Check if this project is built as standalone, or a part of something else -if(PROJECT_IS_TOP_LEVEL OR NOT LANGULUS) +# Check if this project is built as standalone, or a part of something else +if (PROJECT_IS_TOP_LEVEL OR NOT LANGULUS) set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin) - include(LangulusUtilities.cmake) - # Add Langulus::Core/Logger/RTTI/Fractalloc/SIMD libraries - fetch_langulus_module(Core GIT_TAG 35756f11d2f9c475f27b094b8d4c82cd453969fc) - fetch_langulus_module(Logger GIT_TAG dafbeb825071ec60d8403254143f75606151a7e6) - fetch_langulus_module(RTTI GIT_TAG fc49750884ac943dff4261ac5b8dfb2c148423d7) + fetch_langulus_module(RTTI GIT_TAG af0c2f6bf25d0436caf098b354350c7b681d1036) if(LANGULUS_FEATURE_MANAGED_MEMORY) - fetch_langulus_module(Fractalloc GIT_TAG 66408e8557b1bb3c80615909129342bcebd3fb9f) + fetch_langulus_module(Fractalloc GIT_TAG cbb71d9b33c741e8856e8522632559b3082a39e9) endif() - fetch_langulus_module(SIMD GIT_TAG ead5493049e2800b4c3c02d385c0c6314efac69c) + fetch_langulus_module(SIMD GIT_TAG 1238344af641de5d2fbe82e6a1743b041d996c52) endif() file(GLOB_RECURSE @@ -28,18 +24,21 @@ file(GLOB_RECURSE source/*.cpp ) -# Build and install Anyness library +# Build and install Anyness library add_langulus_library(LangulusAnyness $ $ $<$:$> + $<$:$> ${LANGULUS_ANYNESS_SOURCES} ) -target_include_directories(LangulusAnyness PUBLIC include - $ - $ - $<$:$> +target_include_directories(LangulusAnyness + PUBLIC $ + $ + $<$:$> + $<$:$> + include ) target_link_libraries(LangulusAnyness @@ -52,6 +51,6 @@ target_compile_definitions(LangulusAnyness ) if(LANGULUS_TESTING) - enable_testing() + enable_testing() add_subdirectory(test) endif() \ No newline at end of file diff --git a/LangulusUtilities.cmake b/LangulusUtilities.cmake index 5d13ec09..e7eb7639 100644 --- a/LangulusUtilities.cmake +++ b/LangulusUtilities.cmake @@ -1,13 +1,33 @@ include(FetchContent) + +# Utility for fetching Langulus libraries using FetchContent function(fetch_langulus_module NAME GIT_TAG TAG) + if (LANGULUS) + message(FATAL_ERROR "You can't fetch Langulus::${NAME}, because this build \ + indicates LANGULUS is being build along your project. The library you're \ + trying to fetch should already be available locally.") + endif() + if(NOT DEFINED LANGULUS_EXTERNAL_DIRECTORY) set(LANGULUS_EXTERNAL_DIRECTORY "${CMAKE_SOURCE_DIR}/external" CACHE PATH "Place where external dependencies will be downloaded") - message(WARNING "LANGULUS_EXTERNAL_DIRECTORY not defined, using default: ${LANGULUS_EXTERNAL_DIRECTORY}") + message(WARNING "LANGULUS_EXTERNAL_DIRECTORY not defined, using default: \ + ${LANGULUS_EXTERNAL_DIRECTORY}") endif() - message(STATUS "Fetching external Langulus::${NAME}...") + # Completely avoid downloading or updating anything, once the appropriate + # folder exists + string(TOUPPER ${NAME} UPPERCASE_NAME) + if (EXISTS "${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src") + set(FETCHCONTENT_SOURCE_DIR_LANGULUS${UPPERCASE_NAME} "${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src" CACHE INTERNAL "" FORCE) + message(STATUS "Reusing external library Langulus::${NAME}... \ + (delete ${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src manually in order to redownload)") + else() + unset(FETCHCONTENT_SOURCE_DIR_LANGULUS${UPPERCASE_NAME} CACHE) + message(STATUS "Downloading external library Langulus::${NAME}...") + endif() + FetchContent_Declare( Langulus${NAME} GIT_REPOSITORY https://github.com/Langulus/${NAME}.git @@ -19,14 +39,28 @@ function(fetch_langulus_module NAME GIT_TAG TAG) FetchContent_MakeAvailable(Langulus${NAME}) endfunction() + +# Utility for fetching external libraries using FetchContent function(fetch_external_module NAME GIT_REPOSITORY REPO GIT_TAG TAG) if(NOT DEFINED LANGULUS_EXTERNAL_DIRECTORY) set(LANGULUS_EXTERNAL_DIRECTORY "${CMAKE_SOURCE_DIR}/external" CACHE PATH "Place where external dependencies will be downloaded") - message(WARNING "LANGULUS_EXTERNAL_DIRECTORY not defined, using default: ${LANGULUS_EXTERNAL_DIRECTORY}") + message(WARNING "LANGULUS_EXTERNAL_DIRECTORY not defined, \ + using default: ${LANGULUS_EXTERNAL_DIRECTORY}") endif() - message(STATUS "Fetching external library ${NAME}...") + # Completely avoid downloading or updating anything, once the appropriate + # folder exists + string(TOUPPER ${NAME} UPPERCASE_NAME) + if (EXISTS "${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src") + set(FETCHCONTENT_SOURCE_DIR_${UPPERCASE_NAME} "${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src" CACHE INTERNAL "" FORCE) + message(STATUS "Reusing external library ${NAME}... \ + (delete ${LANGULUS_EXTERNAL_DIRECTORY}/${NAME}-src manually in order to redownload)") + else() + unset(FETCHCONTENT_SOURCE_DIR_${UPPERCASE_NAME} CACHE) + message(STATUS "Downloading external library ${NAME}...") + endif() + FetchContent_Declare( ${NAME} GIT_REPOSITORY ${REPO} @@ -41,4 +75,4 @@ function(fetch_external_module NAME GIT_REPOSITORY REPO GIT_TAG TAG) string(TOLOWER ${NAME} LOWERCASE_NAME) set(${NAME}_SOURCE_DIR "${${LOWERCASE_NAME}_SOURCE_DIR}" CACHE INTERNAL "${NAME} source directory") set(${NAME}_BINARY_DIR "${${LOWERCASE_NAME}_BINARY_DIR}" CACHE INTERNAL "${NAME} binary directory") -endfunction() \ No newline at end of file +endfunction() diff --git a/include/Anyness/Bytes.hpp b/include/Langulus/Anyness/Bytes.hpp similarity index 80% rename from include/Anyness/Bytes.hpp rename to include/Langulus/Anyness/Bytes.hpp index 8d93b8e9..234ca1a5 100644 --- a/include/Anyness/Bytes.hpp +++ b/include/Langulus/Anyness/Bytes.hpp @@ -6,6 +6,6 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/TMany.inl" -#include "../../source/many/Bytes.inl" -#include "../../source/maps/TMap.inl" \ No newline at end of file +#include "../../../source/many/TMany.inl" +#include "../../../source/many/Bytes.inl" +#include "../../../source/maps/TMap.inl" \ No newline at end of file diff --git a/include/Anyness/Construct.hpp b/include/Langulus/Anyness/Construct.hpp similarity index 86% rename from include/Anyness/Construct.hpp rename to include/Langulus/Anyness/Construct.hpp index 426c3754..3910f9b0 100644 --- a/include/Anyness/Construct.hpp +++ b/include/Langulus/Anyness/Construct.hpp @@ -6,5 +6,5 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/Construct.inl" -#include "../../source/text/Text.inl" +#include "../../../source/many/Construct.inl" +#include "../../../source/text/Text.inl" diff --git a/include/Anyness/Edit.hpp b/include/Langulus/Anyness/Edit.hpp similarity index 92% rename from include/Anyness/Edit.hpp rename to include/Langulus/Anyness/Edit.hpp index 35d21134..419376a7 100644 --- a/include/Anyness/Edit.hpp +++ b/include/Langulus/Anyness/Edit.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/TEdit.inl" +#include "../../../source/TEdit.inl" diff --git a/include/Anyness/Many.hpp b/include/Langulus/Anyness/Many.hpp similarity index 61% rename from include/Anyness/Many.hpp rename to include/Langulus/Anyness/Many.hpp index c99028fa..483979d7 100644 --- a/include/Anyness/Many.hpp +++ b/include/Langulus/Anyness/Many.hpp @@ -6,11 +6,11 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/Many.inl" -#include "../../source/many/TMany.inl" -#include "../../source/maps/TMap.inl" -#include "../../source/text/Text.inl" -#include "../../source/many/Neat.inl" -#include "../../source/many/Construct.inl" -#include "../../source/many/Bytes.inl" -#include "../../source/verbs/Verb.inl" +#include "../../../source/many/Many.inl" +#include "../../../source/many/TMany.inl" +#include "../../../source/maps/TMap.inl" +#include "../../../source/text/Text.inl" +#include "../../../source/many/Neat.inl" +#include "../../../source/many/Construct.inl" +#include "../../../source/many/Bytes.inl" +#include "../../../source/verbs/Verb.inl" diff --git a/include/Anyness/Map.hpp b/include/Langulus/Anyness/Map.hpp similarity index 93% rename from include/Anyness/Map.hpp rename to include/Langulus/Anyness/Map.hpp index c6f23b53..5409a788 100644 --- a/include/Anyness/Map.hpp +++ b/include/Langulus/Anyness/Map.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/maps/Map.inl" +#include "../../../source/maps/Map.inl" diff --git a/include/Anyness/Neat.hpp b/include/Langulus/Anyness/Neat.hpp similarity index 72% rename from include/Anyness/Neat.hpp rename to include/Langulus/Anyness/Neat.hpp index 6c9d9d7b..3d3c1c04 100644 --- a/include/Anyness/Neat.hpp +++ b/include/Langulus/Anyness/Neat.hpp @@ -6,8 +6,8 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/Neat.inl" -#include "../../source/many/Construct.inl" -#include "../../source/many/Bytes.inl" -#include "../../source/verbs/Verb.inl" -#include "../../source/text/Text.inl" \ No newline at end of file +#include "../../../source/many/Neat.inl" +#include "../../../source/many/Construct.inl" +#include "../../../source/many/Bytes.inl" +#include "../../../source/verbs/Verb.inl" +#include "../../../source/text/Text.inl" \ No newline at end of file diff --git a/include/Anyness/Own.hpp b/include/Langulus/Anyness/Own.hpp similarity index 92% rename from include/Anyness/Own.hpp rename to include/Langulus/Anyness/Own.hpp index 6eb15dd8..42b3ab0e 100644 --- a/include/Anyness/Own.hpp +++ b/include/Langulus/Anyness/Own.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/one/Own.inl" +#include "../../../source/one/Own.inl" diff --git a/include/Anyness/Pair.hpp b/include/Langulus/Anyness/Pair.hpp similarity index 91% rename from include/Anyness/Pair.hpp rename to include/Langulus/Anyness/Pair.hpp index b7a2b6ca..1fb60880 100644 --- a/include/Anyness/Pair.hpp +++ b/include/Langulus/Anyness/Pair.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/pairs/Pair.inl" +#include "../../../source/pairs/Pair.inl" diff --git a/include/Anyness/Path.hpp b/include/Langulus/Anyness/Path.hpp similarity index 91% rename from include/Anyness/Path.hpp rename to include/Langulus/Anyness/Path.hpp index 7c1e242d..ea31d6fe 100644 --- a/include/Anyness/Path.hpp +++ b/include/Langulus/Anyness/Path.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/text/Path.inl" +#include "../../../source/text/Path.inl" diff --git a/include/Anyness/Ref.hpp b/include/Langulus/Anyness/Ref.hpp similarity index 92% rename from include/Anyness/Ref.hpp rename to include/Langulus/Anyness/Ref.hpp index 253af6c8..95e4555c 100644 --- a/include/Anyness/Ref.hpp +++ b/include/Langulus/Anyness/Ref.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/one/Ref.inl" +#include "../../../source/one/Ref.inl" diff --git a/include/Anyness/Serial.hpp b/include/Langulus/Anyness/Serial.hpp similarity index 85% rename from include/Anyness/Serial.hpp rename to include/Langulus/Anyness/Serial.hpp index 2e80ea9f..eac9ca91 100644 --- a/include/Anyness/Serial.hpp +++ b/include/Langulus/Anyness/Serial.hpp @@ -6,6 +6,6 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/text/Text.inl" -#include "../../source/many/Bytes.inl" +#include "../../../source/text/Text.inl" +#include "../../../source/many/Bytes.inl" diff --git a/include/Anyness/Set.hpp b/include/Langulus/Anyness/Set.hpp similarity index 92% rename from include/Anyness/Set.hpp rename to include/Langulus/Anyness/Set.hpp index 999f0cbd..ca4321c8 100644 --- a/include/Anyness/Set.hpp +++ b/include/Langulus/Anyness/Set.hpp @@ -7,4 +7,4 @@ /// #pragma once #include "Many.hpp" -#include "../../source/sets/Set.inl" +#include "../../../source/sets/Set.inl" diff --git a/include/Anyness/THive.hpp b/include/Langulus/Anyness/THive.hpp similarity index 87% rename from include/Anyness/THive.hpp rename to include/Langulus/Anyness/THive.hpp index dccd4418..8486a092 100644 --- a/include/Anyness/THive.hpp +++ b/include/Langulus/Anyness/THive.hpp @@ -6,5 +6,5 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/THive.inl" -#include "../../source/maps/TMap.inl" \ No newline at end of file +#include "../../../source/many/THive.inl" +#include "../../../source/maps/TMap.inl" \ No newline at end of file diff --git a/include/Anyness/TMap.hpp b/include/Langulus/Anyness/TMap.hpp similarity index 93% rename from include/Anyness/TMap.hpp rename to include/Langulus/Anyness/TMap.hpp index 1381ff67..858e0b83 100644 --- a/include/Anyness/TMap.hpp +++ b/include/Langulus/Anyness/TMap.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/maps/TMap.inl" +#include "../../../source/maps/TMap.inl" diff --git a/include/Anyness/TPair.hpp b/include/Langulus/Anyness/TPair.hpp similarity index 91% rename from include/Anyness/TPair.hpp rename to include/Langulus/Anyness/TPair.hpp index a2809d9e..931488d5 100644 --- a/include/Anyness/TPair.hpp +++ b/include/Langulus/Anyness/TPair.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/pairs/TPair.inl" +#include "../../../source/pairs/TPair.inl" diff --git a/include/Anyness/TSet.hpp b/include/Langulus/Anyness/TSet.hpp similarity index 91% rename from include/Anyness/TSet.hpp rename to include/Langulus/Anyness/TSet.hpp index 18ad2039..33d3853a 100644 --- a/include/Anyness/TSet.hpp +++ b/include/Langulus/Anyness/TSet.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/sets/TSet.inl" +#include "../../../source/sets/TSet.inl" diff --git a/include/Anyness/Text.hpp b/include/Langulus/Anyness/Text.hpp similarity index 86% rename from include/Anyness/Text.hpp rename to include/Langulus/Anyness/Text.hpp index 599821ba..38c42ee1 100644 --- a/include/Anyness/Text.hpp +++ b/include/Langulus/Anyness/Text.hpp @@ -6,5 +6,5 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/text/Text.inl" -#include "../../source/maps/TMap.inl" \ No newline at end of file +#include "../../../source/text/Text.inl" +#include "../../../source/maps/TMap.inl" \ No newline at end of file diff --git a/include/Anyness/Trait.hpp b/include/Langulus/Anyness/Trait.hpp similarity index 91% rename from include/Anyness/Trait.hpp rename to include/Langulus/Anyness/Trait.hpp index d1a6f0b3..8fe23cf3 100644 --- a/include/Anyness/Trait.hpp +++ b/include/Langulus/Anyness/Trait.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/many/TTrait.inl" +#include "../../../source/many/TTrait.inl" diff --git a/include/Anyness/Verb.hpp b/include/Langulus/Anyness/Verb.hpp similarity index 91% rename from include/Anyness/Verb.hpp rename to include/Langulus/Anyness/Verb.hpp index 11b1b99f..37c86d19 100644 --- a/include/Anyness/Verb.hpp +++ b/include/Langulus/Anyness/Verb.hpp @@ -6,4 +6,4 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include "../../source/verbs/Verb.inl" +#include "../../../source/verbs/Verb.inl" diff --git a/source/Charge.hpp b/source/Charge.hpp index 1233a40d..45794dda 100644 --- a/source/Charge.hpp +++ b/source/Charge.hpp @@ -45,20 +45,20 @@ namespace Langulus::Anyness Real = DefaultPriority ) noexcept; - NOD() constexpr bool operator == (const Charge&) const noexcept; + constexpr bool operator == (const Charge&) const noexcept; - NOD() constexpr Charge operator * (const Real&) const noexcept; - NOD() constexpr Charge operator ^ (const Real&) const noexcept; + constexpr Charge operator * (const Real&) const noexcept; + constexpr Charge operator ^ (const Real&) const noexcept; - NOD() constexpr Charge& operator *= (const Real&) noexcept; - NOD() constexpr Charge& operator ^= (const Real&) noexcept; + constexpr Charge& operator *= (const Real&) noexcept; + constexpr Charge& operator ^= (const Real&) noexcept; - NOD() constexpr bool IsDefault() const noexcept; - NOD() constexpr bool IsFlowDependent() const noexcept; - NOD() Hash GetHash() const noexcept; + constexpr bool IsDefault() const noexcept; + constexpr bool IsFlowDependent() const noexcept; + Hash GetHash() const noexcept; void Reset() noexcept; - NOD() operator Text() const; + operator Text() const; }; } // namespace Langulus::Anyness \ No newline at end of file diff --git a/source/Config.hpp b/source/Config.hpp index b4705e94..57897373 100644 --- a/source/Config.hpp +++ b/source/Config.hpp @@ -6,8 +6,7 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include -#include +#include #if defined(LANGULUS_EXPORT_ALL) or defined(LANGULUS_EXPORT_ANYNESS) @@ -18,7 +17,7 @@ /// Enable memory manager #if LANGULUS_FEATURE(MANAGED_MEMORY) - #include + #include #else #include "memory/NoAllocator.hpp" #endif @@ -149,3 +148,11 @@ namespace Langulus } // namespace Langulus::Anyness } // namespace Langulus + +#if 0 + #define VERBOSE_COMPARE(...) Logger::Verbose(__VA_ARGS__) + #define VERBOSE_COMPARE_TAB(...) const auto tab = Logger::Verbose(__VA_ARGS__, Logger::Tabs {}) +#else + #define VERBOSE_COMPARE(...) LANGULUS(NOOP) + #define VERBOSE_COMPARE_TAB(...) LANGULUS(NOOP) +#endif diff --git a/source/DataState.hpp b/source/DataState.hpp index e55f14db..2deb19dd 100644 --- a/source/DataState.hpp +++ b/source/DataState.hpp @@ -86,27 +86,26 @@ namespace Langulus explicit constexpr operator bool() const noexcept; constexpr bool operator == (const DataState&) const noexcept = default; - NOD() constexpr DataState operator + (const DataState&) const noexcept; - NOD() constexpr DataState operator - (const DataState&) const noexcept; + constexpr DataState operator + (const DataState&) const noexcept; + constexpr DataState operator - (const DataState&) const noexcept; constexpr DataState& operator += (const DataState&) noexcept; constexpr DataState& operator -= (const DataState&) noexcept; constexpr DataState& operator &= (const DataState&) noexcept; - NOD() constexpr bool operator & (const DataState&) const noexcept; - NOD() constexpr bool operator % (const DataState&) const noexcept; + constexpr bool operator & (const DataState&) const noexcept; + constexpr bool operator % (const DataState&) const noexcept; - NOD() constexpr bool IsDefault() const noexcept; - NOD() constexpr bool IsMissing() const noexcept; - NOD() constexpr bool IsCompressed() const noexcept; - NOD() constexpr bool IsEncrypted() const noexcept; - NOD() constexpr bool IsOr() const noexcept; - NOD() constexpr bool IsNow() const noexcept; - NOD() constexpr bool IsFuture() const noexcept; - NOD() constexpr bool IsPast() const noexcept; - //NOD() constexpr bool IsStatic() const noexcept; - NOD() constexpr bool IsConstant() const noexcept; - NOD() constexpr bool IsTyped() const noexcept; - NOD() constexpr bool IsConstrained() const noexcept; + constexpr bool IsDefault() const noexcept; + constexpr bool IsMissing() const noexcept; + constexpr bool IsCompressed() const noexcept; + constexpr bool IsEncrypted() const noexcept; + constexpr bool IsOr() const noexcept; + constexpr bool IsNow() const noexcept; + constexpr bool IsFuture() const noexcept; + constexpr bool IsPast() const noexcept; + constexpr bool IsConstant() const noexcept; + constexpr bool IsTyped() const noexcept; + constexpr bool IsConstrained() const noexcept; constexpr void Reset() noexcept; }; diff --git a/source/Index.hpp b/source/Index.hpp index 0c20c3d8..8ea5fb78 100644 --- a/source/Index.hpp +++ b/source/Index.hpp @@ -105,21 +105,21 @@ namespace Langulus::Anyness constexpr Index& operator = (const Index&) noexcept = default; public: - NOD() constexpr Index Constrained(Count) const noexcept; - NOD() Offset GetOffset() const; - NOD() Offset GetOffsetUnsafe() const noexcept; + constexpr Index Constrained(Count) const noexcept; + Offset GetOffset() const; + Offset GetOffsetUnsafe() const noexcept; constexpr void Constrain(Count) noexcept; constexpr void Concat(const Index&) noexcept; - NOD() constexpr bool IsValid() const noexcept; - NOD() constexpr bool IsInvalid() const noexcept; - NOD() constexpr bool IsSpecial() const noexcept; - NOD() constexpr bool IsReverse() const noexcept; - NOD() constexpr bool IsArithmetic() const noexcept; + constexpr bool IsValid() const noexcept; + constexpr bool IsInvalid() const noexcept; + constexpr bool IsSpecial() const noexcept; + constexpr bool IsReverse() const noexcept; + constexpr bool IsArithmetic() const noexcept; - NOD() explicit constexpr operator bool() const noexcept; - NOD() explicit constexpr operator const Type& () const noexcept; + explicit constexpr operator bool() const noexcept; + explicit constexpr operator const Type& () const noexcept; constexpr void operator ++ () noexcept; constexpr void operator -- () noexcept; @@ -128,17 +128,17 @@ namespace Langulus::Anyness constexpr void operator *= (const Index&) noexcept; constexpr void operator /= (const Index&) noexcept; - NOD() constexpr Index operator + (const Index&) const noexcept; - NOD() constexpr Index operator - (const Index&) const noexcept; - NOD() constexpr Index operator * (const Index&) const noexcept; - NOD() constexpr Index operator / (const Index&) const noexcept; - NOD() constexpr Index operator - () const noexcept; - - NOD() constexpr bool operator == (const Index&) const noexcept; - NOD() constexpr bool operator < (const Index&) const noexcept; - NOD() constexpr bool operator > (const Index&) const noexcept; - NOD() constexpr bool operator <= (const Index&) const noexcept; - NOD() constexpr bool operator >= (const Index&) const noexcept; + constexpr Index operator + (const Index&) const noexcept; + constexpr Index operator - (const Index&) const noexcept; + constexpr Index operator * (const Index&) const noexcept; + constexpr Index operator / (const Index&) const noexcept; + constexpr Index operator - () const noexcept; + + constexpr bool operator == (const Index&) const noexcept; + constexpr bool operator < (const Index&) const noexcept; + constexpr bool operator > (const Index&) const noexcept; + constexpr bool operator <= (const Index&) const noexcept; + constexpr bool operator >= (const Index&) const noexcept; }; constexpr Index IndexAll {Index::All}; diff --git a/source/Index.inl b/source/Index.inl index 023fa4fa..ce2b83a1 100644 --- a/source/Index.inl +++ b/source/Index.inl @@ -6,8 +6,7 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include -#include +#include namespace Langulus::Anyness diff --git a/source/TEdit.hpp b/source/TEdit.hpp index bf7a3c29..217edea6 100644 --- a/source/TEdit.hpp +++ b/source/TEdit.hpp @@ -54,13 +54,13 @@ namespace Langulus::Anyness Edit& Select(Offset, Offset); Edit& Select(Offset); - NOD() const T& GetSource() const noexcept; - NOD() Offset GetStart() const noexcept; - NOD() Offset GetEnd() const noexcept; - NOD() Count GetLength() const noexcept; + auto GetSource() const noexcept -> const T&; + auto GetStart() const noexcept -> Offset; + auto GetEnd() const noexcept -> Offset; + auto GetLength() const noexcept -> Count; - NOD() auto& operator[] (Offset) const noexcept; - NOD() auto& operator[] (Offset) noexcept; + auto& operator[] (Offset) const noexcept; + auto& operator[] (Offset) noexcept; Edit& operator << (const T&); Edit& operator >> (const T&); diff --git a/source/TEdit.inl b/source/TEdit.inl index 3fa86983..328b7a8b 100644 --- a/source/TEdit.inl +++ b/source/TEdit.inl @@ -33,7 +33,7 @@ namespace Langulus::Anyness /// @param pattern - the pattern to select /// @return a reference to this editor TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Select(const T& pattern) { + auto TME()::Select(const T& pattern) -> Edit& { if (mSource.IsEmpty() or pattern.IsEmpty()) return *this; @@ -76,7 +76,7 @@ namespace Langulus::Anyness /// @param end - the ending marker of the selection /// @return a reference to this editor TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Select(Offset start, Offset end) { + auto TME()::Select(Offset start, Offset end) -> Edit& { mStart = ::std::min(start, mSource.GetCount()); mEnd = ::std::max(::std::min(end, mSource.GetCount()), mStart); return *this; @@ -86,7 +86,7 @@ namespace Langulus::Anyness /// @param start - the starting marker of the selection /// @return a reference to this editor TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Select(Offset start) { + auto TME()::Select(Offset start) -> Edit& { mEnd = mStart = ::std::min(start, mSource.GetCount()); return *this; } @@ -94,7 +94,7 @@ namespace Langulus::Anyness /// Get the container we're editing /// @return a constant reference to the source container TEMPLATE() LANGULUS(INLINED) - const T& TME()::GetSource() const noexcept { + auto TME()::GetSource() const noexcept -> const T& { return mSource; } @@ -139,7 +139,7 @@ namespace Langulus::Anyness /// @param other - the container to concatenate /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::operator << (const T& other) { + auto TME()::operator << (const T& other) -> Edit& { mSource.InsertBlock(mEnd, other); return *this; } @@ -148,7 +148,7 @@ namespace Langulus::Anyness /// @param other - the container to concatenate /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::operator >> (const T& other) { + auto TME()::operator >> (const T& other) -> Edit& { const auto concatenated = mSource.InsertBlock(mStart, other); mStart += concatenated; mEnd += concatenated; @@ -160,7 +160,7 @@ namespace Langulus::Anyness /// replacement /// @param other - the container to use for replacement TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Replace(const T& other) { + auto TME()::Replace(const T& other) -> Edit& { if constexpr (CT::POD or CT::Sparse) { const auto offset = mStart * mSource.GetStride(); @@ -209,7 +209,7 @@ namespace Langulus::Anyness /// @param other - the element to insert /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::operator << (const TypeOf& other) { + auto TME()::operator << (const TypeOf& other) -> Edit& { mSource.InsertAt(other, mEnd); return *this; } @@ -218,7 +218,7 @@ namespace Langulus::Anyness /// @param other - the element to insert /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::operator >> (const TypeOf& other) { + auto TME()::operator >> (const TypeOf& other) -> Edit& { const auto concatenated = mSource.InsertAt(other, mStart); mStart += concatenated; mEnd += concatenated; @@ -231,7 +231,7 @@ namespace Langulus::Anyness /// @param other - the element to use for replacement /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Replace(const TypeOf& other) { + auto TME()::Replace(const TypeOf& other) -> Edit& { return Replace(T {other}); } @@ -239,7 +239,7 @@ namespace Langulus::Anyness /// selection marker /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Delete() { + auto TME()::Delete() -> Edit& { const auto length = GetLength(); if (length) { mSource.RemoveIndex(mStart, length); @@ -260,7 +260,7 @@ namespace Langulus::Anyness /// selection marker /// @return a reference to the editor for chaining TEMPLATE() LANGULUS(INLINED) - TME()& TME()::Backspace() { + auto TME()::Backspace() -> Edit& { const auto length = GetLength(); if (length) { mSource.RemoveIndex(mStart, length); diff --git a/source/blocks/Block.hpp b/source/blocks/Block.hpp index 1b8bc330..fc4959f7 100644 --- a/source/blocks/Block.hpp +++ b/source/blocks/Block.hpp @@ -12,7 +12,7 @@ #include "../Iterator.hpp" #include "../one/Handle.hpp" #include "../one/Own.hpp" -#include +#include namespace Langulus @@ -322,7 +322,35 @@ namespace Langulus::Anyness }; #endif - + /// A reference to an embedded sparse element inside a block + template + struct LocalRef { + T* mPointer; + Allocation const** mEntry; + + LANGULUS(ALWAYS_INLINED) + operator T () const noexcept { return *mPointer; } + + auto operator = (T newPointer) noexcept -> LocalRef&; + + template + auto New(A&&...) -> LocalRef&; + + LANGULUS(ALWAYS_INLINED) + auto operator -> () const noexcept { return *mPointer; } + + LANGULUS(ALWAYS_INLINED) + decltype(auto) operator * () const IF_UNSAFE(noexcept) { + LANGULUS_ASSUME(UserAssumes, *mPointer, "Dereferening null pointer"); + return **mPointer; + } + + LANGULUS(ALWAYS_INLINED) + decltype(auto) operator & () const noexcept { + return mPointer; + } + }; + /// /// Memory block /// @@ -429,55 +457,55 @@ namespace Langulus::Anyness constexpr void AddState(DataState) noexcept; constexpr void RemoveState(DataState) noexcept; - NOD() constexpr explicit operator bool() const noexcept; - - NOD() bool Owns(const void*) const noexcept; - NOD() constexpr auto GetAllocation() const noexcept -> const Allocation*; - NOD() constexpr Count GetUses() const noexcept; - NOD() constexpr DMeta GetType() const noexcept; - NOD() constexpr Count GetCount() const noexcept; - NOD() constexpr Count GetReserved() const noexcept; - NOD() constexpr Size GetReservedSize() const noexcept; - NOD() Count GetCountDeep() const noexcept; - NOD() Count GetCountElementsDeep() const noexcept; - NOD() constexpr bool IsAllocated() const noexcept; - NOD() constexpr bool IsPast() const noexcept; - NOD() constexpr bool IsFuture() const noexcept; - NOD() constexpr bool IsNow() const noexcept; - NOD() constexpr bool IsMissing() const noexcept; - NOD() constexpr bool IsTyped() const noexcept; - NOD() constexpr bool IsUntyped() const noexcept; - NOD() constexpr bool IsTypeConstrained() const noexcept; - NOD() constexpr bool IsEncrypted() const noexcept; - NOD() constexpr bool IsCompressed() const noexcept; - NOD() constexpr bool IsConstant() const noexcept; - NOD() constexpr bool IsMutable() const noexcept; - NOD() constexpr bool IsStatic() const noexcept; - NOD() constexpr bool IsOr() const noexcept; - NOD() constexpr bool IsEmpty() const noexcept; - NOD() constexpr bool IsValid() const noexcept; - NOD() constexpr bool IsInvalid() const noexcept; - NOD() constexpr bool IsDense() const noexcept; - NOD() constexpr bool IsSparse() const noexcept; - NOD() constexpr bool IsPOD() const noexcept; - NOD() constexpr bool IsResolvable() const noexcept; - NOD() constexpr bool IsDeep() const noexcept; - NOD() constexpr bool IsBlock() const noexcept; - NOD() constexpr bool CanFitState(const CT::Block auto&) const noexcept; - NOD() constexpr Size GetBytesize() const noexcept; - NOD() constexpr Token GetToken() const noexcept; - NOD() constexpr Size GetStride() const noexcept; - NOD() constexpr DataState GetState() const noexcept; - NOD() constexpr DataState GetUnconstrainedState() const noexcept; - NOD() constexpr bool IsMissingDeep() const; - NOD() constexpr bool IsConcatable(const CT::Block auto&) const noexcept; + constexpr explicit operator bool() const noexcept; + + bool Owns(const void*) const noexcept; + constexpr auto GetAllocation() const noexcept -> const Allocation*; + constexpr Count GetUses() const noexcept; + constexpr DMeta GetType() const noexcept; + constexpr Count GetCount() const noexcept; + constexpr Count GetReserved() const noexcept; + constexpr Size GetReservedSize() const noexcept; + Count GetCountDeep() const noexcept; + Count GetCountElementsDeep() const noexcept; + constexpr bool IsAllocated() const noexcept; + constexpr bool IsPast() const noexcept; + constexpr bool IsFuture() const noexcept; + constexpr bool IsNow() const noexcept; + constexpr bool IsMissing() const noexcept; + constexpr bool IsTyped() const noexcept; + constexpr bool IsUntyped() const noexcept; + constexpr bool IsTypeConstrained() const noexcept; + constexpr bool IsEncrypted() const noexcept; + constexpr bool IsCompressed() const noexcept; + constexpr bool IsConstant() const noexcept; + constexpr bool IsMutable() const noexcept; + constexpr bool IsStatic() const noexcept; + constexpr bool IsOr() const noexcept; + constexpr bool IsEmpty() const noexcept; + constexpr bool IsValid() const noexcept; + constexpr bool IsInvalid() const noexcept; + constexpr bool IsDense() const noexcept; + constexpr bool IsSparse() const noexcept; + constexpr bool IsPOD() const noexcept; + constexpr bool IsResolvable() const noexcept; + constexpr bool IsDeep() const noexcept; + constexpr bool IsBlock() const noexcept; + constexpr bool CanFitState(const CT::Block auto&) const noexcept; + constexpr Size GetBytesize() const noexcept; + constexpr Token GetToken() const noexcept; + constexpr Size GetStride() const noexcept; + constexpr DataState GetState() const noexcept; + constexpr DataState GetUnconstrainedState() const noexcept; + constexpr bool IsMissingDeep() const; + constexpr bool IsConcatable(const CT::Block auto&) const noexcept; template - NOD() constexpr bool IsInsertable() const noexcept; - NOD() constexpr bool IsInsertable(DMeta) const noexcept; + constexpr bool IsInsertable() const noexcept; + constexpr bool IsInsertable(DMeta) const noexcept; - NOD() bool IsExecutable() const noexcept; - NOD() bool IsExecutableDeep() const noexcept; + bool IsExecutable() const noexcept; + bool IsExecutableDeep() const noexcept; constexpr void MakeConst(bool enable = true) noexcept; constexpr void MakeTypeConstrained(bool enable = true) noexcept; @@ -490,14 +518,14 @@ namespace Langulus::Anyness constexpr void ResetState() noexcept; template - NOD() auto GetRaw() IF_UNSAFE(noexcept) -> T*; + auto GetRaw() IF_UNSAFE(noexcept) -> T*; template - NOD() auto GetRaw() const IF_UNSAFE(noexcept) -> T const*; + auto GetRaw() const IF_UNSAFE(noexcept) -> T const*; template - NOD() auto GetRawEnd() const IF_UNSAFE(noexcept) -> T const*; + auto GetRawEnd() const IF_UNSAFE(noexcept) -> T const*; - NOD() auto GetEntries() const IF_UNSAFE(noexcept) -> Allocation const* const*; - NOD() auto GetEntries() IF_UNSAFE(noexcept) -> Allocation const**; + auto GetEntries() const IF_UNSAFE(noexcept) -> Allocation const* const*; + auto GetEntries() IF_UNSAFE(noexcept) -> Allocation const**; /// /// Descriptor interface @@ -533,21 +561,21 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() decltype(auto) operator[] (CT::Index auto); - NOD() decltype(auto) operator[] (CT::Index auto) const; + decltype(auto) operator[] (CT::Index auto); + decltype(auto) operator[] (CT::Index auto) const; template - NOD() decltype(auto) As(CT::Index auto); + decltype(auto) As(CT::Index auto); template - NOD() decltype(auto) As(CT::Index auto) const; + decltype(auto) As(CT::Index auto) const; - template - NOD() LANGULUS(ALWAYS_INLINED) decltype(auto) As() { + template LANGULUS(ALWAYS_INLINED) + decltype(auto) As() { return As(0); } - template - NOD() LANGULUS(ALWAYS_INLINED) decltype(auto) As() const { + template LANGULUS(ALWAYS_INLINED) + decltype(auto) As() const { return As(0); } @@ -559,45 +587,45 @@ namespace Langulus::Anyness // If you receive missing externals, include the following: // #include template - NOD() T AsCast(CT::Index auto) const; + T AsCast(CT::Index auto) const; - template - NOD() LANGULUS(INLINED) T AsCast() const { + template LANGULUS(INLINED) + T AsCast() const { return AsCast(0); } - template NOD() IF_UNSAFE(constexpr) + template IF_UNSAFE(constexpr) THIS Select(Offset, Count) IF_UNSAFE(noexcept); - template NOD() IF_UNSAFE(constexpr) + template IF_UNSAFE(constexpr) THIS Select(Offset, Count) const IF_UNSAFE(noexcept); template - NOD() Block<> GetElementDense(Offset = 0); + auto GetElementDense(Offset = 0) -> Block<>; template - NOD() Block<> GetElementDense(Offset = 0) const; - - NOD() Block<> GetElementResolved(Offset = 0); - NOD() Block<> GetElementResolved(Offset = 0) const; + auto GetElementDense(Offset = 0) const -> Block<>; - NOD() Block<> GetElement(Offset = 0) IF_UNSAFE(noexcept); - NOD() Block<> GetElement(Offset = 0) const IF_UNSAFE(noexcept); + auto GetElementResolved(Offset = 0) -> Block<>; + auto GetElementResolved(Offset = 0) const -> Block<>; + + auto GetElement(Offset = 0) IF_UNSAFE(noexcept) -> Block<>; + auto GetElement(Offset = 0) const IF_UNSAFE(noexcept) -> Block<>; - NOD() Block<>* GetBlockDeep(Offset) noexcept; - NOD() Block<> const* GetBlockDeep(Offset) const noexcept; + auto GetBlockDeep(Offset) noexcept -> Block<>*; + auto GetBlockDeep(Offset) const noexcept -> Block<> const*; - NOD() Block<> GetElementDeep(Offset) noexcept; - NOD() Block<> GetElementDeep(Offset) const noexcept; + auto GetElementDeep(Offset) noexcept -> Block<>; + auto GetElementDeep(Offset) const noexcept -> Block<>; - NOD() Block<> GetResolved(); - NOD() Block<> GetResolved() const; + auto GetResolved() -> Block<>; + auto GetResolved() const -> Block<>; template - NOD() Block<> GetDense(); + auto GetDense() -> Block<>; template - NOD() Block<> GetDense() const; + auto GetDense() const -> Block<>; - NOD() Block<> operator * (); - NOD() Block<> operator * () const; + auto operator * () -> Block<>; + auto operator * () const -> Block<>; void SwapIndices(CT::Index auto, CT::Index auto); template requires CT::Block> @@ -609,39 +637,39 @@ namespace Langulus::Anyness Count GatherFrom(const CT::Block auto&, DataState); template - NOD() Index GetIndex() const IF_UNSAFE(noexcept); - NOD() Index GetIndexMode(Count&) const IF_UNSAFE(noexcept); + Index GetIndex() const IF_UNSAFE(noexcept); + Index GetIndexMode(Count&) const IF_UNSAFE(noexcept); - template NOD() IF_UNSAFE(constexpr) + template IF_UNSAFE(constexpr) decltype(auto) Get(Offset = 0) IF_UNSAFE(noexcept); - template NOD() IF_UNSAFE(constexpr) + template IF_UNSAFE(constexpr) decltype(auto) Get(Offset = 0) const IF_UNSAFE(noexcept); - NOD() IF_UNSAFE(constexpr) + IF_UNSAFE(constexpr) decltype(auto) GetDeep(Offset = 0) IF_UNSAFE(noexcept); - NOD() IF_UNSAFE(constexpr) + IF_UNSAFE(constexpr) decltype(auto) GetDeep(Offset = 0) const IF_UNSAFE(noexcept); protected: - NOD() Block<> GetElementInner(Offset = 0) IF_UNSAFE(noexcept); - NOD() Block<> GetElementInner(Offset = 0) const IF_UNSAFE(noexcept); + Block<> GetElementInner(Offset = 0) IF_UNSAFE(noexcept); + Block<> GetElementInner(Offset = 0) const IF_UNSAFE(noexcept); - NOD() IF_UNSAFE(constexpr) + IF_UNSAFE(constexpr) auto At(Offset = 0) IF_UNSAFE(noexcept) -> Byte*; - NOD() IF_UNSAFE(constexpr) + IF_UNSAFE(constexpr) auto At(Offset = 0) const IF_UNSAFE(noexcept) -> Byte const*; - NOD() Index Constrain(Index) const IF_UNSAFE(noexcept); - NOD() Block CropInner(Offset, Count) const IF_UNSAFE(noexcept); + Index Constrain(Index) const IF_UNSAFE(noexcept); + Block CropInner(Offset, Count) const IF_UNSAFE(noexcept); template Offset SimplifyIndex(INDEX) const noexcept(not LANGULUS_SAFE() and CT::BuiltinInteger); public: - template NOD() + template auto GetHandle(Offset = 0) IF_UNSAFE(noexcept); - template NOD() + template auto GetHandle(Offset = 0) const IF_UNSAFE(noexcept); /// @@ -650,10 +678,10 @@ namespace Langulus::Anyness using Iterator = TBlockIterator; using ConstIterator = TBlockIterator; - NOD() constexpr auto begin() noexcept -> Iterator; - NOD() constexpr auto begin() const noexcept -> ConstIterator; - NOD() constexpr auto last() noexcept -> Iterator; - NOD() constexpr auto last() const noexcept -> ConstIterator; + constexpr auto begin() noexcept -> Iterator; + constexpr auto begin() const noexcept -> ConstIterator; + constexpr auto last() noexcept -> Iterator; + constexpr auto last() const noexcept -> ConstIterator; constexpr A::IteratorEnd end() const noexcept { return {}; } @@ -700,59 +728,59 @@ namespace Langulus::Anyness LoopControl IterateInner(Count, auto&& f) const noexcept(NoexceptIterator); // Prefix operators - Block& operator ++ () IF_UNSAFE(noexcept); - Block const& operator ++ () const IF_UNSAFE(noexcept); - Block& operator -- () IF_UNSAFE(noexcept); - Block const& operator -- () const IF_UNSAFE(noexcept); + auto operator ++ () IF_UNSAFE(noexcept) -> Block&; + auto operator ++ () const IF_UNSAFE(noexcept) -> Block const&; + auto operator -- () IF_UNSAFE(noexcept) -> Block&; + auto operator -- () const IF_UNSAFE(noexcept) -> Block const&; // Suffix operators - NOD() Block operator ++ (int) const IF_UNSAFE(noexcept); - NOD() Block operator -- (int) const IF_UNSAFE(noexcept); - - NOD() Block operator + (Offset) const IF_UNSAFE(noexcept); - NOD() Block operator - (Offset) const IF_UNSAFE(noexcept); + auto operator ++ (int) const IF_UNSAFE(noexcept) -> Block; + auto operator -- (int) const IF_UNSAFE(noexcept) -> Block; + + auto operator + (Offset) const IF_UNSAFE(noexcept) -> Block; + auto operator - (Offset) const IF_UNSAFE(noexcept) -> Block; - Block& operator += (Offset) IF_UNSAFE(noexcept); - Block const& operator += (Offset) const IF_UNSAFE(noexcept); - Block& operator -= (Offset) IF_UNSAFE(noexcept); - Block const& operator -= (Offset) const IF_UNSAFE(noexcept); + auto operator += (Offset) IF_UNSAFE(noexcept) -> Block&; + auto operator += (Offset) const IF_UNSAFE(noexcept) -> Block const&; + auto operator -= (Offset) IF_UNSAFE(noexcept) -> Block&; + auto operator -= (Offset) const IF_UNSAFE(noexcept) -> Block const&; public: /// /// RTTI /// template - NOD() constexpr bool Is() const noexcept; - NOD() bool Is(DMeta) const noexcept; - NOD() bool Is(const CT::Block auto&) const noexcept; + constexpr bool Is() const noexcept; + bool Is(DMeta) const noexcept; + bool Is(const CT::Block auto&) const noexcept; template - NOD() constexpr bool IsSimilar() const noexcept; - NOD() bool IsSimilar(DMeta) const noexcept; - NOD() bool IsSimilar(const CT::Block auto&) const noexcept; + constexpr bool IsSimilar() const noexcept; + bool IsSimilar(DMeta) const noexcept; + bool IsSimilar(const CT::Block auto&) const noexcept; template - NOD() constexpr bool IsExact() const noexcept; - NOD() bool IsExact(DMeta) const noexcept; - NOD() bool IsExact(const CT::Block auto&) const noexcept; + constexpr bool IsExact() const noexcept; + bool IsExact(DMeta) const noexcept; + bool IsExact(const CT::Block auto&) const noexcept; template - NOD() bool CastsToMeta(DMeta) const; + bool CastsToMeta(DMeta) const; template - NOD() bool CastsToMeta(DMeta, Count) const; + bool CastsToMeta(DMeta, Count) const; template - NOD() bool CastsTo() const; + bool CastsTo() const; template - NOD() bool CastsTo(Count) const; + bool CastsTo(Count) const; template - NOD() B ReinterpretAs(const B&) const; + B ReinterpretAs(const B&) const; template - NOD() TMany ReinterpretAs() const; + TMany ReinterpretAs() const; - NOD() Block<> GetMember(const RTTI::Member&, CT::Index auto); - NOD() Block<> GetMember(const RTTI::Member&, CT::Index auto) const; + Block<> GetMember(const RTTI::Member&, CT::Index auto); + Block<> GetMember(const RTTI::Member&, CT::Index auto) const; template void SetType(DMeta) requires TypeErased; @@ -768,10 +796,10 @@ namespace Langulus::Anyness constexpr void ResetType() noexcept; public: - NOD() Block<> GetBaseMemory(DMeta, const RTTI::Base&); - NOD() Block<> GetBaseMemory(DMeta, const RTTI::Base&) const; - NOD() Block<> GetBaseMemory(const RTTI::Base&); - NOD() Block<> GetBaseMemory(const RTTI::Base&) const; + Block<> GetBaseMemory(DMeta, const RTTI::Base&); + Block<> GetBaseMemory(DMeta, const RTTI::Base&) const; + Block<> GetBaseMemory(const RTTI::Base&); + Block<> GetBaseMemory(const RTTI::Base&) const; /// /// Comparison @@ -783,32 +811,32 @@ namespace Langulus::Anyness requires (TypeErased or CT::Comparable); template - NOD() bool Compare(const CT::Block auto&) const; - NOD() Hash GetHash() const requires (TypeErased or CT::Hashable); + bool Compare(const CT::Block auto&) const; + Hash GetHash() const requires (TypeErased or CT::Hashable); template - NOD() Index Find(const T1&, Offset = 0) const noexcept + Index Find(const T1&, Offset = 0) const noexcept requires (TypeErased or CT::Comparable); - NOD() auto FindIt(const CT::NoIntent auto&) -> Iterator; - NOD() auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; + auto FindIt(const CT::NoIntent auto&) -> Iterator; + auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; template - NOD() Index FindBlock(const CT::Block auto&, CT::Index auto) const noexcept; + Index FindBlock(const CT::Block auto&, CT::Index auto) const noexcept; template void Sort() requires (TypeErased or CT::Sortable); - NOD() bool CompareLoose(const CT::Block auto&) const noexcept; - NOD() Count Matches(const CT::Block auto&) const noexcept; - NOD() Count MatchesLoose(const CT::Block auto&) const noexcept; - NOD() bool Contains(const CT::NoIntent auto&) const; + bool CompareLoose(const CT::Block auto&) const noexcept; + Count Matches(const CT::Block auto&) const noexcept; + Count MatchesLoose(const CT::Block auto&) const noexcept; + bool Contains(const CT::NoIntent auto&) const; protected: - NOD() bool CompareSingleValue(const CT::NoIntent auto&) const; - NOD() bool CompareStates(const Block&) const noexcept; - NOD() bool CompareTypes(const CT::Block auto&, RTTI::Base&) const; - NOD() bool CallComparer(const Block&, const RTTI::Base&) const; + bool CompareSingleValue(const CT::NoIntent auto&) const; + bool CompareStates(const Block&) const noexcept; + bool CompareTypes(const CT::Block auto&, RTTI::Base&) const; + bool CallComparer(const Block&, const RTTI::Base&) const; template Count GatherInner(CT::Block auto&) const; @@ -825,7 +853,7 @@ namespace Langulus::Anyness protected: /// @cond show_protected - NOD() auto RequestSize(Count) const IF_UNSAFE(noexcept) -> AllocationRequest; + auto RequestSize(Count) const IF_UNSAFE(noexcept) -> AllocationRequest; template void AllocateMore(Count); @@ -891,7 +919,7 @@ namespace Langulus::Anyness void Fill(A&&) requires (TypeErased or CT::AssignableFrom); template - NOD() THIS Extend(Count); + THIS Extend(Count); protected: template @@ -995,16 +1023,16 @@ namespace Langulus::Anyness template Offset DeserializeBinary(CT::Block auto&, const Header&, Offset = 0, Loader = nullptr) const; - void ReadInner(Offset, Count, Loader) const; - NOD() Offset DeserializeAtom(Offset&, Offset, const Header&, Loader) const; - NOD() Offset DeserializeMeta(CT::Meta auto&, Offset, const Header&, Loader) const; + void ReadInner(Offset, Count, Loader) const; + Offset DeserializeAtom(Offset&, Offset, const Header&, Loader) const; + Offset DeserializeMeta(CT::Meta auto&, Offset, const Header&, Loader) const; }; template - NOD() auto MakeBlock(auto&&, Count = 1); + auto MakeBlock(auto&&, Count = 1); template - NOD() auto WrapBlock(TN&&...); + auto WrapBlock(TN&&...); /// Cast between block types - does only reinterpret_cast, with some /// additional safety checks. Preserves qualifiers. @@ -1012,7 +1040,7 @@ namespace Langulus::Anyness /// @param from - block we're casting from /// @return the reinterpreted block template - NOD() decltype(auto) BlockCast(CT::Block auto&& from) { + decltype(auto) BlockCast(CT::Block auto&& from) { //TODO move all kinds of checks here instead? //TODO utilize cast operators to type-erased references here if available - they might set type using DAS = Decay; @@ -1136,15 +1164,14 @@ namespace Langulus::Anyness using TypeInner = Conditional; // Current iterator position pointer - TypeInner mValue; + TypeInner mValue = nullptr; // Iterator position which is considered the 'end' iterator - Type const* mEnd; + Type const* mEnd = nullptr; constexpr TBlockIterator(const TypeInner&, Type const*) noexcept; public: - TBlockIterator() noexcept = delete; - + constexpr TBlockIterator() noexcept = default; constexpr TBlockIterator(const TBlockIterator&) noexcept = default; constexpr TBlockIterator(TBlockIterator&&) noexcept = default; constexpr TBlockIterator(A::IteratorEnd) noexcept; @@ -1152,15 +1179,15 @@ namespace Langulus::Anyness constexpr auto operator = (const TBlockIterator&) noexcept -> TBlockIterator& = default; constexpr auto operator = (TBlockIterator&&) noexcept -> TBlockIterator& = default; - NOD() constexpr bool operator == (const TBlockIterator&) const noexcept; - NOD() constexpr bool operator == (A::IteratorEnd) const noexcept; + constexpr bool operator == (const TBlockIterator&) const noexcept; + constexpr bool operator == (A::IteratorEnd) const noexcept; - NOD() constexpr decltype(auto) operator * () const noexcept { + constexpr decltype(auto) operator * () const noexcept { if constexpr (CT::Typed) return *mValue; else return (mValue); } - NOD() constexpr decltype(auto) operator -> () const noexcept { + constexpr decltype(auto) operator -> () const noexcept { if constexpr (CT::Typed) return *mValue; else return &mValue; } @@ -1169,7 +1196,7 @@ namespace Langulus::Anyness constexpr auto operator ++ () noexcept -> TBlockIterator&; // Suffix operator - NOD() constexpr auto operator ++ (int) noexcept -> TBlockIterator; + constexpr auto operator ++ (int) noexcept -> TBlockIterator; constexpr explicit operator bool() const noexcept; @@ -1178,4 +1205,12 @@ namespace Langulus::Anyness requires Mutable { return {mValue, mEnd}; } }; -} // namespace Langulus::Anyness \ No newline at end of file +} // namespace Langulus::Anyness + +namespace Langulus::CT::TI +{ + template + struct SparseTrait<::Langulus::Anyness::LocalRef> { + static constexpr bool Value = true; + }; +} diff --git a/source/blocks/Block/Block-Compare.inl b/source/blocks/Block/Block-Compare.inl index c4bc7257..48b473b1 100644 --- a/source/blocks/Block/Block-Compare.inl +++ b/source/blocks/Block/Block-Compare.inl @@ -9,14 +9,6 @@ #include "../Block.hpp" #include "../../text/Text.hpp" -#if 0 - #define VERBOSE(...) Logger::Verbose(__VA_ARGS__) - #define VERBOSE_TAB(...) const auto tab = Logger::Verbose(__VA_ARGS__, Logger::Tabs {}) -#else - #define VERBOSE(...) LANGULUS(NOOP) - #define VERBOSE_TAB(...) LANGULUS(NOOP) -#endif - namespace Langulus::Anyness { @@ -45,7 +37,7 @@ namespace Langulus::Anyness template template bool Block::Compare(const CT::Block auto& right) const { using RHS = Deref; - VERBOSE_TAB("Comparing ", + VERBOSE_COMPARE_TAB("Comparing ", Logger::PushWhite, mCount, " elements of ", GetToken(), Logger::Pop, " with ", Logger::PushWhite, right.mCount, " elements of ", right.GetToken() @@ -55,18 +47,25 @@ namespace Langulus::Anyness // Both blocks are statically typed - leverage it if constexpr (not CT::Similar>) { //TODO but what if differently typed pointers to the same virtual objects? // Types are different + VERBOSE_COMPARE(Logger::Red, "Types differ (compile-time): ", + NameOf(), " != ", NameOf>()); return false; } else { // Types are similar if (mRaw == right.mRaw) return mCount == right.mCount; - else if (mCount != right.mCount) + else if (mCount != right.mCount) { + VERBOSE_COMPARE(Logger::Red, "Different count (compile-time): ", mCount, " != ", right.mCount); return false; + } if constexpr (CT::POD) { // Batch compare pods or pointers - return 0 == ::std::memcmp(mRaw, right.mRaw, GetBytesize()); + const bool same = 0 == ::std::memcmp(mRaw, right.mRaw, GetBytesize()); + if (not same) + VERBOSE_COMPARE(Logger::Red, "Different POD memory after memcmp (compile-time)"); + return same; } else if constexpr (CT::Comparable) { // Use comparison operator between all elements @@ -77,16 +76,25 @@ namespace Langulus::Anyness ++t1; ++t2; } + + if (t1 != t1end) + VERBOSE_COMPARE(Logger::Red, "Element #", t1 - GetRaw(), " differs (compile-time)"); return t1 == t1end; } - else return false; + else { + VERBOSE_COMPARE(Logger::Red, "Type not comparable (compile-time): ", NameOf()); + return false; + } } } else if constexpr (not TypeErased or not RHS::TypeErased) { // One of the blocks is statically typed - a runtime type // check is required - if ((mCount or right.mCount) and not IsSimilar(right)) //TODO but what if differently typed pointers to the same virtual objects? + if ((mCount or right.mCount) and not IsSimilar(right)) { //TODO but what if differently typed pointers to the same virtual objects? + VERBOSE_COMPARE(Logger::Red, "Types differ (runtime): ", + GetType(), " != ", right.GetType()); return false; + } if constexpr (not TypeErased) return Compare(reinterpret_cast&>(right)); @@ -94,18 +102,26 @@ namespace Langulus::Anyness return right.template Compare(reinterpret_cast(*this)); } else { - if (not IsSimilar(right)) //TODO but what if differently typed pointers to the same virtual objects? + if (not IsSimilar(right)) { //TODO but what if differently typed pointers to the same virtual objects? + VERBOSE_COMPARE(Logger::Red, "Types differ (runtime): ", + mType, " != ", right.mType); return false; + } // Types are similar if (mRaw == right.mRaw) return mCount == right.mCount; - else if (mCount != right.mCount) + else if (mCount != right.mCount) { + VERBOSE_COMPARE(Logger::Red, "Different count (runtime): ", mCount, " != ", right.mCount); return false; + } if (mType->mIsPOD or mType->mIsSparse) { // Batch-compare memory if POD or sparse - return 0 == memcmp(mRaw, right.mRaw, GetBytesize()); + const bool same = 0 == ::std::memcmp(mRaw, right.mRaw, GetBytesize()); + if (not same) + VERBOSE_COMPARE(Logger::Red, "Different POD memory after memcmp (runtime)"); + return same; } else if (mType->mComparer) { // Call compare operator for each element pair @@ -113,212 +129,22 @@ namespace Langulus::Anyness auto rhs = right.mRaw; const auto lhsEnd = GetRawEnd(); while (lhs != lhsEnd) { - if (not mType->mComparer(lhs, rhs)) + if (not mType->mComparer(lhs, rhs)) { + VERBOSE_COMPARE(Logger::Red, "Element #", (lhs - mRaw) / mType->mSize, " differs (runtime)"); return false; + } + lhs += mType->mSize; rhs += mType->mSize; } return true; } - else LANGULUS_OOPS(Compare, "No == operator reflected for type ", mType); - - - // Type-erased blocks - /*if (mCount != right.mCount) { - // Cheap early return for differently sized blocks - VERBOSE(Logger::Red, - "Data count is different: ", mCount, " != ", right.mCount); - return false; - } - - const bool sameTypes = mType->IsSimilar(right.mType); - if (mCount and not sameTypes) { - if (IsUntyped() or right.IsUntyped()) { - // Cheap early return if differing undefined types, when - // packs are not empty - VERBOSE(Logger::Red, - "One of the containers is untyped: ", - GetToken(), " != ", right.GetToken()); - return false; - } - } - else if (not mCount or IsUntyped()) { - // Both blocks are untyped or empty, just compare states - return CompareStates(right); - } - - if (not CompareStates(right)) { - // Cheap early return for blocks of differing states - VERBOSE(Logger::Red, "Data states are not compatible"); - return false; - } - - if (sameTypes) { - // Types are exactly the same - if (mRaw == right.mRaw) { - // Quickly return if memory is exactly the same - VERBOSE(Logger::Green, - "Blocks are the same ", Logger::Cyan, "(optimal)"); - return true; - } - else if (mType->mIsPOD or mType->mIsSparse) { - // Batch-compare memory if POD or sparse - return 0 == memcmp(mRaw, right.mRaw, GetBytesize()); - } - else if (mType->mComparer) { - // Call compare operator for each element pair - auto lhs = mRaw; - auto rhs = right.mRaw; - const auto lhsEnd = GetRawEnd(); - while (lhs != lhsEnd) { - if (not mType->mComparer(lhs, rhs)) - return false; - lhs += mType->mSize; - rhs += mType->mSize; - } - - return true; - } - else LANGULUS_OOPS(Compare, "No == operator reflected for type ", mType); - } - else if (not mType->mIsSparse or not right.mType->mIsSparse) { - VERBOSE(Logger::Red, "Data types differ in sparsity"); - return false; - }*/ - - // If this is reached, then types are different kind of sparse - // and an advanced comparison commences - types may be - // different pointers to the same virtual objects - //TODO not done on the typed path above - /*RTTI::Base baseForComparison {}; - if constexpr (RESOLVE) { - // We will test type for each resolved element, individually - if (not IsResolvable() and not right.IsResolvable() - and not CompareTypes(right, baseForComparison)) { - // Types differ and are not resolvable - VERBOSE(Logger::Red, - "Data types are not related: ", - GetToken(), " != ", right.GetToken()); - return false; - } - } else { - // We won't be resolving, so we have only one global type - if (not CompareTypes(right, baseForComparison)) { - // Types differ - VERBOSE(Logger::Red, - "Data types are not related: ", - GetToken(), " != ", right.GetToken()); - return false; - } + VERBOSE_COMPARE(Logger::Red, "Type not comparable (runtime): ", mType); + LANGULUS_OOPS(Compare, "No == operator reflected for type ", mType); } - if ((IsSparse() and baseForComparison.mBinaryCompatible) - or (baseForComparison.mType and baseForComparison.mType->mIsPOD - and baseForComparison.mBinaryCompatible)) { - // Just compare the memory directly (optimization) - // Regardless if types are sparse or dense, as long as they - // are of the same density, of course - VERBOSE("Batch-comparing POD memory / pointers"); - const auto code = memcmp(mRaw, right.mRaw, GetBytesize()); - if (code != 0) { - VERBOSE(Logger::Red, "POD/pointers are not the same ", - Logger::Yellow, "(fast)"); - return false; - } - - VERBOSE(Logger::Green, "POD/pointers memory is the same ", - Logger::Yellow, "(fast)"); - } - else if (baseForComparison.mType and baseForComparison.mType->mComparer) { - if (IsSparse()) { - if constexpr (RESOLVE) { - // Resolve all elements one by one and compare them by - // their common resolved base - for (Count i = 0; i < mCount; ++i) { - auto lhs = GetElementResolved(i); - auto rhs = right.GetElementResolved(i); - if (not lhs.CompareTypes(rhs, baseForComparison)) { - // Fail comparison on first mismatch - VERBOSE(Logger::Red, - "Pointers at ", i, " have unrelated types: ", - lhs.GetToken(), " != ", rhs.GetToken()); - return false; - } - - // Compare pointers only - if (lhs.mRaw != rhs.mRaw) { - // Fail comparison on first mismatch - VERBOSE(Logger::Red, - "Pointers at ", i, " differ: ", - lhs.GetToken(), " != ", rhs.GetToken()); - return false; - } - } - - VERBOSE(Logger::Green, - "Data is the same, all pointers match ", - Logger::DarkYellow, "(slow)"); - } - else { - // Call the reflected == operator in baseForComparison - VERBOSE("Comparing using reflected operator == for ", - baseForComparison.mType.GetToken()); - - for (Count i = 0; i < mCount; ++i) { - // Densify and compare all elements by the binary - // compatible base - auto lhs = GetElementDense(i); - auto rhs = right.GetElementDense(i); - - if (not lhs.CallComparer(rhs, baseForComparison)) { - // Fail comparison on first mismatch - VERBOSE(Logger::Red, "Elements at ", i, " differ"); - return false; - } - } - - VERBOSE(Logger::Green, - "Data is the same, all elements match ", - Logger::Yellow, "(slow)"); - } - } - else { - // Call the reflected == operator in baseForComparison - VERBOSE("Comparing using reflected operator == for ", - baseForComparison.mType.GetToken()); - - for (Count i = 0; i < mCount; ++i) { - // Compare all elements by the binary compatible base - auto lhs = GetElementInner(i); - auto rhs = right.GetElementInner(i); - - if (not lhs.CallComparer(rhs, baseForComparison)) { - // Fail comparison on first mismatch - VERBOSE(Logger::Red, "Elements at ", i, " differ"); - return false; - } - } - - VERBOSE(Logger::Green, - "Data is the same, all elements match ", - Logger::Yellow, "(slow)"); - } - } - else if (baseForComparison.mType) { - VERBOSE(Logger::Red, - "Can't compare related types because no == operator is reflected, " - "and they're not POD - common base for comparison was: ", - baseForComparison.mType); - return false; - } - else { - VERBOSE(Logger::Red, - "Can't compare unrelated types ", mType, " and ", right.mType); - return false; - }*/ - return true; } } @@ -486,6 +312,7 @@ namespace Langulus::Anyness while (start != end) { if (*start == item) + // Match found return start - GetRaw(); if constexpr (REVERSE) @@ -495,32 +322,6 @@ namespace Langulus::Anyness } } else { - // First check if element is contained inside this block's - // memory, because if so, we can easily find it, without - // calling a single compare function - //TODO these heurisrics are bad! the pattern may appear in memory, - // but there may be other occurences before that memory point! at best, we should - // simply narrow the search scope, and after scanning it, fallback to the - // one found pointer-wise - /*if constexpr (CT::Deep) { - // Deep items have a bit looser type requirements - if (IsDense() and IsDeep() and Owns(&item)) { - const Offset index = &item - GetRawAs(); - // Check required, because Owns tests in reserved range - return index < mCount ? index : IndexNone; - } - } - else { - // Search for a conventional item - if (IsExact() and Owns(&item)) { - const Offset index = &item - GetRawAs(); - // Check required, because Owns tests in reserved range - return index < mCount ? index : IndexNone; - } - }*/ - - // Item is not in this block's memory, so we start comparing by - // values Offset i = REVERSE ? mCount - 1 - cookie : cookie; while (i < mCount) { if (GetElementInner(i) == item) { @@ -585,7 +386,7 @@ namespace Langulus::Anyness // This byte size is used ONLY IF both types are binary // compatible. It is simply precomputed here, so that it isn't // recomputed in the loop. - UNUSED() const auto bytesize = lb.GetBytesize(); + [[maybe_unused]] const auto bytesize = lb.GetBytesize(); while (lhs != lhsEnd) { if (*lhs == *rhs) { @@ -600,6 +401,7 @@ namespace Langulus::Anyness and CT::POD, TypeOf>) { // We can use batch-compare if (0 == memcmp(rhs, lhs, bytesize)) + // Match found return cookie; } else { @@ -611,6 +413,7 @@ namespace Langulus::Anyness } if (rhs == rhsEnd) + // Match found return cookie; } @@ -627,33 +430,6 @@ namespace Langulus::Anyness return IndexNone; } else { - // All of the participators are type-erased - // We do a slow and tedious RTTI-based compare - - // First check if element is contained inside this block's - // memory, because if so, we can easily find it, without - // calling a single compare function - - //TODO these heurisrics are bad! the pattern may appear in memory, - // but there may be other occurences before that memory point! at best, we should - // simply narrow the search scope, and after scanning it, fallback to the - // one found pointer-wise - - /*if (item.IsDense() and item.IsDeep()) { - // Deep items have a bit looser type requirements - if (IsDense() and IsDeep() and Owns(item.mRaw)) { - const Offset index = (item.mRaw - mRaw) / sizeof(Block); - return index + item.GetCount() <= mCount ? index : IndexNone; - } - } - else { - // Search for a conventional item - if (IsExact(item.GetType()) and Owns(item.mRaw)) { - const Offset index = (item.mRaw - mRaw) / mType->mSize; - return index + item.GetCount() <= mCount ? index : IndexNone; - } - }*/ - Offset i = REVERSE ? mCount - 1 - cookie : cookie; const auto iend = REVERSE ? static_cast(-1) @@ -661,6 +437,7 @@ namespace Langulus::Anyness while (i != iend) { if (CropInner(i, item.GetCount()) == item) + // Match found return i; if constexpr (REVERSE) @@ -709,7 +486,7 @@ namespace Langulus::Anyness // Other is derived from this, but it has to be binary // compatible to be able to compare them if (not common.mBinaryCompatible) { - VERBOSE(Logger::Red, + VERBOSE_COMPARE(Logger::Red, "Data types are related, but not binary compatible: ", GetToken(), " != ", right.GetToken()); return false; @@ -721,7 +498,7 @@ namespace Langulus::Anyness // This is derived from other, but it has to be binary // compatible to be able to compare them if (not common.mBinaryCompatible) { - VERBOSE(Logger::Red, + VERBOSE_COMPARE(Logger::Red, "Data types are related, but not binary compatible: ", GetToken(), " != ", right.GetToken()); return false; @@ -752,8 +529,8 @@ namespace Langulus::Anyness /// @return true if comparison returns true template LANGULUS(INLINED) bool Block::CallComparer(const Block& right, const RTTI::Base& base) const { - return mRaw == right.mRaw or (mRaw and right.mRaw - and base.mType->mComparer(mRaw, right.mRaw)); + return mRaw == right.mRaw or (mRaw and right.mRaw + and base.mType->mComparer(mRaw, right.mRaw)); } /// Gather items from input container, and fill output @@ -965,7 +742,4 @@ namespace Langulus::Anyness } } -} // namespace Langulus::Anyness - -#undef VERBOSE_TAB -#undef VERBOSE \ No newline at end of file +} // namespace Langulus::Anyness \ No newline at end of file diff --git a/source/blocks/Block/Block-Construct.inl b/source/blocks/Block/Block-Construct.inl index 9fe2423d..348e69a1 100644 --- a/source/blocks/Block/Block-Construct.inl +++ b/source/blocks/Block/Block-Construct.inl @@ -319,12 +319,13 @@ namespace Langulus::Anyness } else { // We're cloning, so we guarantee, that data is no longer - // static and constant (unless mType is constant) + // static and constant mState -= DataState::Constant; if (0 == from.mCount) return; - + // Pick a preferably typed block to optimize the construction + mType = mType->mDecvq; if constexpr (B::TypeErased) { // A runtime check is required before allocating LANGULUS_ASSERT(mType->mCloneConstructor, Construct, diff --git a/source/blocks/Block/Block-Describe.inl b/source/blocks/Block/Block-Describe.inl index 229efc1c..5685b649 100644 --- a/source/blocks/Block/Block-Describe.inl +++ b/source/blocks/Block/Block-Describe.inl @@ -10,6 +10,7 @@ #include "../../many/Trait.hpp" #include "../../many/Construct.hpp" #include "../../many/Neat.hpp" +#include namespace Langulus::Anyness @@ -64,19 +65,21 @@ namespace Langulus::Anyness using D = Deref; Count progress = 0; - ForEachDeep([&](const Deext& data) { - if constexpr (CT::Array) { + if constexpr (CT::Vector or CT::Array) { + ForEachDeep([&](const TypeOf& data) { //TODO can be optimized-out for POD value[progress] = data; ++progress; - return (progress >= ExtentOf) ? Loop::Break : Loop::Continue; - } - else { + return (progress >= CountOf) ? Loop::Break : Loop::Continue; + }); + } + else { + ForEachDeep([&](const D& data) { value = data; ++progress; return Loop::Break; - } - }); + }); + } return progress; } @@ -90,18 +93,18 @@ namespace Langulus::Anyness Count progress = 0; ForEachDeep([&](const Many& group) { - if constexpr (CT::Array) { - const auto toscan = ::std::min(ExtentOf - progress, group.GetCount()); + if constexpr (CT::Vector or CT::Array) { + const auto toscan = ::std::min(CountOf - progress, group.GetCount()); for (Offset i = 0; i < toscan; ++i) { //TODO can be optimized-out for POD try { - value[progress] = group.template AsCast>(i); + value[progress] = group.template AsCast>(i); ++progress; } catch (...) {} } - return (progress >= ExtentOf) ? Loop::Break : Loop::Continue; + return (progress >= CountOf) ? Loop::Break : Loop::Continue; } else { try { @@ -196,11 +199,9 @@ namespace Langulus::Anyness value = static_cast(trait); satisfied = true; } - else try { - value = trait.template AsCast(); + else if (trait.ExtractDataAs(value)) satisfied = true; - } - catch (...) {} + return Loop::Break; }); diff --git a/source/blocks/Block/Block-Indexing.inl b/source/blocks/Block/Block-Indexing.inl index cd4ab379..01c97526 100644 --- a/source/blocks/Block/Block-Indexing.inl +++ b/source/blocks/Block/Block-Indexing.inl @@ -36,8 +36,12 @@ namespace Langulus::Anyness decltype(auto) Block::operator[] (CT::Index auto idx) { const auto index = SimplifyIndex(idx); LANGULUS_ASSERT(index < mCount, Access, "Index out of range"); - if constexpr (TypeErased) return GetElement(index); - else return GetRaw()[index]; + if constexpr (TypeErased) + return GetElement(index); + else if constexpr (CT::Sparse) + return LocalRef {GetRaw() + index, mEntry ? GetEntries() + index : nullptr}; + else + return GetRaw()[index]; } template LANGULUS(INLINED) @@ -219,7 +223,7 @@ namespace Langulus::Anyness // Optimize if we're interpreting as a container static_assert(CT::Deep>, "Type mismatch"); const auto idx = SimplifyIndex(index); - auto& result = (*this)[idx]; + auto& result = GetRaw()[idx]; if constexpr (CT::Typed) { // Additional check, if T is a typed block @@ -246,9 +250,9 @@ namespace Langulus::Anyness const auto idx = SimplifyIndex(index); Decvq ptr; if constexpr (Sparse) - ptr = dynamic_cast( (*this)[idx]); + ptr = dynamic_cast( GetRaw()[idx]); else - ptr = dynamic_cast(&(*this)[idx]); + ptr = dynamic_cast(&GetRaw()[idx]); LANGULUS_ASSERT(ptr, Access, "Failed dynamic_cast"); return ptr; } @@ -258,15 +262,15 @@ namespace Langulus::Anyness if constexpr (CT::Sparse) { if constexpr (Sparse) - return static_cast( (*this)[idx]); + return static_cast( GetRaw()[idx]); else - return static_cast(&(*this)[idx]); + return static_cast(&GetRaw()[idx]); } else { if constexpr (Sparse) - return static_cast(*(*this)[idx]); + return static_cast(*GetRaw()[idx]); else - return static_cast( (*this)[idx]); + return static_cast( GetRaw()[idx]); } } } @@ -759,7 +763,7 @@ namespace Langulus::Anyness else if (result == IndexSmallest) return GetIndex(); else if (result == IndexMode) { - UNUSED() Count unused; + [[maybe_unused]] Count unused; return GetIndexMode(unused); } diff --git a/source/blocks/Block/Block-Insert.inl b/source/blocks/Block/Block-Insert.inl index f1cc6d61..5b77a241 100644 --- a/source/blocks/Block/Block-Insert.inl +++ b/source/blocks/Block/Block-Insert.inl @@ -9,6 +9,7 @@ #include "../Block.hpp" #include "../../text/Text.hpp" #include "Block-Indexing.inl" +#include namespace Langulus::Anyness @@ -401,7 +402,7 @@ namespace Langulus::Anyness /// Construct an item of this container's type at the specified position /// by forwarding A... as constructor arguments - /// Since this container is type-erased and exact constructor signatures + /// If this container is type-erased and exact constructor signatures /// aren't reflected, the following constructors will be attempted: /// 1. If A is a single argument of exactly the same type, the reflected /// move constructor will be used, if available @@ -444,8 +445,10 @@ namespace Langulus::Anyness ++mCount; if constexpr (TypeErased) return selection; + else if constexpr (Sparse) + return selection[0]; else - return *selection.GetRaw(); //TODO should return a handle if sparse! + return *selection.GetRaw(); } /// Wrap all contained elements inside a sub-block, making this one deep @@ -460,7 +463,7 @@ namespace Langulus::Anyness "Can't deepen with incompatible type"); // Back up the state so that we can restore it if not moved over - UNUSED() const DataState state = mState.mState & DataState::Or; + [[maybe_unused]] const DataState state = mState.mState & DataState::Or; if constexpr (not TRANSFER_OR) mState -= state; @@ -915,6 +918,8 @@ namespace Langulus::Anyness while (ent != entEnd) *(ent++) = allocation; const_cast(allocation)->Keep(mCount); + if constexpr (CT::Referencable>) + (*GetRaw())->Reference(static_cast(mCount)); } else memset(ent, 0, mCount * sizeof(void*)); } @@ -923,7 +928,7 @@ namespace Langulus::Anyness } else { // Constructing type-erased items - // We expect, that type has been previously set + // We expect that type has been previously set LANGULUS_ASSUME(DevAssumes, IsTyped(), "Block was expected to be typed"); @@ -961,6 +966,8 @@ namespace Langulus::Anyness while (ent != entEnd) *(ent++) = allocation; const_cast(allocation)->Keep(mCount); + if (mType->mReference) + mType->mReference(*GetRaw(), static_cast(mCount)); } else memset(ent, 0, mCount * sizeof(void*)); } @@ -1717,4 +1724,40 @@ namespace Langulus::Anyness } } + /// Overwrite a selected pointer + /// @param newPointer - the new pointer to set + /// @return a reference to the selected pointer + template + auto LocalRef::operator = (T newPointer) noexcept -> LocalRef& { + // Leverage handle code to overwrite pointer and reference + Handle interface {mPointer, mEntry}; + interface.AssignWithIntent(Refer(newPointer)); + return *this; + } + + /// Construct a new item behind a selected pointer + /// @param arguments.. - constructor arguments + /// @return a reference to the selected pointer + template template + auto LocalRef::New(A&&...arguments) -> LocalRef& { + static_assert(::std::constructible_from, A...>, + "Type behind pointer isn't constructible with these arguments"); + LANGULUS_ASSERT(mEntry, Construct, + "Can't create a new pointer inside a sparse block which is out of jurisdiction!"); + + // Leverage handle code to free the element, if valid + Handle interface {mPointer, mEntry}; + interface.template FreeInner(); + + // Analogous to what happens in Ref::New + using DT = Decvq>; + *mEntry = Allocator::Allocate(MetaDataOf
(), sizeof(DT)); + LANGULUS_ASSERT(*mEntry, Allocate, "Out of memory"); + *mPointer = reinterpret_cast((*mEntry)->GetBlockStart()); + new (const_cast(*mPointer)) DecvqAll
{ + Forward(arguments)... + }; + return *this; + } + } // namespace Langulus::Anyness \ No newline at end of file diff --git a/source/blocks/Block/Block-Iteration.inl b/source/blocks/Block/Block-Iteration.inl index 147c7eb6..2d356e29 100644 --- a/source/blocks/Block/Block-Iteration.inl +++ b/source/blocks/Block/Block-Iteration.inl @@ -212,18 +212,19 @@ namespace Langulus::Anyness using F = Deref; using A = ArgumentOf; using R = ReturnOf; + using DA = Decay; + using DT = Decay; static_assert(CT::Slab or CT::Constant> or MUTABLE, "Non-constant iterator for constant memory is not allowed"); - UNUSED() static constexpr auto NOE = NoexceptIterator; + [[maybe_unused]] + static constexpr auto NOE = NoexceptIterator; LoopControl loop = Loop::NextLoop; if constexpr (not TypeErased) { // Container is not type-erased - if constexpr (CT::Deep, Decay> - or (not CT::Deep> and CT::DerivedFrom) - or (CT::Same)) { + if constexpr (CT::Deep or (not CT::Deep and CT::DerivedFrom)) { loop = IterateInner(mCount, [&index, &f](T& element) noexcept(NOE) -> R { ++index; @@ -244,14 +245,60 @@ namespace Langulus::Anyness } else return Loop::NextLoop; } - else if (not CT::Trait> and ((CT::Deep> and IsDeep()) - or (not CT::Deep> and CastsTo()))) { + else if constexpr (not CT::Trait) { // Container is type-erased + // And we're NOT iterating using a trait + if ((CT::Deep and IsDeep()) or (not CT::Deep and CastsTo())) { + if (mType->mIsSparse) { + // Iterate sparse container + loop = IterateInner(mCount, + [&index, &f](void*& element) noexcept(NOE) -> R { + ++index; + if constexpr (CT::Dense) + return f(*reinterpret_cast*>(element)); + else + return f( reinterpret_cast(element)); + } + ); + } + else { + // Iterate dense container where A is binary-compatible + // to the type, but may not match it exactly + LANGULUS_ASSUME(DevAssumes, GetStride() % sizeof(DA) == 0, "Unaligned iterator"); + loop = IterateInner(mCount * (GetStride() / sizeof(DA)), + [&index, &f](DA& element) noexcept(NOE) -> R { + ++index; + if constexpr (CT::Dense) + return f( element); + else + return f(&element); + } + ); + } + } + } + else { + // Container is type-erased + // And we're iterating using a trait + if (not CastsTo()) + return Loop::NextLoop; + + // Container is type-erased and full of traits, iterator is + // a static trait, so we iterate all traits, visiting only + // those that match the trait type if (mType->mIsSparse) { // Iterate sparse container loop = IterateInner(mCount, - [&index, &f](void*& element) noexcept(NOE) -> R { + [&index, &f](Trait*& element) noexcept(NOE) -> R { + if constexpr (CT::Void) { + if (not element->template IsTrait()) + return; + } + else if (not element->template IsTrait()) + return Loop::Continue; + ++index; + if constexpr (CT::Dense) return f(*reinterpret_cast*>(element)); else @@ -262,75 +309,24 @@ namespace Langulus::Anyness else { // Iterate dense container loop = IterateInner(mCount, - [&index, &f](Decay& element) noexcept(NOE) -> R { + [&index, &f](Trait& element) noexcept(NOE) -> R { + if constexpr (CT::Void) { + if (not element.template IsTrait()) + return; + } + else if (not element.template IsTrait()) + return Loop::Continue; + ++index; if constexpr (CT::Dense) - return f( element); + return f(reinterpret_cast&>( element)); else - return f(&element); + return f(reinterpret_cast*>(&element)); } ); } } - else { - if constexpr (CT::Trait>) { - if (not CastsTo()) - return Loop::NextLoop; - - // Container is type-erased and full of traits, iterator is - // a static trait, so we iterate all traits, visiting only - // those that match the trait type - if (mType->mIsSparse) { - // Iterate sparse container - loop = IterateInner(mCount, - [&index, &f](Trait*& element) noexcept(NOE) -> R { - if constexpr (CT::Void) { - if (not element->template IsTrait>()) - return; - } - else if (not element->template IsTrait>()) - return Loop::Continue; - - ++index; - - if constexpr (CT::Dense) - return f(*reinterpret_cast*>(element)); - else - return f( reinterpret_cast(element)); - } - ); - } - else { - // Iterate dense container - loop = IterateInner(mCount, - [&index, &f](Trait& element) noexcept(NOE) -> R { - if constexpr (CT::Void) { - if (not element.template IsTrait>()) - return; - } - else if (not element.template IsTrait>()) - return Loop::Continue; - ++index; - if constexpr (CT::Dense) - return f(reinterpret_cast&>( element)); - else - return f(reinterpret_cast*>(&element)); - } - ); - } - } - else return Loop::NextLoop; - } - - /*if (loop == Loop::Repeat) - return ForEachInner(Forward(f), index); - else*/ /*if (loop == Loop::Discard) { - if constexpr (MUTABLE) - const_cast(this)->Reset(); - else - return Loop::NextLoop; - }*/ return loop; } @@ -384,7 +380,6 @@ namespace Langulus::Anyness // with a branch that contains the empty element // and that is bad. So defer the reset up the // chain instead! - //const_cast(this)->Reset(); return Loop::Discard; } else { @@ -473,7 +468,6 @@ namespace Langulus::Anyness // with a branch that contains the empty element // and that is bad. So defer the reset up the // chain instead! - //const_cast(this)->Reset(); return Loop::Discard; } else { @@ -516,14 +510,6 @@ namespace Langulus::Anyness } } - /*if (loop == Loop::Repeat) - return ForEachDeepInner(Forward(call), counter); - else*/ /*if (loop == Loop::Discard) { - if constexpr (MUTABLE) - const_cast(this)->Reset(); - else - return Loop::Continue; - }*/ return loop; } @@ -554,7 +540,9 @@ namespace Langulus::Anyness ); if constexpr (CT::Dense) { - LANGULUS_ASSUME(DevAssumes, (CastsTo()), + using DA = Decay; + LANGULUS_ASSUME(DevAssumes, + (CT::Deep and IsDeep()) or (not CT::Deep and CastsTo()), "Incompatible iterator type", " `", MetaDataOf(), "` (iterating block of type `", mType, "`)" ); diff --git a/source/blocks/Block/Block-Memory.inl b/source/blocks/Block/Block-Memory.inl index 4f08c649..79b03851 100644 --- a/source/blocks/Block/Block-Memory.inl +++ b/source/blocks/Block/Block-Memory.inl @@ -7,6 +7,7 @@ /// #pragma once #include "../Block.hpp" +#include namespace Langulus::Anyness @@ -101,44 +102,16 @@ namespace Langulus::Anyness else { // Memory moved, and we should move all elements in it // We're moving to new memory, so no reverse required - //if (mEntry->GetUses() == 1) { - // Memory is used only once and it is safe to move - // it. Make note, that Allocator::Reallocate - // doesn't copy anything, it doesn't use realloc - // for various reasons, so we still have to call - // move construction for all elements if entry - // moved (enabling MANAGED_MEMORY feature - // significantly reduces the chance for a move). - // Sparse containers have additional memory - // allocated for each pointer's entry, if managed - // memory is enabled. - if constexpr (CT::AbandonMakable - or CT::MoveMakable - or CT::ReferMakable - or CT::CopyMakable) { - mRaw = const_cast(mEntry->GetBlockStart()); - CreateWithIntent(Abandon(previousBlock)); - previousBlock.Free(); - } - else LANGULUS_THROW(Construct, - "Memory moved, but T is not move-constructible"); - /*} - else { - // Memory is used from multiple locations, and we - // must copy the memory for this block - we can't - // move it! This will throw, if data is not - // copiable/referable. - if constexpr (CT::ReferMakable) { - AllocateFresh(request); - CreateWithIntent(Refer(previousBlock)); - } - else if constexpr (CT::CopyMakable) { - AllocateFresh(request); - CreateWithIntent(Copy(previousBlock)); - } - else LANGULUS_THROW(Construct, - "Memory moved, but T is not refer/copy-constructible"); - }*/ + if constexpr (CT::AbandonMakable + or CT::MoveMakable + or CT::ReferMakable + or CT::CopyMakable) { + mRaw = const_cast(mEntry->GetBlockStart()); + CreateWithIntent(Abandon(previousBlock)); + previousBlock.Free(); + } + else LANGULUS_THROW(Construct, + "Memory moved, but T is not move-constructible"); } } else { @@ -318,26 +291,8 @@ namespace Langulus::Anyness if (mEntry != previousBlock.mEntry) { // Memory moved, and we should call abandon-construction // We're moving to a new allocation, so no reverse needed - //if (mEntry->GetUses() == 1) { - // Memory is used only once and it is safe to move it - // Make note, that Allocator::Reallocate doesn't copy - // anything, it doesn't use realloc for various reasons, - // so we still have to call move construction for all - // elements if entry moved (enabling MANAGED_MEMORY - // feature significantly reduces the chance for a move) - // Also, make sure to free the previous mEntry if moved - // Sparse containers have additional memory allocated for - // each pointer's entry, if managed memory is enabled - mRaw = const_cast(mEntry->GetBlockStart()); - CreateWithIntent(Abandon(previousBlock)); - /*} - else { - // Memory is used from multiple locations, and we must - // copy the memory for this block - we can't move it! - AllocateFresh(request); - CreateWithIntent(Refer(previousBlock)); - previousBlock.Free(); - }*/ + mRaw = const_cast(mEntry->GetBlockStart()); + CreateWithIntent(Abandon(previousBlock)); } else { // Memory didn't move, but reserved count changed @@ -394,16 +349,17 @@ namespace Langulus::Anyness template template LANGULUS(INLINED) void Block::KeepInner(MASK mask) const noexcept { constexpr bool MASKED = not CT::Nullptr; - UNUSED() Count remaining; + [[maybe_unused]] Count remaining; if constexpr (MASKED) remaining = GetCount(); + const auto count = MASKED ? mReserved : mCount; if constexpr (not TypeErased) { if constexpr (Sparse and CT::Referencable>) { // Statically typed and sparse const auto entryBeg = GetEntries(); auto entry = entryBeg; - const auto entryEnd = entry + mCount; + const auto entryEnd = entry + count; while (entry != entryEnd) { if constexpr (MASKED) { @@ -430,7 +386,7 @@ namespace Langulus::Anyness // Statically typed and dense const auto rawBeg = GetRaw(); auto raw = rawBeg; - const auto rawEnd = raw + mCount; + const auto rawEnd = raw + count; while (raw != rawEnd) { if constexpr (MASKED) { @@ -445,7 +401,7 @@ namespace Langulus::Anyness --remaining; } - (raw++)->Reference(1); + DecvqCast(raw++)->Reference(1); } } } @@ -454,7 +410,7 @@ namespace Langulus::Anyness const auto reference = mType->mReference; const auto entryBeg = GetEntries(); auto entry = entryBeg; - const auto entryEnd = entry + mCount; + const auto entryEnd = entry + count; while (entry != entryEnd) { if constexpr (MASKED) { @@ -482,7 +438,7 @@ namespace Langulus::Anyness const auto reference = mType->mReference; const auto rawBeg = mRaw; auto raw = rawBeg; - const auto rawEnd = mRaw + mType->mSize * mCount; + const auto rawEnd = mRaw + mType->mSize * count; while (raw != rawEnd) { if constexpr (MASKED) { @@ -575,7 +531,7 @@ namespace Langulus::Anyness auto data = GetRaw(); const auto begMarker = data; const auto endMarker = data + count; - UNUSED() Count remaining; + [[maybe_unused]] Count remaining; if constexpr (MASKED) remaining = GetCount(); @@ -615,12 +571,12 @@ namespace Langulus::Anyness and (DESTROY or mType->mReference)) { // Destroy every dense element // Notice that fully dereferenced elements WILL be destroyed - // regardless if DESTROY has been request or not + // regardless if DESTROY has been requested or not // This prevents leaks. const auto count = not MASKED ? mCount : mReserved; auto data = mRaw; - UNUSED() int index; - UNUSED() Count remaining; + [[maybe_unused]] int index; + [[maybe_unused]] Count remaining; if constexpr (MASKED) { index = 0; remaining = GetCount(); @@ -704,14 +660,14 @@ namespace Langulus::Anyness auto handle = GetHandle(0); const auto begMarker = handle.mValue; const auto endMarker = handle.mValue + count; - UNUSED() Count remaining; + [[maybe_unused]] Count remaining; if constexpr (MASKED) remaining = GetCount(); // Execute a call for each handle that matches current entry const auto for_each_match = [&](auto&& call) { auto handle2 = handle + 1; - UNUSED() Count remaining2; + [[maybe_unused]] Count remaining2; if constexpr (MASKED) remaining2 = remaining; @@ -794,7 +750,7 @@ namespace Langulus::Anyness for_each_match([&](Handle& h) { // We still have to make sure that per-instance // references are also affected - UNUSED() Count remaining_refs = 0; + [[maybe_unused]] Count remaining_refs = 0; if constexpr (TypeErased) { if (mType->mReference) remaining_refs = mType->mReference(h.Get(), -1); @@ -804,11 +760,6 @@ namespace Langulus::Anyness remaining_refs = DecvqCast(static_cast(h.Get()))->Reference(-1); } - /*LANGULUS_ASSUME(DevAssumes, remaining_refs, - "At least one instance ref should remain, " - "otherwise we forgot to reference element on insertion" - );*/ - h.GetEntry() = nullptr; }); } diff --git a/source/blocks/Block/Block-Remove.inl b/source/blocks/Block/Block-Remove.inl index 84df91a8..ef48c466 100644 --- a/source/blocks/Block/Block-Remove.inl +++ b/source/blocks/Block/Block-Remove.inl @@ -7,6 +7,7 @@ /// #pragma once #include "../Block.hpp" +#include namespace Langulus::Anyness @@ -251,8 +252,10 @@ namespace Langulus::Anyness if (mEntry->GetUses() == 1) { // Entry is used only in this block, so it's safe to // destroy all elements. We will reuse the entry and type - FreeInner(); - mCount = 0; + if (mCount) { + FreeInner(); + mCount = 0; + } } else { // If reached, then data is referenced from multiple places diff --git a/source/blocks/BlockMap.hpp b/source/blocks/BlockMap.hpp index 5e98f443..fee52cbb 100644 --- a/source/blocks/BlockMap.hpp +++ b/source/blocks/BlockMap.hpp @@ -29,8 +29,15 @@ namespace Langulus static constexpr bool CTTI_Container = true; static constexpr bool Sequential = false; static constexpr Offset InvalidOffset = -1; + + // Smallest possible table size + // Has to be a power-of-two static constexpr Count MinimalAllocation = 8; - static constexpr Count AllowedMisses = 128; + + // How many consecutive cells can be dedicated to a single + // hash. The bigger the number, the more serial compares may + // need to be performed per hash, but maps will be smaller. + static constexpr InfoType AllowedMisses = 64; protected: // A precomputed pointer for the info/ordering bytes @@ -144,156 +151,157 @@ namespace Langulus::Anyness /// Capsulation /// template - NOD() DMeta GetKeyType() const noexcept; + DMeta GetKeyType() const noexcept; template - NOD() DMeta GetValueType() const noexcept; + DMeta GetValueType() const noexcept; template - NOD() constexpr bool IsKeyTyped() const noexcept; + constexpr bool IsKeyTyped() const noexcept; template - NOD() constexpr bool IsValueTyped() const noexcept; + constexpr bool IsValueTyped() const noexcept; template - NOD() constexpr bool IsKeyUntyped() const noexcept; + constexpr bool IsKeyUntyped() const noexcept; template - NOD() constexpr bool IsValueUntyped() const noexcept; + constexpr bool IsValueUntyped() const noexcept; template - NOD() constexpr bool IsKeyTypeConstrained() const noexcept; + constexpr bool IsKeyTypeConstrained() const noexcept; template - NOD() constexpr bool IsValueTypeConstrained() const noexcept; + constexpr bool IsValueTypeConstrained() const noexcept; template - NOD() constexpr bool IsKeyDeep() const noexcept; + constexpr bool IsKeyDeep() const noexcept; template - NOD() constexpr bool IsValueDeep() const noexcept; + constexpr bool IsValueDeep() const noexcept; template - NOD() constexpr bool IsKeySparse() const noexcept; + constexpr bool IsKeySparse() const noexcept; template - NOD() constexpr bool IsValueSparse() const noexcept; + constexpr bool IsValueSparse() const noexcept; template - NOD() constexpr bool IsKeyDense() const noexcept; + constexpr bool IsKeyDense() const noexcept; template - NOD() constexpr bool IsValueDense() const noexcept; + constexpr bool IsValueDense() const noexcept; template - NOD() constexpr Size GetKeyStride() const noexcept; + constexpr Size GetKeyStride() const noexcept; template - NOD() constexpr Size GetValueStride() const noexcept; + constexpr Size GetValueStride() const noexcept; template - NOD() Count GetKeyCountDeep() const noexcept; + Count GetKeyCountDeep() const noexcept; template - NOD() Count GetKeyCountElementsDeep() const noexcept; + Count GetKeyCountElementsDeep() const noexcept; template - NOD() Count GetValueCountDeep() const noexcept; + Count GetValueCountDeep() const noexcept; template - NOD() Count GetValueCountElementsDeep() const noexcept; + Count GetValueCountElementsDeep() const noexcept; - NOD() constexpr DataState GetKeyState() const noexcept; - NOD() constexpr DataState GetValueState() const noexcept; - NOD() constexpr bool IsKeyCompressed() const noexcept; - NOD() constexpr bool IsValueCompressed() const noexcept; - NOD() constexpr bool IsKeyEncrypted() const noexcept; - NOD() constexpr bool IsValueEncrypted() const noexcept; - NOD() constexpr bool IsKeyConstant() const noexcept; - NOD() constexpr bool IsValueConstant() const noexcept; - NOD() constexpr Count GetCount() const noexcept; - NOD() constexpr Count GetReserved() const noexcept; - NOD() constexpr bool IsEmpty() const noexcept; - NOD() constexpr bool IsValid() const noexcept; - NOD() constexpr bool IsInvalid() const noexcept; - NOD() constexpr bool IsAllocated() const noexcept; + constexpr auto GetKeyState() const noexcept -> DataState; + constexpr auto GetValueState() const noexcept -> DataState; + constexpr bool IsKeyCompressed() const noexcept; + constexpr bool IsValueCompressed() const noexcept; + constexpr bool IsKeyEncrypted() const noexcept; + constexpr bool IsValueEncrypted() const noexcept; + constexpr bool IsKeyConstant() const noexcept; + constexpr bool IsValueConstant() const noexcept; + constexpr auto GetCount() const noexcept -> Count; + constexpr auto GetReserved() const noexcept -> Count; + constexpr bool IsEmpty() const noexcept; + constexpr bool IsValid() const noexcept; + constexpr bool IsInvalid() const noexcept; + constexpr bool IsAllocated() const noexcept; - NOD() bool IsKeyMissing() const noexcept; - NOD() bool IsValueMissing() const noexcept; + bool IsKeyMissing() const noexcept; + bool IsValueMissing() const noexcept; template - NOD() bool IsKeyMissingDeep() const; + bool IsKeyMissingDeep() const; template - NOD() bool IsValueMissingDeep() const; + bool IsValueMissingDeep() const; template - NOD() bool IsKeyExecutable() const noexcept; + bool IsKeyExecutable() const noexcept; template - NOD() bool IsValueExecutable() const noexcept; + bool IsValueExecutable() const noexcept; template - NOD() bool IsKeyExecutableDeep() const; + bool IsKeyExecutableDeep() const; template - NOD() bool IsValueExecutableDeep() const; + bool IsValueExecutableDeep() const; - NOD() constexpr explicit operator bool() const noexcept; + constexpr explicit operator bool() const noexcept; template void Dump() const; template - NOD() auto& GetKeys() const noexcept; + auto& GetKeys() const noexcept; template - NOD() auto& GetKeys() noexcept; + auto& GetKeys() noexcept; template - NOD() auto GetVals() const noexcept; + auto GetVals() const noexcept; - NOD() auto GetInfo() const noexcept -> const InfoType*; - NOD() auto GetInfo() noexcept -> InfoType*; - NOD() auto GetInfoEnd() const noexcept -> const InfoType*; + auto GetInfo() const noexcept -> const InfoType*; + auto GetInfo() noexcept -> InfoType*; + auto GetInfoEnd() const noexcept -> const InfoType*; protected: - NOD() Count GetCountDeep(const CT::Block auto&) const noexcept; - NOD() Count GetCountElementsDeep(const CT::Block auto&) const noexcept; + Count GetCountDeep(const CT::Block auto&) const noexcept; + Count GetCountElementsDeep(const CT::Block auto&) const noexcept; public: /// /// Indexing /// template - NOD() decltype(auto) GetKey(CT::Index auto); + decltype(auto) GetKey(CT::Index auto); template - NOD() decltype(auto) GetKey(CT::Index auto) const; + decltype(auto) GetKey(CT::Index auto) const; template - NOD() decltype(auto) GetValue(CT::Index auto); + decltype(auto) GetValue(CT::Index auto); template - NOD() decltype(auto) GetValue(CT::Index auto) const; + decltype(auto) GetValue(CT::Index auto) const; template - NOD() auto GetPair (CT::Index auto); + auto GetPair (CT::Index auto); template - NOD() auto GetPair (CT::Index auto) const; + auto GetPair (CT::Index auto) const; protected: template - NOD() Offset SimplifyIndex(INDEX) const + Offset SimplifyIndex(INDEX) const noexcept(not LANGULUS_SAFE() and CT::BuiltinInteger); - NOD() static Offset GetBucket(Offset, const CT::NoIntent auto&) noexcept; - NOD() static Offset GetBucketUnknown(Offset, const Block<>&) noexcept; + template + Offset GetBucket(Offset, const CT::NoIntent auto&) const IF_UNSAFE(noexcept); + Offset GetBucketUnknown(Offset, const Block<>&) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRawKey(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetRawKey(Offset) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRawKey(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetRawKey(Offset) IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetKeyRef(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetKeyRef(Offset) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetKeyRef(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetKeyRef(Offset) IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRawVal(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetRawVal(Offset) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRawVal(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetRawVal(Offset) IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetValRef(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetValRef(Offset) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetValRef(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetValRef(Offset) IF_UNSAFE(noexcept); template - NOD() auto GetKeyHandle(Offset) IF_UNSAFE(noexcept); + auto GetKeyHandle(Offset) IF_UNSAFE(noexcept); template - NOD() auto GetKeyHandle(Offset) const IF_UNSAFE(noexcept); + auto GetKeyHandle(Offset) const IF_UNSAFE(noexcept); template - NOD() auto GetValHandle(Offset) IF_UNSAFE(noexcept); + auto GetValHandle(Offset) IF_UNSAFE(noexcept); template - NOD() auto GetValHandle(Offset) const IF_UNSAFE(noexcept); + auto GetValHandle(Offset) const IF_UNSAFE(noexcept); public: /// @@ -303,14 +311,14 @@ namespace Langulus::Anyness struct Iterator; template - NOD() auto begin() noexcept -> Iterator; + auto begin() noexcept -> Iterator; template - NOD() auto begin() const noexcept -> Iterator; + auto begin() const noexcept -> Iterator; template - NOD() auto last() noexcept -> Iterator; + auto last() noexcept -> Iterator; template - NOD() auto last() const noexcept -> Iterator; + auto last() const noexcept -> Iterator; constexpr A::IteratorEnd end() const noexcept { return {}; } @@ -350,34 +358,34 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool IsKey() const noexcept; + constexpr bool IsKey() const noexcept; template - NOD() bool IsKey(DMeta) const noexcept; + bool IsKey(DMeta) const noexcept; template - NOD() constexpr bool IsKeySimilar() const noexcept; + constexpr bool IsKeySimilar() const noexcept; template - NOD() bool IsKeySimilar(DMeta) const noexcept; + bool IsKeySimilar(DMeta) const noexcept; template - NOD() constexpr bool IsKeyExact() const noexcept; + constexpr bool IsKeyExact() const noexcept; template - NOD() bool IsKeyExact(DMeta) const noexcept; + bool IsKeyExact(DMeta) const noexcept; template - NOD() constexpr bool IsValue() const noexcept; + constexpr bool IsValue() const noexcept; template - NOD() bool IsValue(DMeta) const noexcept; + bool IsValue(DMeta) const noexcept; template - NOD() constexpr bool IsValueSimilar() const noexcept; + constexpr bool IsValueSimilar() const noexcept; template - NOD() bool IsValueSimilar(DMeta) const noexcept; + bool IsValueSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsValueExact() const noexcept; + constexpr bool IsValueExact() const noexcept; template - NOD() bool IsValueExact(DMeta) const noexcept; + bool IsValueExact(DMeta) const noexcept; protected: template @@ -386,9 +394,9 @@ namespace Langulus::Anyness void Mutate(DMeta, DMeta); template - NOD() constexpr bool IsTypeCompatibleWith(CT::Map auto const&) const noexcept; + constexpr bool IsTypeCompatibleWith(CT::Map auto const&) const noexcept; template - NOD() constexpr bool IsTypeCompatibleWith(CT::Pair auto const&) const noexcept; + constexpr bool IsTypeCompatibleWith(CT::Pair auto const&) const noexcept; public: /// @@ -400,37 +408,37 @@ namespace Langulus::Anyness bool operator == (CT::Pair auto const&) const; template - NOD() Hash GetHash() const; + Hash GetHash() const; template - NOD() bool ContainsKey(const CT::NoIntent auto&) const; + bool ContainsKey(const CT::NoIntent auto&) const; template - NOD() bool ContainsValue(const CT::NoIntent auto&) const; + bool ContainsValue(const CT::NoIntent auto&) const; template - NOD() bool ContainsPair(const CT::Pair auto&) const; + bool ContainsPair(const CT::Pair auto&) const; template - NOD() auto Find(const CT::NoIntent auto&) const -> Index; + auto Find(const CT::NoIntent auto&) const -> Index; template - NOD() auto FindIt(const CT::NoIntent auto&) -> Iterator; + auto FindIt(const CT::NoIntent auto&) -> Iterator; template - NOD() auto FindIt(const CT::NoIntent auto&) const -> Iterator; + auto FindIt(const CT::NoIntent auto&) const -> Iterator; template - NOD() decltype(auto) At(const CT::NoIntent auto&); + decltype(auto) At(const CT::NoIntent auto&); template - NOD() decltype(auto) At(const CT::NoIntent auto&) const; + decltype(auto) At(const CT::NoIntent auto&) const; template - NOD() decltype(auto) operator[] (const CT::NoIntent auto&); + decltype(auto) operator[] (const CT::NoIntent auto&); template - NOD() decltype(auto) operator[] (const CT::NoIntent auto&) const; + decltype(auto) operator[] (const CT::NoIntent auto&) const; protected: template - NOD() Offset FindInner(const CT::NoIntent auto&) const; + Offset FindInner(const CT::NoIntent auto&) const; template - NOD() Offset FindBlockInner(const Block<>&) const; + Offset FindBlockInner(const Block<>&) const; public: /// @@ -444,9 +452,9 @@ namespace Langulus::Anyness template void AllocateFresh(Count); template - void AllocateData(Count); + bool AllocateData(Count); template - void AllocateInner(Count); + void AllocateMore(); template void Keep() const noexcept; @@ -475,17 +483,12 @@ namespace Langulus::Anyness auto CreateValHandle(auto&&); template - NOD() Size RequestKeyAndInfoSize(Count, Offset&) const IF_UNSAFE(noexcept); - NOD() Size RequestValuesSize(Count) const IF_UNSAFE(noexcept); + Size RequestKeyAndInfoSize(Count, Offset&) const IF_UNSAFE(noexcept); + Size RequestValuesSize(Count) const IF_UNSAFE(noexcept); - template - void RehashBoth(Count); - template - void RehashKeys(BlockMap&); - template - void RehashVals(BlockMap&); - template - void RehashInner(const Count hashmask, const Offset current, Offset& moveTo, auto& key, auto& val); + template + bool Rehash(const InfoType* oldInfo, Count oldCount, KEY_SOURCE&, VAL_SOURCE&); + template void ShiftPairs(); @@ -535,8 +538,8 @@ namespace Langulus::Anyness void RemoveInner(Offset); #if LANGULUS(TESTING) - public: NOD() constexpr const void* GetRawKeysMemory() const noexcept; - public: NOD() constexpr const void* GetRawValsMemory() const noexcept; + public: constexpr const void* GetRawKeysMemory() const noexcept; + public: constexpr const void* GetRawValsMemory() const noexcept; #endif }; @@ -567,13 +570,13 @@ namespace Langulus::Anyness VA mValue; friend struct BlockMap; - const InfoType* mInfo; - const InfoType* mSentinel; + const InfoType* mInfo = nullptr; + const InfoType* mSentinel = nullptr; constexpr Iterator(const InfoType*, const InfoType*, const KA&, const VA&) noexcept; public: - Iterator() noexcept = delete; + constexpr Iterator() noexcept = default; constexpr Iterator(const Iterator&) noexcept = default; constexpr Iterator(Iterator&&) noexcept = default; constexpr Iterator(const A::IteratorEnd&) noexcept; @@ -598,19 +601,20 @@ namespace Langulus::Anyness else return *mValue; } - constexpr Iterator& operator = (const Iterator&) noexcept = default; - constexpr Iterator& operator = (Iterator&&) noexcept = default; + constexpr auto operator = (const Iterator&) noexcept -> Iterator& = default; + constexpr auto operator = (Iterator&&) noexcept -> Iterator& = default; - NOD() constexpr bool operator == (const Iterator&) const noexcept; - NOD() constexpr bool operator == (const A::IteratorEnd&) const noexcept; + constexpr bool operator == (const Iterator&) const noexcept; + constexpr bool operator == (const A::IteratorEnd&) const noexcept; - NOD() constexpr auto operator * () const; + constexpr auto operator * () const; + constexpr auto operator -> () const noexcept { return &GetValue(); } // Prefix operator - constexpr Iterator& operator ++ () noexcept; + constexpr auto operator ++ () noexcept -> Iterator&; // Suffix operator - NOD() constexpr Iterator operator ++ (int) noexcept; + constexpr auto operator ++ (int) noexcept -> Iterator; constexpr explicit operator bool() const noexcept; constexpr operator Iterator() const noexcept requires Mutable { diff --git a/source/blocks/BlockMap/BlockMap-Compare.inl b/source/blocks/BlockMap/BlockMap-Compare.inl index e667738c..1575cbfb 100644 --- a/source/blocks/BlockMap/BlockMap-Compare.inl +++ b/source/blocks/BlockMap/BlockMap-Compare.inl @@ -263,7 +263,7 @@ namespace Langulus::Anyness } // Get the starting index based on the key hash - const auto start = GetBucket(GetReserved() - 1, match); + const auto start = GetBucket(GetReserved() - 1, match); auto info = GetInfo() + start; if (not *info) return InvalidOffset; diff --git a/source/blocks/BlockMap/BlockMap-Construct.inl b/source/blocks/BlockMap/BlockMap-Construct.inl index 93c74edf..3e914d80 100644 --- a/source/blocks/BlockMap/BlockMap-Construct.inl +++ b/source/blocks/BlockMap/BlockMap-Construct.inl @@ -274,7 +274,7 @@ namespace Langulus::Anyness // allocations for (auto pair : *asFrom) { coalescedKeys.template InsertInner( - IndexBack, SS::Nest(*pair.mKey)); + IndexBack, SS::Nest(*pair.GetKey())); } const_cast(coalescedKeys.mEntry) @@ -334,7 +334,7 @@ namespace Langulus::Anyness // allocations for (auto pair : *asFrom) { coalescedKeys.template InsertBlockInner( - IndexBack, SS::Nest(*pair.mKey)); + IndexBack, SS::Nest(*pair.GetKey())); } const_cast(coalescedKeys.mEntry) @@ -394,7 +394,7 @@ namespace Langulus::Anyness coalescedVals.Reserve(asFrom->GetCount()); for (auto pair : *asFrom) { coalescedVals.template InsertInner( - IndexBack, SS::Nest(*pair.mValue)); + IndexBack, SS::Nest(*pair.GetValue())); } // We're using Handle::Create, instead of CreateWithIntent @@ -458,7 +458,7 @@ namespace Langulus::Anyness coalescedVals.Reserve(asFrom->GetCount()); for (auto pair : *asFrom) { coalescedVals.template InsertBlockInner( - IndexBack, SS::Nest(*pair.mValue)); + IndexBack, SS::Nest(*pair.GetValue())); } const_cast(coalescedVals.mEntry) @@ -492,6 +492,7 @@ namespace Langulus::Anyness /// @attention assumes key and value types are clone-constructible template class S, CT::Map B> requires CT::Intent> void BlockMap::CloneValuesReinsertInner(CT::Block auto& coalescedKeys, S&& asFrom) { + LANGULUS_ASSUME(DevAssumes, IsKeySparse(), "Keys should be sparse"); using SS = S; if constexpr (CT::Typed) { @@ -513,7 +514,7 @@ namespace Langulus::Anyness while (ptr != ptrEnd) { InsertInner( - GetBucket(GetReserved() - 1, ptr), + GetBucket(GetReserved() - 1, ptr), Abandon(HandleLocal {ptr, coalescedKeys.mEntry}), SS::Nest(asFrom->template GetValHandle(valIdx)) ); @@ -534,7 +535,7 @@ namespace Langulus::Anyness coalescedVals.Reserve(asFrom->GetCount()); for (auto pair : *asFrom) { coalescedVals.template InsertInner( - IndexBack, SS::Nest(*pair.mValue)); + IndexBack, SS::Nest(*pair.GetValue())); } const_cast(coalescedVals.mEntry) @@ -543,7 +544,7 @@ namespace Langulus::Anyness auto ptrVal = coalescedVals.GetRaw(); while (ptr != ptrEnd) { InsertInner( - GetBucket(GetReserved() - 1, ptr), + GetBucket(GetReserved() - 1, ptr), Abandon(HandleLocal {ptr, coalescedKeys.mEntry}), Abandon(HandleLocal {ptrVal, coalescedVals.mEntry}) ); @@ -575,7 +576,7 @@ namespace Langulus::Anyness while (ptr != ptrEnd) { InsertInner( - GetBucket(GetReserved() - 1, ptr), + GetBucket(GetReserved() - 1, ptr), Abandon(HandleLocal {ptr, coalescedKeys.mEntry}), SS::Nest(asFrom->template GetValHandle(valIdx)) ); @@ -595,7 +596,7 @@ namespace Langulus::Anyness coalescedVals.Reserve(asFrom->GetCount()); for (auto pair : *asFrom) { coalescedVals.template InsertBlockInner( - IndexBack, SS::Nest(*pair.mValue)); + IndexBack, SS::Nest(*pair.GetValue())); } const_cast(coalescedVals.mEntry) @@ -605,7 +606,7 @@ namespace Langulus::Anyness const Size valstride = coalescedVals.GetStride(); while (ptr != ptrEnd) { InsertInner( - GetBucket(GetReserved() - 1, ptr), + GetBucket(GetReserved() - 1, ptr), Abandon(HandleLocal {ptr, coalescedKeys.mEntry}), Abandon(HandleLocal {ptrVal, coalescedVals.mEntry}) ); @@ -627,6 +628,9 @@ namespace Langulus::Anyness template bool BlockMap::BranchOut() { if (mKeys.GetUses() > 1) { + if (mKeys.GetUses() <= 1 or mValues.GetUses() <= 1) + TODO(); + LANGULUS_ASSUME(DevAssumes, mKeys.GetUses() > 1 and mValues.GetUses() > 1, "Shouldn't be possible" diff --git a/source/blocks/BlockMap/BlockMap-Indexing.inl b/source/blocks/BlockMap/BlockMap-Indexing.inl index 72d53168..ae7b556e 100644 --- a/source/blocks/BlockMap/BlockMap-Indexing.inl +++ b/source/blocks/BlockMap/BlockMap-Indexing.inl @@ -121,20 +121,44 @@ namespace Langulus::Anyness /// Get the bucket index, based on the provided value's hash /// @param mask - a mask for ANDing the relevant part of the hash - /// @param value - the value to hash + /// @param key - the key to hash /// @return the bucket index - LANGULUS(ALWAYS_INLINED) - Offset BlockMap::GetBucket(Offset mask, const CT::NoIntent auto& value) noexcept { - return HashOf(value).mHash & mask; + template LANGULUS(INLINED) + Offset BlockMap::GetBucket(Offset mask, const CT::NoIntent auto& key) const IF_UNSAFE(noexcept) { + using K_ALT = Deref; + + if constexpr (CT::Typed) { + using K = typename THIS::Key; + + if constexpr (CT::Similar) + return HashOf(key).mHash & mask; + else { + // Make sure we hash the contained type for correct results + return HashOf(static_cast(key)).mHash & mask; + } + } + else { + LANGULUS_ASSUME(DevAssumes, + mKeys.IsSimilar() or (CT::Sparse and mKeys.IsSparse()), + "Key type ", MetaDataOf(), " differs from contained type ", mKeys.GetType(), + ", hash integrity is compromised " + ); + return HashOf(key).mHash & mask; + } } /// Get the bucket index, based on the wrapped value's hash /// @param mask - a mask for ANDing the relevant part of the hash - /// @param value - the value to hash, wrapped in a block + /// @param key - the key to hash, wrapped in a block /// @return the bucket index - LANGULUS(ALWAYS_INLINED) - Offset BlockMap::GetBucketUnknown(Offset mask, const Block<>& value) noexcept { - return value.GetHash().mHash & mask; + LANGULUS(INLINED) + Offset BlockMap::GetBucketUnknown(Offset mask, const Block<>& key) const IF_UNSAFE(noexcept) { + LANGULUS_ASSUME(DevAssumes, + mKeys.IsSimilar(key.GetType()) or (key.IsSparse() and mKeys.IsSparse()), + "Key type ", key.GetType(), " differs from contained type ", mKeys.GetType(), + ", hash integrity is compromised " + ); + return key.GetHash().mHash & mask; } /// Get a key reference if THIS is typed, otherwise get a block diff --git a/source/blocks/BlockMap/BlockMap-Insert.inl b/source/blocks/BlockMap/BlockMap-Insert.inl index 7ace8b40..77e94612 100644 --- a/source/blocks/BlockMap/BlockMap-Insert.inl +++ b/source/blocks/BlockMap/BlockMap-Insert.inl @@ -37,12 +37,6 @@ namespace Langulus::Anyness // And make sure that type is set to the contained value type result.mType = mKeys.mType; return result; - - /*auto result = Many::FromMeta(mKeys.mType); - result.AllocateFresh(result.RequestSize(1)); - result.CreateWithIntent(S::Nest(key)); - ++result.mCount; - return result;*/ } } @@ -69,12 +63,6 @@ namespace Langulus::Anyness // And make sure that type is set to the contained value type result.mType = mValues.mType; return result; - - /*auto result = Many::FromMeta(mValues.mType); - result.AllocateFresh(result.RequestSize(1)); - result.CreateWithIntent(S::Nest(val)); - ++result.mCount; - return result;*/ } } @@ -201,7 +189,7 @@ namespace Langulus::Anyness Mutate, TypeOf>(); Reserve(GetCount() + 1); InsertInner( - GetBucket(GetReserved() - 1, DeintCast(key)), + GetBucket(GetReserved() - 1, DeintCast(key)), SK::Nest(key), SV::Nest(val) ); return 1; @@ -250,7 +238,7 @@ namespace Langulus::Anyness // Static type insertion auto& keyRef = DeintCast(key)[i]; InsertInner( - GetBucket(GetReserved() - 1, keyRef), + GetBucket(GetReserved() - 1, keyRef), SK::Nest(keyRef), SV::Nest(DeintCast(val)[i]) ); @@ -316,89 +304,17 @@ namespace Langulus::Anyness return valueByteSize; } - /// - template - void BlockMap::RehashInner(const Count hashmask, const Offset current, Offset& moveTo, auto& key, auto& val) { - Offset attempt = 0; - Offset wrapped = moveTo + attempt >= GetReserved() - ? (moveTo + attempt) - GetReserved() - : moveTo + attempt; - - while (mInfo[wrapped]) { - if (wrapped == current) - break; // Don't swap with self - - // While there's something on the rehashed slot - swap - // with it and continue swapping - auto nextKey = GetKeyHandle(wrapped); - if constexpr (CT::TypedMap) { - LANGULUS_ASSUME(DevAssumes, key.Get() != nextKey.Get(), - "Duplicated key - are map keys interfaced as static and change outside the map?" - " You should clone them when inserting!" - ); - } - else { - LANGULUS_ASSUME(DevAssumes, key != nextKey, - "Duplicated key - are map keys interfaced as static and change outside the map?" - " You should clone them when inserting!" - ); - } - - nextKey.Swap(key); - GetValHandle(wrapped).Swap(val); - mInfo[wrapped] = attempt + 1; - - // Where does the next element want to go? - Offset moveTo2 = 0; - if constexpr (CT::TypedMap) - moveTo2 = GetBucket(hashmask, key.Get()); - else - moveTo2 = GetBucketUnknown(hashmask, key); - - // Does it want to return here again? - // If so, continuously insert next to it - if ((moveTo2 >= moveTo and moveTo2 <= moveTo + attempt) - or (moveTo2 + GetReserved() >= moveTo - and moveTo2 + GetReserved() <= moveTo + attempt)) { - ++attempt; - - wrapped = moveTo + attempt >= GetReserved() - ? (moveTo + attempt) - GetReserved() - : moveTo + attempt; - - if (attempt == AllowedMisses) { - // Attempts go beyond the allowed count - the map - // has to be widened further - throw Except::Overflow(); - } - } - else { - moveTo = moveTo2; - attempt = 0; - wrapped = moveTo; - } - } - - if (wrapped != current) { - // This is reached when an empty desired slot was found - GetKeyHandle(wrapped).CreateWithIntent(Abandon(key)); - key.FreeInner(); - - GetValHandle(wrapped).CreateWithIntent(Abandon(val)); - val.FreeInner(); - - mInfo[current] = 0; - } - - mInfo[wrapped] = attempt + 1; - } - - /// Rehashes and reinserts each pair in the same block + /// Rehashes the table, by optionally reusing parts of the map /// @attention assumes count and oldCount are power-of-two /// @attention assumes count > oldCount + /// @attention will deallocate oldKeys and oldVals if provided + /// @param oldInfo - pointer to old info (used only if reusing keys) /// @param oldCount - the old number of pairs - template - void BlockMap::RehashBoth(const Count oldCount) { + /// @param oldKeys - source of keys (use nullptr to reuse the current) + /// @param oldVals - source of values (use nullptr to reuse the current) + /// @return true if map requires another resize and rehash (very rare) + template + bool BlockMap::Rehash(const InfoType* oldInfo, const Count oldCount, KEY_SOURCE& oldKeys, VAL_SOURCE& oldVals) { LANGULUS_ASSUME(DevAssumes, mKeys.mReserved > oldCount, "New count is not larger than oldCount"); LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(mKeys.mReserved), @@ -406,186 +322,235 @@ namespace Langulus::Anyness LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(oldCount), "Old count is not a power-of-two"); - // Keys were reused, but their entries shift forward - if (IsKeySparse()) { - MoveMemory( - mKeys.mRawSparse + GetReserved(), - mKeys.mRawSparse + oldCount, - oldCount - ); - }; - - // Vals were reused, but their entries shift forward - if (IsValueSparse()) { - MoveMemory( - mValues.mRawSparse + GetReserved(), - mValues.mRawSparse + oldCount, - oldCount - ); - }; - - auto info = mInfo; - const auto infoend = info + oldCount; - const auto hashmask = GetReserved() - 1; - - while (info != infoend) { - if (*info) { - // Use the 'current' slot as a swapper - const Offset current = info - mInfo; - auto key = GetKeyHandle(current); + constexpr bool ReusingKeys = CT::Nullptr; + constexpr bool ReusingVals = CT::Nullptr; + static_assert(ReusingKeys or ReusingVals, + "No need for a rehash call when nothing is reused " + "- just reinsert instead" + ); - // Where does the pair want to move after a rehash? - Offset moveTo = 0; - if constexpr (CT::TypedMap) - moveTo = GetBucket(hashmask, key.Get()); - else - moveTo = GetBucketUnknown(hashmask, key); - - // If it's the same position then we just move on, just - // make sure that info has been set to 1 - if (moveTo == current) { - mInfo[moveTo] = 1; - ++info; - continue; - } + if (IsEmpty()) { + ZeroMemory(mInfo, GetReserved()); - auto val = GetValHandle(current); - RehashInner(hashmask, current, moveTo, key, val); + // We should discard the old keys or values before returning + if constexpr (not ReusingKeys) { + LANGULUS_ASSUME(DevAssumes, oldKeys.mKeys.mEntry->GetUses() == 1, + "Deallocating old keys data that is still in use"); + Allocator::Deallocate(const_cast(oldKeys.mKeys.mEntry)); } - ++info; + if constexpr (not ReusingVals) { + LANGULUS_ASSUME(DevAssumes, oldVals.mValues.mEntry->GetUses() == 1, + "Deallocating old values data that is still in use"); + Allocator::Deallocate(const_cast(oldVals.mValues.mEntry)); + } + return false; + } + else { + // Make sure new info data is zeroed + // Moving memory to account for overlap + // IT IS CRITICAL THAT THIS IS DONE BEFORE ENTRIES! + MoveMemory(mInfo, oldInfo, oldCount); + ZeroMemory(mInfo + oldCount, GetReserved() - oldCount); } - } - - /// Rehashes and reinserts each key in the same block, and moves all - /// values in from the provided block - /// @attention assumes count and oldCount are power-of-two - /// @attention assumes count > oldCount - /// @param old - the old block, where keys and values come from - template - void BlockMap::RehashKeys(BlockMap& old) { - LANGULUS_ASSUME(DevAssumes, GetReserved() > old.GetReserved(), - "New count is not larger than oldCount"); - LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(GetReserved()), - "New count is not a power-of-two"); - - // Keys were reused, but their entries shift forward - if (IsKeySparse()) { - MoveMemory( - mKeys.mRawSparse + GetReserved(), - mKeys.mRawSparse + old.GetReserved(), - old.GetReserved() - ); - }; - // Reusing keys means reusing info, but we still have to mark - // which values have been initialized. So we move the info array - // to a temporary, and rebuild the one in the map. - TMany temp_info {Copy(MakeBlock(old.mInfo, old.GetReserved()))}; - ZeroMemory(mInfo, GetReserved()); + if constexpr (ReusingKeys) { + // Keys were reused, but their entries shift forward + if (IsKeySparse()) { + MoveMemory( + mKeys.mRawSparse + GetReserved(), + mKeys.mRawSparse + oldCount, + oldCount + ); + }; + } - auto info = temp_info.GetRaw(); - const auto infoend = info + old.GetReserved(); + if constexpr (ReusingVals) { + // Vals were reused, but their entries shift forward + if (IsValueSparse()) { + MoveMemory( + mValues.mRawSparse + GetReserved(), + mValues.mRawSparse + oldCount, + oldCount + ); + }; + } + + (void) oldInfo; + auto info = mInfo; + const auto infoend = info + oldCount; const auto hashmask = GetReserved() - 1; - + constexpr auto MarkedForReinsertion = AllowedMisses; + + // In order to minimize swaps, we do the rehash in three passes + // First pass immediately moves any pair into an empty slot, if + // such exists after a rehash (rehashing onto itself also counts). + // This provides the table with some breathing room. The rest of + // the pairs are marked for next pass by their offset being + // exactly AllowedMisses while (info != infoend) { - if (*info) { - const Offset current = info - temp_info.GetRaw(); - auto key = GetKeyHandle(current); - auto val = GetValHandle(current); - auto oldVal = old.GetValHandle(current); - val.CreateWithIntent(Abandon(oldVal)); - oldVal.FreeInner(); - - // Where does the pair want to move after a rehash? - Offset moveTo = 0; - if constexpr (CT::TypedMap) - moveTo = GetBucket(hashmask, key.Get()); - else - moveTo = GetBucketUnknown(hashmask, key); - - // If it's the same position, then just initialize value, - // and make sure that info has been reset to 1 - if (moveTo == current) { - mInfo[moveTo] = 1; - ++info; - continue; + if (not *info) { + ++info; + continue; + } + + // Where does the pair want to move after a rehash? + const Offset current = info - mInfo; + auto key = [&] { + if constexpr (ReusingKeys) return GetKeyHandle(current); + else return oldKeys.template GetKeyHandle(current); + }(); + auto val = [&] { + if constexpr (ReusingVals) return GetValHandle(current); + else return oldVals.template GetValHandle(current); + }(); + + Offset moveTo = 0; + if constexpr (CT::TypedMap) + moveTo = GetBucket(hashmask, key.Get()); + else + moveTo = GetBucketUnknown(hashmask, key); + + if (moveTo == current) { + // It rehashes onto itself + // Reset the offset and don't forget to copy from sources + if constexpr (not ReusingKeys) { + GetKeyHandle(current).CreateWithIntent(Abandon(key)); + key.FreeInner(); + } + if constexpr (not ReusingVals) { + GetValHandle(current).CreateWithIntent(Abandon(val)); + val.FreeInner(); + } + + *info = 1; + } + else if (not mInfo[moveTo]) { + // Immediately move it if destination is empty + mInfo[moveTo] = 1; + GetKeyHandle(moveTo).CreateWithIntent(Abandon(key)); + GetValHandle(moveTo).CreateWithIntent(Abandon(val)); + key.FreeInner(); + val.FreeInner(); + + *info = 0; + } + else { + // Other mark for stage 2. Just make sure data that is from + // outside is moved in + if constexpr (not ReusingKeys) { + GetKeyHandle(current).CreateWithIntent(Abandon(key)); + key.FreeInner(); + } + if constexpr (not ReusingVals) { + GetValHandle(current).CreateWithIntent(Abandon(val)); + val.FreeInner(); } - RehashInner(hashmask, current, moveTo, key, val); + *info = MarkedForReinsertion; } ++info; } - // We can discard the old values - LANGULUS_ASSUME(DevAssumes, old.mValues.mEntry->GetUses() == 1, - "Deallocating old values data that is still in use"); - Allocator::Deallocate(const_cast(old.mValues.mEntry)); - } - - /// Rehashes and reinserts each value in the same block, and moves all - /// keys in from the provided block - /// @attention assumes count and oldCount are power-of-two - /// @attention assumes count > oldCount - /// @param old - the old block, where keys and values come from - template - void BlockMap::RehashVals(BlockMap& old) { - LANGULUS_ASSUME(DevAssumes, GetReserved() > old.GetReserved(), - "New count is not larger than oldCount"); - LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(GetReserved()), - "New count is not a power-of-two"); + // We can discard the old keys or values at this point, because + // the second stage works only with local stuff + if constexpr (not ReusingKeys) { + LANGULUS_ASSUME(DevAssumes, oldKeys.mKeys.mEntry->GetUses() == 1, + "Deallocating old keys data that is still in use"); + Allocator::Deallocate(const_cast(oldKeys.mKeys.mEntry)); + } - // Vals were reused, but their entries shift forward - if (IsValueSparse()) { - MoveMemory( - mValues.mRawSparse + GetReserved(), - mValues.mRawSparse + old.GetReserved(), - old.GetReserved() - ); - }; + if constexpr (not ReusingVals) { + LANGULUS_ASSUME(DevAssumes, oldVals.mValues.mEntry->GetUses() == 1, + "Deallocating old values data that is still in use"); + Allocator::Deallocate(const_cast(oldVals.mValues.mEntry)); + } - // Not reusing keys means not reusing info - ZeroMemory(mInfo, GetReserved()); + // The second pass is interested only in pairs that have offset + // of exactly AllowedMisses. A duplicate is inserted by as many + // swaps as needed, after which the old slot is freed. + info = mInfo; + while (info != infoend) { + if (*info != MarkedForReinsertion) { + ++info; + continue; + } - auto info = old.GetInfo(); - const auto infoend = old.GetInfoEnd(); - const auto hashmask = GetReserved() - 1; + // Where does the pair want to move after a rehash? + const Offset current = info - mInfo; + auto key = GetKeyHandle(current); + auto val = GetValHandle(current); + Offset moveTo = 0; + if constexpr (CT::TypedMap) + moveTo = GetBucket(hashmask, key.Get()); + else + moveTo = GetBucketUnknown(hashmask, key); + + // Insert, swap if we have to + { + // This is like a simplified InsertInner, keep it in sync + // Get the starting index based on the key hash + auto psl = mInfo + moveTo; + const auto pslEnd = GetInfoEnd(); + InfoType attempts = 1; + while (*psl) { + const auto index = psl - GetInfo(); + if (attempts > *psl) { + // Pair we're inserting is closer to bucket, so swap + GetKeyHandle(index).Swap(key); + GetValHandle(index).Swap(val); + ::std::swap(attempts, *psl); + } - while (info != infoend) { - if (*info) { - const Offset current = info - old.GetInfo(); - auto key = GetKeyHandle(current); - auto val = GetValHandle(current); - auto oldKey = old.GetKeyHandle(current); - key.CreateWithIntent(Abandon(oldKey)); - oldKey.FreeInner(); - - // Where does the pair want to move after a rehash? - Offset moveTo = 0; - if constexpr (CT::TypedMap) - moveTo = GetBucket(hashmask, key.Get()); - else - moveTo = GetBucketUnknown(hashmask, key); - - // If it's the same position, then just initialize key, and - // make sure that info has been set to 1 - if (moveTo == current) { - mInfo[moveTo] = 1; - ++info; - continue; + if (attempts >= AllowedMisses) { + // Oh boy, we need a resize while resizing! + // Stop whatever we're doing, just dump the last thing + // anywhere that is empty. The offsets will be wrong + // but it doesn't matter mid-rehashing. Just inform + // we need another one, and it should tidy things up. + // This can repeat indefinitely until RAM ends. + //Logger::Special("Sequential resize triggered, ", GetCount(), "/", GetReserved(), " full"); + Offset last = 0; + while (mInfo[last] and last < GetReserved()) + ++last; + + LANGULUS_ASSUME(DevAssumes, last < GetReserved(), + "Shouldn't ever happen, but better safe than sorry"); + + GetKeyHandle(last).CreateWithIntent(Abandon(key)); + GetValHandle(last).CreateWithIntent(Abandon(val)); + key.FreeInner(); + val.FreeInner(); + mInfo[last] = 1; + return true; + } + + ++attempts; + + // Wrap around and start from the beginning if we have to + if (psl < pslEnd - 1) ++psl; + else psl = mInfo; } - RehashInner(hashmask, current, moveTo, key, val); + const Offset index = psl - GetInfo(); + LANGULUS_ASSUME(DevAssumes, current != index, + "Shouldn't ever happen, but better safe than sorry"); + + GetKeyHandle(index).CreateWithIntent(Abandon(key)); + GetValHandle(index).CreateWithIntent(Abandon(val)); + key.FreeInner(); + val.FreeInner(); + *psl = attempts; } + *info = 0; ++info; } - // We can discard the old keys - LANGULUS_ASSUME(DevAssumes, old.mKeys.mEntry->GetUses() == 1, - "Deallocating old keys data that is still in use"); - Allocator::Deallocate(const_cast(old.mKeys.mEntry)); + // Third pass shifts element left wherever possible to fill haps + ShiftPairs(); + return false; } /// Shift elements left where possible @@ -619,22 +584,24 @@ namespace Langulus::Anyness if (not mInfo[to] and attempt < *oldInfo) { // Empty spot found, so move pair there auto key = GetKeyHandle(oldIndex); - GetKeyHandle(to).CreateWithIntent(Abandon(key)); - key.FreeInner(); - auto val = GetValHandle(oldIndex); + GetKeyHandle(to).CreateWithIntent(Abandon(key)); GetValHandle(to).CreateWithIntent(Abandon(val)); + key.FreeInner(); val.FreeInner(); mInfo[to] = attempt; *oldInfo = 0; ++moves_performed; + //Logger::Verbose(Logger::Red, oldIndex, " shifted to ", to); } } ++oldInfo; } + //Logger::Verbose(moves_performed, " moves performed"); + } while (moves_performed); } @@ -647,7 +614,7 @@ namespace Langulus::Anyness /// @param val - value to insert, with or without intent /// @return the offset at which pair was inserted template - Offset BlockMap::InsertInner(const Offset start, auto&& key, auto&& val) { + Offset BlockMap::InsertInner(Offset start, auto&& key, auto&& val) { BranchOut(); using SK = IntentOf; using SV = IntentOf; @@ -656,7 +623,7 @@ namespace Langulus::Anyness // Get the starting index based on the key hash auto psl = GetInfo() + start; - const auto pslEnd = GetInfoEnd(); + auto pslEnd = GetInfoEnd(); InfoType attempts = 1; Offset insertedAt = mKeys.mReserved; while (*psl) { @@ -680,14 +647,35 @@ namespace Langulus::Anyness insertedAt = index; } - ++attempts; + if (attempts >= AllowedMisses) { + // Oops, this is bad - we've reached the limit of the + // robin-hood algorithm. The map is too saturated, and we + // need to widen its table. We should also do it while + // conscious of the loop we're in currently, so that we + // don't break anything. + //Logger::Special("Attempt will go out of bounds (", AllowedMisses, + // ") - map is ", GetCount(), "/", GetReserved(), " full"); + + // Make map twice as big. This will invalidate any iterator + // Can repeat indefinitely + while (AllocateData(GetReserved() * 2)); - if (attempts == AllowedMisses) { - // Attempts go beyond the allowed count - the map has to - // be widened further - throw Except::Overflow(); + // Rehash the key that currently resides in keyswapper + if constexpr (CT::TypedMap) + start = GetBucket(GetReserved() - 1, keyswapper.Get()); + else + start = GetBucketUnknown(GetReserved() - 1, keyswapper); + + // Refresh all local variables before continuing the loop + psl = GetInfo() + start; + pslEnd = GetInfoEnd(); + attempts = 1; + // Continue as if nothing had happened + continue; } + ++attempts; + // Wrap around and start from the beginning if we have to if (psl < pslEnd - 1) ++psl; @@ -708,7 +696,7 @@ namespace Langulus::Anyness *psl = attempts; ++mKeys.mCount; - return insertedAt; + return insertedAt; //TODO insertedAt will mostly likely be invalid if (attempts >= AllowedMisses) branch happened!!!!! can't figure out a way to compensate for that :( } /// Inner insertion function based on reflected move-assignment @@ -754,6 +742,9 @@ namespace Langulus::Anyness insertedAt = index; } + LANGULUS_ASSUME(DevAssumes, attempts < AllowedMisses, + "Attempt will go out of bounds"); + ++attempts; // Wrap around and start from the beginning if needed @@ -801,17 +792,17 @@ namespace Langulus::Anyness if constexpr (CT::Typed) { // Insert a statically typed pair InsertInner( - GetBucket(hashmask, pair->mKey), - S::Nest(pair->GetKeyHandle()), - S::Nest(pair->GetValueHandle()) + GetBucket(hashmask, pair->GetKey()), + pair.Nest(pair->GetKeyHandle()), + pair.Nest(pair->GetValueHandle()) ); } else { // Insert a type-erased pair InsertBlockInner( - GetBucketUnknown(hashmask, pair->mKey), - S::Nest(pair->mKey), - S::Nest(pair->mValue) + GetBucketUnknown(hashmask, pair->GetKey()), + pair.Nest(pair->GetKey()), + pair.Nest(pair->GetValue()) ); } return GetCount() - initialCount; diff --git a/source/blocks/BlockMap/BlockMap-Iteration.inl b/source/blocks/BlockMap/BlockMap-Iteration.inl index 1b125d92..c989f70c 100644 --- a/source/blocks/BlockMap/BlockMap-Iteration.inl +++ b/source/blocks/BlockMap/BlockMap-Iteration.inl @@ -517,24 +517,26 @@ namespace Langulus::Anyness /// Construct from end point template LANGULUS(INLINED) constexpr BlockMap::Iterator::Iterator(const A::IteratorEnd&) noexcept - : mKey {} - , mValue {} - , mInfo {} - , mSentinel {} {} + : Iterator {} {} /// Prefix increment operator /// Moves pointers to the right, unless end has been reached /// @return the modified iterator template LANGULUS(INLINED) - constexpr BlockMap::Iterator& BlockMap::Iterator::operator ++ () noexcept { - if (mInfo == mSentinel) - return *this; + constexpr auto BlockMap::Iterator::operator ++ () noexcept -> Iterator& { + LANGULUS_ASSUME(UserAssumes, mInfo < mSentinel, + "Don't ++ an iterator if end was reached"); // Seek next valid info, or hit sentinel at the end const auto previous = mInfo; - while (not *++mInfo) - ; + do ++mInfo; + while (not *mInfo); + + // No point in doing anything if end was reached + if (mInfo >= mSentinel) + return *this; + // Move all pointers forward const auto offset = mInfo - previous; if constexpr (CT::Typed) { const_cast(mKey) += offset; @@ -558,7 +560,7 @@ namespace Langulus::Anyness /// Moves pointers to the right, unless end has been reached /// @return the previous value of the iterator template LANGULUS(INLINED) - constexpr BlockMap::Iterator BlockMap::Iterator::operator ++ (int) noexcept { + constexpr auto BlockMap::Iterator::operator ++ (int) noexcept -> Iterator { const auto backup = *this; operator ++ (); return backup; @@ -585,8 +587,8 @@ namespace Langulus::Anyness /// @return the pair at the current iterator position template LANGULUS(INLINED) constexpr auto BlockMap::Iterator::operator * () const { - if (mInfo >= mSentinel) - LANGULUS_OOPS(Access, "Trying to access end of iteration"); + LANGULUS_ASSUME(UserAssumes, mInfo < mSentinel, + "Accessing an end operator"); const auto me = const_cast*>(this); using B = Conditional, Block<>&, const Block<>&>; diff --git a/source/blocks/BlockMap/BlockMap-Memory.inl b/source/blocks/BlockMap/BlockMap-Memory.inl index eb083074..3412ca20 100644 --- a/source/blocks/BlockMap/BlockMap-Memory.inl +++ b/source/blocks/BlockMap/BlockMap-Memory.inl @@ -17,12 +17,22 @@ namespace Langulus::Anyness /// @param count - number of pairs to allocate template LANGULUS(INLINED) void BlockMap::Reserve(const Count count) { - AllocateInner( - Roof2(count < MinimalAllocation ? MinimalAllocation : count) - ); + if (GetReserved()) { + while (count > GetReserved()) + AllocateMore(); + } + else if (count) { + AllocateFresh( + Roof2(count < MinimalAllocation ? MinimalAllocation : count) + ); + + // Zero the info array and set the sentinel at the end + ZeroMemory(mInfo, GetReserved()); + mInfo[GetReserved()] = 1; + } } - /// Allocate a fresh set keys and values (for internal use only) + /// Allocate a fresh set of keys and values (for internal use only) /// @attention doesn't initialize anything, but the memory state /// @attention doesn't modify count, doesn't set info sentinel /// @attention assumes count is a power-of-two @@ -59,8 +69,9 @@ namespace Langulus::Anyness /// @attention assumes key and value types have been set prior /// @tparam REUSE - true to reallocate, false to allocate fresh /// @param count - the new number of pairs + /// @return true if another resize is required after this one template - void BlockMap::AllocateData(const Count count) { + bool BlockMap::AllocateData(const Count count) { LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(count), "Table reallocation count is not a power-of-two"); LANGULUS_ASSUME(DevAssumes, mKeys.mType and mValues.mType, @@ -118,30 +129,17 @@ namespace Langulus::Anyness if (mKeys.mEntry == old.mKeys.mEntry or mValues.mEntry == old.mValues.mEntry) { // No escape from this scope - // Check if keys were reused + std::nullptr_t force_reuse; + bool continue_resizing; if (mKeys.mEntry == old.mKeys.mEntry) { - if (mValues.mEntry == old.mValues.mEntry) { - // Both keys and values come from 'this' - // Reusing keys means reusing info, but it shifts - // Moving memory to account for potential overlap - //TODO is overlap really possible, if map always doubles?? - MoveMemory(mInfo, old.mInfo, old.GetReserved()); - // Make sure new info data is zeroed - ZeroMemory(mInfo + old.GetReserved(), count - old.GetReserved()); - - RehashBoth(old.GetReserved()); - } - else { - // Keys come from 'this', values come from 'old' - RehashKeys(old); - } - } - else { - // Keys come from 'old', values come from 'this' - RehashVals(old); + if (mValues.mEntry == old.mValues.mEntry) + continue_resizing = Rehash(old.mInfo, old.GetReserved(), force_reuse, force_reuse); + else + continue_resizing = Rehash(old.mInfo, old.GetReserved(), force_reuse, old); } + else continue_resizing = Rehash(old.mInfo, old.GetReserved(), old, force_reuse); - return; + return continue_resizing; } } @@ -150,24 +148,25 @@ namespace Langulus::Anyness if (old.IsEmpty()) { // There are no old values, the previous map was empty // Just do an early return right here - return; + return false; } // If reached, then keys or values (or both) moved // Reinsert all pairs to rehash mKeys.mCount = 0; - UNUSED() auto& me = reinterpret_cast(*this); auto key = old.GetKeyHandle(0); auto val = old.GetValHandle(0); - const auto hashmask = GetReserved() - 1; const auto infoend = old.GetInfoEnd(); + // This should gracefully handle oversaturation by nesting + // the AllocateData calls. Shouldn't affect anything but the + // hashmask, because the iterators are in the old block... while (old.mInfo != infoend) { if (*old.mInfo) { if constexpr (CT::TypedMap) { InsertInner( - GetBucket(hashmask, key.Get()), + GetBucket(GetReserved() - 1, key.Get()), Abandon(key), Abandon(val) ); key.FreeInner(); @@ -175,19 +174,15 @@ namespace Langulus::Anyness } else { InsertBlockInner( - GetBucketUnknown(hashmask, key), + GetBucketUnknown(GetReserved() - 1, key), Abandon(key), Abandon(val) ); - if (key) - key.FreeInner(); - else - key.mCount = 1; + if (key) key.FreeInner(); + else key.mCount = 1; - if (val) - val.FreeInner(); - else - val.mCount = 1; + if (val) val.FreeInner(); + else val.mCount = 1; } } @@ -200,11 +195,17 @@ namespace Langulus::Anyness if constexpr (REUSE) { // When reusing, keys and values can potentially remain same // Avoid deallocating them if that's the case - if (old.mValues.mEntry != mValues.mEntry) + if (old.mValues.mEntry != mValues.mEntry) { + LANGULUS_ASSUME(DevAssumes, old.mValues.mEntry->GetUses() == 1, + "Shouln't happen"); Allocator::Deallocate(const_cast(old.mValues.mEntry)); + } - if (old.mKeys.mEntry != mKeys.mEntry) + if (old.mKeys.mEntry != mKeys.mEntry) { + LANGULUS_ASSUME(DevAssumes, old.mKeys.mEntry->GetUses() == 1, + "Shouln't happen"); Allocator::Deallocate(const_cast(old.mKeys.mEntry)); + } } else { // Not reusing, so either deallocate, or dereference @@ -222,24 +223,20 @@ namespace Langulus::Anyness Allocator::Deallocate(const_cast(old.mValues.mEntry)); } } + + return false; } - /// Reserves space for the specified number of pairs - /// @attention does nothing if reserving less than current reserve - /// @attention assumes count is a power-of-two number - /// @param count - number of pairs to allocate + /// Doubles the reserved memory template LANGULUS(INLINED) - void BlockMap::AllocateInner(Count count) { - // Shrinking is never allowed, you'll have to do it explicitly - // via Compact() - if (count <= GetReserved()) - return; + void BlockMap::AllocateMore() { + LANGULUS_ASSUME(DevAssumes, GetReserved(), + "Can't AllocateMore, needs to AllocateFresh first"); - // Allocate/Reallocate the keys and info if (IsAllocated() and mKeys.GetUses() == 1 and mValues.GetUses() == 1) - AllocateData(count); + while (AllocateData(GetReserved() * 2)); else - AllocateData(count); + while (AllocateData(GetReserved() * 2)); } /// Reference memory block once diff --git a/source/blocks/BlockSet.hpp b/source/blocks/BlockSet.hpp index 7608558f..1d67c420 100644 --- a/source/blocks/BlockSet.hpp +++ b/source/blocks/BlockSet.hpp @@ -108,55 +108,55 @@ namespace Langulus::Anyness /// Capsulation /// template - NOD() DMeta GetType() const noexcept; + DMeta GetType() const noexcept; template - NOD() constexpr bool IsTyped() const noexcept; + constexpr bool IsTyped() const noexcept; template - NOD() constexpr bool IsUntyped() const noexcept; + constexpr bool IsUntyped() const noexcept; template - NOD() constexpr bool IsTypeConstrained() const noexcept; + constexpr bool IsTypeConstrained() const noexcept; template - NOD() constexpr bool IsDeep() const noexcept; + constexpr bool IsDeep() const noexcept; template - NOD() constexpr bool IsSparse() const noexcept; + constexpr bool IsSparse() const noexcept; template - NOD() constexpr bool IsDense() const noexcept; + constexpr bool IsDense() const noexcept; template - NOD() constexpr Size GetStride() const noexcept; - NOD() constexpr DataState GetState() const noexcept; - NOD() constexpr Count GetCount() const noexcept; - NOD() Count GetCountDeep() const noexcept; - NOD() Count GetCountElementsDeep() const noexcept; - NOD() constexpr Count GetReserved() const noexcept; - NOD() constexpr bool IsEmpty() const noexcept; - NOD() constexpr bool IsValid() const noexcept; - NOD() constexpr bool IsInvalid() const noexcept; - NOD() constexpr bool IsAllocated() const noexcept; - - NOD() bool IsConstant() const noexcept; - NOD() bool IsCompressed() const noexcept; - NOD() bool IsEncrypted() const noexcept; - NOD() bool IsMissing() const noexcept; + constexpr Size GetStride() const noexcept; + constexpr auto GetState() const noexcept -> DataState; + constexpr auto GetCount() const noexcept -> Count; + Count GetCountDeep() const noexcept; + Count GetCountElementsDeep() const noexcept; + constexpr auto GetReserved() const noexcept -> Count; + constexpr bool IsEmpty() const noexcept; + constexpr bool IsValid() const noexcept; + constexpr bool IsInvalid() const noexcept; + constexpr bool IsAllocated() const noexcept; + + bool IsConstant() const noexcept; + bool IsCompressed() const noexcept; + bool IsEncrypted() const noexcept; + bool IsMissing() const noexcept; template - NOD() bool IsMissingDeep() const; + bool IsMissingDeep() const; template - NOD() bool IsExecutable() const noexcept; + bool IsExecutable() const noexcept; template - NOD() bool IsExecutableDeep() const; + bool IsExecutableDeep() const; template - NOD() constexpr bool IsInsertable(DMeta) const noexcept; + constexpr bool IsInsertable(DMeta) const noexcept; template - NOD() constexpr bool IsInsertable() const noexcept; + constexpr bool IsInsertable() const noexcept; template - NOD() bool IsOrdered() const noexcept; + bool IsOrdered() const noexcept; - NOD() constexpr auto GetAllocation() const noexcept -> const Allocation*; - NOD() constexpr Count GetUses() const noexcept; + constexpr auto GetAllocation() const noexcept -> const Allocation*; + constexpr auto GetUses() const noexcept -> Count; - NOD() constexpr explicit operator bool() const noexcept; + constexpr explicit operator bool() const noexcept; #if LANGULUS(DEBUG) template void Dump() const; @@ -164,47 +164,47 @@ namespace Langulus::Anyness protected: template - NOD() auto& GetValues() const noexcept; + auto& GetValues() const noexcept; template - NOD() auto& GetValues() noexcept; + auto& GetValues() noexcept; - NOD() InfoType const* GetInfo() const noexcept; - NOD() InfoType* GetInfo() noexcept; - NOD() InfoType const* GetInfoEnd() const noexcept; + auto GetInfo() const noexcept -> InfoType const*; + auto GetInfo() noexcept -> InfoType*; + auto GetInfoEnd() const noexcept -> InfoType const*; - NOD() Count GetCountDeep(const Block<>&) const noexcept; - NOD() Count GetCountElementsDeep(const Block<>&) const noexcept; + Count GetCountDeep(const Block<>&) const noexcept; + Count GetCountElementsDeep(const Block<>&) const noexcept; public: /// /// Indexing /// template - NOD() decltype(auto) Get(CT::Index auto) const; + decltype(auto) Get(CT::Index auto) const; template - NOD() decltype(auto) operator[] (CT::Index auto) const; + decltype(auto) operator[] (CT::Index auto) const; protected: template - NOD() Offset SimplifyIndex(INDEX) const + Offset SimplifyIndex(INDEX) const noexcept(not LANGULUS_SAFE() and CT::BuiltinInteger); - NOD() static Offset GetBucket(Offset, const CT::NoIntent auto&) noexcept; - NOD() static Offset GetBucketUnknown(Offset, const Block<>&) noexcept; + static Offset GetBucket(Offset, const CT::NoIntent auto&) noexcept; + static Offset GetBucketUnknown(Offset, const Block<>&) noexcept; template - NOD() decltype(auto) GetRaw(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetRaw(Offset) IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRaw(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetRaw(Offset) const IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRef(Offset) IF_UNSAFE(noexcept); + decltype(auto) GetRef(Offset) IF_UNSAFE(noexcept); template - NOD() decltype(auto) GetRef(Offset) const IF_UNSAFE(noexcept); + decltype(auto) GetRef(Offset) const IF_UNSAFE(noexcept); template - NOD() auto GetHandle(Offset) IF_UNSAFE(noexcept); + auto GetHandle(Offset) IF_UNSAFE(noexcept); public: /// @@ -214,14 +214,14 @@ namespace Langulus::Anyness struct Iterator; template - NOD() Iterator begin() noexcept; + auto begin() noexcept -> Iterator; template - NOD() Iterator begin() const noexcept; + auto begin() const noexcept -> Iterator; template - NOD() Iterator last() noexcept; + auto last() noexcept -> Iterator; template - NOD() Iterator last() const noexcept; + auto last() const noexcept -> Iterator; constexpr A::IteratorEnd end() const noexcept { return {}; } @@ -250,19 +250,19 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool Is() const noexcept; + constexpr bool Is() const noexcept; template - NOD() bool Is(DMeta) const noexcept; + bool Is(DMeta) const noexcept; template - NOD() constexpr bool IsSimilar() const noexcept; + constexpr bool IsSimilar() const noexcept; template - NOD() bool IsSimilar(DMeta) const noexcept; + bool IsSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsExact() const noexcept; + constexpr bool IsExact() const noexcept; template - NOD() bool IsExact(DMeta) const noexcept; + bool IsExact(DMeta) const noexcept; template void SetType(DMeta); @@ -276,7 +276,7 @@ namespace Langulus::Anyness bool Mutate(DMeta); template - NOD() constexpr bool IsTypeCompatibleWith(CT::Set auto const&) const noexcept; + constexpr bool IsTypeCompatibleWith(CT::Set auto const&) const noexcept; public: /// @@ -286,23 +286,23 @@ namespace Langulus::Anyness bool operator == (const CT::NoIntent auto&) const; template - NOD() Hash GetHash() const; + Hash GetHash() const; template - NOD() bool Contains(const CT::NoIntent auto&) const; + bool Contains(const CT::NoIntent auto&) const; template - NOD() Index Find(const CT::NoIntent auto&) const; + auto Find(const CT::NoIntent auto&) const -> Index; template - NOD() Iterator FindIt(const CT::NoIntent auto&); + auto FindIt(const CT::NoIntent auto&) -> Iterator; template - NOD() Iterator FindIt(const CT::NoIntent auto&) const; + auto FindIt(const CT::NoIntent auto&) const -> Iterator; protected: template - NOD() Offset FindInner(const CT::NoIntent auto&) const; + Offset FindInner(const CT::NoIntent auto&) const; template - NOD() Offset FindBlockInner(const Block<>&) const; + Offset FindBlockInner(const Block<>&) const; public: /// @@ -344,7 +344,7 @@ namespace Langulus::Anyness auto CreateValHandle(auto&&); template - NOD() Size RequestKeyAndInfoSize(Count, Offset&) const IF_UNSAFE(noexcept); + Size RequestKeyAndInfoSize(Count, Offset&) const IF_UNSAFE(noexcept); template void Rehash(Count); @@ -382,8 +382,8 @@ namespace Langulus::Anyness Count RemoveKeyInner(const CT::NoIntent auto&); #if LANGULUS(TESTING) - public: NOD() constexpr const void* GetRawMemory() const noexcept; - public: NOD() const Allocation* GetEntry() const noexcept; + public: constexpr auto GetRawMemory() const noexcept -> const void*; + public: auto GetEntry() const noexcept -> const Allocation*; #endif }; @@ -425,16 +425,16 @@ namespace Langulus::Anyness constexpr Iterator& operator = (const Iterator&) noexcept = default; constexpr Iterator& operator = (Iterator&&) noexcept = default; - NOD() constexpr bool operator == (const Iterator&) const noexcept; - NOD() constexpr bool operator == (const A::IteratorEnd&) const noexcept; + constexpr bool operator == (const Iterator&) const noexcept; + constexpr bool operator == (const A::IteratorEnd&) const noexcept; - NOD() constexpr decltype(auto) operator * () const; + constexpr decltype(auto) operator * () const; // Prefix operator constexpr Iterator& operator ++ () noexcept; // Suffix operator - NOD() constexpr Iterator operator ++ (int) noexcept; + constexpr Iterator operator ++ (int) noexcept; constexpr explicit operator bool() const noexcept; constexpr operator Iterator() const noexcept requires Mutable; diff --git a/source/blocks/BlockSet/BlockSet-Capsulation.inl b/source/blocks/BlockSet/BlockSet-Capsulation.inl index 408943da..bea203f4 100644 --- a/source/blocks/BlockSet/BlockSet-Capsulation.inl +++ b/source/blocks/BlockSet/BlockSet-Capsulation.inl @@ -251,7 +251,7 @@ namespace Langulus::Anyness while (info != infoEnd) { const auto index = info - GetInfo(); if (*info) - Logger::Info('[', index, "] -", (*info-1), " -> ", GetRaw(index).GetHash().mHash); + Logger::Info('[', index, "] -", (*info-1), " -> ", GetRaw(index).GetHash()); else Logger::Info('[', index, "] empty"); diff --git a/source/blocks/BlockSet/BlockSet-Construct.inl b/source/blocks/BlockSet/BlockSet-Construct.inl index 798fbbc5..3d780e34 100644 --- a/source/blocks/BlockSet/BlockSet-Construct.inl +++ b/source/blocks/BlockSet/BlockSet-Construct.inl @@ -7,6 +7,7 @@ /// #pragma once #include "../BlockSet.hpp" +#include namespace Langulus::Anyness diff --git a/source/blocks/BlockSet/BlockSet-Insert.inl b/source/blocks/BlockSet/BlockSet-Insert.inl index 1a34d9fb..dce1d7e6 100644 --- a/source/blocks/BlockSet/BlockSet-Insert.inl +++ b/source/blocks/BlockSet/BlockSet-Insert.inl @@ -345,7 +345,7 @@ namespace Langulus::Anyness LANGULUS_ASSUME(DevAssumes, IsPowerOfTwo(oldCount), "Old count is not a power-of-two"); - UNUSED() auto& me = reinterpret_cast(*this); + [[maybe_unused]] auto& me = reinterpret_cast(*this); auto oldKey = GetHandle(0); auto oldInfo = GetInfo(); const auto oldInfoEnd = oldInfo + oldCount; diff --git a/source/components/Components.hpp b/source/components/Components.hpp deleted file mode 100644 index 763f11ce..00000000 --- a/source/components/Components.hpp +++ /dev/null @@ -1,159 +0,0 @@ -/// -/// Langulus::Anyness -/// Copyright (c) 2012 Dimo Markov -/// Part of the Langulus framework, see https://langulus.com -/// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses -/// -#pragma once -#include "../DataState.hpp" -#include "../Compare.hpp" -#include "../Index.hpp" -#include "../Iterator.hpp" -#include "../one/Handle.hpp" -#include "../one/Own.hpp" - - -/// -/// Components are simple structures that when combined, define the size of -/// containers and their behavior. Any change in these structures' layout -/// will need to be paired with a major version change. -/// -namespace Langulus::Anyness::Component -{ - - /// - /// The data component has a type-erased pointer to some data - /// - struct Data { - union { - // Display as a string for ease of debugging - DEBUGGERY(char* mStartChar); - // Raw pointer to first element inside the memory block - Byte* mStart {}; - // The pointer can point to another pointer - Byte** mStartSparse; - }; - }; - - /// - /// The source component keeps a pointer to an allocation - /// - struct Source { - // Pointer to an allocation. If this entry is zero, then data - // is static, and we have no authority over resizing it - Allocation* mSource {}; - }; - - /// - /// The range component allows us to represent contiguous memory - /// If N is CountMax, then the memory is resizable at runtime. - /// - template - struct Range { - static_assert(N > 0, "N must be greater than zero"); - static constexpr Count CellCount = N; - }; - - template<> - struct Range { - // Pointer to the first uninitialized element - Byte* mNext; - union { - // Pointer to the end - Byte* mEnd; - // Also, this is where usually sources of pointers start - Allocation** mSparseSources; - } - }; - - /// - /// The meta component contains RTTI type information. If T is void, the - /// container is considered type-erased - its type may change at runtime. - /// - template - struct Meta { - using CellType = T; - }; - - template<> - struct Meta { - // The contained type - DMeta mType; - }; - - /// - /// The ownership component makes sure that contained data and sources - /// are properly referenced when transferred between containers. - /// - struct Ownership {}; - - /// - /// The hashed component makes sure that hashing is cached, so that it - /// isn't recomputed every time. - /// - struct Hashed { - // The cached hash - Hash mHash {}; - }; - - /// - /// The Small Value Optimization component allows for part of the layout - /// to be reused to allocate small data on the stack, instead of on the - /// heap. - /// - struct SVO {}; - - /// - /// The table component allows for cells to be reused - /// - struct Table { - // Pointer to the start of the table array - Byte* mTable; - }; - - /// - /// The ordered component generates indices for sorting - /// - struct Ordered { - - }; - - /// - /// The missing component allows for a container to be marked missing - /// - struct Missing { - - }; - - /// - /// The 'or' component allows container to be marked as disjunctive - /// - struct Or { - - }; - - /// - /// The compress component allows contained memory to be compressed - /// - struct Compress { - - }; - - /// - /// The encrypt component allows contained memory to be encrypted - /// - struct Encrypt { - - }; - - /// - /// The constant component allows contained memory to be marked as - /// constant, to prevent any change at runtime. - /// - struct Constant { - - }; - -} // namespace Langulus::Anyness::Layout \ No newline at end of file diff --git a/source/components/Layouts.hpp b/source/components/Layouts.hpp deleted file mode 100644 index 73bb4c99..00000000 --- a/source/components/Layouts.hpp +++ /dev/null @@ -1,40 +0,0 @@ -/// -/// Langulus::Anyness -/// Copyright (c) 2012 Dimo Markov -/// Part of the Langulus framework, see https://langulus.com -/// -/// Distributed under GNU General Public License v3+ -/// See LICENSE file, or https://www.gnu.org/licenses -/// -#pragma once -#include "Components.hpp" -#include - - -/// -/// Layouts are component compositions, designed to describe an archetypal -/// container. Each call to the interface of a container goes through all -/// the components, in the order they appear. -/// -namespace Langulus::Anyness::Layout -{ - - using Handle = Types< - Component::Data, - Component::Source - >; - - using Block = Types< - Component::Data, - Component::Source, - Component::Range, - Component::Meta, - Component::Missing, - Component::Or, - Component::Compress, - Component::Encrypt, - Component::Constant, - Component::LockType - >; - -} // namespace Langulus::Anyness::Layout \ No newline at end of file diff --git a/source/many/Bytes.hpp b/source/many/Bytes.hpp index fbc36fc3..ef915a08 100644 --- a/source/many/Bytes.hpp +++ b/source/many/Bytes.hpp @@ -126,8 +126,8 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() Bytes Select(Offset, Count) const IF_UNSAFE(noexcept); - NOD() Bytes Select(Offset, Count) IF_UNSAFE(noexcept); + Bytes Select(Offset, Count) const IF_UNSAFE(noexcept); + Bytes Select(Offset, Count) IF_UNSAFE(noexcept); /// /// Comparison @@ -138,7 +138,7 @@ namespace Langulus::Anyness /// /// Insertion /// - NOD() Bytes Extend(Count); + Bytes Extend(Count); template requires CT::Binable> Bytes& operator << (T&&); @@ -149,7 +149,7 @@ namespace Langulus::Anyness /// Concatenation /// template requires CT::Binable> - NOD() Bytes operator + (T&&) const; + Bytes operator + (T&&) const; template requires CT::Binable> Bytes& operator += (T&&); @@ -166,7 +166,7 @@ namespace Langulus::Anyness /// /// Deserialization /// - NOD() Count Deserialize(CT::Data auto&) const; + Count Deserialize(CT::Data auto&) const; /// /// Conversion diff --git a/source/many/Construct.hpp b/source/many/Construct.hpp index 1ff89170..ae7db816 100644 --- a/source/many/Construct.hpp +++ b/source/many/Construct.hpp @@ -56,49 +56,49 @@ namespace Langulus::Anyness Construct& operator = (S&&); public: - NOD() Hash GetHash() const; + Hash GetHash() const; template - NOD() static Construct From(T1&&, TN&&...); + static Construct From(T1&&, TN&&...); template - NOD() static Construct From(); + static Construct From(); #if LANGULUS_FEATURE(MANAGED_REFLECTION) template - NOD() static Construct FromToken(const Token&, T1&&, TN&&...); - NOD() static Construct FromToken(const Token&); + static Construct FromToken(const Token&, T1&&, TN&&...); + static Construct FromToken(const Token&); #endif // Intentionally undefined, because it requires Langulus::Flow // and relies on Verbs::Create - NOD() bool StaticCreation(Many&) const; + bool StaticCreation(Many&) const; public: - NOD() bool operator == (const Construct&) const; + bool operator == (const Construct&) const; template - NOD() bool CastsTo() const; - NOD() bool CastsTo(DMeta) const; + bool CastsTo() const; + bool CastsTo(DMeta) const; template - NOD() bool Is() const; - NOD() bool Is(DMeta) const; + bool Is() const; + bool Is(DMeta) const; template void SetType(); void SetType(DMeta) noexcept; - NOD() auto GetDescriptor() const noexcept -> Many const&; - NOD() auto GetDescriptor() noexcept -> Many&; - NOD() auto GetCharge() const noexcept -> Charge const&; - NOD() auto GetCharge() noexcept -> Charge&; - - NOD() DMeta GetType() const noexcept; - NOD() Token GetToken() const noexcept; - NOD() DMeta GetProducer() const noexcept; - NOD() bool IsExecutable() const noexcept; - NOD() bool IsTyped() const noexcept; - NOD() bool IsUntyped() const noexcept; + auto GetDescriptor() const noexcept -> Many const&; + auto GetDescriptor() noexcept -> Many&; + auto GetCharge() const noexcept -> Charge const&; + auto GetCharge() noexcept -> Charge&; + + DMeta GetType() const noexcept; + Token GetToken() const noexcept; + DMeta GetProducer() const noexcept; + bool IsExecutable() const noexcept; + bool IsTyped() const noexcept; + bool IsUntyped() const noexcept; void Clear(); void Reset(); diff --git a/source/many/Construct.inl b/source/many/Construct.inl index 7d866c29..5a18cc3d 100644 --- a/source/many/Construct.inl +++ b/source/many/Construct.inl @@ -201,6 +201,18 @@ namespace Langulus::Anyness /// @return true if both constructs are the same LANGULUS(INLINED) bool Construct::operator == (const Construct& rhs) const { + VERBOSE_COMPARE_TAB("Comparing Construct of type ", + Logger::PushWhite, mType, Logger::Pop, " with construct of type ", + Logger::PushWhite, rhs.mType + ); + + if (GetHash() != rhs.GetHash()) + VERBOSE_COMPARE(Logger::Red, "Hashes differ: ", GetHash(), " != ", rhs.GetHash()); + if (!(mType & rhs.mType)) + VERBOSE_COMPARE(Logger::Red, "Types not compatible"); + if (mDescriptor != rhs.mDescriptor) + VERBOSE_COMPARE(Logger::Red, "Contents differ"); + return GetHash() == rhs.GetHash() and mType & rhs.mType and mDescriptor == rhs.mDescriptor; diff --git a/source/many/Many.hpp b/source/many/Many.hpp index f4340ecf..0ba2ee37 100644 --- a/source/many/Many.hpp +++ b/source/many/Many.hpp @@ -64,15 +64,26 @@ namespace Langulus::Anyness ~Many(); - NOD() static Many FromMeta(DMeta, DataState = {}) noexcept; - NOD() static Many FromBlock(const CT::Block auto&, DataState = {}) noexcept; - NOD() static Many FromState(const CT::Block auto&, DataState = {}) noexcept; + static Many FromMeta(DMeta, DataState = {}) noexcept; + static Many FromBlock(const CT::Block auto&, DataState = {}) noexcept; + static Many FromState(const CT::Block auto&, DataState = {}) noexcept; template - NOD() static Many From(DataState = {}) noexcept; + static Many From(DataState = {}) noexcept; + template - NOD() static Many Wrap(TN&&...); - NOD() static Many Past() noexcept; - NOD() static Many Future() noexcept; + static Many Wrap(TN&&...); + + template + static Many Past() noexcept; + template + static Many Future() noexcept; + + #if LANGULUS_FEATURE(MANAGED_REFLECTION) + template requires (sizeof...(T) > 0) + static Many Past(T&&...); + template requires (sizeof...(T) > 0) + static Many Future(T&&...); + #endif #if LANGULUS(DEBUG) using Base::TrackingReport; @@ -88,8 +99,8 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() Many Select(Offset, Count) const IF_UNSAFE(noexcept); - NOD() Many Select(Offset, Count) IF_UNSAFE(noexcept); + Many Select(Offset, Count) const IF_UNSAFE(noexcept); + Many Select(Offset, Count) IF_UNSAFE(noexcept); /// /// Comparison @@ -108,8 +119,8 @@ namespace Langulus::Anyness /// /// Concatenation /// - NOD() Many operator + (CT::UnfoldInsertable auto&&) const; - Many& operator += (CT::UnfoldInsertable auto&&); + Many operator + (CT::UnfoldInsertable auto&&) const; + Many& operator += (CT::UnfoldInsertable auto&&); }; } // namespace Langulus::Anyness \ No newline at end of file diff --git a/source/many/Many.inl b/source/many/Many.inl index 8793e950..bbc9ba90 100644 --- a/source/many/Many.inl +++ b/source/many/Many.inl @@ -106,21 +106,75 @@ namespace Langulus::Anyness } } - /// Make an empty container with a missing past state - LANGULUS(INLINED) + /// Make a container with a missing past state and optional filter + /// @tparam T... - optionally add filter(s) for the missing past + /// @return a container marked as missing past with chosen filters + template LANGULUS(INLINED) Many Many::Past() noexcept { Many result; result.MakePast(); + (void) (result << ... << MetaDataOf()); return result; } - /// Make an empty container with a missing future state - LANGULUS(INLINED) + /// Make a container with a missing future state and optional filter + /// @tparam T... - optionally add filter(s) for the missing future + /// @return a container marked as missing future with chosen filters + template LANGULUS(INLINED) Many Many::Future() noexcept { Many result; result.MakeFuture(); + (void) (result << ... << MetaDataOf()); + return result; + } + +#if LANGULUS_FEATURE(MANAGED_REFLECTION) + /// Make a container with a missing past state and optional filter + /// at runtime, using reflected tokens + /// @param types... - reflected tokens + /// @return a container marked as missing past with chosen filters + template requires (sizeof...(T) > 0) LANGULUS(INLINED) + Many Many::Past(T&&...types) { + Many result; + result.MakePast(); + + auto filter = [&result](const AMeta& meta) { + auto dmeta = meta.As(); + if (dmeta) + result << dmeta; + else if (not meta) + LANGULUS_THROW(Meta, "Missing meta for past filter"); + else + LANGULUS_THROW(Meta, "Past filter isn't a data type token"); + }; + + (filter(RTTI::DisambiguateMeta(types)), ...); + return result; + } + + /// Make a container with a missing future state and optional filter + /// at runtime, using reflected tokens + /// @param types... - reflected tokens + /// @return a container marked as missing future with chosen filters + template requires (sizeof...(T) > 0) LANGULUS(INLINED) + Many Many::Future(T&&...types) { + Many result; + result.MakeFuture(); + + auto filter = [&result](const AMeta& meta) { + auto dmeta = meta.As(); + if (dmeta) + result << dmeta; + else if (not meta) + LANGULUS_THROW(Meta, "Missing meta for future filter"); + else + LANGULUS_THROW(Meta, "Future filter isn't a data type token"); + }; + + (filter(RTTI::DisambiguateMeta(types)), ...); return result; } +#endif /// Refer assignment /// @param rhs - the container to refer to diff --git a/source/many/Neat.hpp b/source/many/Neat.hpp index 08bc4551..9cfce865 100644 --- a/source/many/Neat.hpp +++ b/source/many/Neat.hpp @@ -10,7 +10,7 @@ #include "Trait.hpp" #include "Construct.hpp" #include "../maps/TMap.hpp" -#include +#include namespace Langulus::Anyness @@ -93,12 +93,12 @@ namespace Langulus::Anyness /// /// Encapsulation /// - NOD() Hash GetHash() const; - NOD() bool IsEmpty() const noexcept; - NOD() bool IsMissingDeep() const; - NOD() bool IsExecutable() const noexcept; + Hash GetHash() const; + bool IsEmpty() const noexcept; + bool IsMissingDeep() const; + bool IsExecutable() const noexcept; - NOD() explicit operator bool() const noexcept; + explicit operator bool() const noexcept; template auto GetTraits() -> TraitList*; @@ -137,8 +137,8 @@ namespace Langulus::Anyness auto ExtractDataAs(CT::Data auto&) const -> Count; template - NOD() auto GetTrait(Offset = 0) const -> const Trait*; - NOD() auto GetTrait(TMeta, Offset = 0) const -> const Trait*; + auto GetTrait(Offset = 0) const -> const Trait*; + auto GetTrait(TMeta, Offset = 0) const -> const Trait*; protected: template diff --git a/source/many/Neat.inl b/source/many/Neat.inl index 4fbc232c..7888055a 100644 --- a/source/many/Neat.inl +++ b/source/many/Neat.inl @@ -428,7 +428,7 @@ namespace Langulus::Anyness // Fill a bounded array Count scanned = 0; for (auto pair : mAnythingElse) { - for (auto& group : pair.mValue) { + for (auto& group : pair.GetValue()) { const auto toscan = ::std::min(ExtentOf - scanned, group.GetCount()); for (Offset i = 0; i < toscan; ++i) { //TODO can be optimized-out for POD @@ -449,7 +449,7 @@ namespace Langulus::Anyness else { // Fill a single value for (auto pair : mAnythingElse) { - for (auto& group : pair.mValue) { + for (auto& group : pair.GetValue()) { try { value = group.template AsCast(); return 1; @@ -928,7 +928,7 @@ namespace Langulus::Anyness else { // Iterate all traits, either using type-erased trait, or deep for (auto group : mTraits) { - for (auto& data : group.mValue) { + for (auto& data : group.GetValue()) { if constexpr (CT::Deep) { auto wrapper = MakeBlock>(data); if constexpr (CT::Bool) { @@ -981,7 +981,7 @@ namespace Langulus::Anyness // Iterate all constructs Count index = 0; for (auto group : mConstructs) { - for (auto& data : group.mValue) { + for (auto& data : group.GetValue()) { if constexpr (CT::Deep) { // Iterate using deep A auto wrapper = MakeBlock>(data); @@ -1051,7 +1051,7 @@ namespace Langulus::Anyness else if constexpr (CT::Deep) { // Type-erased container provided, iterate the entire tail for (auto group : mAnythingElse) { - for (auto& data : group.mValue) { + for (auto& data : group.GetValue()) { if constexpr (CT::Bool) { if (not call(data)) return index + 1; @@ -1120,12 +1120,12 @@ namespace Langulus::Anyness } Count count = 0; - for (auto data : KeepIterator(found.GetValue())) { + for (auto data : KeepIterator(found.mValue)) { if (not *data) continue; // Remove only matching data entries, that aren't empty - data = found.GetValue().RemoveIt(data); + data = found.mValue.RemoveIt(data); ++count; } @@ -1216,33 +1216,33 @@ namespace Langulus::Anyness bool separator = false; for (auto pair : mAnythingElse) { - for (auto& group : pair.mValue) { + for (auto& group : pair.GetValue()) { if (separator) to += ", "; if (group.IsValid()) group.SerializeToText(to); else - to += static_cast(pair.mKey); + to += static_cast(pair.GetKey()); separator = true; } } for (auto pair : mTraits) { - for (auto& trait : pair.mValue) { + for (auto& trait : pair.GetValue()) { if (separator) to += ", "; if (trait.IsValid()) trait.Serialize(to); else - to += static_cast(pair.mKey); + to += static_cast(pair.GetKey()); separator = true; } } for (auto pair : mConstructs) { - for (auto& construct : pair.mValue) { + for (auto& construct : pair.GetValue()) { if (separator) to += ", "; @@ -1250,7 +1250,7 @@ namespace Langulus::Anyness or not construct.GetCharge().IsDefault()) construct.Serialize(to); else - to += static_cast(pair.mKey); + to += static_cast(pair.GetKey()); separator = true; } } diff --git a/source/many/THive.hpp b/source/many/THive.hpp index 4f851107..d941e891 100644 --- a/source/many/THive.hpp +++ b/source/many/THive.hpp @@ -92,28 +92,25 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() auto Owns(const void*) const noexcept -> const Frame*; - NOD() auto GetType() const noexcept -> DMeta; - NOD() auto GetCount() const noexcept -> Count; - NOD() bool IsEmpty() const noexcept; - NOD() constexpr explicit operator bool() const noexcept; + auto Owns(const void*) const noexcept -> const Frame*; + auto GetType() const noexcept -> DMeta; + auto GetCount() const noexcept -> Count; + bool IsEmpty() const noexcept; + constexpr explicit operator bool() const noexcept; #if LANGULUS(TESTING) auto GetReusable() const { return mReusable; } - auto& GetFrames() const { return mFrames; } + auto& GetFrames() const { return mFrames; } #endif /// /// Iteration /// - template + template struct Iterator; - NOD() constexpr auto begin() noexcept -> Iterator; - NOD() constexpr auto begin() const noexcept -> Iterator; - - NOD() constexpr auto last() noexcept -> Iterator; - NOD() constexpr auto last() const noexcept -> Iterator; + constexpr auto begin() noexcept -> Iterator; + constexpr auto begin() const noexcept -> Iterator; constexpr A::IteratorEnd end() const noexcept { return {}; } @@ -177,10 +174,9 @@ namespace Langulus::Anyness /// /// Hive iterator /// - template template + template template struct THive::Iterator { - static_assert(CT::Hive, "HIVE must be a CT::Hive type"); - static constexpr bool Mutable = CT::Mutable; + static constexpr bool Mutable = MUTABLE; LANGULUS(ABSTRACT) false; LANGULUS(TYPED) T; @@ -195,9 +191,8 @@ namespace Langulus::Anyness // Current frame Frame* mFrame; - // The last valid frame - // @attention this is not the one-past-count! - Frame const* mFrameLast; + // Frame position which is considered the 'end' all iterator + Frame const* mFrameEnd; constexpr Iterator(Cell*, Cell const*, Frame*, Frame const*) noexcept; @@ -207,23 +202,26 @@ namespace Langulus::Anyness constexpr Iterator(Iterator&&) noexcept = default; constexpr Iterator(const A::IteratorEnd&) noexcept; - constexpr auto operator = (const Iterator&) noexcept -> Iterator& = default; - constexpr auto operator = (Iterator&&) noexcept -> Iterator& = default; + constexpr auto operator = (const Iterator&) noexcept -> Iterator& = default; + constexpr auto operator = (Iterator&&) noexcept -> Iterator& = default; - NOD() constexpr bool operator == (const Iterator&) const noexcept; - NOD() constexpr bool operator == (const A::IteratorEnd&) const noexcept; + constexpr bool operator == (const Iterator&) const noexcept; + constexpr bool operator == (const A::IteratorEnd&) const noexcept; - NOD() constexpr decltype(auto) operator * () const noexcept; - NOD() constexpr decltype(auto) operator -> () const noexcept; + constexpr decltype(auto) operator * () const noexcept; + constexpr decltype(auto) operator -> () const noexcept; // Prefix operator constexpr auto operator ++ () noexcept -> Iterator&; // Suffix operator - NOD() constexpr auto operator ++ (int) noexcept -> Iterator; + constexpr auto operator ++ (int) noexcept -> Iterator; constexpr explicit operator bool() const noexcept; - constexpr operator Iterator() const noexcept requires Mutable; + + // Implicit cast to an immutable iterator is allowed, but not vice + // versa + constexpr operator Iterator() const noexcept requires Mutable; }; } // namespace Langulus::Flow diff --git a/source/many/THive.inl b/source/many/THive.inl index a7aa8f68..b1672a7c 100644 --- a/source/many/THive.inl +++ b/source/many/THive.inl @@ -119,51 +119,24 @@ namespace Langulus::Anyness /// Get iterator to first element /// @return an iterator to the first element, or end if empty TEMPLATE() LANGULUS(INLINED) - constexpr auto THive::begin() noexcept -> Iterator { + constexpr auto THive::begin() noexcept -> Iterator { if (IsEmpty()) return end(); auto& firstFrame = mFrames[0]; - Cell* cell = firstFrame.GetRaw(); - Cell const* const cellEnd = cell + firstFrame.GetReserved(); - while (cell->mNextFreeCell and cell < cellEnd) - ++cell; - return { - cell, cellEnd, - &firstFrame, &firstFrame + mFrames.GetCount() - 1 + firstFrame.GetRaw(), + firstFrame.GetRaw() + firstFrame.GetReserved(), + &firstFrame, + &firstFrame + mFrames.GetCount() }; } TEMPLATE() LANGULUS(INLINED) - constexpr auto THive::begin() const noexcept -> Iterator { + constexpr auto THive::begin() const noexcept -> Iterator { return const_cast(this)->begin(); } - /// Get iterator to the last element - /// @return an iterator to the last element, or end if empty - TEMPLATE() LANGULUS(INLINED) - constexpr auto THive::last() noexcept -> Iterator { - if (IsEmpty()) - return end(); - - auto& lastFrame = mFrames.Last(); - auto cell = lastFrame.GetRaw() + (lastFrame.GetReserved() - 1); - const auto cellEnd = lastFrame.GetRaw(); - while (cell->mNextFreeCell and cell >= cellEnd) - --cell; - - return { - cell, cell + lastFrame.GetReserved(), - &lastFrame, &lastFrame - }; - } - - TEMPLATE() LANGULUS(INLINED) - constexpr auto THive::last() const noexcept -> Iterator { - return const_cast(this)->last(); - } - /// Emplace a new instance inside the hive /// @param args... - arguments to forward to T's constructor /// @return a pointer to the newly constructed instance of T @@ -185,17 +158,18 @@ namespace Langulus::Anyness // Reuse a slot const auto nextReusable = mReusable->mNextFreeCell; try { result = new (mReusable) Cell {Forward(args)...}; } - catch (...) { return nullptr; } + catch (...) { + mReusable->mNextFreeCell = nextReusable; + return nullptr; + } - mReusable = nextReusable; + auto frame = Owns(mReusable); + const_cast(frame)->mCount += 1; // Make sure that the mReusable is inside limits, as it may // go out of bounds in edge cases - auto frame = Owns(mReusable); - if (not frame) - mReusable = nullptr; - else - ++const_cast(frame)->mCount; + mReusable->mNextFreeCell = nullptr; + mReusable = Owns(nextReusable) ? nextReusable : nullptr; } else { // Add new frame @@ -204,7 +178,7 @@ namespace Langulus::Anyness : DefaultFrameSize; // Use first cell to initialize our object - Frame* frame = nullptr; + Frame* volatile frame = nullptr; try { mFrames.New(1); frame = &mFrames.Last(); @@ -215,10 +189,12 @@ namespace Langulus::Anyness catch (...) { // Pass through all new unused cells, and set their markers // We allocated a new frame, let's not let it go to waste - mReusable = frame->GetRaw(); - const auto cellEnd = frame->GetRaw() + frame->GetReserved(); - for (auto cell = mReusable; cell < cellEnd; ++cell) - cell->mNextFreeCell = cell + 1; + if (frame->GetRaw()) { + mReusable = frame->GetRaw(); + const auto cellEnd = frame->GetRaw() + frame->GetReserved(); + for (auto cell = mReusable; cell < cellEnd; ++cell) + cell->mNextFreeCell = cell + 1; + } return nullptr; } @@ -302,8 +278,8 @@ namespace Langulus::Anyness -#define TEMPLATE_IT() TEMPLATE() template -#define TME_IT() THive::Iterator +#define TEMPLATE_IT() TEMPLATE() template +#define TME_IT() THive::Iterator /// Construct an iterator @@ -311,12 +287,15 @@ namespace Langulus::Anyness /// @param end - the ending marker TEMPLATE_IT() LANGULUS(INLINED) constexpr TME_IT()::Iterator( - Cell* start, Cell const* end, Frame* startf, Frame const* lastf + Cell* start, Cell const* end, Frame* startf, Frame const* endf ) noexcept : mCell {start} , mCellEnd {end} , mFrame {startf} - , mFrameLast {lastf} {} + , mFrameEnd {endf} { + while (mCell and mCell->mNextFreeCell) + operator ++ (); + } /// Construct an end iterator TEMPLATE_IT() LANGULUS(INLINED) @@ -324,7 +303,7 @@ namespace Langulus::Anyness : mCell {nullptr} , mCellEnd {nullptr} , mFrame {nullptr} - , mFrameLast {nullptr} {} + , mFrameEnd {nullptr} {} /// Compare two iterators /// @param rhs - the other iterator @@ -339,7 +318,7 @@ namespace Langulus::Anyness /// @return true element is at or beyond the end marker TEMPLATE_IT() LANGULUS(INLINED) constexpr bool TME_IT()::operator == (const A::IteratorEnd&) const noexcept { - return mCell ? mCell >= mFrameLast->GetRawEnd() : true; + return mFrame == mFrameEnd; } /// Iterator access operator @@ -364,18 +343,19 @@ namespace Langulus::Anyness ++mCell; // Skip uninitialized cells + skip_empty: while (mCell->mNextFreeCell and mCell < mCellEnd) ++mCell; - if (mCell >= mCellEnd) { + if (mCell == mCellEnd) { // If end of frame was reached, move to the next frame ++mFrame; - if (mFrame <= mFrameLast) { + if (mFrame != mFrameEnd) { mCell = mFrame->GetRaw(); mCellEnd = mCell + mFrame->GetReserved(); + goto skip_empty; } - else mCell = nullptr; } return *this; @@ -397,10 +377,10 @@ namespace Langulus::Anyness return *this != A::IteratorEnd {}; } - /// Implicitly convert to a constant iterator + /// Implicitly convert to a immutable iterator TEMPLATE_IT() LANGULUS(INLINED) - constexpr TME_IT()::operator Iterator() const noexcept requires Mutable { - return {mCell, mCellEnd, mFrame, mFrameLast}; + constexpr TME_IT()::operator Iterator() const noexcept requires Mutable { + return {mCell, mCellEnd, mFrame, mFrameEnd}; } } // namespace Langulus::Flow diff --git a/source/many/TMany.hpp b/source/many/TMany.hpp index 5ff92e89..c3658ece 100644 --- a/source/many/TMany.hpp +++ b/source/many/TMany.hpp @@ -77,7 +77,7 @@ namespace Langulus::Anyness ~TMany(); template - NOD() static auto Wrap(TN&&...) -> TMany; + static auto Wrap(TN&&...) -> TMany; /// /// Assignment @@ -91,8 +91,8 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() auto Select(Offset, Count) IF_UNSAFE(noexcept) -> TMany; - NOD() auto Select(Offset, Count) const IF_UNSAFE(noexcept) -> TMany; + auto Select(Offset, Count) IF_UNSAFE(noexcept) -> TMany; + auto Select(Offset, Count) const IF_UNSAFE(noexcept) -> TMany; /// /// RTTI @@ -113,7 +113,7 @@ namespace Langulus::Anyness /// /// Insertion /// - NOD() auto Extend(Count) -> TMany; + auto Extend(Count) -> TMany; template requires CT::UnfoldMakableFrom auto operator << (T1&&) -> TMany&; @@ -128,7 +128,7 @@ namespace Langulus::Anyness /// /// Concatenation /// - template requires CT::DeepMakable NOD() + template requires CT::DeepMakable auto operator + (T1&&) const -> TMany; template requires CT::DeepMakable diff --git a/source/many/TTrait.hpp b/source/many/TTrait.hpp index de40a6bc..b0511248 100644 --- a/source/many/TTrait.hpp +++ b/source/many/TTrait.hpp @@ -31,13 +31,12 @@ namespace Langulus::Anyness TTrait(const TTrait&); TTrait(TTrait&&); - template requires ( - CT::Trait> and not CT::Same) + template requires (CT::Trait> and not CT::Same) TTrait(T&&); template - NOD() static TRAIT OfType(); - NOD() static TRAIT OfType(DMeta); + static TRAIT OfType(); + static TRAIT OfType(DMeta); TRAIT& operator = (const TTrait&); TRAIT& operator = (TTrait&&); @@ -45,26 +44,26 @@ namespace Langulus::Anyness public: template - NOD() constexpr bool IsTrait() const; - NOD() constexpr bool IsTrait(TMeta, auto...) const; + constexpr bool IsTrait() const; + constexpr bool IsTrait(TMeta, auto...) const; - NOD() TMeta GetTrait() const noexcept; + TMeta GetTrait() const noexcept; - NOD() constexpr bool IsTraitValid() const noexcept; - NOD() constexpr bool IsTraitSimilar(const CT::TraitBased auto&) const noexcept; - NOD() constexpr bool HasCorrectData() const; + constexpr bool IsTraitValid() const noexcept; + constexpr bool IsTraitSimilar(const CT::TraitBased auto&) const noexcept; + constexpr bool HasCorrectData() const; /// /// Compare /// template requires CT::NotOwned - NOD() bool operator == (const T&) const; + bool operator == (const T&) const; /// /// Concatenation /// - NOD() TRAIT operator + (CT::UnfoldInsertable auto&&) const; - TRAIT& operator += (CT::UnfoldInsertable auto&&); + TRAIT operator + (CT::UnfoldInsertable auto&&) const; + TRAIT& operator += (CT::UnfoldInsertable auto&&); /// /// Conversion @@ -93,8 +92,8 @@ namespace Langulus::Anyness using TTrait::operator ==; \ using TTrait::operator +; \ using TTrait::operator +=; \ - NOD() T Select(Offset s, Langulus::Count c) IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ - NOD() T Select(Offset s, Langulus::Count c) const IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ + T Select(Offset s, Langulus::Count c) IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ + T Select(Offset s, Langulus::Count c) const IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ }; \ } @@ -113,8 +112,8 @@ namespace Langulus::Anyness using TTrait::operator ==; \ using TTrait::operator +; \ using TTrait::operator +=; \ - NOD() T Select(Offset s, Langulus::Count c) IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ - NOD() T Select(Offset s, Langulus::Count c) const IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ + T Select(Offset s, Langulus::Count c) IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ + T Select(Offset s, Langulus::Count c) const IF_UNSAFE(noexcept) { return {Many::Select(s, c)}; } \ PROPERTIES; \ }; \ } diff --git a/source/many/Trait.hpp b/source/many/Trait.hpp index 45f90665..5a952cd5 100644 --- a/source/many/Trait.hpp +++ b/source/many/Trait.hpp @@ -88,12 +88,12 @@ namespace Langulus::Anyness Trait& operator = (CT::UnfoldInsertable auto&&); template - NOD() static Trait From(); - NOD() static Trait FromMeta(TMeta, DMeta); + static Trait From(); + static Trait FromMeta(TMeta, DMeta); template - NOD() static Trait From(auto&&); - NOD() static Trait From(TMeta, auto&&); + static Trait From(auto&&); + static Trait From(TMeta, auto&&); /// /// Capsulation @@ -103,41 +103,41 @@ namespace Langulus::Anyness void SetTrait(TMeta) noexcept; template - NOD() constexpr bool IsTrait() const; + constexpr bool IsTrait() const; template requires CT::Exact - NOD() bool IsTrait(TMeta, TN...) const; + bool IsTrait(TMeta, TN...) const; template - NOD() TMeta GetTrait() const noexcept; + TMeta GetTrait() const noexcept; template - NOD() bool IsTraitValid() const noexcept; + bool IsTraitValid() const noexcept; template - NOD() bool IsTraitSimilar(const CT::TraitBased auto&) const noexcept; + bool IsTraitSimilar(const CT::TraitBased auto&) const noexcept; template - NOD() bool HasCorrectData() const; + bool HasCorrectData() const; /// /// Indexing /// - NOD() Trait Select(Offset, Count) IF_UNSAFE(noexcept); - NOD() Trait Select(Offset, Count) const IF_UNSAFE(noexcept); + Trait Select(Offset, Count) IF_UNSAFE(noexcept); + Trait Select(Offset, Count) const IF_UNSAFE(noexcept); /// /// Compare /// template requires CT::NotOwned - NOD() bool operator == (const T&) const; + bool operator == (const T&) const; /// /// Concatenation /// template - NOD() THIS operator + (CT::UnfoldInsertable auto&&) const; + THIS operator + (CT::UnfoldInsertable auto&&) const; template THIS& operator += (CT::UnfoldInsertable auto&&); diff --git a/source/maps/Map.hpp b/source/maps/Map.hpp index 1a941a26..992521cc 100644 --- a/source/maps/Map.hpp +++ b/source/maps/Map.hpp @@ -56,12 +56,12 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() auto GetKey (CT::Index auto) -> Block<>; - NOD() auto GetKey (CT::Index auto) const -> Block<>; - NOD() auto GetValue(CT::Index auto) -> Block<>; - NOD() auto GetValue(CT::Index auto) const -> Block<>; - NOD() auto GetPair (CT::Index auto) -> Pair; - NOD() auto GetPair (CT::Index auto) const -> Pair; + auto GetKey (CT::Index auto) -> Block<>; + auto GetKey (CT::Index auto) const -> Block<>; + auto GetValue(CT::Index auto) -> Block<>; + auto GetValue(CT::Index auto) const -> Block<>; + auto GetPair (CT::Index auto) -> Pair; + auto GetPair (CT::Index auto) const -> Pair; /// /// Iteration @@ -69,10 +69,10 @@ namespace Langulus::Anyness using Iterator = BlockMap::Iterator; using ConstIterator = BlockMap::Iterator; - NOD() auto begin() noexcept -> Iterator; - NOD() auto last() noexcept -> Iterator; - NOD() auto begin() const noexcept -> ConstIterator; - NOD() auto last() const noexcept -> ConstIterator; + auto begin() noexcept -> Iterator; + auto begin() const noexcept -> ConstIterator; + auto last() noexcept -> Iterator; + auto last() const noexcept -> ConstIterator; template Count ForEach(auto&&) const; @@ -113,43 +113,43 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool IsKey() const noexcept; - NOD() bool IsKey(DMeta) const noexcept; + constexpr bool IsKey() const noexcept; + bool IsKey(DMeta) const noexcept; template - NOD() constexpr bool IsKeySimilar() const noexcept; - NOD() bool IsKeySimilar(DMeta) const noexcept; + constexpr bool IsKeySimilar() const noexcept; + bool IsKeySimilar(DMeta) const noexcept; template - NOD() constexpr bool IsKeyExact() const noexcept; - NOD() bool IsKeyExact(DMeta) const noexcept; + constexpr bool IsKeyExact() const noexcept; + bool IsKeyExact(DMeta) const noexcept; template - NOD() constexpr bool IsValue() const noexcept; - NOD() bool IsValue(DMeta) const noexcept; + constexpr bool IsValue() const noexcept; + bool IsValue(DMeta) const noexcept; template - NOD() constexpr bool IsValueSimilar() const noexcept; - NOD() bool IsValueSimilar(DMeta) const noexcept; + constexpr bool IsValueSimilar() const noexcept; + bool IsValueSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsValueExact() const noexcept; - NOD() bool IsValueExact(DMeta) const noexcept; + constexpr bool IsValueExact() const noexcept; + bool IsValueExact(DMeta) const noexcept; /// /// Comparison /// using BlockMap::operator ==; - NOD() auto Find(const CT::NoIntent auto&) const -> Index; - NOD() auto FindIt(const CT::NoIntent auto&) -> Iterator; - NOD() auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; + auto Find (const CT::NoIntent auto&) const -> Index; + auto FindIt(const CT::NoIntent auto&) -> Iterator; + auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; - NOD() decltype(auto) At(const CT::NoIntent auto&); - NOD() decltype(auto) At(const CT::NoIntent auto&) const; + decltype(auto) At(const CT::NoIntent auto&); + decltype(auto) At(const CT::NoIntent auto&) const; - NOD() decltype(auto) operator[] (const CT::NoIntent auto&); - NOD() decltype(auto) operator[] (const CT::NoIntent auto&) const; + decltype(auto) operator[] (const CT::NoIntent auto&); + decltype(auto) operator[] (const CT::NoIntent auto&) const; /// /// Memory management diff --git a/source/maps/TMap.hpp b/source/maps/TMap.hpp index 0eba5bb6..a01a9e04 100644 --- a/source/maps/TMap.hpp +++ b/source/maps/TMap.hpp @@ -88,34 +88,34 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() DMeta GetKeyType() const noexcept; - NOD() DMeta GetValueType() const noexcept; - NOD() constexpr bool IsKeyTyped() const noexcept; - NOD() constexpr bool IsValueTyped() const noexcept; - NOD() constexpr bool IsKeyUntyped() const noexcept; - NOD() constexpr bool IsValueUntyped() const noexcept; - NOD() constexpr bool IsKeyTypeConstrained() const noexcept; - NOD() constexpr bool IsValueTypeConstrained() const noexcept; - NOD() constexpr bool IsKeyDeep() const noexcept; - NOD() constexpr bool IsValueDeep() const noexcept; - NOD() constexpr bool IsKeySparse() const noexcept; - NOD() constexpr bool IsValueSparse() const noexcept; - NOD() constexpr bool IsKeyDense() const noexcept; - NOD() constexpr bool IsValueDense() const noexcept; - NOD() constexpr Size GetKeyStride() const noexcept; - NOD() constexpr Size GetValueStride() const noexcept; - NOD() Count GetKeyCountDeep() const noexcept; - NOD() Count GetKeyCountElementsDeep() const noexcept; - NOD() Count GetValueCountDeep() const noexcept; - NOD() Count GetValueCountElementsDeep() const noexcept; - - NOD() bool IsKeyMissingDeep() const; - NOD() bool IsValueMissingDeep() const; - - NOD() bool IsKeyExecutable() const; - NOD() bool IsValueExecutable() const; - NOD() bool IsKeyExecutableDeep() const; - NOD() bool IsValueExecutableDeep() const; + DMeta GetKeyType() const noexcept; + DMeta GetValueType() const noexcept; + constexpr bool IsKeyTyped() const noexcept; + constexpr bool IsValueTyped() const noexcept; + constexpr bool IsKeyUntyped() const noexcept; + constexpr bool IsValueUntyped() const noexcept; + constexpr bool IsKeyTypeConstrained() const noexcept; + constexpr bool IsValueTypeConstrained() const noexcept; + constexpr bool IsKeyDeep() const noexcept; + constexpr bool IsValueDeep() const noexcept; + constexpr bool IsKeySparse() const noexcept; + constexpr bool IsValueSparse() const noexcept; + constexpr bool IsKeyDense() const noexcept; + constexpr bool IsValueDense() const noexcept; + constexpr Size GetKeyStride() const noexcept; + constexpr Size GetValueStride() const noexcept; + Count GetKeyCountDeep() const noexcept; + Count GetKeyCountElementsDeep() const noexcept; + Count GetValueCountDeep() const noexcept; + Count GetValueCountElementsDeep() const noexcept; + + bool IsKeyMissingDeep() const; + bool IsValueMissingDeep() const; + + bool IsKeyExecutable() const; + bool IsValueExecutable() const; + bool IsKeyExecutableDeep() const; + bool IsValueExecutableDeep() const; using Base::GetCount; using Base::GetReserved; @@ -127,28 +127,28 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool IsKey() const noexcept; - NOD() bool IsKey(DMeta) const noexcept; + constexpr bool IsKey() const noexcept; + bool IsKey(DMeta) const noexcept; template - NOD() constexpr bool IsKeySimilar() const noexcept; - NOD() bool IsKeySimilar(DMeta) const noexcept; + constexpr bool IsKeySimilar() const noexcept; + bool IsKeySimilar(DMeta) const noexcept; template - NOD() constexpr bool IsKeyExact() const noexcept; - NOD() bool IsKeyExact(DMeta) const noexcept; + constexpr bool IsKeyExact() const noexcept; + bool IsKeyExact(DMeta) const noexcept; template - NOD() constexpr bool IsValue() const noexcept; - NOD() bool IsValue(DMeta) const noexcept; + constexpr bool IsValue() const noexcept; + bool IsValue(DMeta) const noexcept; template - NOD() constexpr bool IsValueSimilar() const noexcept; - NOD() bool IsValueSimilar(DMeta) const noexcept; + constexpr bool IsValueSimilar() const noexcept; + bool IsValueSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsValueExact() const noexcept; - NOD() bool IsValueExact(DMeta) const noexcept; + constexpr bool IsValueExact() const noexcept; + bool IsValueExact(DMeta) const noexcept; protected: template @@ -159,12 +159,12 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() auto GetKey (CT::Index auto) -> K&; - NOD() auto GetKey (CT::Index auto) const -> K const&; - NOD() auto GetValue(CT::Index auto) -> V&; - NOD() auto GetValue(CT::Index auto) const -> V const&; - NOD() auto GetPair (CT::Index auto) -> PairRef; - NOD() auto GetPair (CT::Index auto) const -> PairConstRef; + auto GetKey (CT::Index auto) -> K&; + auto GetKey (CT::Index auto) const -> K const&; + auto GetValue(CT::Index auto) -> V&; + auto GetValue(CT::Index auto) const -> V const&; + auto GetPair (CT::Index auto) -> PairRef; + auto GetPair (CT::Index auto) const -> PairConstRef; protected: using Base::GetBucket; @@ -177,10 +177,10 @@ namespace Langulus::Anyness using Iterator = BlockMap::Iterator; using ConstIterator = BlockMap::Iterator; - NOD() auto begin() noexcept -> Iterator; - NOD() auto last() noexcept -> Iterator; - NOD() auto begin() const noexcept -> ConstIterator; - NOD() auto last() const noexcept -> ConstIterator; + auto begin() noexcept -> Iterator; + auto begin() const noexcept -> ConstIterator; + auto last() noexcept -> Iterator; + auto last() const noexcept -> ConstIterator; template Count ForEach(auto&&) const; @@ -223,37 +223,37 @@ namespace Langulus::Anyness bool operator == (CT::Map auto const&) const requires CT::Comparable; bool operator == (CT::Pair auto const&) const requires CT::Comparable; - NOD() Hash GetHash() const requires CT::Hashable; + Hash GetHash() const requires CT::Hashable; template requires CT::Comparable - NOD() bool ContainsKey(K1 const&) const; + bool ContainsKey(K1 const&) const; template requires CT::Comparable - NOD() bool ContainsValue(V1 const&) const; + bool ContainsValue(V1 const&) const; template requires CT::Comparable, P> - NOD() bool ContainsPair(P const&) const; + bool ContainsPair(P const&) const; template requires CT::Comparable - NOD() auto Find(K1 const&) const -> Index; + auto Find(K1 const&) const -> Index; template requires CT::Comparable - NOD() auto FindIt(K1 const&) -> Iterator; + auto FindIt(K1 const&) -> Iterator; template requires CT::Comparable - NOD() auto FindIt(K1 const&) const -> ConstIterator; + auto FindIt(K1 const&) const -> ConstIterator; template requires CT::Comparable - NOD() decltype(auto) At(K1 const&); + decltype(auto) At(K1 const&); template requires CT::Comparable - NOD() decltype(auto) At(K1 const&) const; + decltype(auto) At(K1 const&) const; template requires CT::Comparable - NOD() decltype(auto) operator[] (K1 const&); + decltype(auto) operator[] (K1 const&); template requires CT::Comparable - NOD() decltype(auto) operator[] (K1 const&) const; + decltype(auto) operator[] (K1 const&) const; /// /// Memory management @@ -304,7 +304,7 @@ namespace Langulus::Anyness void Compact(); protected: - NOD() static Size RequestValuesSize(Count) noexcept; + static Size RequestValuesSize(Count) noexcept; }; } // namespace Langulus::Anyness diff --git a/source/maps/TMap.inl b/source/maps/TMap.inl index 7e822120..1db95dda 100644 --- a/source/maps/TMap.inl +++ b/source/maps/TMap.inl @@ -510,14 +510,14 @@ namespace Langulus::Anyness TEMPLATE() LANGULUS(INLINED) auto TABLE()::operator += (const TABLE()& rhs) -> TMap& { for (auto pair : rhs) { - auto found = Find(pair.mKey); + auto found = Find(pair.GetKey()); if (found) { if constexpr (requires (V& lhs) { lhs += rhs; }) - GetValue(found) += pair.mValue; + GetValue(found) += pair.GetValue(); else LANGULUS_THROW(Concat, "No concat operator available"); } - else Insert(pair.mKey, pair.mValue); + else Insert(pair.GetKey(), pair.GetValue()); //TODO use handles instead? or better yed - directly insert pair? } return *this; diff --git a/source/memory/Allocation.hpp b/source/memory/Allocation.hpp index 44a68110..ba213f31 100644 --- a/source/memory/Allocation.hpp +++ b/source/memory/Allocation.hpp @@ -6,7 +6,7 @@ /// SPDX-License-Identifier: GPL-3.0-or-later /// #pragma once -#include +#include namespace Langulus::Anyness @@ -64,20 +64,20 @@ namespace Langulus::Anyness constexpr Allocation(Offset, Pool*) noexcept; - NOD() static constexpr Offset GetSize() noexcept; - NOD() static constexpr Offset GetNewAllocationSize(Offset) noexcept; - NOD() static constexpr Offset GetMinAllocation() noexcept; + static constexpr Offset GetSize() noexcept; + static constexpr Offset GetNewAllocationSize(Offset) noexcept; + static constexpr Offset GetMinAllocation() noexcept; - NOD() constexpr Count GetUses() const noexcept; - NOD() Byte* GetBlockStart() const noexcept; - NOD() Byte const* GetBlockEnd() const noexcept; - NOD() constexpr Offset GetTotalSize() const noexcept; - NOD() constexpr Offset GetAllocatedSize() const noexcept; - NOD() bool Contains(const void*) const noexcept; - NOD() bool CollisionFree(const Allocation&) const noexcept; + auto GetUses() const noexcept -> Count; + auto GetBlockStart() const noexcept -> Byte*; + auto GetBlockEnd() const noexcept -> Byte const*; + auto GetTotalSize() const noexcept -> Offset; + auto GetAllocatedSize() const noexcept -> Offset; + bool Contains(const void*) const noexcept; + bool CollisionFree(const Allocation&) const noexcept; template - NOD() T* As() const noexcept; + T* As() const noexcept; constexpr void Keep() noexcept; constexpr void Keep(Count) noexcept; diff --git a/source/memory/Allocation.inl b/source/memory/Allocation.inl index 530f45b8..00fd58f6 100644 --- a/source/memory/Allocation.inl +++ b/source/memory/Allocation.inl @@ -7,7 +7,6 @@ /// #pragma once #include "Allocation.hpp" -#include namespace Langulus::Anyness @@ -63,8 +62,8 @@ namespace Langulus::Anyness LANGULUS(INLINED) constexpr Allocation::Allocation(Offset bytes, Pool* pool) noexcept : mAllocatedBytes {bytes} - , mReferences {1} - , mPool {pool} {} + , mReferences {1} + , mPool {pool} {} /// Get the size of the Allocation structure, rounded up for alignment /// @return the byte size of the entry, including alignment @@ -96,21 +95,21 @@ namespace Langulus::Anyness /// Check if the memory of the entry is in use /// @return true if entry has any references LANGULUS(INLINED) - constexpr Count Allocation::GetUses() const noexcept { + auto Allocation::GetUses() const noexcept -> Count { return mReferences; } /// Return the end of usable block memory (always const) /// @return pointer to the entry's memory end LANGULUS(INLINED) - Byte const* Allocation::GetBlockEnd() const noexcept { + auto Allocation::GetBlockEnd() const noexcept -> Byte const* { return GetBlockStart() + mAllocatedBytes; } /// Return the aligned start of usable block memory /// @return pointer to the entry's publicly usable memory LANGULUS(INLINED) - Byte* Allocation::GetBlockStart() const noexcept { + auto Allocation::GetBlockStart() const noexcept -> Byte* { const auto entryStart = reinterpret_cast(this); return const_cast(entryStart + Allocation::GetSize()); } @@ -118,14 +117,14 @@ namespace Langulus::Anyness /// Get the total of the entry, and its allocated data, in bytes /// @return the byte size of the entry plus the usable region after it LANGULUS(INLINED) - constexpr Offset Allocation::GetTotalSize() const noexcept { + Offset Allocation::GetTotalSize() const noexcept { return Allocation::GetSize() + mAllocatedBytes; } /// Get the number of allocated bytes in this entry /// @return the byte size of usable memory region LANGULUS(INLINED) - constexpr Offset Allocation::GetAllocatedSize() const noexcept { + Offset Allocation::GetAllocatedSize() const noexcept { return mAllocatedBytes; } @@ -154,8 +153,7 @@ namespace Langulus::Anyness /// @return a pointer to the first element template LANGULUS(INLINED) T* Allocation::As() const noexcept { - return reinterpret_cast( - const_cast(this)->GetBlockStart()); + return reinterpret_cast(const_cast(this)->GetBlockStart()); } /// Reference the entry once diff --git a/source/memory/NoAllocator.hpp b/source/memory/NoAllocator.hpp index e8eed347..a9ad1fdb 100644 --- a/source/memory/NoAllocator.hpp +++ b/source/memory/NoAllocator.hpp @@ -25,7 +25,7 @@ namespace Langulus::Anyness T* AlignedAllocate(Offset size) noexcept { const auto finalSize = T::GetNewAllocationSize(size) + Alignment; const auto base = ::std::malloc(finalSize); - if (not base) UNLIKELY() + if (not base) return nullptr; // Align pointer to the alignment LANGULUS was built with @@ -49,14 +49,14 @@ namespace Langulus::Anyness consteval bool Assert() const noexcept { return true; } }; - NOD() LANGULUS(INLINED) + LANGULUS(INLINED) static Allocation* Allocate(DMeta, Offset size) IF_UNSAFE(noexcept) { LANGULUS_ASSUME(DevAssumes, size, "Zero allocation is not allowed"); return AlignedAllocate(size); } - NOD() LANGULUS(INLINED) - static Allocation* Reallocate(Offset size, UNUSED() Allocation* previous) IF_UNSAFE(noexcept) { + LANGULUS(INLINED) + static Allocation* Reallocate(Offset size, Allocation* previous) IF_UNSAFE(noexcept) { LANGULUS_ASSUME(DevAssumes, previous, "Reallocating nullptr"); LANGULUS_ASSUME(DevAssumes, size != previous->GetAllocatedSize(), @@ -66,6 +66,7 @@ namespace Langulus::Anyness LANGULUS_ASSUME(DevAssumes, previous->mReferences, "Deallocating an unused allocation"); + (void) previous; return Allocator::Allocate(nullptr, size); } diff --git a/source/one/Handle.hpp b/source/one/Handle.hpp index 37414c8e..ae45c4bc 100644 --- a/source/one/Handle.hpp +++ b/source/one/Handle.hpp @@ -98,7 +98,7 @@ namespace Langulus::Anyness ~Handle(); - NOD() auto MakeConst() const noexcept -> Handle { + auto MakeConst() const noexcept -> Handle { return {mValue, mEntry}; } @@ -108,17 +108,17 @@ namespace Langulus::Anyness constexpr bool operator == (const auto&) const noexcept requires (not TypeErased or Sparse); - NOD() auto Get() noexcept -> Type&; - NOD() auto Get() const noexcept -> Type const&; + auto Get() noexcept -> Type&; + auto Get() const noexcept -> Type const&; - NOD() auto GetEntry() noexcept -> AllocType&; - NOD() auto GetEntry() const noexcept -> AllocType const&; + auto GetEntry() noexcept -> AllocType&; + auto GetEntry() const noexcept -> AllocType const&; void CreateWithIntent(auto&&, DMeta = {}); void Assign(const Type&, AllocType = nullptr) noexcept requires (Embedded and Mutable); void AssignWithIntent(auto&&, DMeta = {}) requires Mutable; void Swap(CT::Handle auto&, DMeta = {}) requires Mutable; - NOD() bool Compare(const auto&, DMeta = {}) const; + bool Compare(const auto&, DMeta = {}) const; template void FreeInner(DMeta = {}) requires Mutable; @@ -128,11 +128,11 @@ namespace Langulus::Anyness auto operator -- () noexcept -> Handle& requires Embedded; // Suffix operators - NOD() auto operator ++ (int) const noexcept -> Handle requires Embedded; - NOD() auto operator -- (int) const noexcept -> Handle requires Embedded; + auto operator ++ (int) const noexcept -> Handle requires Embedded; + auto operator -- (int) const noexcept -> Handle requires Embedded; - NOD() auto operator + (Offset) const noexcept -> Handle requires Embedded; - NOD() auto operator - (Offset) const noexcept -> Handle requires Embedded; + auto operator + (Offset) const noexcept -> Handle requires Embedded; + auto operator - (Offset) const noexcept -> Handle requires Embedded; auto operator += (Offset) noexcept -> Handle& requires Embedded; auto operator -= (Offset) noexcept -> Handle& requires Embedded; diff --git a/source/one/Own.hpp b/source/one/Own.hpp index 16faf994..131a5059 100644 --- a/source/one/Own.hpp +++ b/source/one/Own.hpp @@ -130,34 +130,34 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() DMeta GetType() const; - NOD() Hash GetHash() const requires CT::Hashable; - NOD() constexpr auto Get() const noexcept -> T const&; - NOD() constexpr auto Get() noexcept -> T&; + DMeta GetType() const; + Hash GetHash() const requires CT::Hashable; + constexpr auto Get() const noexcept -> T const&; + constexpr auto Get() noexcept -> T&; template - NOD() auto As() const noexcept requires CT::Sparse; + auto As() const noexcept requires CT::Sparse; - NOD() constexpr auto operator -> () const; - NOD() constexpr auto operator -> (); + constexpr auto operator -> () const; + constexpr auto operator -> (); - NOD() constexpr auto& operator * () const IF_UNSAFE(noexcept) + constexpr auto& operator * () const IF_UNSAFE(noexcept) requires (CT::Sparse and not CT::Void>); - NOD() constexpr auto& operator * () IF_UNSAFE(noexcept) + constexpr auto& operator * () IF_UNSAFE(noexcept) requires (CT::Sparse and not CT::Void>); - NOD() auto GetHandle() const; + auto GetHandle() const; /// Makes Own CT::Resolvable - NOD() constexpr auto GetBlock() const -> Block; + constexpr auto GetBlock() const -> Block; /// /// Services /// void Reset(); - NOD() explicit constexpr operator bool() const noexcept; - NOD() constexpr operator T&() const noexcept; + explicit constexpr operator bool() const noexcept; + constexpr operator T&() const noexcept; }; } // namespace Langulus::Anyness diff --git a/source/one/Ref.hpp b/source/one/Ref.hpp index e458d626..50e5c8a0 100644 --- a/source/one/Ref.hpp +++ b/source/one/Ref.hpp @@ -49,7 +49,7 @@ namespace Langulus::Anyness constexpr ~Ref(); template requires ::std::constructible_from - void New(A&&...); + auto New(A&&...) -> Ref&; /// /// Assignment @@ -66,24 +66,24 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() auto GetHandle() const -> Handle; - NOD() auto GetHandle() -> Handle; - NOD() constexpr auto GetAllocation() const noexcept -> const Allocation*; - NOD() constexpr auto GetUses() const noexcept -> Count; + auto GetHandle() const -> Handle; + auto GetHandle() -> Handle; + constexpr auto GetAllocation() const noexcept -> const Allocation*; + constexpr auto GetUses() const noexcept -> Count; using Base::operator bool; using Base::operator ->; using Base::operator *; /// Makes Ref CT::Resolvable - NOD() auto GetBlock() const -> Block; + auto GetBlock() const -> Block; /// /// Services /// void Reset(); - NOD() operator Ref() const noexcept requires CT::Mutable; + operator Ref() const noexcept requires CT::Mutable; }; diff --git a/source/one/Ref.inl b/source/one/Ref.inl index f3456971..bcf1772d 100644 --- a/source/one/Ref.inl +++ b/source/one/Ref.inl @@ -88,7 +88,7 @@ namespace Langulus::Anyness /// @return the new instance TEMPLATE() template requires ::std::constructible_from LANGULUS(INLINED) - void TME()::New(A&&...arguments) { + auto TME()::New(A&&...arguments) -> Ref& { Ref pointer; pointer.mEntry = Allocator::Allocate(MetaDataOf(), sizeof(T)); LANGULUS_ASSERT(pointer.mEntry, Allocate, "Out of memory"); @@ -97,6 +97,7 @@ namespace Langulus::Anyness Forward(arguments)... }; *this = Abandon(pointer); + return *this; } /// Reset the pointer diff --git a/source/pairs/Pair.hpp b/source/pairs/Pair.hpp index 1cb3abd2..ec49f96f 100644 --- a/source/pairs/Pair.hpp +++ b/source/pairs/Pair.hpp @@ -52,9 +52,11 @@ namespace Langulus struct Pair : A::Pair { LANGULUS_ABSTRACT() false; + private: Many mKey; Many mValue; + public: /// /// Construction & Assignment /// @@ -76,12 +78,17 @@ namespace Langulus /// /// Capsulation /// - NOD() Hash GetHash() const; + Hash GetHash() const; - Many const& GetKeyBlock() const noexcept; - Many& GetKeyBlock() noexcept; - Many const& GetValueBlock() const noexcept; - Many& GetValueBlock() noexcept; + auto GetKey() const noexcept -> Many const&; + auto GetKey() noexcept -> Many&; + auto GetKeyBlock() const noexcept -> Many const&; + auto GetKeyBlock() noexcept -> Many&; + + auto GetValue() const noexcept -> Many const&; + auto GetValue() noexcept -> Many&; + auto GetValueBlock() const noexcept -> Many const&; + auto GetValueBlock() noexcept -> Many&; /// /// Comparison diff --git a/source/pairs/Pair.inl b/source/pairs/Pair.inl index e0ff420c..80d3f831 100644 --- a/source/pairs/Pair.inl +++ b/source/pairs/Pair.inl @@ -46,6 +46,18 @@ namespace Langulus::Anyness return HashOf(mKey, mValue); } + /// Get the contained key + /// @return a reference to the contained key + LANGULUS(INLINED) + Many const& Pair::GetKey() const noexcept { + return mKey; + } + + LANGULUS(INLINED) + Many& Pair::GetKey() noexcept { + return mKey; + } + /// Get the contained key /// @return a reference to the contained key LANGULUS(INLINED) @@ -58,6 +70,18 @@ namespace Langulus::Anyness return mKey; } + /// Get the contained value + /// @return a reference to the contained key + LANGULUS(INLINED) + Many const& Pair::GetValue() const noexcept { + return mValue; + } + + LANGULUS(INLINED) + Many& Pair::GetValue() noexcept { + return mValue; + } + /// Get the contained value /// @return a reference to the contained key LANGULUS(INLINED) diff --git a/source/pairs/TPair.hpp b/source/pairs/TPair.hpp index 0bd0d32b..c19bf5fd 100644 --- a/source/pairs/TPair.hpp +++ b/source/pairs/TPair.hpp @@ -59,9 +59,11 @@ namespace Langulus::Anyness LANGULUS_ABSTRACT() false; LANGULUS(TYPED) TPair; + private: Conditional or CT::Dense, K, Ref>> mKey; Conditional or CT::Dense, V, Ref>> mValue; + public: /// /// Construction & Assignment /// @@ -87,17 +89,21 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() Hash GetHash() const requires CT::Hashable; - - Block GetKeyBlock() const noexcept; - Block GetKeyBlock() noexcept; - Block GetValueBlock() const noexcept; - Block GetValueBlock() noexcept; - - Handle GetKeyHandle(); - Handle GetValueHandle(); - Handle GetKeyHandle() const; - Handle GetValueHandle() const; + Hash GetHash() const requires CT::Hashable; + + auto GetKey() const noexcept -> const K&; + auto GetKey() noexcept -> Conditional, K&, K>; + auto GetKeyBlock() const noexcept -> Block; + auto GetKeyBlock() noexcept -> Block; + auto GetKeyHandle() -> Handle; + auto GetKeyHandle() const -> Handle; + + auto GetValue() const noexcept -> const V&; + auto GetValue() noexcept -> Conditional, V&, V>; + auto GetValueBlock() const noexcept -> Block; + auto GetValueBlock() noexcept -> Block; + auto GetValueHandle() -> Handle; + auto GetValueHandle() const -> Handle; /// /// Comparison diff --git a/source/pairs/TPair.inl b/source/pairs/TPair.inl index b692165d..213a18bd 100644 --- a/source/pairs/TPair.inl +++ b/source/pairs/TPair.inl @@ -78,6 +78,18 @@ namespace Langulus::Anyness } /// Get contained key + /// @return the key + TEMPLATE() LANGULUS(INLINED) + auto PAIR()::GetKey() noexcept -> Conditional, K&, K> { + return mKey; + } + + TEMPLATE() LANGULUS(ALWAYS_INLINED) + auto PAIR()::GetKey() const noexcept -> const K& { + return mKey; + } + + /// Get contained key as a block /// @return the key block TEMPLATE() LANGULUS(INLINED) Block PAIR()::GetKeyBlock() noexcept { @@ -93,7 +105,34 @@ namespace Langulus::Anyness return block; } + /// Get contained key as a handle + /// @return the handle + TEMPLATE() LANGULUS(INLINED) + Handle PAIR()::GetKeyHandle() { + if constexpr (CT::Sparse and not CT::Reference) + return mKey.GetHandle(); + else + return {&mKey}; + } + + TEMPLATE() LANGULUS(ALWAYS_INLINED) + Handle PAIR()::GetKeyHandle() const { + return const_cast(this)->GetKeyHandle().MakeConst(); + } + /// Get contained value + /// @return the value + TEMPLATE() LANGULUS(INLINED) + auto PAIR()::GetValue() noexcept -> Conditional, V&, V> { + return mValue; + } + + TEMPLATE() LANGULUS(ALWAYS_INLINED) + auto PAIR()::GetValue() const noexcept -> const V& { + return mValue; + } + + /// Get contained value as a block /// @return the value block TEMPLATE() LANGULUS(INLINED) Block PAIR()::GetValueBlock() noexcept { @@ -109,14 +148,8 @@ namespace Langulus::Anyness return block; } - TEMPLATE() LANGULUS(INLINED) - Handle PAIR()::GetKeyHandle() { - if constexpr (CT::Sparse and not CT::Reference) - return mKey.GetHandle(); - else - return {&mKey}; - } - + /// Get contained value as a handle + /// @return the handle TEMPLATE() LANGULUS(INLINED) Handle PAIR()::GetValueHandle() { if constexpr (CT::Sparse and not CT::Reference) @@ -124,11 +157,6 @@ namespace Langulus::Anyness else return {&mValue}; } - - TEMPLATE() LANGULUS(ALWAYS_INLINED) - Handle PAIR()::GetKeyHandle() const { - return const_cast(this)->GetKeyHandle().MakeConst(); - } TEMPLATE() LANGULUS(ALWAYS_INLINED) Handle PAIR()::GetValueHandle() const { diff --git a/source/sets/Set.hpp b/source/sets/Set.hpp index 5da90704..3ce75f3a 100644 --- a/source/sets/Set.hpp +++ b/source/sets/Set.hpp @@ -49,9 +49,9 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() decltype(auto) Get(CT::Index auto) const; + decltype(auto) Get(CT::Index auto) const; - NOD() decltype(auto) operator[] (CT::Index auto) const; + decltype(auto) operator[] (CT::Index auto) const; /// /// Iteration @@ -59,10 +59,10 @@ namespace Langulus::Anyness using Iterator = BlockSet::Iterator; using ConstIterator = BlockSet::Iterator; - NOD() auto begin() noexcept -> Iterator; - NOD() auto last() noexcept -> Iterator; - NOD() auto begin() const noexcept -> ConstIterator; - NOD() auto last() const noexcept -> ConstIterator; + auto begin() noexcept -> Iterator; + auto begin() const noexcept -> ConstIterator; + auto last() noexcept -> Iterator; + auto last() const noexcept -> ConstIterator; template Count ForEach(auto&&...); @@ -83,25 +83,25 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool Is() const noexcept; - NOD() bool Is(DMeta) const noexcept; + constexpr bool Is() const noexcept; + bool Is(DMeta) const noexcept; template - NOD() constexpr bool IsSimilar() const noexcept; - NOD() bool IsSimilar(DMeta) const noexcept; + constexpr bool IsSimilar() const noexcept; + bool IsSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsExact() const noexcept; - NOD() bool IsExact(DMeta) const noexcept; + constexpr bool IsExact() const noexcept; + bool IsExact(DMeta) const noexcept; /// /// Comparison /// using BlockSet::operator ==; - NOD() auto Find (const CT::NoIntent auto&) const -> Index; - NOD() auto FindIt(const CT::NoIntent auto&) -> Iterator; - NOD() auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; + auto Find (const CT::NoIntent auto&) const -> Index; + auto FindIt(const CT::NoIntent auto&) -> Iterator; + auto FindIt(const CT::NoIntent auto&) const -> ConstIterator; /// /// Memory management diff --git a/source/sets/TSet.hpp b/source/sets/TSet.hpp index ca462cc2..d81dce1a 100644 --- a/source/sets/TSet.hpp +++ b/source/sets/TSet.hpp @@ -83,23 +83,23 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() DMeta GetType() const; - NOD() constexpr bool IsTyped() const noexcept; - NOD() constexpr bool IsUntyped() const noexcept; - NOD() constexpr bool IsTypeConstrained() const noexcept; - NOD() constexpr bool IsDeep() const noexcept; - NOD() constexpr bool IsSparse() const noexcept; - NOD() constexpr bool IsDense() const noexcept; - NOD() constexpr Size GetStride() const noexcept; - - NOD() constexpr bool IsInsertable(DMeta) const noexcept; + DMeta GetType() const; + constexpr bool IsTyped() const noexcept; + constexpr bool IsUntyped() const noexcept; + constexpr bool IsTypeConstrained() const noexcept; + constexpr bool IsDeep() const noexcept; + constexpr bool IsSparse() const noexcept; + constexpr bool IsDense() const noexcept; + constexpr Size GetStride() const noexcept; + + constexpr bool IsInsertable(DMeta) const noexcept; template - NOD() constexpr bool IsInsertable() const noexcept; + constexpr bool IsInsertable() const noexcept; - NOD() bool IsMissingDeep() const; + bool IsMissingDeep() const; - NOD() bool IsExecutable() const; - NOD() bool IsExecutableDeep() const; + bool IsExecutable() const; + bool IsExecutableDeep() const; using Base::GetReserved; using Base::GetInfo; @@ -112,9 +112,9 @@ namespace Langulus::Anyness /// /// Indexing /// - NOD() T const& Get(CT::Index auto) const; + T const& Get(CT::Index auto) const; - NOD() T const& operator[] (CT::Index auto) const; + T const& operator[] (CT::Index auto) const; public: /// @@ -123,10 +123,10 @@ namespace Langulus::Anyness using Iterator = BlockSet::Iterator; using ConstIterator = BlockSet::Iterator; - NOD() auto begin() noexcept -> Iterator; - NOD() auto last() noexcept -> Iterator; - NOD() auto begin() const noexcept -> ConstIterator; - NOD() auto last() const noexcept -> ConstIterator; + auto begin() noexcept -> Iterator; + auto last() noexcept -> Iterator; + auto begin() const noexcept -> ConstIterator; + auto last() const noexcept -> ConstIterator; using Base::end; template @@ -148,16 +148,16 @@ namespace Langulus::Anyness /// RTTI /// template - NOD() constexpr bool Is() const noexcept; - NOD() bool Is(DMeta) const noexcept; + constexpr bool Is() const noexcept; + bool Is(DMeta) const noexcept; template - NOD() constexpr bool IsSimilar() const noexcept; - NOD() bool IsSimilar(DMeta) const noexcept; + constexpr bool IsSimilar() const noexcept; + bool IsSimilar(DMeta) const noexcept; template - NOD() constexpr bool IsExact() const noexcept; - NOD() bool IsExact(DMeta) const noexcept; + constexpr bool IsExact() const noexcept; + bool IsExact(DMeta) const noexcept; protected: template @@ -172,18 +172,18 @@ namespace Langulus::Anyness bool operator == (const T1&) const; template requires CT::Comparable - NOD() bool Contains(T1 const&) const; + bool Contains(T1 const&) const; template requires (not CT::Comparable) static consteval bool Contains(T1 const&) { return false; } template requires CT::Comparable - NOD() auto Find(T1 const&) const -> Index; + auto Find(T1 const&) const -> Index; template requires CT::Comparable - NOD() auto FindIt(T1 const&) -> Iterator; + auto FindIt(T1 const&) -> Iterator; template requires CT::Comparable - NOD() auto FindIt(T1 const&) const ->ConstIterator; + auto FindIt(T1 const&) const -> ConstIterator; /// /// Memory management @@ -212,8 +212,8 @@ namespace Langulus::Anyness /// /// Removal /// - Count Remove(const T&); - Iterator RemoveIt(const Iterator&); + auto Remove(const T&) -> Count; + auto RemoveIt(const Iterator&) -> Iterator; void Clear(); void Reset(); diff --git a/source/text/Path.hpp b/source/text/Path.hpp index 9d0c8487..ea0e4391 100644 --- a/source/text/Path.hpp +++ b/source/text/Path.hpp @@ -31,11 +31,11 @@ namespace Langulus::Anyness Path(const Text&); Path(Text&&); - NOD() auto GetExtension() const -> Text; - NOD() auto GetDirectory() const -> Path; - NOD() auto GetFilename() const -> Path; + auto GetExtension() const -> Text; + auto GetDirectory() const -> Path; + auto GetFilename() const -> Path; - NOD() auto operator / (const Text&) const -> Path; + auto operator / (const Text&) const -> Path; auto operator /= (const Text&) -> Path&; private: diff --git a/source/text/Text.hpp b/source/text/Text.hpp index 994751c8..6017fe80 100644 --- a/source/text/Text.hpp +++ b/source/text/Text.hpp @@ -8,7 +8,7 @@ #pragma once #include "../many/TMany.hpp" #include "../many/Bytes.hpp" -#include // Logger has some core fmt::formatters defined +#include // Logger has some core fmt::formatters defined namespace Langulus::Anyness::Serial @@ -292,10 +292,10 @@ namespace Langulus::Anyness Text(const CT::Meta auto&); Text(const CT::Exception auto&); Text(const CT::Bytes auto&); - Text(Byte); - - explicit Text(Operator); + explicit Text(Byte); + explicit Text(bool); + explicit Text(Operator); explicit Text(const CT::HasNamedValues auto&); template requires (not CT::Character) @@ -308,10 +308,10 @@ namespace Langulus::Anyness ~Text(); template requires CT::String> - NOD() static Text From(T&&, Count); + static Text From(T&&, Count); template - NOD() static Text FromNumber(const T&); + static Text FromNumber(const T&); /// /// Assignment @@ -325,17 +325,17 @@ namespace Langulus::Anyness /// /// Capsulation /// - NOD() Count GetLineCount() const noexcept; + Count GetLineCount() const noexcept; - NOD() operator Token () const noexcept; + operator Token () const noexcept; /// /// Indexing /// - NOD() Text Select(CT::Index auto, Count) const IF_UNSAFE(noexcept); - NOD() Text Select(CT::Index auto, Count) IF_UNSAFE(noexcept); - NOD() Text Select(CT::Index auto) const IF_UNSAFE(noexcept); - NOD() Text Select(CT::Index auto) IF_UNSAFE(noexcept); + Text Select(CT::Index auto, Count) const IF_UNSAFE(noexcept); + Text Select(CT::Index auto, Count) IF_UNSAFE(noexcept); + Text Select(CT::Index auto) const IF_UNSAFE(noexcept); + Text Select(CT::Index auto) IF_UNSAFE(noexcept); /// /// Comparison @@ -350,7 +350,7 @@ namespace Langulus::Anyness /// Insertion /// Text Extend(Count); - NOD() Text Terminate() const; + Text Terminate() const; template requires CT::Stringifiable> Text& operator << (T&&); @@ -365,14 +365,15 @@ namespace Langulus::Anyness /// /// Removal /// - NOD() Text Strip (const CT::Text auto&) const; - NOD() Text Replace(const CT::Text auto& what, const CT::Text auto& with) const; + Text Strip (const CT::Text auto&) const; + Text Replace(const CT::Text auto& what, const CT::Text auto& with) const; /// /// Concatenation /// template requires CT::Stringifiable> - NOD() Text operator + (T&&) const; + Text operator + (T&&) const; + template requires (CT::Stringifiable> and not CT::TextBased) friend Text operator + (T&&, const Text&); @@ -396,21 +397,21 @@ namespace Langulus::Anyness /// /// Services /// - NOD() Text Lowercase() const; - NOD() Text Uppercase() const; + Text Lowercase() const; + Text Uppercase() const; #if LANGULUS_FEATURE(UNICODE) - NOD() TMany Widen16() const; - NOD() TMany Widen32() const; + TMany Widen16() const; + TMany Widen32() const; #endif - NOD() static Text Hex(const auto&); + static Text Hex(const auto&); template - NOD() static Text Template(const Token&, ARGS&&...); + static Text Template(const Token&, ARGS&&...); template - NOD() static Text TemplateRt(const Token&, ARGS&&...); + static Text TemplateRt(const Token&, ARGS&&...); template - NOD() static constexpr auto TemplateCheck(const Token&, ARGS&&...); + static constexpr auto TemplateCheck(const Token&, ARGS&&...); protected: template<::std::size_t...N> diff --git a/source/text/Text.inl b/source/text/Text.inl index 5ac5f60e..6edb1901 100644 --- a/source/text/Text.inl +++ b/source/text/Text.inl @@ -181,6 +181,22 @@ namespace Langulus::Anyness mCount = 2; } + /// Stringify a boolean, by writing either `yes` or `no` + /// @param from - the boolean to stringify + LANGULUS(INLINED) + Text::Text(bool from) { + mType = MetaDataOf(); + AllocateFresh(RequestSize(4)); + if (from) { + fmt::format_to_n(mRaw, 3, "{}", "yes"); + mCount = 3; + } + else { + fmt::format_to_n(mRaw, 2, "{}", "no"); + mCount = 2; + } + } + /// Stringify a serialization operator /// @param from - the op to stringify LANGULUS(INLINED) @@ -270,7 +286,20 @@ namespace Langulus::Anyness if constexpr (PRECISION) { // We can truncate even more if (lastChar > dot + PRECISION) { - --lastChar; + if (lastChar == dot + PRECISION + 1 and *lastChar > '4') { + // Round up + while (*lastChar == '9') { + // Propagate up until <9 or . + --lastChar; + } + + if (*lastChar == '.') + ++(*(--lastChar)); + else + ++(*lastChar); + } + else --lastChar; + approximate = true; continue; } diff --git a/source/verbs/Verb.hpp b/source/verbs/Verb.hpp index d1c2fcec..80c33206 100644 --- a/source/verbs/Verb.hpp +++ b/source/verbs/Verb.hpp @@ -33,6 +33,7 @@ namespace Langulus::A using VMeta = Anyness::VMeta; using VerbState = Anyness::VerbState; using Many = Anyness::Many; + using Text = Anyness::Text; // Verb meta, mass, rate, time and priority mutable VMeta mVerb {}; @@ -73,44 +74,45 @@ namespace Langulus::A /// /// Capsulation /// - NOD() auto GetVerb() const noexcept -> VMeta; - NOD() auto GetHash() const -> Hash; - NOD() auto GetCharge() const noexcept -> const Charge&; - NOD() auto GetMass() const noexcept -> Real; - NOD() auto GetRate() const noexcept -> Real; - NOD() auto GetTime() const noexcept -> Real; - NOD() auto GetPriority() const noexcept -> Real; - - NOD() auto GetSource() noexcept -> Many&; - NOD() auto GetSource() const noexcept -> Many const&; - - NOD() auto GetArgument() noexcept -> Many&; - NOD() auto GetArgument() const noexcept -> Many const&; - - NOD() auto GetOutput() noexcept -> Many&; - NOD() auto GetOutput() const noexcept -> Many const&; - - NOD() auto operator -> () noexcept -> Many*; - NOD() auto operator -> () const noexcept -> Many const*; + auto GetVerb() const noexcept -> VMeta; + auto GetHash() const -> Hash; + auto GetCharge() const noexcept -> const Charge&; + auto GetMass() const noexcept -> Real; + auto GetRate() const noexcept -> Real; + auto GetTime() const noexcept -> Real; + auto GetPriority() const noexcept -> Real; + auto GetOperatorToken(bool& tokenized) const -> Text; + + auto GetSource() noexcept -> Many&; + auto GetSource() const noexcept -> Many const&; + + auto GetArgument() noexcept -> Many&; + auto GetArgument() const noexcept -> Many const&; + + auto GetOutput() noexcept -> Many&; + auto GetOutput() const noexcept -> Many const&; + + auto operator -> () noexcept -> Many*; + auto operator -> () const noexcept -> Many const*; - NOD() Count GetSuccesses() const noexcept; - NOD() auto GetVerbState() const noexcept -> VerbState; - NOD() bool IsDone() const noexcept; + auto GetSuccesses() const noexcept -> Count; + auto GetVerbState() const noexcept -> VerbState; + bool IsDone() const noexcept; - NOD() constexpr bool IsMulticast() const noexcept; - NOD() constexpr bool IsMonocast() const noexcept; - NOD() constexpr bool IsShortCircuited() const noexcept; - NOD() constexpr bool IsLongCircuited() const noexcept; + /*constexpr bool IsMulticast() const noexcept; + constexpr bool IsMonocast() const noexcept;*/ + constexpr bool IsShortCircuited() const noexcept; + constexpr bool IsLongCircuited() const noexcept; - NOD() bool IsMissing() const noexcept; - NOD() bool IsMissingDeep() const noexcept; - NOD() bool Validate(Anyness::Index) const noexcept; + bool IsMissing() const noexcept; + bool IsMissingDeep() const noexcept; + bool Validate(Anyness::Index) const noexcept; void Done(Count) noexcept; void Done() noexcept; void Undo() noexcept; - NOD() explicit operator Anyness::Text() const; + explicit operator Anyness::Text() const; protected: void SerializeVerb(CT::Serial auto&) const; @@ -119,14 +121,14 @@ namespace Langulus::A /// /// Comparison /// - NOD() bool operator == (const Verb&) const; - NOD() bool operator == (VMeta) const noexcept; + bool operator == (const Verb&) const; + bool operator == (VMeta) const noexcept; - NOD() bool operator < (const Verb&) const noexcept; - NOD() bool operator > (const Verb&) const noexcept; + bool operator < (const Verb&) const noexcept; + bool operator > (const Verb&) const noexcept; - NOD() bool operator <= (const Verb&) const noexcept; - NOD() bool operator >= (const Verb&) const noexcept; + bool operator <= (const Verb&) const noexcept; + bool operator >= (const Verb&) const noexcept; /// /// Removal diff --git a/source/verbs/Verb.inl b/source/verbs/Verb.inl index 6c01e781..085d70ab 100644 --- a/source/verbs/Verb.inl +++ b/source/verbs/Verb.inl @@ -100,7 +100,7 @@ namespace Langulus::A /// Check if verb is multicast /// @return true if verb is multicast - LANGULUS(INLINED) + /*LANGULUS(INLINED) constexpr bool Verb::IsMulticast() const noexcept { return mState.IsMulticast(); } @@ -110,7 +110,7 @@ namespace Langulus::A LANGULUS(INLINED) constexpr bool Verb::IsMonocast() const noexcept { return mState.IsMonocast(); - } + }*/ /// Check if verb is short-circuited /// @return true if verb is short-circuited @@ -316,9 +316,10 @@ namespace Langulus::A } /// Serialize verb to any form of text - /// @return the serialized verb + /// @param out - [in/out] the serialized verb void Verb::SerializeVerb(CT::Serial auto& out) const { using OUT = Deref; + using Rules = typename OUT::SerializationRules; if (mSuccesses and mOutput) { // If verb has been executed with output, just dump the output mOutput.Serialize(out); @@ -328,63 +329,28 @@ namespace Langulus::A // If reached, then verb hasn't been executed yet // Let's check if there's a source in which verb is executed if (mSource.IsValid()) { - OUT::SerializationRules::BeginScope(mSource, out); + Rules::BeginScope(mSource, out); mSource.Serialize(out); - OUT::SerializationRules::EndScope(mSource, out); + Rules::EndScope(mSource, out); } // After the source, we decide whether to write verb token or // verb operator, depending on the verb definition, state and // charge bool writtenAsToken = false; - if (not mVerb) { - // An invalid verb is always written as token - if (mSource.IsValid()) - out += ' '; - out += NameOf(); - writtenAsToken = true; - } - else { - // A valid verb is written either as token, or as operator - if (mMass < 0) { - if (not mVerb->mOperatorReverse.empty() and (GetCharge().operator*(-1)).IsDefault()) { - // Write as operator - out += mVerb->mOperatorReverse; - } - else { - // Write as token - if (mSource.IsValid()) - out += ' '; - out += mVerb->mTokenReverse; - out += static_cast(GetCharge().operator*(-1)); - writtenAsToken = true; - } - } - else { - if (not mVerb->mOperator.empty() and GetCharge().IsDefault()) { - // Write as operator - out += mVerb->mOperator; - } - else { - // Write as token - if (mSource.IsValid()) - out += ' '; - out += mVerb->mToken; - out += static_cast(GetCharge()); - writtenAsToken = true; - } - } - } + const auto token = GetOperatorToken(writtenAsToken); + if (writtenAsToken and mSource.IsValid()) + out += ' '; + out += token; if (not IsValid()) return; - if (not OUT::SerializationRules::BeginScope(GetArgument(), out) - and writtenAsToken) + if (not Rules::BeginScope(GetArgument(), out) and writtenAsToken) out += ' '; GetArgument().Serialize(out); - OUT::SerializationRules::EndScope(GetArgument(), out); + Rules::EndScope(GetArgument(), out); } /// Serialize verb for logger @@ -414,5 +380,53 @@ namespace Langulus::A bool Verb::operator == (VMeta rhs) const noexcept { return mVerb == rhs; } + + /// Get the verb token or operator depending on context and energy + /// @return the token as a literal + LANGULUS(INLINED) + auto Verb::GetOperatorToken(bool& tokenized) const -> Text { + Text out; + if (not mVerb) { + // An invalid verb is always written as token + out += NameOf(); + tokenized = true; + return out.Lowercase(); + } + + // A valid verb is written either as token, or as operator + if (mMass < 0) { + if (not mVerb->mOperatorReverse.empty() + and (GetCharge().operator*(-1)).IsDefault()) { + // Write as operator + out += mVerb->mOperatorReverse; + } + else if (not mVerb->mTokenReverse.empty()) { + // Write as token + out += mVerb->mTokenReverse; + out += static_cast(GetCharge().operator*(-1)); + tokenized = true; + } + else { + // Write as token + out += mVerb->mToken; + out += static_cast(GetCharge()); + tokenized = true; + } + } + else { + if (not mVerb->mOperator.empty() and GetCharge().IsDefault()) { + // Write as operator + out += mVerb->mOperator; + } + else { + // Write as token + out += mVerb->mToken; + out += static_cast(GetCharge()); + tokenized = true; + } + } + + return out.Lowercase(); + } } // namespace Langulus::A \ No newline at end of file diff --git a/source/verbs/VerbState.hpp b/source/verbs/VerbState.hpp index 2ef49724..fc483764 100644 --- a/source/verbs/VerbState.hpp +++ b/source/verbs/VerbState.hpp @@ -34,7 +34,7 @@ namespace Langulus::Anyness // When verb is monocast (as opposite to multicast) it will // not iterate deep items, but be executed on the context once // as a whole. Used extensively when executing at compile-time - Monocast = 2 + //Monocast = 2 }; using Type = TypeOf; @@ -48,19 +48,19 @@ namespace Langulus::Anyness explicit constexpr operator bool() const noexcept; constexpr bool operator == (const VerbState&) const noexcept = default; - NOD() constexpr VerbState operator + (const VerbState&) const noexcept; - NOD() constexpr VerbState operator - (const VerbState&) const noexcept; + constexpr VerbState operator + (const VerbState&) const noexcept; + constexpr VerbState operator - (const VerbState&) const noexcept; constexpr VerbState& operator += (const VerbState&) noexcept; constexpr VerbState& operator -= (const VerbState&) noexcept; - NOD() constexpr bool operator & (const VerbState&) const noexcept; - NOD() constexpr bool operator % (const VerbState&) const noexcept; + constexpr bool operator & (const VerbState&) const noexcept; + constexpr bool operator % (const VerbState&) const noexcept; - NOD() constexpr bool IsDefault() const noexcept; - NOD() constexpr bool IsMulticast() const noexcept; - NOD() constexpr bool IsMonocast() const noexcept; - NOD() constexpr bool IsShortCircuited() const noexcept; - NOD() constexpr bool IsLongCircuited() const noexcept; + constexpr bool IsDefault() const noexcept; + /*constexpr bool IsMulticast() const noexcept; + constexpr bool IsMonocast() const noexcept;*/ + constexpr bool IsShortCircuited() const noexcept; + constexpr bool IsLongCircuited() const noexcept; constexpr void Reset() noexcept; }; diff --git a/source/verbs/VerbState.inl b/source/verbs/VerbState.inl index c6e99ce0..be95cbd8 100644 --- a/source/verbs/VerbState.inl +++ b/source/verbs/VerbState.inl @@ -78,7 +78,7 @@ namespace Langulus::Anyness } /// Check if state is multicast - LANGULUS(INLINED) + /*LANGULUS(INLINED) constexpr bool VerbState::IsMulticast() const noexcept { return (mState & VerbState::Monocast) == 0; } @@ -87,7 +87,7 @@ namespace Langulus::Anyness LANGULUS(INLINED) constexpr bool VerbState::IsMonocast() const noexcept { return mState & VerbState::Monocast; - } + }*/ /// Check if state is long-circuited LANGULUS(INLINED) diff --git a/test/Main.cpp b/test/Common.cpp similarity index 62% rename from test/Main.cpp rename to test/Common.cpp index a770b5aa..993f2ff0 100644 --- a/test/Main.cpp +++ b/test/Common.cpp @@ -5,23 +5,9 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include "Main.hpp" - -#define CATCH_CONFIG_RUNNER -#include +#include +#include "Common.hpp" LANGULUS_RTTI_BOUNDARY(RTTI::MainBoundary) TMany BANK {}; - - -int main(int argc, char* argv[]) { - Catch::Session session; - const auto result = session.run(argc, argv); - - // Destroy BANK before static data - otherwise problems happen if - // not using managed reflection - BANK.Reset(); - - return result; -} diff --git a/test/Common.hpp b/test/Common.hpp index 5fc85539..bb98d6de 100644 --- a/test/Common.hpp +++ b/test/Common.hpp @@ -8,39 +8,571 @@ /// INTENTIONALLY NOT GUARDED /// Include this file once in each cpp file, after all other headers -#ifdef TWOBLUECUBES_SINGLE_INCLUDE_CATCH_HPP_INCLUDED - #error Catch has already been included prior to this header -#endif +#include +#include -#include -#include "TestTypes.hpp" +using namespace Anyness; -/// See https://github.com/catchorg/Catch2/blob/devel/docs/tostring.md -CATCH_TRANSLATE_EXCEPTION(::Langulus::Exception const& ex) { - const Text serialized {ex}; - return ::std::string {Token {serialized}}; + +template +struct TypePair { + using LHS = L; + using RHS = R; +}; + +/// Used to configure a map test +/// @param C - the map type we're testing +/// @param K - the tested key type +/// @param V - the tested value type +/// @param MANAGED - true to contain memory allocated by our manager +template +struct MapTest { + using Container = C; + using Key = K; + using Value = V; + static constexpr bool Managed = MANAGED; +}; + +/// Used to configure a set test +/// @param C - the map type we're testing +/// @param K - the tested key type +/// @param MANAGED - true to contain memory allocated by our manager +template +struct SetTest { + using Container = C; + using Key = K; + static constexpr bool Managed = MANAGED; +}; + +/// Type for testing hashing consistency between two containers +/// @tparam K - the left container +/// @tparam V - the right container +template +struct HashTest { + using Key = K; + using Value = V; +}; + + +/// Create a dense element, on the stack +/// @tparam T - type of element we're creating +/// @param e - the data we'll use to initialize an instance of T +/// @return the new instance of T +/*template +T CreateElement(const auto& e) { + T element; + if constexpr (CT::Same) + element = e; + else if constexpr (not CT::Same>) + element = Decay {e}; + else { + element = Block<> {}; + element.Insert(e); + } + + return element; +}*/ + +/// Create a sparse element, on the heap +/// @tparam T - type of element we're creating +/// @tparam MANAGED - whether we'll have authority over the pointer or not +/// @param e - the data we'll use to initialize an instance of T +/// @return pointer to the new instance of T +/*template +T CreateElement(const auto& e) { + void* element; + + if constexpr (not MANAGED) { + // Create a pointer that is guaranteed to not be owned by the + // memory manager. Notice we don't use 'new' operator here, + // because it is weakly linked, and can be overriden to use our + // memory manager. + if constexpr (not CT::Same>) { + element = malloc(sizeof(Decay)); + new (element) Decay {e}; + } + else { + element = malloc(sizeof(Block<>)); + new (element) Block<> {}; + static_cast*>(element)->Insert(e); + } + } + else { + // Create a pointer owned by the memory manager + auto& container = BANK.Emplace(IndexBack); + + if constexpr (not CT::Same>) { + container << Decay {e}; + element = container.GetRaw(); + } + else { + container << e; + element = &container; + } + } + + return static_cast(element); } -namespace Catch -{ - template - struct StringMaker { - static std::string convert(T const& value) { - return ::std::string {Token {static_cast(value)}}; +template +void DestroyElement(auto e) { + using E = decltype(e); + if constexpr (CT::Sparse) { + if constexpr (CT::Referencable>) + e->Reference(-1); + + if constexpr (CT::Destroyable>) + e->~Decay(); + + if constexpr (not MANAGED) + free(e); + } +}*/ + +/// Create a test pair +/// @tparam P - the pair type +/// @tparam K - the pair key type +/// @tparam V - the pair value type +/// @tparam MANAGED - whether or not we have auhtority over the data +/// @param key - the key initialization data +/// @param value - the value initialization data +/// @return the pair +template +P CreatePair(const auto& key, const auto& value) { + return P { + CreateElement(key), + CreateElement(value) + }; +} + +/// Destroy a test pair created via CreatePair +/// @tparam MANAGED - was it created by the memory manager? +/// @param pair - the pair to destroy +template +void DestroyPair(auto& pair) { + using P = Deref; + + if constexpr (not MANAGED) { + if constexpr (requires { pair.GetKey(); }) { + if constexpr (CT::Typed

) { + // It's a statically typed langulus pair + using K = typename P::Key; + using V = typename P::Value; + + if constexpr (CT::Sparse) { + if constexpr (CT::Referencable>) + REQUIRE(pair.GetKey()->Reference(-1) == 0); + if constexpr (CT::Destroyable>) + pair.GetKey()->~Decay(); + free(pair.GetKey()); + } + else if constexpr (requires (K k) { k.Reset(); }) + DecvqCast(pair.GetKey()).Reset(); + + if constexpr (CT::Sparse) { + if constexpr (CT::Referencable>) + REQUIRE(pair.GetValue()->Reference(-1) == 0); + if constexpr (CT::Destroyable>) + pair.GetValue()->~Decay(); + free(pair.GetValue()); + } + else if constexpr (requires (V v) { v.Reset(); }) + DecvqCast(pair.GetValue()).Reset(); + } + else { + if (pair.GetKey().IsSparse()) { + if (pair.GetKey().GetType()->mReference) + REQUIRE(pair.GetKey().GetType()->mReference(*pair.GetKey().template GetRaw(), -1) == 0); + if (pair.GetKey().GetType()->mDestructor) + pair.GetKey().GetType()->mDestructor(*pair.GetKey().template GetRaw()); + free(*pair.GetKey().template GetRaw()); + } + + DecvqCast(pair.GetKey()).Reset(); + + if (pair.GetValue().IsSparse()) { + if (pair.GetValue().GetType()->mReference) + REQUIRE(pair.GetValue().GetType()->mReference(*pair.GetValue().template GetRaw(), -1) == 0); + if (pair.GetValue().GetType()->mDestructor) + pair.GetValue().GetType()->mDestructor(*pair.GetValue().template GetRaw()); + free(*pair.GetValue().template GetRaw()); + } + + DecvqCast(pair.GetValue()).Reset(); + } + } + else if constexpr (requires { pair.first; }) { + // It's an std::pair + using K = decltype(pair.first); + using V = decltype(pair.second); + + if constexpr (CT::Sparse) { + if constexpr (CT::Referencable>) + REQUIRE(pair.first->Reference(-1) == 0); + if constexpr (CT::Destroyable>) + pair.first->~Decay(); + free(pair.first); + } + else if constexpr (requires (K k) { k.Reset(); }) + DecvqCast(pair.first).Reset(); + + if constexpr (CT::Sparse) { + if constexpr (CT::Referencable>) + REQUIRE(pair.second->Reference(-1) == 0); + if constexpr (CT::Destroyable>) + pair.second->~Decay(); + free(pair.second); + } + else if constexpr (requires (V v) { v.Reset(); }) + DecvqCast(pair.second).Reset(); } + else static_assert(false, "What kind of pair is this? Are you making stuff up?"); + } + else BANK.Reset(); +} + + +namespace Langulus::Flow +{ + struct Verb {}; + class Construct {}; + class Constructconst {}; + class constConstructconst {}; + class constconst {}; +} + +/// An empty trivial type +class ImplicitlyConstructible {}; + +/// A simple aggregate type +struct AggregateType { + int m1, m2, m3, m4; + bool m5; +}; + +/// Explicitly deleted destructor +class NonDestructible { + ~NonDestructible() = delete; +}; + +/// Has an explicit destructor +class Destructible { +public: + char* someptr {}; + + ~Destructible() { + if (someptr) + delete someptr; + } +}; + +/// Default-constructible, but only privately +class PrivatelyConstructible { + LANGULUS(POD) false; +private: + PrivatelyConstructible() = default; + PrivatelyConstructible(const PrivatelyConstructible&) = default; + PrivatelyConstructible(PrivatelyConstructible&&) = default; +}; + +/// Has no explicit intent constructors and assigners +/// Has only implicit refer & move constructors and assigners +class NonIntentConstructible { + LANGULUS(POD) false; +public: + NonIntentConstructible(CT::NoIntent auto&&) {} +}; + +/// Has explicit copy, move, refer, clone, abandon, disown constructors +/// Has implicit refer & move constructors, too +/// Has no explicit intent assigners, only implicit refer & move +class PartiallyIntentConstructible { +public: + template class S, class T> + PartiallyIntentConstructible(S&&) requires CT::Intent> {} +}; + +/// Has all intent constructors + implicit refer & move ones +/// Has no explicit intent assigners, only implicit refer & move ones +/// Making constructor explicit makes sure, that no implicit intent assign +/// happens +class AllIntentConstructible { +public: + LANGULUS(POD) false; + explicit AllIntentConstructible(CT::Intent auto&&) {} +}; + +/// Has all intent constructors + implicit refer & move ones +/// Has no explicit intent assigners, only implicit refer & move ones +/// Making constructor implicit also allows for intent assignments +class AllIntentConstructibleImplicit { +public: + LANGULUS(POD) false; + AllIntentConstructibleImplicit(CT::Intent auto&&) {} +}; + +/// Has all intnet constructors and assigners + implicit refer & move ones +class AllIntentConstructibleAndAssignable { +public: + LANGULUS(POD) false; + AllIntentConstructibleAndAssignable(CT::Intent auto&&) {} + AllIntentConstructibleAndAssignable& operator = (CT::Intent auto&&) { return *this; } +}; + +/// Has explicit descriptor constructor, and implicit refer & move ones +/// Has no explicit intent assigners, only implicit refer & move +class DescriptorConstructible { +public: + DescriptorConstructible(Describe) {} +}; + + +enum class Pi { + Number = 314 +}; + +struct IncompleteType; + +namespace One::Two::Three { + struct TypeDeepIntoNamespaces; + + template + struct TemplatedTypeDeepIntoNamespaces { + enum VeryDeeplyTemplatedEnum { YesYouGotThatRight }; + + template + struct Nested; }; - /// Save catch2 from doing infinite recursions with Block types - template - struct is_range { - static const bool value = false; + template + struct VeryComplexTemplate; +} + +namespace Verbs +{ + + /// + /// A testing verb, similar to the ones used in Langulus::Flow + /// + struct Create : public Flow::Verb { + LANGULUS(POSITIVE_VERB) "Create"; + LANGULUS(NEGATIVE_VERB) "Destroy"; + LANGULUS(POSITIVE_OPERATOR) " + "; + LANGULUS(NEGATIVE_OPERATOR) " - "; + LANGULUS(PRECEDENCE) 5; + LANGULUS(INFO) + "Used for allocating new elements. " + "If the type you're creating has a producer, " + "you need to execute the verb in a matching producer, " + "or that producer will be created automatically for you, if possible"; + + /// Check if the verb is available in a type, and with given arguments + /// @return true if verb is available in T with arguments A... + template + static constexpr bool AvailableFor() noexcept { + if constexpr (sizeof...(A) == 0) + return requires (T & t, Verb & v) { t.Create(v); }; + else + return requires (T & t, Verb & v, A... a) { t.Create(v, a...); }; + } + + /// Get the verb functor for the given type and arguments + /// @return the function, or nullptr if not available + template + static constexpr auto Of() noexcept { + if constexpr (!Create::AvailableFor()) { + return nullptr; + } + else if constexpr (CT::Constant) { + return [](const void* context, Flow::Verb& verb, A... args) { + auto typedContext = static_cast(context); + typedContext->Create(verb, args...); + }; + } + else { + return [](void* context, Flow::Verb& verb, A... args) { + auto typedContext = static_cast(context); + typedContext->Create(verb, args...); + }; + } + } + + template + static bool ExecuteIn(T&, Verb&); + + static bool ExecuteDefault(const Anyness::Block<>&, Verb&) { + return true; + } + + static bool ExecuteDefault(Anyness::Block<>&, Verb&) { + return false; + } + + static bool ExecuteStateless(Verb&) { + return false; + } }; } -#ifdef CATCH_CONFIG_ENABLE_BENCHMARKING -using timer = Catch::Benchmark::Chronometer; +struct ImplicitlyReflectedData { + LANGULUS(POD) true; + LANGULUS(FILES) "ASE"; + + enum Named {One, Two, Three}; + LANGULUS_NAMED_VALUES(One, Two, Three); + LANGULUS(TYPED) Named; + + Named v = One; + + inline bool operator == (const ImplicitlyReflectedData&) const noexcept = default; +}; + +class alignas(128) ImplicitlyReflectedDataWithTraits : public ImplicitlyReflectedData { +public: + int member {664}; + RTTI::Tag anotherMember {}; + int anotherMemberArray [12] {}; + int* sparseMember {}; + + inline operator int() const noexcept { + return member; + } + + void Create(Flow::Verb&) const { + //++member; + } + + void Create(Flow::Verb&) { + ++member; + } + + ImplicitlyReflectedDataWithTraits() = default; + explicit ImplicitlyReflectedDataWithTraits(Pi) + : member {314} {} + + LANGULUS(NAME) "MyType"; + LANGULUS(INFO) "Info about MyType"; + LANGULUS(FILES) "txt, pdf"; + LANGULUS(VERSION_MAJOR) 2; + LANGULUS(VERSION_MINOR) 1; + LANGULUS(DEEP) true; + LANGULUS(POD) true; + LANGULUS(NULLIFIABLE) true; + LANGULUS(POOL_TACTIC) RTTI::PoolTactic::Size; + LANGULUS(CONCRETE) ImplicitlyReflectedData; + LANGULUS(ACT_AS) void; + LANGULUS(ALLOCATION_PAGE) 250; + LANGULUS(ABSTRACT) true; + LANGULUS_BASES(ImplicitlyReflectedData); + LANGULUS_VERBS(Verbs::Create); + LANGULUS_CONVERTS_TO(int); + LANGULUS_CONVERTS_FROM(Pi); + LANGULUS_NAMED_VALUES(); + + using Self = ImplicitlyReflectedDataWithTraits; + LANGULUS_MEMBERS( + &Self::member, + &Self::anotherMember, + &Self::anotherMemberArray, + &Self::sparseMember + ); +}; + +/// Doesn't have implicit copy/move, so it is abandon-makable by explicit move +/// but not abandon-assignable +class alignas(128) Complex { +public: + int member; + bool anotherMember {}; + int anotherMemberArray [12] {}; + int* sparseMember {}; + + LANGULUS(NAME) "ComplexType"; + LANGULUS(INFO) "Info about ComplexType"; + LANGULUS(VERSION_MAJOR) 2; + LANGULUS(VERSION_MINOR) 1; + LANGULUS(POOL_TACTIC) RTTI::PoolTactic::Size; + LANGULUS(ALLOCATION_PAGE) 250; + + using Self = Complex; + LANGULUS_MEMBERS( + &Self::member, + &Self::anotherMember, + &Self::anotherMemberArray, + &Self::sparseMember + ); + + Complex(const Complex& s) + : member(s.member) {} + Complex(Complex&& s) + : member(s.member) {} + Complex(int stuff) + : member(stuff) {} + + ~Complex() { + if (sparseMember) + delete sparseMember; + } +}; + +struct AnotherTypeWithSimilarilyNamedValues { + enum Named {One = 501, Two, Three}; + LANGULUS_NAMED_VALUES(One, Two, Three); + LANGULUS(NAME) "YetAnotherNamedType"; + + int v = One; + + inline bool operator == (const AnotherTypeWithSimilarilyNamedValues&) const noexcept = default; +}; + +struct CheckingWhatGetsInherited : ImplicitlyReflectedDataWithTraits { + LANGULUS(NAME) "CheckingWhatGetsInherited"; + + using ImplicitlyReflectedDataWithTraits::ImplicitlyReflectedDataWithTraits; +}; + +class ContainsComplex { + Complex mData; +}; + +/// A complex aggregate type +struct AggregateTypeComplex { + int m1, m2, m3, m4; + bool m5; + Complex mData; +}; + +/// A complex aggregate type +struct AggregateThatCanBeConfusedWithDescriptorMakable { + DescriptorConstructible mConfusable; + int m1, m2, m3, m4; +}; + +class ForcefullyPod { + LANGULUS(POD) true; + Complex mData; +}; + +struct Type {}; + +struct TypeErasedContainer { + LANGULUS(TYPED) void; +}; + +namespace N1 { + struct Type {}; + struct Create {}; +} + +namespace N2 { + struct Type {}; +} + +namespace N3 { + struct type {}; +} -template -using uninitialized = Catch::Benchmark::storage_for; -#endif \ No newline at end of file +enum class TypedEnum : int16_t { + E1, E2, E3 +}; diff --git a/test/Main.hpp b/test/Main.hpp deleted file mode 100644 index f30299ee..00000000 --- a/test/Main.hpp +++ /dev/null @@ -1,231 +0,0 @@ -/// -/// Langulus::Anyness -/// Copyright (c) 2012 Dimo Markov -/// Part of the Langulus framework, see https://langulus.com -/// -/// SPDX-License-Identifier: GPL-3.0-or-later -/// -#pragma once -#include - -using namespace Langulus; -using namespace Langulus::Anyness; - -//#define LANGULUS_STD_BENCHMARK - -//#ifdef LANGULUS_STD_BENCHMARK -//#define CATCH_CONFIG_ENABLE_BENCHMARKING -//#endif - - -/// Just a bank container, used to contain owned items -extern TMany BANK; - -using uint = unsigned int; -template -using some = std::vector; - -template -struct TypePair { - using LHS = L; - using RHS = R; -}; - -/// Used to configure a map test -/// @param C - the map type we're testing -/// @param K - the tested key type -/// @param V - the tested value type -/// @param MANAGED - true to contain memory allocated by our manager -template -struct MapTest { - using Container = C; - using Key = K; - using Value = V; - static constexpr bool Managed = MANAGED; -}; - -/// Used to configure a set test -/// @param C - the map type we're testing -/// @param K - the tested key type -/// @param MANAGED - true to contain memory allocated by our manager -template -struct SetTest { - using Container = C; - using Key = K; - static constexpr bool Managed = MANAGED; -}; - -/// Type for testing hashing consistency between two containers -/// @tparam K - the left container -/// @tparam V - the right container -template -struct HashTest { - using Key = K; - using Value = V; -}; - - -/// Create a dense element, on the stack -/// @tparam T - type of element we're creating -/// @param e - the data we'll use to initialize an instance of T -/// @return the new instance of T -template -T CreateElement(const auto& e) { - T element; - if constexpr (CT::Same) - element = e; - else if constexpr (not CT::Same>) - element = Decay {e}; - else { - element = Block<> {}; - element.Insert(e); - } - - return element; -} - -/// Create a sparse element, on the heap -/// @tparam T - type of element we're creating -/// @tparam MANAGED - whether we'll have authority over the pointer or not -/// @param e - the data we'll use to initialize an instance of T -/// @return pointer to the new instance of T -template -T CreateElement(const auto& e) { - void* element; - - if constexpr (not MANAGED) { - // Create a pointer that is guaranteed to not be owned by the - // memory manager. Notice we don't use 'new' operator here, - // because it is weakly linked, and can be overriden to use our - // memory manager. - if constexpr (not CT::Same>) { - element = malloc(sizeof(Decay)); - new (element) Decay {e}; - } - else { - element = malloc(sizeof(Block<>)); - new (element) Block<> {}; - static_cast*>(element)->Insert(e); - } - } - else { - // Create a pointer owned by the memory manager - auto& container = BANK.Emplace(IndexBack); - - if constexpr (not CT::Same>) { - container << Decay {e}; - element = container.GetRaw(); - } - else { - container << e; - element = &container; - } - } - - return static_cast(element); -} - -template -void DestroyElement(auto e) { - using E = decltype(e); - if constexpr (CT::Sparse) { - if constexpr (CT::Referencable>) - e->Reference(-1); - - if constexpr (CT::Destroyable>) - e->~Decay(); - - if constexpr (not MANAGED) - free(e); - } -} - -/// Create a test pair -/// @tparam P - the pair type -/// @tparam K - the pair key type -/// @tparam V - the pair value type -/// @tparam MANAGED - whether or not we have auhtority over the data -/// @param key - the key initialization data -/// @param value - the value initialization data -/// @return the pair -template -P CreatePair(const auto& key, const auto& value) { - return P { - CreateElement(key), - CreateElement(value) - }; -} - -/// Destroy a test pair created via CreatePair -/// @tparam MANAGED - was it created by the memory manager? -/// @param pair - the pair to destroy -template -void DestroyPair(auto& pair) { - using P = Deref; - - if constexpr (not MANAGED) { - if constexpr (requires { pair.mKey; }) { - if constexpr (CT::Typed

) { - // It's a statically typed langulus pair - using K = typename P::Key; - using V = typename P::Value; - - if constexpr (CT::Sparse) { - if constexpr (CT::Referencable>) - REQUIRE(pair.mKey->Reference(-1) == 0); - if constexpr (CT::Destroyable>) - pair.mKey->~Decay(); - free(pair.mKey.Get()); - } - - if constexpr (CT::Sparse) { - if constexpr (CT::Referencable>) - REQUIRE(pair.mValue->Reference(-1) == 0); - if constexpr (CT::Destroyable>) - pair.mValue->~Decay(); - free(pair.mValue.Get()); - } - } - else { - if (pair.mKey.IsSparse()) { - if (pair.mKey.GetType()->mReference) - REQUIRE(pair.mKey.GetType()->mReference(*pair.mKey.template GetRaw(), -1) == 0); - if (pair.mKey.GetType()->mDestructor) - pair.mKey.GetType()->mDestructor(*pair.mKey.template GetRaw()); - free(*pair.mKey.template GetRaw()); - } - - if (pair.mValue.IsSparse()) { - if (pair.mValue.GetType()->mReference) - REQUIRE(pair.mValue.GetType()->mReference(*pair.mValue.template GetRaw(), -1) == 0); - if (pair.mValue.GetType()->mDestructor) - pair.mValue.GetType()->mDestructor(*pair.mValue.template GetRaw()); - free(*pair.mValue.template GetRaw()); - } - } - } - else if constexpr (requires { pair.first; }) { - // It's an std::pair - using K = decltype(pair.first); - using V = decltype(pair.second); - - if constexpr (CT::Sparse) { - if constexpr (CT::Referencable>) - REQUIRE(pair.first->Reference(-1) == 0); - if constexpr (CT::Destroyable>) - pair.first->~Decay(); - free(pair.first); - } - - if constexpr (CT::Sparse) { - if constexpr (CT::Referencable>) - REQUIRE(pair.second->Reference(-1) == 0); - if constexpr (CT::Destroyable>) - pair.second->~Decay(); - free(pair.second); - } - } - else static_assert(false, "What kind of pair is this? Are you making stuff up?"); - } - else BANK.Reset(); -} diff --git a/test/TestBytes.cpp b/test/TestBytes.cpp index 9fbdd691..5c4074b7 100644 --- a/test/TestBytes.cpp +++ b/test/TestBytes.cpp @@ -5,21 +5,18 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include -#include +#include +#include #include "Common.hpp" SCENARIO("Byte manipulation", "[bytes]") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); static Allocator::State memoryState; GIVEN("An empty byte container") { Bytes data; WHEN("Capacity is reserved, via Allocate()") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - data.Reserve(500); auto memory = data.GetRaw(); @@ -157,4 +154,10 @@ SCENARIO("Byte manipulation", "[bytes]") { } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/TestConstruct.cpp b/test/TestConstruct.cpp index f831ed31..33baec4b 100644 --- a/test/TestConstruct.cpp +++ b/test/TestConstruct.cpp @@ -5,7 +5,7 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include +#include #include "Common.hpp" @@ -25,4 +25,8 @@ SCENARIO("Constructs", "[construct]") { } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); } diff --git a/test/TestHandle.cpp b/test/TestHandle.cpp index 3930e491..de31570e 100644 --- a/test/TestHandle.cpp +++ b/test/TestHandle.cpp @@ -5,7 +5,7 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include +#include #include "Common.hpp" @@ -14,7 +14,7 @@ template TMany CreateManagedElements(FROM&&...from) { static_assert(CT::MakableFrom, Decay...>); #if LANGULUS_FEATURE(MANAGED_MEMORY) - TMany> base {DecayCast(from)...}; + TMany> base {TypedCast(from)...}; if constexpr (CT::Similar>) return base; else { @@ -425,6 +425,12 @@ TEMPLATE_TEST_CASE("Handles from sequential containers", "[handle]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } @@ -439,25 +445,24 @@ TEMPLATE_TEST_CASE("Managed handle swapping", "[handle]", RT*, RT, int, int*) { constexpr Count refs1_1 = CT::Sparse and LANGULUS_FEATURE(MANAGED_MEMORY) ? 11 : 1; constexpr Count refs2 = CT::Sparse and LANGULUS_FEATURE(MANAGED_MEMORY) ? 2 : 1; - TMany factory1 = CreateManagedElements(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); - REQUIRE(factory1.GetAllocation()->GetUses() == 1); - GIVEN("A stack-based swapper") { - TMany factory2 = CreateManagedElements(100); - REQUIRE(factory2.GetAllocation()->GetUses() == 1); + TMany factory1 = CreateManagedElements(1, 2, 3, 4, 5, 6, 7, 8, 9, 10); + REQUIRE(factory1.GetAllocation()->GetUses() == 1); - // Create a handle to an element inside factory2 - // The entry will be searched for in the memory manager - // Since we're using a local handle, the element will be reffed - HandleLocal swapper {factory2[0]}; + WHEN("Swap through all elements and insert at the end") { + TMany factory2 = CreateManagedElements(100); + REQUIRE(factory2.GetAllocation()->GetUses() == 1); - if constexpr (sparse) - REQUIRE(swapper.GetEntry()->GetUses() == refs2); - if constexpr (referenced) - REQUIRE(DenseCast(swapper.Get()).GetReferences() == 2); + // Create a handle to an element inside factory2 + // The entry will be searched for in the memory manager + // Since we're using a local handle, the element will be reffed + HandleLocal swapper {factory2[0]}; + if constexpr (sparse) + REQUIRE(swapper.GetEntry()->GetUses() == refs2); + if constexpr (referenced) + REQUIRE(DenseCast(swapper.Get()).GetReferences() == 2); - WHEN("Swap through all elements and insert at the end") { { auto h = factory1.GetHandle(0); if constexpr (LANGULUS_FEATURE(MANAGED_MEMORY)) @@ -626,26 +631,32 @@ TEMPLATE_TEST_CASE("Managed handle swapping", "[handle]", RT*, RT, int, int*) { REQUIRE(DenseCast(hi.Get()).GetReferences() == 1); } } - } - } - - REQUIRE(factory1.GetAllocation()->GetUses() == 1); - - auto start = factory1.GetHandle(0); - if constexpr (LANGULUS_FEATURE(MANAGED_MEMORY)) - REQUIRE(start.GetEntry()->GetUses() == 1); - REQUIRE(DenseCast(start.Get()) == 100); - if constexpr (referenced) - REQUIRE(DenseCast(start.Get()).GetReferences() == 1); - - for (Count i = 1; i < factory1.GetCount(); ++i) { - auto h = factory1.GetHandle(i); + } + + REQUIRE(factory1.GetAllocation()->GetUses() == 1); + + auto start = factory1.GetHandle(0); if constexpr (LANGULUS_FEATURE(MANAGED_MEMORY)) - REQUIRE(h.GetEntry()->GetUses() == refs1); - REQUIRE(DenseCast(h.Get()) == static_cast(i)); + REQUIRE(start.GetEntry()->GetUses() == 1); + REQUIRE(DenseCast(start.Get()) == 100); if constexpr (referenced) - REQUIRE(DenseCast(h.Get()).GetReferences() == 1); + REQUIRE(DenseCast(start.Get()).GetReferences() == 1); + + for (Count i = 1; i < factory1.GetCount(); ++i) { + auto h = factory1.GetHandle(i); + if constexpr (LANGULUS_FEATURE(MANAGED_MEMORY)) + REQUIRE(h.GetEntry()->GetUses() == refs1); + REQUIRE(DenseCast(h.Get()) == static_cast(i)); + if constexpr (referenced) + REQUIRE(DenseCast(h.Get()).GetReferences() == 1); + } + + REQUIRE(memoryState.Assert()); } - REQUIRE(memoryState.Assert()); + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/TestHashing.cpp b/test/TestHashing.cpp index ef0f9473..a5a23d17 100644 --- a/test/TestHashing.cpp +++ b/test/TestHashing.cpp @@ -5,11 +5,11 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "Common.hpp" @@ -34,7 +34,10 @@ SCENARIO("Hashing different kinds of containers", "[hash]") { REQUIRE(HashOf(same1) == HashBytes("Same1", 5)); } + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection BANK.Reset(); + REQUIRE_FALSE(Allocator::CollectGarbage()); } @@ -87,7 +90,10 @@ TEMPLATE_TEST_CASE( DestroyPair(pair); } + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection BANK.Reset(); + REQUIRE_FALSE(Allocator::CollectGarbage()); } @@ -131,6 +137,9 @@ TEMPLATE_TEST_CASE( DestroyElement(element); } + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection BANK.Reset(); + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/TestHive.cpp b/test/TestHive.cpp index 2763169f..2d179e95 100644 --- a/test/TestHive.cpp +++ b/test/TestHive.cpp @@ -5,9 +5,8 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include "Main.hpp" -#include -#include +#include +#include "Common.hpp" struct Producible : Referenced { @@ -22,6 +21,7 @@ struct Producible : Referenced { SCENARIO("Test hives", "[hive]") { static Allocator::State memoryState; + const Producible one {1}; const Producible two {2}; @@ -49,10 +49,45 @@ SCENARIO("Test hives", "[hive]") { REQUIRE(hive.GetFrames()[0].GetRaw()[0].mData == one); REQUIRE(hive.GetFrames()[0].GetRaw()[1].mData == two); } + + WHEN("30 elements produced") { + for (int i = 1; i <= 30; ++i) + REQUIRE(hive.New(i)); + + REQUIRE(hive.GetCount() == 30); + REQUIRE(hive.GetFrames().GetCount() == 2); + //REQUIRE(hive.GetReusable() == nullptr); + REQUIRE(hive.GetType() == MetaOf()); + + for (Count i = 0; i < hive.GetFrames()[0].GetReserved(); ++i) { + auto v = hive.GetFrames()[0].GetRaw()[i].mData; + REQUIRE(v.v == i + 1); + } + + for (Count i = hive.GetFrames()[0].GetReserved(); i < hive.GetFrames()[0].GetReserved() + hive.GetFrames()[1].GetReserved() - 1; ++i) { + auto v = hive.GetFrames()[1].GetRaw()[i - hive.GetFrames()[0].GetReserved()].mData; + REQUIRE(v.v == i + 1); + } + + THEN("Iterated using range") { + int counter = 0; + for (auto& i : hive) { + ++counter; + REQUIRE(i == counter); + } + REQUIRE(counter == 30); + } + } } const_cast(one).Reference(-1); const_cast(two).Reference(-1); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/TestIncomplete.cpp b/test/TestIncomplete.cpp index 9b88d272..61f88ba3 100644 --- a/test/TestIncomplete.cpp +++ b/test/TestIncomplete.cpp @@ -5,11 +5,11 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include -#include -#include -#include -#include +#include +#include +#include +#include +#include #include "Common.hpp" @@ -51,4 +51,10 @@ SCENARIO("Testing incomplete type hierarchy", "[incomplete]") { GIVEN("A thing instance") { Thing thing; } + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/TestIteration.cpp b/test/TestIteration.cpp index 67471172..47202071 100644 --- a/test/TestIteration.cpp +++ b/test/TestIteration.cpp @@ -5,13 +5,11 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include +#include #include "Common.hpp" SCENARIO("Iterating containers", "[iteration]") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - GIVEN("Templated Any with some POD items") { TMany dense; dense << int(1) << int(2) << int(3) << int(4) << int(5); @@ -552,4 +550,10 @@ SCENARIO("Iterating containers", "[iteration]") { REQUIRE(subpack3.GetUses() == 1); } } + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/TestNeat.cpp b/test/TestNeat.cpp index 7471c77f..14fc0701 100644 --- a/test/TestNeat.cpp +++ b/test/TestNeat.cpp @@ -5,7 +5,7 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include +#include #include "Common.hpp" @@ -228,4 +228,10 @@ SCENARIO("Data normalization", "[neat]") { } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/TestPointers.cpp b/test/TestPointers.cpp index 78cd9b40..92f40809 100644 --- a/test/TestPointers.cpp +++ b/test/TestPointers.cpp @@ -5,8 +5,8 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include -#include +#include +#include #include "Common.hpp" @@ -177,4 +177,10 @@ TEMPLATE_TEST_CASE("Shared pointer", "[Ref]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/TestText.cpp b/test/TestText.cpp index 950a0cc2..089e00a5 100644 --- a/test/TestText.cpp +++ b/test/TestText.cpp @@ -5,9 +5,9 @@ /// /// SPDX-License-Identifier: GPL-3.0-or-later /// -#include -#include -#include +#include +#include +#include #include "Common.hpp" @@ -342,6 +342,12 @@ TEMPLATE_TEST_CASE("Testing text containers", "[text]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Unsigned number stringification", "[text]", @@ -376,6 +382,12 @@ TEMPLATE_TEST_CASE("Unsigned number stringification", "[text]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Signed number stringification", "[text]", int8_t, int16_t, int32_t, int64_t) { @@ -408,13 +420,35 @@ TEMPLATE_TEST_CASE("Signed number stringification", "[text]", int8_t, int16_t, i } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Logging text containers", "[text]", Text, Path) { - TestType text {"some text"}; + static Allocator::State memoryState; + + WHEN("Logging") { + TestType text {"some text"}; + Logger::Info() << "You should see " << text; + Logger::Info("You should also see ", text); + } + + WHEN("Logging literal") { + Logger::Info() << "You should see " << "some text"_text; + Logger::Info("You should also see ", "some text"_text); + } - Logger::Info() << "You should see " << text; - Logger::Info("You should also see ", text); + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Reflected coverters to text", "[text]", /*Stringifiable,*/ StringifiableConst) { @@ -438,6 +472,12 @@ TEMPLATE_TEST_CASE("Reflected coverters to text", "[text]", /*Stringifiable,*/ S } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Text container interoperability", "[text]", @@ -480,6 +520,12 @@ TEMPLATE_TEST_CASE("Text container interoperability", "[text]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Text container conversion at runtime", "[text]", @@ -500,6 +546,12 @@ TEMPLATE_TEST_CASE("Text container conversion at runtime", "[text]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Containing literals", "[text]", @@ -550,6 +602,12 @@ TEMPLATE_TEST_CASE("Containing literals", "[text]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } void Text_CheckState_Default(const Text& text) { diff --git a/test/TestTypes.hpp b/test/TestTypes.hpp deleted file mode 100644 index 8bd3e54a..00000000 --- a/test/TestTypes.hpp +++ /dev/null @@ -1,416 +0,0 @@ -/// -/// Langulus::Anyness -/// Copyright (c) 2012 Dimo Markov -/// Part of the Langulus framework, see https://langulus.com -/// -/// SPDX-License-Identifier: GPL-3.0-or-later -/// -#pragma once -#include "Main.hpp" - - -namespace Langulus::Flow -{ - struct Verb {}; - class Construct {}; - class Constructconst {}; - class constConstructconst {}; - class constconst {}; -} - -/// An empty trivial type -class ImplicitlyConstructible {}; - -/// A simple aggregate type -struct AggregateType { - int m1, m2, m3, m4; - bool m5; -}; - -/// Explicitly deleted destructor -class NonDestructible { - ~NonDestructible() = delete; -}; - -/// Has an explicit destructor -class Destructible { -public: - char* someptr {}; - - ~Destructible() { - if (someptr) - delete someptr; - } -}; - -/// Default-constructible, but only privately -class PrivatelyConstructible { - LANGULUS(POD) false; -private: - PrivatelyConstructible() = default; - PrivatelyConstructible(const PrivatelyConstructible&) = default; - PrivatelyConstructible(PrivatelyConstructible&&) = default; -}; - -/// Has no explicit intent constructors and assigners -/// Has only implicit refer & move constructors and assigners -class NonIntentConstructible { - LANGULUS(POD) false; -public: - NonIntentConstructible(CT::NoIntent auto&&) {} -}; - -/// Has explicit copy, move, refer, clone, abandon, disown constructors -/// Has implicit refer & move constructors, too -/// Has no explicit intent assigners, only implicit refer & move -class PartiallyIntentConstructible { -public: - template class S, class T> - PartiallyIntentConstructible(S&&) requires CT::Intent> {} -}; - -/// Has all intent constructors + implicit refer & move ones -/// Has no explicit intent assigners, only implicit refer & move ones -/// Making constructor explicit makes sure, that no implicit intent assign -/// happens -class AllIntentConstructible { -public: - LANGULUS(POD) false; - explicit AllIntentConstructible(CT::Intent auto&&) {} -}; - -/// Has all intent constructors + implicit refer & move ones -/// Has no explicit intent assigners, only implicit refer & move ones -/// Making constructor implicit also allows for intent assignments -class AllIntentConstructibleImplicit { -public: - LANGULUS(POD) false; - AllIntentConstructibleImplicit(CT::Intent auto&&) {} -}; - -/// Has all intnet constructors and assigners + implicit refer & move ones -class AllIntentConstructibleAndAssignable { -public: - LANGULUS(POD) false; - AllIntentConstructibleAndAssignable(CT::Intent auto&&) {} - AllIntentConstructibleAndAssignable& operator = (CT::Intent auto&&) { return *this; } -}; - -/// Has explicit descriptor constructor, and implicit refer & move ones -/// Has no explicit intent assigners, only implicit refer & move -class DescriptorConstructible { -public: - DescriptorConstructible(Describe) {} -}; - - -enum class Pi { - Number = 314 -}; - -struct IncompleteType; - -namespace One::Two::Three { - struct TypeDeepIntoNamespaces; - - template - struct TemplatedTypeDeepIntoNamespaces { - enum VeryDeeplyTemplatedEnum { YesYouGotThatRight }; - - template - struct Nested; - }; - - template - struct VeryComplexTemplate; -} - -namespace Verbs -{ - - /// - /// A testing verb, similar to the ones used in Langulus::Flow - /// - struct Create : public Flow::Verb { - LANGULUS(POSITIVE_VERB) "Create"; - LANGULUS(NEGATIVE_VERB) "Destroy"; - LANGULUS(POSITIVE_OPERATOR) " + "; - LANGULUS(NEGATIVE_OPERATOR) " - "; - LANGULUS(PRECEDENCE) 5; - LANGULUS(INFO) - "Used for allocating new elements. " - "If the type you're creating has a producer, " - "you need to execute the verb in a matching producer, " - "or that producer will be created automatically for you, if possible"; - - /// Check if the verb is available in a type, and with given arguments - /// @return true if verb is available in T with arguments A... - template - static constexpr bool AvailableFor() noexcept { - if constexpr (sizeof...(A) == 0) - return requires (T & t, Verb & v) { t.Create(v); }; - else - return requires (T & t, Verb & v, A... a) { t.Create(v, a...); }; - } - - /// Get the verb functor for the given type and arguments - /// @return the function, or nullptr if not available - template - static constexpr auto Of() noexcept { - if constexpr (!Create::AvailableFor()) { - return nullptr; - } - else if constexpr (CT::Constant) { - return [](const void* context, Flow::Verb& verb, A... args) { - auto typedContext = static_cast(context); - typedContext->Create(verb, args...); - }; - } - else { - return [](void* context, Flow::Verb& verb, A... args) { - auto typedContext = static_cast(context); - typedContext->Create(verb, args...); - }; - } - } - - template - static bool ExecuteIn(T&, Verb&); - - static bool ExecuteDefault(const Anyness::Block<>&, Verb&) { - return true; - } - - static bool ExecuteDefault(Anyness::Block<>&, Verb&) { - return false; - } - - static bool ExecuteStateless(Verb&) { - return false; - } - }; - -} - -struct ImplicitlyReflectedData { - LANGULUS(POD) true; - LANGULUS(FILES) "ASE"; - - enum Named {One, Two, Three}; - LANGULUS_NAMED_VALUES(One, Two, Three); - LANGULUS(TYPED) Named; - - Named v = One; - - inline bool operator == (const ImplicitlyReflectedData&) const noexcept = default; -}; - -class alignas(128) ImplicitlyReflectedDataWithTraits : public ImplicitlyReflectedData { -public: - int member {664}; - RTTI::Tag anotherMember {}; - int anotherMemberArray [12] {}; - int* sparseMember {}; - - inline operator int() const noexcept { - return member; - } - - void Create(Flow::Verb&) const { - //++member; - } - - void Create(Flow::Verb&) { - ++member; - } - - ImplicitlyReflectedDataWithTraits() = default; - explicit ImplicitlyReflectedDataWithTraits(Pi) - : member {314} {} - - LANGULUS(NAME) "MyType"; - LANGULUS(INFO) "Info about MyType"; - LANGULUS(FILES) "txt, pdf"; - LANGULUS(VERSION_MAJOR) 2; - LANGULUS(VERSION_MINOR) 1; - LANGULUS(DEEP) true; - LANGULUS(POD) true; - LANGULUS(NULLIFIABLE) true; - LANGULUS(POOL_TACTIC) RTTI::PoolTactic::Size; - LANGULUS(CONCRETE) ImplicitlyReflectedData; - LANGULUS(ACT_AS) void; - LANGULUS(ALLOCATION_PAGE) 250; - LANGULUS(ABSTRACT) true; - LANGULUS_BASES(ImplicitlyReflectedData); - LANGULUS_VERBS(Verbs::Create); - LANGULUS_CONVERTS_TO(int); - LANGULUS_CONVERTS_FROM(Pi); - LANGULUS_NAMED_VALUES(); - - using Self = ImplicitlyReflectedDataWithTraits; - LANGULUS_MEMBERS( - &Self::member, - &Self::anotherMember, - &Self::anotherMemberArray, - &Self::sparseMember - ); -}; - -/// Doesn't have implicit copy/move, so it is abandon-makable by explicit move -/// but not abandon-assignable -class alignas(128) Complex { -public: - int member; - bool anotherMember {}; - int anotherMemberArray [12] {}; - int* sparseMember {}; - - LANGULUS(NAME) "ComplexType"; - LANGULUS(INFO) "Info about ComplexType"; - LANGULUS(VERSION_MAJOR) 2; - LANGULUS(VERSION_MINOR) 1; - LANGULUS(POOL_TACTIC) RTTI::PoolTactic::Size; - LANGULUS(ALLOCATION_PAGE) 250; - - using Self = Complex; - LANGULUS_MEMBERS( - &Self::member, - &Self::anotherMember, - &Self::anotherMemberArray, - &Self::sparseMember - ); - - Complex(const Complex& s) - : member(s.member) {} - Complex(Complex&& s) - : member(s.member) {} - Complex(int stuff) - : member(stuff) {} - - ~Complex() { - if (sparseMember) - delete sparseMember; - } -}; - -struct AnotherTypeWithSimilarilyNamedValues { - enum Named {One = 501, Two, Three}; - LANGULUS_NAMED_VALUES(One, Two, Three); - LANGULUS(NAME) "YetAnotherNamedType"; - - int v = One; - - inline bool operator == (const AnotherTypeWithSimilarilyNamedValues&) const noexcept = default; -}; - -struct CheckingWhatGetsInherited : ImplicitlyReflectedDataWithTraits { - LANGULUS(NAME) "CheckingWhatGetsInherited"; - - using ImplicitlyReflectedDataWithTraits::ImplicitlyReflectedDataWithTraits; -}; - -class ContainsComplex { - Complex mData; -}; - -/// A complex aggregate type -struct AggregateTypeComplex { - int m1, m2, m3, m4; - bool m5; - Complex mData; -}; - -/// A complex aggregate type -struct AggregateThatCanBeConfusedWithDescriptorMakable { - DescriptorConstructible mConfusable; - int m1, m2, m3, m4; -}; - -class ForcefullyPod { - LANGULUS(POD) true; - Complex mData; -}; - -struct Type {}; - -struct TypeErasedContainer { - LANGULUS(TYPED) void; -}; - -namespace N1 { - struct Type {}; - struct Create {}; -} - -namespace N2 { - struct Type {}; -} - -namespace N3 { - struct type {}; -} - -enum class TypedEnum : int16_t { - E1, E2, E3 -}; - -/// Simple type for testing Referenced types -struct RT : Referenced { - int data; - const char* t; - bool destroyed = false; - bool copied_in = false; - bool cloned_in = false; - bool moved_in = false; - bool moved_out = false; - - RT() - : data {0}, t {nullptr} {} - - RT(int a) - : data {a}, t {nullptr} {} - - RT(const char* tt) - : data(0), t {tt} {} - - RT(const RT& rhs) - : data(rhs.data), t {rhs.t}, copied_in {true} {} - - RT(RT&& rhs) - : data(rhs.data), t {rhs.t}, moved_in {true} { - rhs.moved_in = false; - rhs.moved_out = true; - } - - RT(Cloned&& rhs) - : data(rhs->data), t {rhs->t}, cloned_in {true} { - } - - ~RT() { - destroyed = true; - } - - RT& operator = (const RT& rhs) { - data = rhs.data; - t = rhs.t; - copied_in = true; - moved_in = moved_out = false; - return *this; - } - - RT& operator = (RT&& rhs) { - data = rhs.data; - t = rhs.t; - copied_in = false; - moved_in = true; - moved_out = false; - rhs.copied_in = false; - rhs.moved_in = false; - rhs.moved_out = true; - return *this; - } - - operator const int& () const noexcept { - return data; - } -}; \ No newline at end of file diff --git a/test/many/TestManyCommon.hpp b/test/many/TestManyCommon.hpp index 523c1d47..a0d09597 100644 --- a/test/many/TestManyCommon.hpp +++ b/test/many/TestManyCommon.hpp @@ -8,9 +8,9 @@ /// INTENTIONALLY NOT GUARDED /// Include this file once in each cpp file, after all other headers -#include -#include -#include +#include +#include +#include #include "../Common.hpp" @@ -235,9 +235,10 @@ void Any_CheckState_Abandoned(const auto& any) { } -void Any_CheckState_ContainsOne(const auto& pack, const auto& e, UNUSED() Allocation* entry = nullptr) { +void Any_CheckState_ContainsOne(const auto& pack, const auto& e, Allocation* entry = nullptr) { using T = Deref; using E = Deref; + (void) entry; REQUIRE(pack.GetCount() == 1); REQUIRE(pack.GetUses() == 1); @@ -264,9 +265,10 @@ void Any_CheckState_ContainsOne(const auto& pack, const auto& e, UNUSED() Alloca } } -void Any_CheckState_ContainsN(Count n, const auto& pack, const CT::Sparse auto& e, UNUSED() Allocation* entry = nullptr) { +void Any_CheckState_ContainsN(Count n, const auto& pack, const CT::Sparse auto& e, Allocation* entry = nullptr) { using T = Deref; using E = Deref; + (void)entry; REQUIRE(pack.GetCount() == n); REQUIRE(pack.GetUses() == 1); @@ -289,9 +291,10 @@ void Any_CheckState_ContainsN(Count n, const auto& pack, const CT::Sparse auto& } } -void Any_CheckState_ContainsArray(const auto& pack, const CT::Array auto& e, UNUSED() Allocation* entry = nullptr) { +void Any_CheckState_ContainsArray(const auto& pack, const CT::Array auto& e, Allocation* entry = nullptr) { using T = Deref; using E = Deext; + (void)entry; constexpr int n = ExtentOf; REQUIRE(pack.GetCount() == n); diff --git a/test/many/TestManyConversion.cpp b/test/many/TestManyConversion.cpp index 78a44e4f..f597712b 100644 --- a/test/many/TestManyConversion.cpp +++ b/test/many/TestManyConversion.cpp @@ -34,4 +34,10 @@ TEMPLATE_TEST_CASE("Converting to text", "[many]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/many/TestManyCornerCases.cpp b/test/many/TestManyCornerCases.cpp index c08d731d..6844024a 100644 --- a/test/many/TestManyCornerCases.cpp +++ b/test/many/TestManyCornerCases.cpp @@ -9,8 +9,6 @@ SCENARIO("Pushing one sparse container, and then two more, one being the first", "[many]") { - BANK.Reset(); - static Allocator::State memoryState; auto p1 = CreateElement(1); @@ -136,4 +134,10 @@ SCENARIO("Pushing one sparse container, and then two more, one being the first", #endif REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/many/TestManyDeep.cpp b/test/many/TestManyDeep.cpp index c40cf432..825335d8 100644 --- a/test/many/TestManyDeep.cpp +++ b/test/many/TestManyDeep.cpp @@ -8,12 +8,8 @@ #include "TestManyCommon.hpp" -TEMPLATE_TEST_CASE("Deep sequential containers 1", "[any]", int, RT, int*, RT*) { - BANK.Reset(); - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - +TEMPLATE_TEST_CASE("Deep sequential containers 1", "[any]", RT*, int, RT, int*) { static Allocator::State memoryState; - static_assert(sizeof(A::Block) == sizeof(Block<>)); using E = TestType; @@ -30,7 +26,6 @@ TEMPLATE_TEST_CASE("Deep sequential containers 1", "[any]", int, RT, int*, RT*) CreateElement(10) }; - GIVEN("Any with some deep items") { Many pack; Many subpack1; @@ -469,14 +464,19 @@ TEMPLATE_TEST_CASE("Deep sequential containers 1", "[any]", int, RT, int*, RT*) } } - BANK.Reset(); + for (auto& i : darray) + DestroyElement(i); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } TEMPLATE_TEST_CASE("Deep sequential containers 2", "[any]", int, RT, int*, RT*) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; static_assert(sizeof(A::Block) == sizeof(Block<>)); using E = TestType; @@ -494,7 +494,6 @@ TEMPLATE_TEST_CASE("Deep sequential containers 2", "[any]", int, RT, int*, RT*) CreateElement(10) }; - GIVEN("Any with some deep items, and their Blocks coalesced") { Many pack; Many subpack1; @@ -543,9 +542,16 @@ TEMPLATE_TEST_CASE("Deep sequential containers 2", "[any]", int, RT, int*, RT*) } } - BANK.Reset(); + for (auto& i : darray) + DestroyElement(i); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } SCENARIO("Test BlockCast", "[block]") { diff --git a/test/many/TestManyDense.cpp b/test/many/TestManyDense.cpp index e7b13535..579d0d9a 100644 --- a/test/many/TestManyDense.cpp +++ b/test/many/TestManyDense.cpp @@ -28,11 +28,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", using T = typename TestType::LHS; using E = typename TestType::RHS; - using DenseE = Decay; - E element = CreateElement(555); - const DenseE& denseValue {DenseCast(element)}; - const DenseE* const sparseValue {SparseCast(element)}; + const E element = CreateElement(555); const E darray1[5] { CreateElement(1), @@ -75,7 +72,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -83,7 +79,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -91,7 +86,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -105,8 +99,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -124,7 +118,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -132,7 +125,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {value}; @@ -140,7 +132,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -159,8 +150,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -179,7 +170,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -187,7 +177,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -195,7 +184,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -210,8 +198,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -229,7 +217,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = Disown(value); @@ -237,7 +224,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {value}; @@ -245,7 +231,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -264,8 +249,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -283,7 +268,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = Abandon(value); @@ -291,7 +275,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -299,7 +282,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -315,7 +297,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -323,7 +304,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -331,7 +311,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -916,7 +895,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](const int&) {FAIL();}, [&](const Trait&) {FAIL();}, - [&](const Many&) {FAIL();} + [&](const Many&) {FAIL();} ); REQUIRE(0 == foreachit); @@ -926,7 +905,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](int&) {FAIL(); }, [&](Trait&) {FAIL(); }, - [&](Many&) {FAIL(); } + [&](Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -936,7 +915,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -946,7 +925,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](int*) {FAIL(); }, [&](Trait*) {FAIL(); }, - [&](Many*) {FAIL(); } + [&](Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -956,7 +935,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEachRev( [&](const int&) {FAIL(); }, [&](const Trait&) {FAIL(); }, - [&](const Many&) {FAIL(); } + [&](const Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -966,7 +945,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = pack.ForEachRev( [&](const int&) {FAIL(); }, [&](const Trait&) {FAIL(); }, - [&](const Many&) {FAIL(); } + [&](const Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -976,7 +955,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEachRev( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -986,7 +965,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", const auto foreachit = pack.ForEachRev( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -1006,8 +985,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 2); } else if constexpr (CT::Same) { @@ -1023,7 +1002,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(source); @@ -1031,7 +1009,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); StdT source {1, 555}; some> storage(meter.runs()); meter.measure([&](int i) { @@ -1040,7 +1017,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); std::any source {555}; some> storage(meter.runs()); meter.measure([&](int i) { @@ -1055,8 +1031,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1071,7 +1047,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1079,7 +1054,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, value); @@ -1087,7 +1061,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1100,8 +1073,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1119,7 +1092,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1127,7 +1099,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {value}; @@ -1135,7 +1106,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1153,8 +1123,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1171,7 +1141,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1179,7 +1148,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -1187,7 +1155,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1201,8 +1168,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1219,7 +1186,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = Disown(value); @@ -1227,7 +1193,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {value}; @@ -1235,7 +1200,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1253,8 +1217,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1271,7 +1235,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = Abandon(value); @@ -1279,7 +1242,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -1287,7 +1249,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1303,7 +1264,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1311,7 +1271,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1319,7 +1278,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1342,7 +1300,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1350,7 +1307,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1358,7 +1314,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1377,8 +1332,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1388,16 +1343,16 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", REQUIRE(pack.GetAllocation() == element.GetAllocation()); } else { - REQUIRE(pack.template As().GetRaw() == sparseValue->GetRaw()); + REQUIRE(pack.template As().GetRaw() == element.GetRaw()); if constexpr (CT::Typed) REQUIRE(pack.template IsExact>()); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); - REQUIRE_FALSE(pack.template As().IsStatic()); - REQUIRE_FALSE(pack.template As().IsConstant()); - REQUIRE(pack.template As().GetAllocation()); - REQUIRE(pack.template As().GetUses() == 2); - REQUIRE(pack.template As() == element); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); + REQUIRE_FALSE(pack.template As().IsStatic()); + REQUIRE_FALSE(pack.template As().IsConstant()); + REQUIRE(pack.template As().GetAllocation()); + REQUIRE(pack.template As().GetUses() == 2); + REQUIRE(pack.template As() == element); //REQUIRE(pack != element); REQUIRE(pack == element); REQUIRE(pack.GetUses() == 1); @@ -1414,7 +1369,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1422,7 +1376,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, ::std::move(value)); @@ -1430,7 +1383,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1444,8 +1396,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1455,16 +1407,16 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", REQUIRE_FALSE(pack.GetAllocation()); } else { - REQUIRE(pack.template As().GetRaw() == sparseValue->GetRaw()); + REQUIRE(pack.template As().GetRaw() == element.GetRaw()); if constexpr (CT::Typed) REQUIRE(pack.template IsExact>()); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); - REQUIRE(pack.template As().IsStatic()); - REQUIRE_FALSE(pack.template As().IsConstant()); - REQUIRE_FALSE(pack.template As().GetAllocation()); - REQUIRE(pack.template As().GetUses() == 0); - REQUIRE(pack.template As() == element); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); + REQUIRE(pack.template As().IsStatic()); + REQUIRE_FALSE(pack.template As().IsConstant()); + REQUIRE_FALSE(pack.template As().GetAllocation()); + REQUIRE(pack.template As().GetUses() == 0); + REQUIRE(pack.template As() == element); REQUIRE(pack == element); //REQUIRE(pack != element); REQUIRE(pack.GetUses() == 1); @@ -1481,7 +1433,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(Disowned(value)); @@ -1489,7 +1440,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, value); @@ -1497,7 +1447,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1515,8 +1464,8 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Flat) { Any_CheckState_OwnedFull(pack); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); REQUIRE(pack.GetUses() == 1); } else if constexpr (CT::Same) { @@ -1527,16 +1476,16 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", REQUIRE(pack.GetAllocation() == element.GetAllocation()); } else { - REQUIRE(pack.template As().GetRaw() == sparseValue->GetRaw()); + REQUIRE(pack.template As().GetRaw() == element.GetRaw()); if constexpr (CT::Typed) REQUIRE(pack.template IsExact>()); - REQUIRE(pack.template As() == denseValue); - REQUIRE(*pack.template As() == denseValue); - REQUIRE_FALSE(pack.template As().IsStatic()); - REQUIRE_FALSE(pack.template As().IsConstant()); - REQUIRE(pack.template As().GetAllocation()); - REQUIRE(pack.template As().GetUses() == 2); - REQUIRE(pack.template As() == element); + REQUIRE(pack.template As() == element); + REQUIRE(*pack.template As() == element); + REQUIRE_FALSE(pack.template As().IsStatic()); + REQUIRE_FALSE(pack.template As().IsConstant()); + REQUIRE(pack.template As().GetAllocation()); + REQUIRE(pack.template As().GetUses() == 2); + REQUIRE(pack.template As() == element); //REQUIRE(pack != element); REQUIRE(pack == element); REQUIRE(pack.GetUses() == 1); @@ -1553,7 +1502,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(Abandon(value)); @@ -1561,7 +1509,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, ::std::move(value)); @@ -1569,7 +1516,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1592,13 +1538,13 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", GIVEN("Container constructed by static list of somewhat different shallow-copied elements") { if constexpr (CT::Untyped) { - const T pack {denseValue, sparseValue}; + const T pack {element, &element}; Any_CheckState_OwnedFull(pack); REQUIRE(pack.GetCount() == 2); REQUIRE(pack.GetReserved() >= 2); - REQUIRE(pack[0] == Many {denseValue}); - REQUIRE(pack[1] == Many {sparseValue}); + REQUIRE(pack[0] == Many {element}); + REQUIRE(pack[1] == Many {&element}); } } @@ -2264,7 +2210,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", if constexpr (CT::Same) { // Works only if E doesn't move entries around WHEN("Pack is reset, then immediately allocated again") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); pack.Reset(); pack << CreateElement(6) << CreateElement(7) @@ -2545,7 +2490,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", ++it; }, [&](const Many& i) { - const auto temp = CreateElement(it + 1); + const auto temp = CreateElement(it + 1); REQUIRE(i == static_cast(temp)); ++it; } @@ -2570,7 +2515,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", ++it; }, [&](const Many& i) { - const auto temp = CreateElement(it + 1); + const auto temp = CreateElement(it + 1); REQUIRE(i == static_cast(temp)); ++it; } @@ -2596,7 +2541,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", ++it; }, [&](const Many& i) { - const auto temp = CreateElement(5 - it); + const auto temp = CreateElement(5 - it); REQUIRE(i == static_cast(temp)); ++it; } @@ -2622,7 +2567,7 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", ++it; }, [&](const Many& i) { - const auto temp = CreateElement(5 - it); + const auto temp = CreateElement(5 - it); REQUIRE(i == static_cast(temp)); ++it; } @@ -2638,8 +2583,6 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", } GIVEN("Two containers with some items") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - T pack1 {darray1[0], darray1[1], darray1[2], darray1[3], darray1[4]}; T pack2 {darray2[0], darray2[1], darray2[2], darray2[3], darray2[4]}; const T memory1 = pack1; @@ -2760,5 +2703,19 @@ TEMPLATE_TEST_CASE("Dense Many/TMany", "[many]", } } + if constexpr (requires(E e) { e.Reset(); }) { + const_cast(element).Reset(); + for (auto& i : darray1) + const_cast(i).Reset(); + for (auto& i : darray2) + const_cast(i).Reset(); + } + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/many/TestManySparse.cpp b/test/many/TestManySparse.cpp index 61ad48c7..0ae93cc4 100644 --- a/test/many/TestManySparse.cpp +++ b/test/many/TestManySparse.cpp @@ -83,7 +83,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -91,7 +90,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -99,7 +97,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::default construction") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(); @@ -115,7 +112,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -123,7 +119,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {value}; @@ -131,7 +126,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -163,7 +157,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -171,7 +164,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -179,7 +171,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -204,7 +195,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = Disown(value); @@ -212,7 +202,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {value}; @@ -220,7 +209,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; @@ -248,27 +236,24 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single cloned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = Clone(value); - }); + }); }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {value}; - }); + }); }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = value; - }); + }); }; #endif } @@ -283,7 +268,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = Abandon(value); @@ -291,7 +275,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -299,7 +282,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -315,7 +297,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -323,7 +304,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -331,7 +311,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs()); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -592,13 +571,13 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto i666backup = i666; if constexpr (CT::Typed) { - auto& instance = pack.Emplace(IndexFront, ::std::move(i666)); + auto instance = pack.Emplace(IndexFront, ::std::move(i666)); Any_CheckState_OwnedFull(pack); REQUIRE(pack.GetCount() == 1); REQUIRE(pack.GetReserved() >= 1); REQUIRE(pack[0] == i666backup); - REQUIRE(&pack[0] == &instance); + REQUIRE(pack[0] == instance); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TMany::Emplace(single move at the front)") (timer meter) { @@ -635,13 +614,13 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto i666backup = i666; if constexpr (CT::Typed) { - auto& instance = pack.Emplace(IndexBack, ::std::move(i666)); + auto instance = pack.Emplace(IndexBack, ::std::move(i666)); Any_CheckState_OwnedFull(pack); REQUIRE(pack.GetCount() == 1); REQUIRE(pack.GetReserved() >= 1); REQUIRE(pack[0] == i666backup); - REQUIRE(&pack[0] == &instance); + REQUIRE(pack[0] == instance); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TMany::Emplace(single move at the back)") (timer meter) { @@ -900,7 +879,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](const int&) {FAIL();}, [&](const Trait&) {FAIL();}, - [&](const Many&) {FAIL();} + [&](const Many&) {FAIL();} ); REQUIRE(0 == foreachit); @@ -910,7 +889,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](int&) {FAIL(); }, [&](Trait&) {FAIL(); }, - [&](Many&) {FAIL(); } + [&](Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -920,7 +899,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -930,7 +909,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEach( [&](int*) {FAIL(); }, [&](Trait*) {FAIL(); }, - [&](Many*) {FAIL(); } + [&](Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -940,7 +919,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEachRev( [&](const int&) {FAIL(); }, [&](const Trait&) {FAIL(); }, - [&](const Many&) {FAIL(); } + [&](const Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -950,7 +929,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = pack.ForEachRev( [&](const int&) {FAIL(); }, [&](const Trait&) {FAIL(); }, - [&](const Many&) {FAIL(); } + [&](const Many&) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -960,7 +939,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = const_cast(pack).ForEachRev( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -970,7 +949,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", const auto foreachit = pack.ForEachRev( [&](const int*) {FAIL(); }, [&](const Trait*) {FAIL(); }, - [&](const Many*) {FAIL(); } + [&](const Many*) {FAIL(); } ); REQUIRE(0 == foreachit); @@ -996,7 +975,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(source); @@ -1004,7 +982,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); StdT source {1, 555}; some> storage(meter.runs()); meter.measure([&](int i) { @@ -1013,7 +990,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single container copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); std::any source {555}; some> storage(meter.runs()); meter.measure([&](int i) { @@ -1042,7 +1018,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1050,7 +1025,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, value); @@ -1058,7 +1032,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1084,7 +1057,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1092,7 +1064,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {value}; @@ -1100,7 +1071,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1128,7 +1098,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1136,7 +1105,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -1144,7 +1112,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1171,7 +1138,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = Disown(value); @@ -1179,7 +1145,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {value}; @@ -1187,7 +1152,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = value; @@ -1215,7 +1179,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = Abandon(value); @@ -1223,7 +1186,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = {::std::move(value)}; @@ -1231,7 +1193,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = ::std::move(value); @@ -1247,7 +1208,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1255,7 +1215,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1263,7 +1222,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1281,7 +1239,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1289,7 +1246,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1297,7 +1253,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::operator = (self)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some storage(meter.runs(), element); meter.measure([&](int i) { return storage[i] = storage[i]; @@ -1333,7 +1288,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1341,7 +1295,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, ::std::move(value)); @@ -1349,7 +1302,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1380,7 +1332,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single disowned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(Disowned(value)); @@ -1388,7 +1339,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, value); @@ -1396,7 +1346,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value copy)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(value); @@ -1430,7 +1379,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("construction (single abandoned value)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(Abandon(value)); @@ -1438,7 +1386,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::vector::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(1, ::std::move(value)); @@ -1446,7 +1393,6 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", }; BENCHMARK_ADVANCED("std::any::construction (single value move)") (timer meter) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); some> storage(meter.runs()); meter.measure([&](int i) { return storage[i].construct(::std::move(value)); @@ -1926,7 +1872,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", WHEN("Emplace item at a specific place") { auto i666 = CreateElement(666); const auto i666backup = i666; - decltype(auto) instance = pack.Emplace(3, ::std::move(i666)); + auto instance = pack.Emplace(3, ::std::move(i666)); REQUIRE(pack.GetCount() == 6); REQUIRE(pack.GetReserved() >= 6); @@ -1942,7 +1888,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", REQUIRE(pack[5] == darray1[4]); if constexpr (CT::Typed) - REQUIRE(&pack[3] == &instance); + REQUIRE(pack[3] == instance); else { REQUIRE(pack[3].GetRaw() == instance.GetRaw()); REQUIRE(pack[3].GetCount() == 1); @@ -1976,7 +1922,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", WHEN("Emplace item at the front") { auto i666 = CreateElement(666); const auto i666backup = i666; - decltype(auto) instance = pack.Emplace(IndexFront, ::std::move(i666)); + auto instance = pack.Emplace(IndexFront, ::std::move(i666)); REQUIRE(pack.GetCount() == 6); REQUIRE(pack.GetReserved() >= 6); @@ -1992,7 +1938,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", REQUIRE(pack[5] == darray1[4]); if constexpr (CT::Typed) - REQUIRE(&pack[0] == &instance); + REQUIRE(pack[0] == instance); else { REQUIRE(pack[0].GetRaw() == instance.GetRaw()); REQUIRE(pack[0].GetCount() == 1); @@ -2026,7 +1972,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", WHEN("Emplace item at the back") { auto i666 = CreateElement(666); const auto i666backup = i666; - decltype(auto) instance = pack.Emplace(IndexBack, ::std::move(i666)); + auto instance = pack.Emplace(IndexBack, ::std::move(i666)); REQUIRE(pack.GetCount() == 6); REQUIRE(pack.GetReserved() >= 6); @@ -2042,7 +1988,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", REQUIRE(pack[5] == i666backup); if constexpr (CT::Typed) - REQUIRE(&pack[5] == &instance); + REQUIRE(pack[5] == instance); else { REQUIRE(pack[5].GetRaw() == instance.GetRaw()); REQUIRE(pack[5].GetCount() == 1); @@ -2169,7 +2115,7 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", if constexpr (CT::Same) { // Works only if E doesn't move entries around WHEN("Pack is reset, then immediately allocated again") { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); + (void) Allocator::CollectGarbage(); pack.Reset(); pack << darray2; REQUIRE(pack.GetRaw() == memory); @@ -2807,4 +2753,10 @@ TEMPLATE_TEST_CASE("Sparse Many/TMany", "[many]", } REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/map/TestMapCommon.hpp b/test/map/TestMapCommon.hpp index 9d754719..13c6d1e0 100644 --- a/test/map/TestMapCommon.hpp +++ b/test/map/TestMapCommon.hpp @@ -8,10 +8,10 @@ /// INTENTIONALLY NOT GUARDED /// Include this file once in each cpp file, after all other headers -#include -#include -#include -#include +#include +#include +#include +#include #include #include "../Common.hpp" diff --git a/test/map/TestMapCornerCases.cpp b/test/map/TestMapCornerCases.cpp index 06e7cb4b..a9dd4fe3 100644 --- a/test/map/TestMapCornerCases.cpp +++ b/test/map/TestMapCornerCases.cpp @@ -95,4 +95,10 @@ TEMPLATE_TEST_CASE("Map corner cases", "[map]", REQUIRE (map[MetaOf()] == "Cursor"); } } + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/map/TestMapDense.cpp b/test/map/TestMapDense.cpp index 7cce0496..2747022b 100644 --- a/test/map/TestMapDense.cpp +++ b/test/map/TestMapDense.cpp @@ -34,8 +34,6 @@ TEMPLATE_TEST_CASE( (MapTest), (MapTest) ) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; using T = typename TestType::Container; @@ -64,7 +62,7 @@ TEMPLATE_TEST_CASE( } const auto pair = CreatePair("five hundred", 555); - UNUSED() const auto stdpair = CreatePair("five hundred", 555); + [[maybe_unused]] const auto stdpair = CreatePair("five hundred", 555); const Pair darray1[5] { CreatePair("one", 1), @@ -81,14 +79,14 @@ TEMPLATE_TEST_CASE( CreatePair("ten", 10) }; - UNUSED() const StdPair darray1std[5] { + [[maybe_unused]] const StdPair darray1std[5] { CreatePair("one", 1), CreatePair("two", 2), CreatePair("three", 3), CreatePair("four", 4), CreatePair("five", 5) }; - UNUSED() const StdPair darray2std[5] { + [[maybe_unused]] const StdPair darray2std[5] { CreatePair("six", 6), CreatePair("seven", 7), CreatePair("eight", 8), @@ -128,9 +126,9 @@ TEMPLATE_TEST_CASE( REQUIRE(movablePair != pair); REQUIRE(map.GetCount() == 1); - REQUIRE(map[pair.mKey] == pair.mValue); - REQUIRE(map["five hundred"] == pair.mValue); - REQUIRE_THROWS(map["missing"] != pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); + REQUIRE(map["five hundred"] == pair.GetValue()); + REQUIRE_THROWS(map["missing"] != pair.GetValue()); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TUnorderedMap::operator = (single pair copy)") (timer meter) { @@ -164,9 +162,9 @@ TEMPLATE_TEST_CASE( Map_CheckState_OwnedFull(map); REQUIRE(map.GetCount() == 1); - REQUIRE(map[pair.mKey] == pair.mValue); - REQUIRE(map["five hundred"] == pair.mValue); - REQUIRE_THROWS(map["missing"] != pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); + REQUIRE(map["five hundred"] == pair.GetValue()); + REQUIRE_THROWS(map["missing"] != pair.GetValue()); } GIVEN("A pair array copy-initialized map instance") { @@ -176,7 +174,7 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetCount() == 5); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetReserved() >= 5); } @@ -199,40 +197,49 @@ TEMPLATE_TEST_CASE( REQUIRE_FALSE(map.template IsValue()); REQUIRE_FALSE(map.template IsValue()); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetReserved() >= 5); WHEN("Shallow-copy more of the same stuff") { for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[0]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[1]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[2]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); + + /*Logger::SpecialTab("Map before: "); + for (auto p : map) + Logger::Append(p.mKey.As(), ", ");*/ map << darray2[3]; + + /*Logger::SpecialTab("Map after: "); + for (auto p : map) + Logger::Append(p.mKey.As(), ", ");*/ + for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[4]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); Map_CheckState_OwnedFull(map); REQUIRE(map.GetCount() == 10); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); for (auto& comparer : darray2) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); #if LANGULUS_FEATURE(MANAGED_MEMORY) REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); @@ -323,9 +330,9 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetCount() == 10); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); for (auto& comparer : darray2) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); #if LANGULUS_FEATURE(MANAGED_MEMORY) REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); @@ -359,8 +366,8 @@ TEMPLATE_TEST_CASE( } WHEN("Removing elements by value") { - const auto removed2 = map.RemoveValue(darray1[1].mValue); - const auto removed4 = map.RemoveValue(darray1[3].mValue); + const auto removed2 = map.RemoveValue(darray1[1].GetValue()); + const auto removed4 = map.RemoveValue(darray1[3].GetValue()); Map_CheckState_OwnedFull(map); @@ -371,17 +378,17 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TUnorderedMap::RemoveValue") (timer meter) { @@ -421,8 +428,8 @@ TEMPLATE_TEST_CASE( for (int iii = 0; iii < 10; ++iii) { WHEN(std::string("Removing elements by key #") + std::to_string(iii)) { - const auto removed2 = map.RemoveKey(darray1[1].mKey); - const auto removed4 = map.RemoveKey(darray1[3].mKey); + const auto removed2 = map.RemoveKey(darray1[1].GetKey()); + const auto removed4 = map.RemoveKey(darray1[3].GetKey()); Map_CheckState_OwnedFull(map); @@ -433,17 +440,17 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TUnorderedMap::RemoveKey") (timer meter) { @@ -475,55 +482,55 @@ TEMPLATE_TEST_CASE( } WHEN("Removing non-available elements by value") { - const auto removed9 = map.RemoveValue(darray2[3].mValue); + const auto removed9 = map.RemoveValue(darray2[3].GetValue()); Map_CheckState_OwnedFull(map); REQUIRE(removed9 == 0); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetCount() == 5); REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); - - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); + + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); } WHEN("Removing non-available elements by key") { - const auto removed9 = map.RemoveKey(darray2[3].mKey); + const auto removed9 = map.RemoveKey(darray2[3].GetKey()); Map_CheckState_OwnedFull(map); REQUIRE(removed9 == 0); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetCount() == 5); REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); - - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); + + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); } WHEN("More capacity is reserved") { @@ -576,11 +583,11 @@ TEMPLATE_TEST_CASE( REQUIRE(copy.GetRawKeysMemory() == map.GetRawKeysMemory()); REQUIRE(copy.GetRawValsMemory() == map.GetRawValsMemory()); for (auto& comparer : darray1) - REQUIRE(copy[comparer.mKey] == comparer.mValue); + REQUIRE(copy[comparer.GetKey()] == comparer.GetValue()); if constexpr (CT::Typed) { for (auto& comparer : darray1) - REQUIRE(&map[comparer.mKey] == ©[comparer.mKey]); + REQUIRE(&map[comparer.GetKey()] == ©[comparer.GetKey()]); } } @@ -599,20 +606,20 @@ TEMPLATE_TEST_CASE( REQUIRE(clone.GetRawValsMemory() != map.GetRawValsMemory()); for (auto& comparer : darray1) { if constexpr (CT::Sparse) { - REQUIRE(clone[comparer.mKey] != comparer.mValue); - REQUIRE(map[comparer.mKey] != clone[comparer.mKey]); + REQUIRE(clone[comparer.GetKey()] != comparer.GetValue()); + REQUIRE(map[comparer.GetKey()] != clone[comparer.GetKey()]); } else { - REQUIRE(clone[comparer.mKey] == comparer.mValue); - REQUIRE(map[comparer.mKey] == clone[comparer.mKey]); + REQUIRE(clone[comparer.GetKey()] == comparer.GetValue()); + REQUIRE(map[comparer.GetKey()] == clone[comparer.GetKey()]); } - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); if constexpr (CT::Typed) - REQUIRE(&map[comparer.mKey] != &clone[comparer.mKey]); + REQUIRE(&map[comparer.GetKey()] != &clone[comparer.GetKey()]); else - REQUIRE(map[comparer.mKey].GetRaw() != clone[comparer.mKey].GetRaw()); + REQUIRE(map[comparer.GetKey()].GetRaw() != clone[comparer.GetKey()].GetRaw()); } } @@ -631,7 +638,7 @@ TEMPLATE_TEST_CASE( REQUIRE(moved.GetKeys().GetUses() == 2); REQUIRE(moved.GetVals().GetUses() == 2); for (auto& comparer : darray1) - REQUIRE(moved[comparer.mKey] == comparer.mValue); + REQUIRE(moved[comparer.GetKey()] == comparer.GetValue()); } WHEN("Maps are compared") { @@ -650,37 +657,37 @@ TEMPLATE_TEST_CASE( WHEN("Maps are iterated with ranged-for") { for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); unsigned i = 0; for (auto pair : map) { - static_assert(not CT::Typed or ::std::is_reference_v, + static_assert(not CT::Typed or ::std::is_reference_v, "Pair key type is not a reference for statically optimized map"); - static_assert(not CT::Typed or ::std::is_reference_v, + static_assert(not CT::Typed or ::std::is_reference_v, "Pair value type is not a reference for statically optimized map"); // Different architectures result in different hashes if constexpr (Bitness == 32) { switch (i) { case 0: - REQUIRE(pair.mKey == darray1[2].mKey); - REQUIRE(pair.mValue == darray1[2].mValue); + REQUIRE(pair.GetKey() == darray1[2].GetKey()); + REQUIRE(pair.GetValue() == darray1[2].GetValue()); break; case 1: - REQUIRE(pair.mKey == darray1[3].mKey); - REQUIRE(pair.mValue == darray1[3].mValue); + REQUIRE(pair.GetKey() == darray1[3].GetKey()); + REQUIRE(pair.GetValue() == darray1[3].GetValue()); break; case 2: - REQUIRE(pair.mKey == darray1[1].mKey); - REQUIRE(pair.mValue == darray1[1].mValue); + REQUIRE(pair.GetKey() == darray1[1].GetKey()); + REQUIRE(pair.GetValue() == darray1[1].GetValue()); break; case 3: - REQUIRE(pair.mKey == darray1[4].mKey); - REQUIRE(pair.mValue == darray1[4].mValue); + REQUIRE(pair.GetKey() == darray1[4].GetKey()); + REQUIRE(pair.GetValue() == darray1[4].GetValue()); break; case 4: - REQUIRE(pair.mKey == darray1[0].mKey); - REQUIRE(pair.mValue == darray1[0].mValue); + REQUIRE(pair.GetKey() == darray1[0].GetKey()); + REQUIRE(pair.GetValue() == darray1[0].GetValue()); break; default: FAIL("Index out of bounds in ranged-for"); @@ -690,24 +697,24 @@ TEMPLATE_TEST_CASE( else if constexpr (Bitness == 64) { switch (i) { case 0: - REQUIRE(pair.mKey == darray1[1].mKey); - REQUIRE(pair.mValue == darray1[1].mValue); + REQUIRE(pair.GetKey() == darray1[1].GetKey()); + REQUIRE(pair.GetValue() == darray1[1].GetValue()); break; case 1: - REQUIRE(pair.mKey == darray1[2].mKey); - REQUIRE(pair.mValue == darray1[2].mValue); + REQUIRE(pair.GetKey() == darray1[2].GetKey()); + REQUIRE(pair.GetValue() == darray1[2].GetValue()); break; case 2: - REQUIRE(pair.mKey == darray1[3].mKey); - REQUIRE(pair.mValue == darray1[3].mValue); + REQUIRE(pair.GetKey() == darray1[3].GetKey()); + REQUIRE(pair.GetValue() == darray1[3].GetValue()); break; case 3: - REQUIRE(pair.mKey == darray1[4].mKey); - REQUIRE(pair.mValue == darray1[4].mValue); + REQUIRE(pair.GetKey() == darray1[4].GetKey()); + REQUIRE(pair.GetValue() == darray1[4].GetValue()); break; case 4: - REQUIRE(pair.mKey == darray1[0].mKey); - REQUIRE(pair.mValue == darray1[0].mValue); + REQUIRE(pair.GetKey() == darray1[0].GetKey()); + REQUIRE(pair.GetValue() == darray1[0].GetValue()); break; default: FAIL("Index out of bounds in ranged-for"); @@ -724,7 +731,7 @@ TEMPLATE_TEST_CASE( WHEN("ForEach flat dense key (immutable)") { for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); unsigned i = 0; const auto done = map.ForEachKey([&](const K& key) { @@ -732,19 +739,19 @@ TEMPLATE_TEST_CASE( if constexpr (Bitness == 32) { switch (i) { case 0: - REQUIRE(key == darray1[2].mKey); + REQUIRE(key == darray1[2].GetKey()); break; case 1: - REQUIRE(key == darray1[3].mKey); + REQUIRE(key == darray1[3].GetKey()); break; case 2: - REQUIRE(key == darray1[1].mKey); + REQUIRE(key == darray1[1].GetKey()); break; case 3: - REQUIRE(key == darray1[4].mKey); + REQUIRE(key == darray1[4].GetKey()); break; case 4: - REQUIRE(key == darray1[0].mKey); + REQUIRE(key == darray1[0].GetKey()); break; default: FAIL("Index out of bounds in ranged-for"); @@ -754,19 +761,19 @@ TEMPLATE_TEST_CASE( else if constexpr (Bitness == 64) { switch (i) { case 0: - REQUIRE(key == darray1[1].mKey); + REQUIRE(key == darray1[1].GetKey()); break; case 1: - REQUIRE(key == darray1[2].mKey); + REQUIRE(key == darray1[2].GetKey()); break; case 2: - REQUIRE(key == darray1[3].mKey); + REQUIRE(key == darray1[3].GetKey()); break; case 3: - REQUIRE(key == darray1[4].mKey); + REQUIRE(key == darray1[4].GetKey()); break; case 4: - REQUIRE(key == darray1[0].mKey); + REQUIRE(key == darray1[0].GetKey()); break; default: FAIL("Index out of bounds in ranged-for"); @@ -783,6 +790,84 @@ TEMPLATE_TEST_CASE( REQUIRE(i == done); } } + + DestroyPair(pair); + DestroyPair(stdpair); + + for (auto& i : darray1) + DestroyPair(i); + for (auto& i : darray2) + DestroyPair(i); + + for (auto& i : darray1std) + DestroyPair(i); + for (auto& i : darray2std) + DestroyPair(i); + + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); +} + +TEMPLATE_TEST_CASE("Dense templated map stress test", "[map]", + (MapTest, int, int>), + (MapTest, int, Trait>), + (MapTest, int, Traits::Count>), + (MapTest, int, Many>), + + (MapTest, int, int>), + (MapTest, int, Trait>), + (MapTest, int, Traits::Count>), + (MapTest, int, Many>) +) { + static Allocator::State memoryState; + + using T = typename TestType::Container; + //using K = typename TestType::Key; + using V = typename TestType::Value; + + const V darray[5] { + CreateElement(111), + CreateElement(222), + CreateElement(333), + CreateElement(444), + CreateElement(555) + }; + + GIVEN("Map with some items") { + T map {}; + + // Insert 5,000,000 elements at random places + // Tested with up to that many, but takes a lot of time, so i've + // lowered the number + for (int i = 0; i < 2'000; ++i) { + for (auto& item : darray) + map.Insert(i, item); + } + + WHEN("Iterated") { + Count iterated = 0; + for (auto pair : map) { + (void) pair; + ++iterated; + } + + REQUIRE(iterated == 2'000); + } + } + + for (auto& i : darray) + DestroyElement(i); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/map/TestMapSparse.cpp b/test/map/TestMapSparse.cpp index 0e1c4c06..df010dbb 100644 --- a/test/map/TestMapSparse.cpp +++ b/test/map/TestMapSparse.cpp @@ -7,7 +7,6 @@ /// #include "TestMapCommon.hpp" - #define MAP_TESTS(MANAGED) \ (MapTest, Text, Trait*, MANAGED>), \ (MapTest), \ @@ -71,8 +70,6 @@ TEMPLATE_TEST_CASE( MAP_TESTS(false) ) { #endif - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; using T = typename TestType::Container; @@ -82,12 +79,9 @@ TEMPLATE_TEST_CASE( using StdPair = ::std::pair; constexpr bool MANAGED = TestType::Managed; - const auto pair - = CreatePair("five hundred", 555); - const auto pairMissing - = CreatePair("missing", 554); - const auto stdpair - = CreatePair("five hundred", 555); + const auto pair = CreatePair("five hundred", 555); + const auto pairMissing = CreatePair("missing", 554); + const auto stdpair = CreatePair("five hundred", 555); const Pair darray1[5] { CreatePair("one", 1), @@ -173,15 +167,15 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetCount() == 1); REQUIRE(map.GetKeys().GetUses() == 1); REQUIRE(map.GetVals().GetUses() == 1); - REQUIRE(map[pair.mKey] == pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); if constexpr (CT::Text) { - REQUIRE(map["five hundred"] == pair.mValue); - REQUIRE_THROWS(map["missing"] != pair.mValue); + REQUIRE(map["five hundred"] == pair.GetValue()); + REQUIRE_THROWS(map["missing"] != pair.GetValue()); } else { - REQUIRE(map[pair.mKey] == pair.mValue); - REQUIRE_THROWS(map[pairMissing.mKey] != pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); + REQUIRE_THROWS(map[pairMissing.GetKey()] != pair.GetValue()); } #ifdef LANGULUS_STD_BENCHMARK @@ -219,15 +213,15 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetCount() == 1); REQUIRE(map.GetKeys().GetUses() == 1); REQUIRE(map.GetVals().GetUses() == 1); - REQUIRE(map[pair.mKey] == pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); if constexpr (CT::Text) { - REQUIRE(map["five hundred"] == pair.mValue); - REQUIRE_THROWS(map["missing"] != pair.mValue); + REQUIRE(map["five hundred"] == pair.GetValue()); + REQUIRE_THROWS(map["missing"] != pair.GetValue()); } else { - REQUIRE(map[pair.mKey] == pair.mValue); - REQUIRE_THROWS(map[pairMissing.mKey] != pair.mValue); + REQUIRE(map[pair.GetKey()] == pair.GetValue()); + REQUIRE_THROWS(map[pairMissing.GetKey()] != pair.GetValue()); } //TODO benchmark @@ -244,7 +238,7 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetKeys().GetUses() == 1); REQUIRE(map.GetVals().GetUses() == 1); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetReserved() >= 5); //TODO benchmark @@ -269,33 +263,45 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetKeys().GetUses() == 1); REQUIRE(map.GetVals().GetUses() == 1); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetReserved() >= 5); } WHEN("Shallow-copy more of the same stuff") { for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[0]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[1]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); map << darray2[2]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); + + + /*Logger::SpecialTab("Map before: "); + for (auto p : map) + Logger::Append(p.mKey->As(), ", ");*/ map << darray2[3]; - for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + + /*Logger::SpecialTab("Map after: "); + for (auto p : map) + Logger::Append(p.mKey->As(), ", ");*/ + + for (auto& comparer : darray1) { + //Logger::Special("Searching for: ", comparer.mKey->As()); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); + } map << darray2[4]; for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); Map_CheckState_OwnedFull(map); @@ -304,9 +310,9 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetCount() == 10); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); for (auto& comparer : darray2) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); #if LANGULUS_FEATURE(MANAGED_MEMORY) REQUIRE(map.GetRawKeysMemory() == keyMemory); @@ -402,9 +408,9 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetVals().GetUses() == 1); REQUIRE(map.GetCount() == 10); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); for (auto& comparer : darray2) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); #if LANGULUS_FEATURE(MANAGED_MEMORY) REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); @@ -446,8 +452,8 @@ TEMPLATE_TEST_CASE( static_assert(CT::Comparable>); static_assert(CT::Comparable>); - const auto removed2 = map.RemoveValue(darray1[1].mValue); - const auto removed4 = map.RemoveValue(darray1[3].mValue); + const auto removed2 = map.RemoveValue(darray1[1].GetValue()); + const auto removed4 = map.RemoveValue(darray1[3].GetValue()); Map_CheckState_OwnedFull(map); @@ -460,65 +466,65 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE (map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE (map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE (map.ContainsValue(darray1[4].mValue)); + REQUIRE (map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE (map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE (map.ContainsValue(darray1[4].GetValue())); - REQUIRE (map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE (map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE (map.ContainsKey(darray1[4].mKey)); + REQUIRE (map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE (map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE (map.ContainsKey(darray1[4].GetKey())); - const auto removed3 = map.RemoveValue(darray1[2].mValue); + const auto removed3 = map.RemoveValue(darray1[2].GetValue()); REQUIRE(removed3 == 1); REQUIRE(map.GetCount() == 2); - REQUIRE (map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE (map.ContainsValue(darray1[4].mValue)); + REQUIRE (map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE (map.ContainsValue(darray1[4].GetValue())); - REQUIRE (map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE (map.ContainsKey(darray1[4].mKey)); + REQUIRE (map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE (map.ContainsKey(darray1[4].GetKey())); - const auto removed1 = map.RemoveValue(darray1[0].mValue); + const auto removed1 = map.RemoveValue(darray1[0].GetValue()); REQUIRE(removed1 == 1); REQUIRE(map.GetCount() == 1); - REQUIRE_FALSE(map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE (map.ContainsValue(darray1[4].mValue)); + REQUIRE_FALSE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE (map.ContainsValue(darray1[4].GetValue())); - REQUIRE_FALSE(map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE (map.ContainsKey(darray1[4].mKey)); + REQUIRE_FALSE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE (map.ContainsKey(darray1[4].GetKey())); - const auto removed5 = map.RemoveValue(darray1[4].mValue); + const auto removed5 = map.RemoveValue(darray1[4].GetValue()); REQUIRE(removed5 == 1); REQUIRE(map.GetCount() == 0); - REQUIRE_FALSE(map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[4].mValue)); + REQUIRE_FALSE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[4].GetValue())); - REQUIRE_FALSE(map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[4].mKey)); + REQUIRE_FALSE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[4].GetKey())); #ifdef LANGULUS_STD_BENCHMARK @@ -560,8 +566,8 @@ TEMPLATE_TEST_CASE( for (int iii = 0; iii < 10; ++iii) { WHEN(std::string("Removing elements by key #") + std::to_string(iii)) { - const auto removed2 = map.RemoveKey(darray1[1].mKey); - const auto removed4 = map.RemoveKey(darray1[3].mKey); + const auto removed2 = map.RemoveKey(darray1[1].GetKey()); + const auto removed4 = map.RemoveKey(darray1[3].GetKey()); Map_CheckState_OwnedFull(map); @@ -574,17 +580,17 @@ TEMPLATE_TEST_CASE( REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE_FALSE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE_FALSE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE_FALSE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE_FALSE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::TUnorderedMap::RemoveKey") (timer meter) { @@ -616,55 +622,55 @@ TEMPLATE_TEST_CASE( } WHEN("Removing non-available elements by value") { - const auto removed9 = map.RemoveValue(darray2[3].mValue); + const auto removed9 = map.RemoveValue(darray2[3].GetValue()); Map_CheckState_OwnedFull(map); REQUIRE(removed9 == 0); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetCount() == 5); REQUIRE(map.GetRawKeysMemory() == keyMemory); REQUIRE(map.GetRawValsMemory() == valueMemory); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); - - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); + + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); } WHEN("Removing non-available elements by key") { - const auto removed9 = map.RemoveKey(darray2[3].mKey); + const auto removed9 = map.RemoveKey(darray2[3].GetKey()); Map_CheckState_OwnedFull(map); REQUIRE(removed9 == 0); for (auto& comparer : darray1) - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); REQUIRE(map.GetCount() == 5); REQUIRE(map.GetKeys().GetUses() == 1); REQUIRE(map.GetVals().GetUses() == 1); REQUIRE(map.GetReserved() >= 5); - REQUIRE(map.ContainsKey(darray1[0].mKey)); - REQUIRE(map.ContainsKey(darray1[1].mKey)); - REQUIRE(map.ContainsKey(darray1[2].mKey)); - REQUIRE(map.ContainsKey(darray1[3].mKey)); - REQUIRE(map.ContainsKey(darray1[4].mKey)); - - REQUIRE(map.ContainsValue(darray1[0].mValue)); - REQUIRE(map.ContainsValue(darray1[1].mValue)); - REQUIRE(map.ContainsValue(darray1[2].mValue)); - REQUIRE(map.ContainsValue(darray1[3].mValue)); - REQUIRE(map.ContainsValue(darray1[4].mValue)); + REQUIRE(map.ContainsKey(darray1[0].GetKey())); + REQUIRE(map.ContainsKey(darray1[1].GetKey())); + REQUIRE(map.ContainsKey(darray1[2].GetKey())); + REQUIRE(map.ContainsKey(darray1[3].GetKey())); + REQUIRE(map.ContainsKey(darray1[4].GetKey())); + + REQUIRE(map.ContainsValue(darray1[0].GetValue())); + REQUIRE(map.ContainsValue(darray1[1].GetValue())); + REQUIRE(map.ContainsValue(darray1[2].GetValue())); + REQUIRE(map.ContainsValue(darray1[3].GetValue())); + REQUIRE(map.ContainsValue(darray1[4].GetValue())); } WHEN("More capacity is reserved") { @@ -723,11 +729,11 @@ TEMPLATE_TEST_CASE( REQUIRE(copy.GetRawValsMemory() == map.GetRawValsMemory()); for (auto& comparer : darray1) - REQUIRE(copy[comparer.mKey] == comparer.mValue); + REQUIRE(copy[comparer.GetKey()] == comparer.GetValue()); if constexpr (CT::Typed) { for (auto& comparer : darray1) - REQUIRE(&map[comparer.mKey] == ©[comparer.mKey]); + REQUIRE(&map[comparer.GetKey()] == ©[comparer.GetKey()]); } } @@ -748,19 +754,19 @@ TEMPLATE_TEST_CASE( for (auto& comparer : darray1) { if constexpr (CT::Sparse) { // Pointer changes, hence no longer findable - REQUIRE_THROWS(clone[comparer.mKey]); + REQUIRE_THROWS(clone[comparer.GetKey()]); } else { - REQUIRE(clone[comparer.mKey] != comparer.mValue); - REQUIRE(map[comparer.mKey] != clone[comparer.mKey]); + REQUIRE(clone[comparer.GetKey()] != comparer.GetValue()); + REQUIRE(map[comparer.GetKey()] != clone[comparer.GetKey()]); if constexpr (CT::Typed) - REQUIRE(&map[comparer.mKey] != &clone[comparer.mKey]); + REQUIRE(&map[comparer.GetKey()] != &clone[comparer.GetKey()]); else - REQUIRE(map[comparer.mKey].GetRaw() != clone[comparer.mKey].GetRaw()); + REQUIRE(map[comparer.GetKey()].GetRaw() != clone[comparer.GetKey()].GetRaw()); } - REQUIRE(map[comparer.mKey] == comparer.mValue); + REQUIRE(map[comparer.GetKey()] == comparer.GetValue()); } } else if constexpr (CT::Untyped) { @@ -784,7 +790,7 @@ TEMPLATE_TEST_CASE( REQUIRE(moved.GetKeys().GetUses() == 2); REQUIRE(moved.GetVals().GetUses() == 2); for (auto& comparer : darray1) - REQUIRE(moved[comparer.mKey] == comparer.mValue); + REQUIRE(moved[comparer.GetKey()] == comparer.GetValue()); } WHEN("Maps are compared") { @@ -807,9 +813,9 @@ TEMPLATE_TEST_CASE( WHEN("Maps are iterated with ranged-for") { unsigned i = 0; for (auto pair : map) { - static_assert(CT::Untyped or CT::Reference, + static_assert(CT::Untyped or CT::Reference, "Pair key type is not a reference for statically optimized map"); - static_assert(CT::Untyped or CT::Reference, + static_assert(CT::Untyped or CT::Reference, "Pair value type is not a reference for statically optimized map"); // Pointers are always random, can't ensure order @@ -850,4 +856,116 @@ TEMPLATE_TEST_CASE( DestroyPair(i); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } + +TEMPLATE_TEST_CASE("Sparse templated map stress test", "[map]", + (MapTest, int*, Trait>), + + (MapTest, int, int*>), + (MapTest, int, Trait*>), + (MapTest, int, Traits::Count*>), + (MapTest, int, Many*>), + + (MapTest, int, int*>), + (MapTest, int, Trait*>), + (MapTest, int, Traits::Count*>), + (MapTest, int, Many*>), + + (MapTest, int*, int>), + (MapTest, int*, Traits::Count>), + (MapTest, int*, Many>), + + (MapTest, int*, int>), + (MapTest, int*, Trait>), + (MapTest, int*, Traits::Count>), + (MapTest, int*, Many>), + + (MapTest, int*, int*>), + (MapTest, int*, Trait*>), + (MapTest, int*, Traits::Count*>), + (MapTest, int*, Many*>), + + (MapTest, int*, int*>), + (MapTest, int*, Trait*>), + (MapTest, int*, Traits::Count*>), + (MapTest, int*, Many*>) +) { + static Allocator::State memoryState; + + using T = typename TestType::Container; + using K = typename TestType::Key; + using V = typename TestType::Value; + + const V darray[5] { + CreateElement(111), + CreateElement(222), + CreateElement(333), + CreateElement(444), + CreateElement(555) + }; + + GIVEN("Map with some items") { + T map {}; + + // Insert 5,000,000 elements at random places + // Tested with up to that many, but takes a lot of time, so i've + // lowered the number. 14'980 has shown historically to be + // associated with some bugs in the past, so it's a number of + // interest. + for (int i = 0; i < 1'000; ++i) { + for (auto& item : darray) { + //if (i == 14'979) + // Logger::Fatal("Break to debug"); + + map.Insert(CreateElement(i), item); + + // Check integrity + Count iterated = 0; + for (auto pair : map) { + (void) pair; + ++iterated; + } + + if (iterated != map.GetCount()) + Logger::Fatal("Map integrity check failure after inserting ", i); + + REQUIRE(iterated == map.GetCount()); + } + } + + WHEN("Iterated") { + Count iterated = 0; + for (auto pair : map) { + (void) pair; + ++iterated; + } + + if constexpr (CT::Sparse) + REQUIRE(iterated == 1'000*5); + else + REQUIRE(iterated == 1'000); + } + + for (auto i : map) + DestroyElement(i.GetKey()); + } + + // Friendly note for a future Dimo: If you ever get memory manager + // integrity failures, its due to lack of these destruction calls + for (auto& i : darray) + DestroyElement(i); + + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); +} \ No newline at end of file diff --git a/test/pair/TestPairCommon.hpp b/test/pair/TestPairCommon.hpp index d5a4e971..9ff87843 100644 --- a/test/pair/TestPairCommon.hpp +++ b/test/pair/TestPairCommon.hpp @@ -8,10 +8,10 @@ /// INTENTIONALLY NOT GUARDED /// Include this file once in each cpp file, after all other headers -#include -#include -#include -#include +#include +#include +#include +#include #include #include "../many/TestManyCommon.hpp" diff --git a/test/pair/TestPairDense.cpp b/test/pair/TestPairDense.cpp index cbe7041d..dd806199 100644 --- a/test/pair/TestPairDense.cpp +++ b/test/pair/TestPairDense.cpp @@ -22,7 +22,6 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", (MapTest), (MapTest) ) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); static Allocator::State memoryState; using T = typename TestType::Container; @@ -53,7 +52,7 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", Any_Helper_TestType(lp.GetKeyBlock()); Any_Helper_TestType(lp.GetValueBlock()); - UNUSED() const auto sp = CreatePair("five hundred", 555); + [[maybe_unused]] const auto sp = CreatePair("five hundred", 555); GIVEN("A default-initialized pair instance") { @@ -88,8 +87,8 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", REQUIRE(movablePair != lp); REQUIRE(pair == lp); - REQUIRE(pair.mKey == lp.mKey); - REQUIRE(pair.mValue == lp.mValue); + REQUIRE(pair.GetKey() == lp.GetKey()); + REQUIRE(pair.GetValue() == lp.GetValue()); #ifdef LANGULUS_STD_BENCHMARK BENCHMARK_ADVANCED("Anyness::pair::operator = (single pair copy)") (timer meter) { @@ -123,8 +122,8 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(pair); REQUIRE(pair == lp); - REQUIRE(pair.mKey == lp.mKey); - REQUIRE(pair.mValue == lp.mValue); + REQUIRE(pair.GetKey() == lp.GetKey()); + REQUIRE(pair.GetValue() == lp.GetValue()); } GIVEN("Pair with some items") { @@ -136,7 +135,7 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", Pair_CheckState_Default(pair); REQUIRE(pair != lp); - REQUIRE(((pair.mKey != lp.mKey) or (pair.mValue != lp.mValue))); + REQUIRE(((pair.GetKey() != lp.GetKey()) or (pair.GetValue() != lp.GetValue()))); } WHEN("Pair is reset") { @@ -152,8 +151,8 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(copy); REQUIRE(copy == pair); - REQUIRE(copy.mKey == pair.mKey); - REQUIRE(copy.mValue == pair.mValue); + REQUIRE(copy.GetKey() == pair.GetKey()); + REQUIRE(copy.GetValue() == pair.GetValue()); } WHEN("Pair is cloned") { @@ -163,8 +162,8 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(clone); REQUIRE((clone != pair) == (CT::Sparse or CT::Sparse)); - REQUIRE(clone.mKey == pair.mKey); - REQUIRE(clone.mValue == pair.mValue); + REQUIRE(clone.GetKey() == pair.GetKey()); + REQUIRE(clone.GetValue() == pair.GetValue()); } WHEN("Pair is move-constructed") { @@ -191,5 +190,14 @@ TEMPLATE_TEST_CASE("Dense TPair/Pair", "[pair]", } } + DestroyPair(lp); + DestroyPair(sp); + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/pair/TestPairSparse.cpp b/test/pair/TestPairSparse.cpp index c37f5d01..4d435f1d 100644 --- a/test/pair/TestPairSparse.cpp +++ b/test/pair/TestPairSparse.cpp @@ -32,8 +32,6 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", PAIR_TESTS(false) ) { #endif - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; using T = typename TestType::Container; @@ -64,7 +62,6 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", static_assert(CT::DisownAssignable); } - GIVEN("A default-initialized pair instance") { T pair {}; @@ -95,8 +92,8 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", Pair_CheckState_Default(movablePair); Pair_CheckState_OwnedFull(pair); - REQUIRE(pair.mKey == lp.mKey); - REQUIRE(pair.mValue == lp.mValue); + REQUIRE(pair.GetKey() == lp.GetKey()); + REQUIRE(pair.GetValue() == lp.GetValue()); REQUIRE(pair == lp); #ifdef LANGULUS_STD_BENCHMARK @@ -130,8 +127,8 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(pair); - REQUIRE(pair.mKey == lp.mKey); - REQUIRE(pair.mValue == lp.mValue); + REQUIRE(pair.GetKey() == lp.GetKey()); + REQUIRE(pair.GetValue() == lp.GetValue()); REQUIRE(pair == lp); //TODO benchmark } @@ -157,8 +154,8 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(pair); Pair_CheckState_OwnedFull(copy); - REQUIRE(copy.mKey == pair.mKey); - REQUIRE(copy.mValue == pair.mValue); + REQUIRE(copy.GetKey() == pair.GetKey()); + REQUIRE(copy.GetValue() == pair.GetValue()); REQUIRE(copy == pair); REQUIRE(copy == lp); //TODO benchmark @@ -171,8 +168,8 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", Pair_CheckState_OwnedFull(pair); Pair_CheckState_OwnedFull(clone); - REQUIRE(clone.mKey != pair.mKey); - REQUIRE(clone.mValue != pair.mValue); + REQUIRE(clone.GetKey() != pair.GetKey()); + REQUIRE(clone.GetValue() != pair.GetValue()); REQUIRE(clone != pair); } else if constexpr (CT::Untyped) { @@ -188,8 +185,8 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", Pair_CheckState_Default(movable); Pair_CheckState_OwnedFull(moved); - REQUIRE(moved.mKey == pair.mKey); - REQUIRE(moved.mValue == pair.mValue); + REQUIRE(moved.GetKey() == pair.GetKey()); + REQUIRE(moved.GetValue() == pair.GetValue()); REQUIRE(moved != movable); REQUIRE(moved == pair); //TODO benchmark @@ -210,5 +207,12 @@ TEMPLATE_TEST_CASE("Sparse TPair/Pair", "[pair]", DestroyPair(lp); DestroyPair(sp); + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/set/TestSetCommon.hpp b/test/set/TestSetCommon.hpp index 5e09475a..b6842168 100644 --- a/test/set/TestSetCommon.hpp +++ b/test/set/TestSetCommon.hpp @@ -8,10 +8,10 @@ /// INTENTIONALLY NOT GUARDED /// Include this file once in each cpp file, after all other headers -#include -#include -#include -#include +#include +#include +#include +#include #include #include "../Common.hpp" diff --git a/test/set/TestSetCornerCases.cpp b/test/set/TestSetCornerCases.cpp index 30b3b2de..5b69dfc6 100644 --- a/test/set/TestSetCornerCases.cpp +++ b/test/set/TestSetCornerCases.cpp @@ -58,6 +58,12 @@ TEMPLATE_TEST_CASE("Set corner cases", "[set]", REQUIRE_FALSE(set.Contains("VulkanRenderable")); } } + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } /// Testing some corner cases encountered during the use of the container @@ -67,7 +73,6 @@ TEMPLATE_TEST_CASE("Set of outside-referenced elements", "[set]", UnorderedSet, OrderedSet ) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); static Allocator::State memoryState; using T = TestType; TMany factory {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}; @@ -118,5 +123,13 @@ TEMPLATE_TEST_CASE("Set of outside-referenced elements", "[set]", } }} + factory.Reset(); + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } diff --git a/test/set/TestSetDense.cpp b/test/set/TestSetDense.cpp index 896cf317..c60af59d 100644 --- a/test/set/TestSetDense.cpp +++ b/test/set/TestSetDense.cpp @@ -37,8 +37,6 @@ TEMPLATE_TEST_CASE( (SetTest), (SetTest) ) { - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; using T = typename TestType::Container; @@ -699,5 +697,18 @@ TEMPLATE_TEST_CASE( } } + DestroyElement(element); + + for (auto& i : darray1) + DestroyElement(i); + for (auto& i : darray2) + DestroyElement(i); + REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); } \ No newline at end of file diff --git a/test/set/TestSetSparse.cpp b/test/set/TestSetSparse.cpp index b541be68..1ec9ce71 100644 --- a/test/set/TestSetSparse.cpp +++ b/test/set/TestSetSparse.cpp @@ -53,8 +53,6 @@ TEMPLATE_TEST_CASE( SET_TESTS(false) ) { #endif - IF_LANGULUS_MANAGED_MEMORY(Allocator::CollectGarbage()); - static Allocator::State memoryState; using T = typename TestType::Container; @@ -527,21 +525,18 @@ TEMPLATE_TEST_CASE( } } - if constexpr (CT::Referencable>) - element->Reference(-1); - delete element; - - for (auto item : darray1) { - if constexpr (CT::Referencable>) - item->Reference(-1); - delete item; - } + DestroyElement(element); - for (auto item : darray2) { - if constexpr (CT::Referencable>) - item->Reference(-1); - delete item; - } + for (auto& i : darray1) + DestroyElement(i); + for (auto& i : darray2) + DestroyElement(i); REQUIRE(memoryState.Assert()); + + // Destroy BANK before static data - otherwise problems happen if + // not using managed reflection + BANK.Reset(); + + REQUIRE_FALSE(Allocator::CollectGarbage()); }