diff --git a/.github/workflows/dispatch.yml b/.github/workflows/dispatch.yml index 3f88e4d..5eee801 100644 --- a/.github/workflows/dispatch.yml +++ b/.github/workflows/dispatch.yml @@ -7,7 +7,7 @@ jobs: build: strategy: matrix: - dependents: [Logger, RTTI, SIMD, Anyness, Flow, Entity, Math] + dependents: [Logger, RTTI, SIMD, Fractalloc, Anyness, Flow, Math, Entity] name: Trigger Langulus::${{matrix.dependents}}'s workflow runs-on: ubuntu-latest steps: diff --git a/CMakeLists.txt b/CMakeLists.txt index 26bd7b0..7072533 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,5 +1,10 @@ cmake_minimum_required(VERSION 3.24) -project(LangulusCore) +project(LangulusCore + VERSION 1.0.0 + DESCRIPTION "Langulus core library" + HOMEPAGE_URL https://langulus.com + LANGUAGES CXX +) add_library(LangulusCore INTERFACE) target_compile_features(LangulusCore INTERFACE cxx_std_20) diff --git a/source/Core/Utilities.hpp b/source/Core/Utilities.hpp index 1e1aa74..4991eb8 100644 --- a/source/Core/Utilities.hpp +++ b/source/Core/Utilities.hpp @@ -282,5 +282,197 @@ namespace Langulus const auto r = v % alignment; return r > 0 ? v + (alignment - r) : v; } + + /// Wrapper for memcpy + /// @tparam TO - destination memory type (deducible) + /// @tparam FROM - source memory type (deducible) + /// @param to - [out] destination memory + /// @param from - source of data to copy + template + LANGULUS(INLINED) + void CopyMemory(TO* to, const FROM* from) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(you can suppress this error by casting pointer to void*)"); + + static_assert(CT::Void || (CT::Same && CT::Sparse == CT::Sparse), + "TO and FROM must be the exact same types" + "(you can suppress this error by casting pointer to void*)"); + + if constexpr (CT::Void) + LANGULUS_ERROR("Bytecount not specified when copying void pointers"); + + ::std::memcpy( + static_cast(to), + static_cast(from), + sizeof(TO) + ); + } + + /// Wrapper for memcpy + /// @tparam TO - destination memory type (deducible) + /// @tparam FROM - source memory type (deducible) + /// @param to - [out] destination memory + /// @param from - source of data to copy + /// @param count - number of elements to copy + /// @attention count becomes bytecount, when TO is void + template + LANGULUS(INLINED) + void CopyMemory(TO* to, const FROM* from, const Count& count) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(you can suppress this error by casting pointer to void*)"); + + static_assert(CT::Void || (CT::Same && CT::Sparse == CT::Sparse), + "TO and FROM must be the exact same types" + "(you can suppress this error by casting pointer to void*)"); + + if constexpr (CT::Void) { + ::std::memcpy( + static_cast(to), + static_cast(from), + count + ); + } + else { + ::std::memcpy( + static_cast(to), + static_cast(from), + sizeof(TO) * count + ); + } + } + + /// Wrapper for memset + /// @tparam TO - destination memory type (deducible) + /// @tparam FILLER - value to fill in with + /// @param to - [out] destination memory + template + LANGULUS(INLINED) + void FillMemory(TO* to) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(you can suppress this error by casting to void*)"); + + static_assert(FILLER || CT::Nullifiable || CT::Void || CT::Sparse || CT::Fundamental, + "Filling with zeroes requires the type to be reflected as nullifiable, " + "or be a pointer/fundamental (you can suppress this error by casting to void*)"); + + if constexpr (CT::Void) + LANGULUS_ERROR("Bytecount not specified when filling void pointer"); + + ::std::memset(static_cast(to), FILLER, sizeof(TO)); + } + + /// Wrapper for memset + /// @tparam TO - destination memory type (deducible) + /// @tparam FILLER - value to fill in with + /// @param to - [out] destination memory + /// @param count - number of elements to fill + /// @attention count becomes bytecount, when TO is void + template + LANGULUS(INLINED) + void FillMemory(TO* to, const Count& count) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(you can suppress this error by casting to void*)"); + + static_assert(FILLER || CT::Nullifiable || CT::Void || CT::Sparse || CT::Fundamental, + "Filling with zeroes requires the type to be reflected as nullifiable, " + "or be a pointer/fundamental (you can suppress this error by casting to void*)"); + + if constexpr (CT::Void) + ::std::memset(static_cast(to), FILLER, count); + else + ::std::memset(static_cast(to), FILLER, sizeof(TO) * count); + } + + /// Wrapper for memset 0 + /// @tparam TO - destination memory type (deducible) + /// @param to - [out] destination memory + template + LANGULUS(INLINED) + void ZeroMemory(TO* to) noexcept { + return FillMemory<0>(to); + } + + /// Wrapper for memset 0 + /// @tparam TO - destination memory type (deducible) + /// @param to - [out] destination memory + /// @param count - number of elements to fill + /// @attention count becomes bytecount, when TO is void + template + LANGULUS(INLINED) + void ZeroMemory(TO* to, const Count& count) noexcept { + return FillMemory<0>(to, count); + } + + /// Wrapper for memmove + /// @tparam TO - destination memory type (deducible) + /// @tparam FROM - source memory type (deducible) + /// @param to - [out] destination memory + /// @param from - source of data to move + template + LANGULUS(INLINED) + void MoveMemory(TO* to, const FROM* from) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(You can suppress this error by casting pointer to void*)"); + + static_assert(CT::Void || (CT::Same && CT::Sparse == CT::Sparse), + "TO and FROM must be the exact same types" + "(you can suppress this error by casting pointer to void*)"); + + if constexpr (CT::Void) + LANGULUS_ERROR("Bytecount not specified when filling void pointer"); + + ::std::memmove( + static_cast(to), + static_cast(from), + sizeof(TO) + ); + + #if LANGULUS(PARANOID) + TODO() // zero old memory, but beware - `from` and `to` might overlap + #endif + } + + /// Wrapper for memmove + /// @tparam TO - destination memory type (deducible) + /// @tparam FROM - source memory type (deducible) + /// @param to - [out] destination memory + /// @param from - source of data to move + /// @param count - number of elements to move + /// @attention count becomes bytecount, when TO is void + template + LANGULUS(INLINED) + void MoveMemory(TO* to, const FROM* from, const Count& count) noexcept { + static_assert(CT::Void || CT::Sparse || CT::POD || ::std::is_trivial_v, + "TO must be either pointer, reflected as POD, or trivial. " + "(You can suppress this error by casting pointer to void*)"); + + static_assert(CT::Void || (CT::Same && CT::Sparse == CT::Sparse), + "TO and FROM must be the exact same types" + "(you can suppress this error by casting pointer to void*)"); + + if constexpr (CT::Void) { + ::std::memmove( + static_cast(to), + static_cast(from), + count + ); + } + else { + ::std::memmove( + static_cast(to), + static_cast(from), + sizeof(TO) * count + ); + } + + #if LANGULUS(PARANOID) + TODO() // zero old memory, but beware - `from` and `to` might overlap + #endif + } } // namespace Langulus