-
Notifications
You must be signed in to change notification settings - Fork 34
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
5 changed files
with
207 additions
and
0 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,67 @@ | ||
/// @file | ||
/// @brief Class @ref cubos::core::memory::AnyValue. | ||
/// @ingroup core-memory | ||
|
||
#pragma once | ||
|
||
namespace cubos::core::reflection | ||
{ | ||
class Type; | ||
} // namespace cubos::core::reflection | ||
|
||
namespace cubos::core::memory | ||
{ | ||
/// @brief Stores a blob of a given reflected type. | ||
/// @ingroup core-memory | ||
class AnyValue final | ||
{ | ||
public: | ||
~AnyValue(); | ||
|
||
/// @brief Move constructs. | ||
/// @param other Value. | ||
AnyValue(AnyValue&& other) noexcept; | ||
|
||
/// @brief Default constructs a value with the given type. | ||
/// @note @p type must have @ref reflection::ConstructibleTrait and be default | ||
/// constructible. | ||
/// @param type Value type. | ||
/// @return Value. | ||
static AnyValue defaultConstruct(const reflection::Type& type) noexcept; | ||
|
||
/// @brief Copy constructs a value with the given type. | ||
/// @note @p type must have @ref reflection::ConstructibleTrait and be copy constructible. | ||
/// @param type Value type. | ||
/// @param value Value to copy. | ||
/// @return Value. | ||
static AnyValue copyConstruct(const reflection::Type& type, const void* value) noexcept; | ||
|
||
/// @brief Move constructs a value with the given type. | ||
/// @note @p type must have @ref reflection::ConstructibleTrait and be move constructible. | ||
/// @param type Value type. | ||
/// @param value Value to move. | ||
/// @return Value. | ||
static AnyValue moveConstruct(const reflection::Type& type, void* value) noexcept; | ||
|
||
/// @brief Get the type of the elements stored in the vector. | ||
/// @return Element type. | ||
const reflection::Type& type() const; | ||
|
||
/// @brief Gets a pointer to the underlying value. | ||
/// @return Value. | ||
void* get(); | ||
|
||
/// @copydoc get() | ||
const void* get() const; | ||
|
||
private: | ||
/// @brief Constructs with allocated uninitialized memory. | ||
/// @warning The constructor must be called immediately after this. Will cause UB if the | ||
/// returned value is deconstructed before being initialized. | ||
/// @param type Value type. | ||
AnyValue(const reflection::Type& type) noexcept; | ||
|
||
const reflection::Type& mType; | ||
void* mValue; | ||
}; | ||
} // namespace cubos::core::memory |
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,86 @@ | ||
#include <new> | ||
|
||
#include <cubos/core/log.hpp> | ||
#include <cubos/core/memory/any_value.hpp> | ||
#include <cubos/core/memory/move.hpp> | ||
#include <cubos/core/reflection/traits/constructible.hpp> | ||
#include <cubos/core/reflection/type.hpp> | ||
|
||
using cubos::core::memory::AnyValue; | ||
using cubos::core::reflection::ConstructibleTrait; | ||
using cubos::core::reflection::Type; | ||
|
||
AnyValue::~AnyValue() | ||
{ | ||
// Might have been moved, we must check it here. | ||
if (mValue != nullptr) | ||
{ | ||
const auto& trait = mType.get<ConstructibleTrait>(); | ||
trait.destruct(mValue); | ||
operator delete(mValue, static_cast<std::align_val_t>(trait.alignment())); | ||
} | ||
} | ||
|
||
AnyValue::AnyValue(AnyValue&& other) noexcept | ||
: mType(other.mType) | ||
, mValue(other.mValue) | ||
{ | ||
other.mValue = nullptr; | ||
} | ||
|
||
AnyValue AnyValue::defaultConstruct(const Type& type) noexcept | ||
{ | ||
CUBOS_ASSERT(type.has<ConstructibleTrait>(), "Type must be constructible"); | ||
const auto& trait = type.get<ConstructibleTrait>(); | ||
CUBOS_ASSERT(trait.hasDefaultConstruct(), "Type must be default constructible"); | ||
|
||
AnyValue any{type}; | ||
trait.defaultConstruct(any.get()); | ||
return move(any); | ||
} | ||
|
||
AnyValue AnyValue::copyConstruct(const Type& type, const void* value) noexcept | ||
{ | ||
CUBOS_ASSERT(type.has<ConstructibleTrait>(), "Type must be constructible"); | ||
const auto& trait = type.get<ConstructibleTrait>(); | ||
CUBOS_ASSERT(trait.hasCopyConstruct(), "Type must be copy constructible"); | ||
|
||
AnyValue any{type}; | ||
trait.copyConstruct(any.get(), value); | ||
return move(any); | ||
} | ||
|
||
AnyValue AnyValue::moveConstruct(const Type& type, void* value) noexcept | ||
{ | ||
CUBOS_ASSERT(type.has<ConstructibleTrait>(), "Type must be constructible"); | ||
const auto& trait = type.get<ConstructibleTrait>(); | ||
CUBOS_ASSERT(trait.hasMoveConstruct(), "Type must be move constructible"); | ||
|
||
AnyValue any{type}; | ||
trait.moveConstruct(any.get(), value); | ||
return move(any); | ||
} | ||
|
||
const Type& AnyValue::type() const | ||
{ | ||
return mType; | ||
} | ||
|
||
void* AnyValue::get() | ||
{ | ||
return mValue; | ||
} | ||
|
||
const void* AnyValue::get() const | ||
{ | ||
return mValue; | ||
} | ||
|
||
AnyValue::AnyValue(const Type& type) noexcept | ||
: mType(type) | ||
{ | ||
const auto& trait = type.get<ConstructibleTrait>(); | ||
mValue = operator new(trait.size(), static_cast<std::align_val_t>(trait.alignment()), std::nothrow); | ||
|
||
CUBOS_ASSERT(mValue != nullptr, "Could not allocate memory for value of type '{}'", type.name()); | ||
} |
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 |
---|---|---|
@@ -0,0 +1,52 @@ | ||
#include <doctest/doctest.h> | ||
|
||
#include <cubos/core/memory/any_value.hpp> | ||
#include <cubos/core/reflection/external/primitives.hpp> | ||
#include <cubos/core/reflection/type.hpp> | ||
|
||
#include "../utils.hpp" | ||
|
||
TEST_CASE("memory::AnyValue") | ||
{ | ||
using cubos::core::memory::AnyValue; | ||
using cubos::core::reflection::reflect; | ||
|
||
SUBCASE("with integers") | ||
{ | ||
SUBCASE("defaultConstruct") | ||
{ | ||
const auto any = AnyValue::defaultConstruct(reflect<int>()); | ||
CHECK(any.type().is<int>()); | ||
CHECK(*static_cast<const int*>(any.get()) == 0); | ||
} | ||
|
||
SUBCASE("copyConstruct") | ||
{ | ||
int value = 1337; | ||
auto any = AnyValue::copyConstruct(reflect<int>(), &value); | ||
CHECK(any.type().is<int>()); | ||
CHECK(*static_cast<int*>(any.get()) == value); | ||
} | ||
|
||
SUBCASE("moveConstruct") | ||
{ | ||
int value = 1337; | ||
auto any = AnyValue::moveConstruct(reflect<int>(), &value); | ||
CHECK(any.type().is<int>()); | ||
CHECK(*static_cast<int*>(any.get()) == value); | ||
} | ||
} | ||
|
||
SUBCASE("detect destructor") | ||
{ | ||
bool destructed = false; | ||
DetectDestructor detector{&destructed}; | ||
|
||
{ | ||
auto any = AnyValue::moveConstruct(reflect<DetectDestructor>(), &detector); | ||
CHECK_FALSE(destructed); | ||
} | ||
|
||
CHECK(destructed); | ||
} | ||
} |