-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added basic implementation of
memory
module (#15)
* Added `construct/destroy` algorithms for `memory` module * Fixed formatting * Updated `.codecov.yml` * Added more unit tests for `relocate` algorithms * Reworked `uninitialized_algorithms` and added more unit-tests * Check return values from algorithms * Added `uninitialized_storage` implementation
- Loading branch information
Showing
31 changed files
with
2,753 additions
and
105 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,10 @@ | ||
#pragma once | ||
#include <flux/config.hpp> | ||
#include <flux/io.hpp> | ||
#include <flux/meta.hpp> | ||
|
||
#include <flux/foundation/utility.hpp> | ||
// clang-format off | ||
#include <flux/foundation/types.hpp> | ||
#include <flux/foundation/utility.hpp> | ||
#include <flux/foundation/memory.hpp> | ||
// clang-format on |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
#pragma once | ||
|
||
#include <flux/foundation/memory/uninitialized_algorithms.hpp> | ||
#include <flux/foundation/memory/uninitialized_storage.hpp> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
#include <flux/foundation.hpp> | ||
|
||
#include <catch2/catch.hpp> | ||
|
||
using namespace flux; | ||
|
||
struct A { | ||
int i; | ||
}; | ||
|
||
struct B { | ||
A a; | ||
float f; | ||
char c; | ||
}; | ||
|
||
TEST_CASE("fou::construct_in_place", "[flux-memory/construct.hpp]") { | ||
SECTION("construct in place lvalue") { | ||
alignas(A) std::byte buffer[sizeof(A)]; | ||
A* object = (A*)buffer; | ||
|
||
int expected_value = 2024; | ||
fou::construct_in_place(object, expected_value); | ||
CHECK(object->i == expected_value); | ||
|
||
fou::destroy_in_place(object); | ||
} | ||
|
||
SECTION("construct in place rvalue") { | ||
alignas(A) std::byte buffer[sizeof(A)]; | ||
A* object = (A*)buffer; | ||
|
||
fou::construct_in_place(object, 2025); | ||
CHECK(object->i == 2025); | ||
|
||
fou::destroy_in_place(object); | ||
} | ||
|
||
SECTION("construct in place variadic") { | ||
alignas(B) std::byte buffer[sizeof(B)]; | ||
B* object = (B*)buffer; | ||
|
||
fou::construct_in_place(object, A{10}, 3.14f, 'w'); | ||
CHECK(object->a.i == 10); | ||
CHECK(object->f == 3.14f); | ||
CHECK(object->c == 'w'); | ||
|
||
fou::destroy_in_place(object); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,36 @@ | ||
#pragma once | ||
#include <flux/foundation/memory/detail/construct_at.hpp> | ||
#include <flux/foundation/memory/detail/to_address.hpp> | ||
|
||
namespace flux::fou { | ||
|
||
template <meta::forward_iterator Iterator, typename T> | ||
constexpr void construct_in_place(Iterator iterator, T const& value) noexcept { | ||
detail::construct_at(detail::to_address(iterator), value); | ||
} | ||
template <meta::forward_iterator Iterator, typename T> | ||
constexpr void construct_in_place(Iterator iterator, T&& value) noexcept { | ||
detail::construct_at(detail::to_address(iterator), ::std::move(value)); | ||
} | ||
template <meta::forward_iterator Iterator, typename... Args> | ||
constexpr void construct_in_place(Iterator iterator, Args&&... args) noexcept { | ||
detail::construct_at(detail::to_address(iterator), ::std::forward<Args>(args)...); | ||
} | ||
|
||
template <meta::forward_iterator Iterator> | ||
constexpr Iterator destroy_range(Iterator first, Iterator last) noexcept { | ||
for (; first != last; ++first) { | ||
detail::destroy_at(detail::to_address(first)); | ||
} | ||
return first; | ||
} | ||
|
||
template <meta::input_iterator Iterator> | ||
constexpr void destroy_in_place(Iterator iterator) noexcept { | ||
using value_type = meta::iter_value_t<Iterator>; | ||
if constexpr (meta::not_trivially_destructible<value_type>) { | ||
detail::destroy_at(detail::to_address(iterator)); | ||
} | ||
} | ||
|
||
} // namespace flux::fou |
52 changes: 52 additions & 0 deletions
52
flux-foundation/flux/foundation/memory/detail/constexpr_memcpy-test.cpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#include <flux/foundation.hpp> | ||
|
||
#include <catch2/catch.hpp> | ||
|
||
constexpr unsigned char Banand[] = "Banand"; | ||
constexpr unsigned char Banane[] = "Banane"; | ||
constexpr unsigned char Bananf[] = "Bananf"; | ||
|
||
constexpr bool true1[] = {true, true, true}; | ||
constexpr bool true2[] = {true, true, true}; | ||
constexpr bool false1[] = {false, false, false}; | ||
|
||
using flux::fou::detail::constexpr_memcmp; | ||
using flux::fou::detail::constexpr_memcmp_equal; | ||
using flux::fou::detail::constexpr_memcpy; | ||
|
||
constexpr bool char_copy() noexcept { | ||
unsigned char dest[4]; | ||
|
||
constexpr_memcpy(dest, Banand + 1, sizeof dest); | ||
unsigned char expected[] = "anan"; | ||
return constexpr_memcmp_equal(expected, dest, 4); | ||
} | ||
|
||
TEST_CASE("fou::detail::constexpr_memcpy", "[flux-memory/constexpr_memcpy.hpp]") { | ||
SECTION("compile time") { | ||
STATIC_REQUIRE(char_copy()); | ||
} | ||
|
||
SECTION("runtime") { | ||
unsigned char source[] = "once upon a midnight dreary..."; | ||
unsigned char dest[4]; | ||
|
||
constexpr_memcpy(dest, source, sizeof dest); | ||
unsigned char expected[] = "once"; | ||
CHECK(constexpr_memcmp_equal(expected, dest, 4)); | ||
} | ||
} | ||
|
||
TEST_CASE("fou::detail::constexpr_memcmp", "[flux-memory/constexpr_memcpy.hpp]") { | ||
STATIC_REQUIRE(constexpr_memcmp(Banane, Banand, 6) == 1); | ||
STATIC_REQUIRE(constexpr_memcmp(Banane, Banane, 6) == 0); | ||
STATIC_REQUIRE(constexpr_memcmp(Banane, Bananf, 6) == -1); | ||
} | ||
|
||
TEST_CASE("fou::detail::constexpr_memcmp_equal", "[flux-memory/constexpr_memcpy.hpp]") { | ||
STATIC_REQUIRE_FALSE(constexpr_memcmp_equal(Banane, Banand, 6)); | ||
STATIC_REQUIRE(constexpr_memcmp_equal(Banane, Banane, 6)); | ||
|
||
STATIC_REQUIRE_FALSE(constexpr_memcmp_equal(true1, false1, 3)); | ||
STATIC_REQUIRE(constexpr_memcmp_equal(true1, true2, 3)); | ||
} |
134 changes: 134 additions & 0 deletions
134
flux-foundation/flux/foundation/memory/detail/constexpr_memcpy.hpp
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
#pragma once | ||
#include <flux/meta/datasizeof.hpp> | ||
|
||
namespace flux::fou::detail { | ||
|
||
template <typename T, typename U> | ||
requires meta::trivially_lexicographically_comparable<T, U> | ||
constexpr int constexpr_memcmp(T const* lhs, U const* rhs, ::std::size_t count = 1) noexcept { | ||
if consteval { | ||
if (1 == sizeof(T) && !meta::same_as<T, bool>) { | ||
return __builtin_memcmp(lhs, rhs, count * sizeof(T)); | ||
} | ||
|
||
// clang-format off | ||
for (; count != 0; --count, ++lhs, ++rhs) { | ||
if (*lhs < *rhs) return -1; | ||
if (*rhs < *lhs) return 1; | ||
} | ||
// clang-format on | ||
return 0; | ||
} | ||
return __builtin_memcmp(lhs, rhs, count * sizeof(T)); | ||
} | ||
|
||
// clang-format off | ||
template <typename T, typename U> | ||
requires meta::trivially_equality_comparable<T, U> | ||
constexpr bool constexpr_memcmp_equal(T const* lhs, U const* rhs, ::std::size_t count = 1) noexcept { | ||
if consteval { | ||
if (1 == sizeof(T) && meta::integer<T>) { | ||
return __builtin_memcmp(lhs, rhs, count * sizeof(T)) == 0; | ||
} | ||
|
||
for (; count != 0; --count, ++lhs, ++rhs) { | ||
if (!(*lhs == *rhs)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
} | ||
return __builtin_memcmp(lhs, rhs, count * sizeof(T)) == 0; | ||
} | ||
// clang-format on | ||
|
||
// This function performs an assignment to an existing, already alive TriviallyCopyable object | ||
// from another TriviallyCopyable object. | ||
// | ||
// It basically works around the fact that TriviallyCopyable objects are not required to be | ||
// syntactically copy/move constructible or copy/move assignable. Technically, only one of the | ||
// four operations is required to be syntactically valid -- but at least one definitely has to | ||
// be valid. | ||
// clang-format off | ||
template <typename T, typename U> | ||
requires meta::assignable<T&, U const&> | ||
constexpr auto assign_trivially_copyable(T& dest, U const& src) noexcept { | ||
dest = src; | ||
return dest; | ||
} | ||
|
||
template <typename T, typename U> | ||
requires (not meta::assignable<T&, U const&> and meta::assignable<T&, U&&>) | ||
constexpr auto assign_trivially_copyable(T& dest, U& src) noexcept { | ||
dest = static_cast<U&&>(src); | ||
return dest; | ||
} | ||
|
||
template <typename T, typename U> | ||
requires (not meta::assignable <T&, U const&> and | ||
not meta::assignable <T&, U&&> and | ||
meta::constructible<T&, U const&>) | ||
constexpr auto assign_trivially_copyable(T& dest, U const& src) noexcept { | ||
construct_at(addressof(dest), src); | ||
return dest; | ||
} | ||
|
||
template <typename T, typename U> | ||
requires (not meta::assignable <T&, U const&> and | ||
not meta::assignable <T&, U&&> and | ||
not meta::constructible<T&, U const&> and | ||
meta::constructible<T&, U&&>) | ||
constexpr auto assign_trivially_copyable(T& dest, U& src) noexcept { | ||
construct_at(addressof(dest), static_cast<U&&>(src)); | ||
return dest; | ||
} | ||
// clang-format on | ||
|
||
template <typename T, typename U> | ||
requires meta::trivially_copyable<meta::remove_cv_t<U>> | ||
constexpr auto constexpr_memcpy(T* dest, U const* src, ::std::size_t count = 1) noexcept { | ||
if consteval { | ||
if constexpr (meta::same_as<meta::remove_cv_t<T>, meta::remove_cv_t<U>>) { | ||
__builtin_memcpy(dest, src, count * sizeof(T)); | ||
return dest; | ||
} else { | ||
for (::std::size_t i = 0; i != count; ++i) { | ||
assign_trivially_copyable(dest[i], src[i]); | ||
} | ||
} | ||
} else { | ||
if (count > 0) { | ||
__builtin_memcpy(dest, src, (count - 1) * sizeof(T) + meta::data_size_of<T>); | ||
} | ||
} | ||
return dest; | ||
} | ||
|
||
template <typename T, typename U> | ||
requires meta::trivially_copyable<meta::remove_cv_t<U>> | ||
constexpr auto constexpr_memmove(T* dest, U const* src, ::std::size_t count = 1) noexcept { | ||
if consteval { | ||
if constexpr (meta::same_as<meta::remove_cv_t<T>, meta::remove_cv_t<U>>) { | ||
__builtin_memmove(dest, src, count * sizeof(T)); | ||
return dest; | ||
} else { | ||
if (is_pointer_in_range(src, src + count, dest)) { | ||
for (; count > 0; --count) { | ||
assign_trivially_copyable(dest[count - 1], src[count - 1]); | ||
} | ||
} else { | ||
for (::std::size_t i = 0; i != count; ++i) { | ||
assign_trivially_copyable(dest[i], src[i]); | ||
} | ||
} | ||
} | ||
} else { | ||
if (count > 0) { | ||
__builtin_memmove(dest, src, (count - 1) * sizeof(T) + meta::data_size_of<T>); | ||
} | ||
} | ||
return dest; | ||
} | ||
// clang-format on | ||
|
||
} // namespace flux::fou::detail |
Oops, something went wrong.