From 0e6ae18a3230f1cd26a21245a274d75bb9509211 Mon Sep 17 00:00:00 2001 From: Deukhoofd Date: Fri, 11 Dec 2020 14:58:16 +0100 Subject: [PATCH] Reworked memory model. --- .clang-tidy | 11 ++++ src/Memory/BorrowedPtr.hpp | 40 ++++++++------ src/Memory/Memory.hpp | 15 ++++++ src/Memory/OptionalBorrowedPtr.hpp | 87 ++++++++++++++++++++++++++++++ src/Memory/OptionalUniquePtr.hpp | 75 ++++++++++++++++++++++++++ src/Memory/ScopedPtr.hpp | 73 +++++++++++++++++++++++++ src/Memory/UniquePtr.hpp | 71 ++++++++++++++++++++++++ 7 files changed, 356 insertions(+), 16 deletions(-) create mode 100644 .clang-tidy create mode 100644 src/Memory/Memory.hpp create mode 100644 src/Memory/OptionalBorrowedPtr.hpp create mode 100644 src/Memory/OptionalUniquePtr.hpp create mode 100644 src/Memory/ScopedPtr.hpp create mode 100644 src/Memory/UniquePtr.hpp diff --git a/.clang-tidy b/.clang-tidy new file mode 100644 index 0000000..884002b --- /dev/null +++ b/.clang-tidy @@ -0,0 +1,11 @@ +Checks: 'readability-*,clang-diagnostic-*,clang-analyzer-*,-clang-analyzer-alpha*,performance-*,cppcoreguidelines-*, +bugprone-*,modernize-*,-modernize-use-trailing-return-type' +HeaderFilterRegex: '' +AnalyzeTemporaryDtors: false +CheckOptions: + - key: readability-identifier-naming.ClassCase + value: CamelCase + - key: readability-identifier-naming.PrivateMemberCase + value: camelBack + - key: readability-identifier-naming.PrivateMemberPrefix + value: '_' \ No newline at end of file diff --git a/src/Memory/BorrowedPtr.hpp b/src/Memory/BorrowedPtr.hpp index b95649d..37f338f 100644 --- a/src/Memory/BorrowedPtr.hpp +++ b/src/Memory/BorrowedPtr.hpp @@ -4,7 +4,8 @@ #include "../Assert.hpp" namespace ArbUt { - /// @brief A borrowed pointer is used to indicate a pointer that is not owned by its holder. + /// @brief A borrowed pointer is used to indicate a pointer that is not owned by its holder. As with all Arbutils + /// pointers, this cannot be assigned null. Use an OptionalBorrowedPtr for pointers that can be null. /// @details A borrowed pointer is used to indicate a pointer that is not owned by an object, but instead borrowed /// from another owning object that is assumed to always be kept alive during the entire lifetime of the borrowing // object. @@ -13,42 +14,46 @@ namespace ArbUt { T* _raw; public: - /// @brief Initialise a BorrowedPtr with a null pointer. - inline BorrowedPtr() noexcept : _raw(nullptr){}; /// @brief Initialise a BorrowedPtr with a specific raw pointer. - inline BorrowedPtr(T* ptr) noexcept : _raw(ptr){}; + inline BorrowedPtr(__attribute__((nonnull)) T* ptr) : _raw(ptr) { AssertNotNull(ptr); }; /// @brief Initialise a BorrowedPtr from a copy. - inline BorrowedPtr(const BorrowedPtr& other) noexcept : _raw(other._raw){}; + inline BorrowedPtr(const BorrowedPtr& other) : _raw(other._raw){}; /// @brief Initialise a BorrowedPtr with a std unique_ptr. - inline BorrowedPtr(const std::unique_ptr& other) noexcept : _raw(other.get()){}; + inline BorrowedPtr(const std::unique_ptr& other) : _raw(other.get()){}; ~BorrowedPtr() noexcept = default; /// @brief Copy operator. - inline BorrowedPtr& operator=(const BorrowedPtr& rhs) noexcept { + inline BorrowedPtr& operator=(const BorrowedPtr& rhs) { if (this == &rhs) return *this; _raw = rhs._raw; return *this; } + inline BorrowedPtr& operator=(__attribute__((nonnull)) T* rhs) { + if (_raw == &rhs) + return *this; + AssertNotNull(rhs); + _raw = rhs; + return *this; + } + /// @brief Operator for access into underlying pointer. /// @warning Note that this asserts that the underlying pointer is not null first, to prevent segfaults. - inline T* operator->() const { - AssertNotNull(_raw); - return _raw; - } + inline T* operator->() const noexcept { return _raw; } /// @brief Get the raw underlying pointer. inline T* GetRaw() const noexcept { return _raw; } /// @brief Check equality of two BorrowedPtr objects - inline bool operator==(const BorrowedPtr& rhs) const noexcept { return _raw == rhs._raw; } + inline bool operator==(const BorrowedPtr& rhs) const noexcept { return _raw == rhs._raw; } + /// @brief Check equality of pointers + inline bool operator==(T* rhs) const noexcept { return _raw == rhs; } /// @brief Check equality of two BorrowedPtr objects - inline bool operator!=(const BorrowedPtr& rhs) const noexcept { return _raw != rhs._raw; } - - /// @brief Returns whether the underlying pointer is a nullptr or not. - [[nodiscard]] inline constexpr bool IsNull() const noexcept { return _raw == nullptr; } + inline bool operator!=(const BorrowedPtr& rhs) const noexcept { return _raw != rhs._raw; } + /// @brief Check equality of pointers + inline bool operator!=(T* rhs) const noexcept { return _raw == rhs; } /// @brief Returns a const version of the underlying pointer. inline BorrowedPtr Const() const noexcept { return BorrowedPtr(_raw); } @@ -73,6 +78,9 @@ namespace ArbUt { auto cast = reinterpret_cast(_raw); return BorrowedPtr(cast); } + + /// @brief Implicit cast to retrieve raw pointer. + inline operator T*() const noexcept { return _raw; } }; } diff --git a/src/Memory/Memory.hpp b/src/Memory/Memory.hpp new file mode 100644 index 0000000..c38f922 --- /dev/null +++ b/src/Memory/Memory.hpp @@ -0,0 +1,15 @@ +#ifndef ARBUTILS_MEMORY_HPP +#define ARBUTILS_MEMORY_HPP + +#include "BorrowedPtr.hpp" +#include "OptionalBorrowedPtr.hpp" +#include "UniquePtr.hpp" +#include "OptionalUniquePtr.hpp" +#include "UniquePtrList.hpp" + +namespace ArbUt { + template + using OwnedPtr = T*; +} + +#endif // ARBUTILS_MEMORY_HPP diff --git a/src/Memory/OptionalBorrowedPtr.hpp b/src/Memory/OptionalBorrowedPtr.hpp new file mode 100644 index 0000000..36c7f2a --- /dev/null +++ b/src/Memory/OptionalBorrowedPtr.hpp @@ -0,0 +1,87 @@ +#ifndef ARBUTILS_OPTIONALBORROWEDPTR_HPP +#define ARBUTILS_OPTIONALBORROWEDPTR_HPP + +#include "../Assert.hpp" + +namespace ArbUt { + /// @brief An optional borrowed pointer is used to indicate a pointer that is not owned by its holder. This pointer + /// can be null. + /// @details A borrowed pointer is used to indicate a pointer that is not owned by an object, but instead borrowed + /// from another owning object that is assumed to always be kept alive during the entire lifetime of the borrowing + // object. + template class OptionalBorrowedPtr { + private: + T* _raw; + + public: + /// @brief Initialise a BorrowedPtr with a specific raw pointer. + inline OptionalBorrowedPtr(T* ptr) : _raw(ptr){}; + /// @brief Initialise a BorrowedPtr from a copy. + inline OptionalBorrowedPtr(const BorrowedPtr& other) : _raw(other._raw){}; + /// @brief Initialise a BorrowedPtr with a std unique_ptr. + inline OptionalBorrowedPtr(const std::unique_ptr& other) : _raw(other.get()){}; + + ~OptionalBorrowedPtr() noexcept = default; + + /// @brief Copy operator. + inline OptionalBorrowedPtr& operator=(const BorrowedPtr& rhs) { + if (this == &rhs) + return *this; + _raw = rhs._raw; + return *this; + } + + /// @brief Return whether the pointer is null or not. + [[nodiscard]] inline bool HasValue() const noexcept { return _raw == nullptr; } + + /// @brief Get the raw underlying pointer. + inline T* GetValue() const noexcept { return _raw; } + + /// @brief Check equality of two BorrowedPtr objects + inline bool operator==(const OptionalBorrowedPtr& rhs) const noexcept { return _raw == rhs._raw; } + /// @brief Check equality of pointers + inline bool operator==(T* rhs) const noexcept { return _raw == rhs; } + /// @brief Check equality of two BorrowedPtr objects + inline bool operator!=(const OptionalBorrowedPtr& rhs) const noexcept { return _raw != rhs._raw; } + /// @brief Check equality of pointers + inline bool operator!=(T* rhs) const noexcept { return _raw == rhs; } + + /// @brief Returns a const version of the underlying pointer. + inline OptionalBorrowedPtr Const() const noexcept { return BorrowedPtr(_raw); } + + /// @brief Casts the underlying pointer to another type using dynamic_cast. + template inline OptionalBorrowedPtr As() const { + auto cast = dynamic_cast(_raw); + return BorrowedPtr(cast); + } + + /// @brief Try to cast the underlying pointer to another type using dynamic_cast. + template inline bool TryAs(OptionalBorrowedPtr& out) const noexcept { + auto cast = dynamic_cast(_raw); + if (cast == nullptr) + return false; + out = OptionalBorrowedPtr(cast); + return true; + } + + /// @brief Force cast the underlying pointer to another type using reinterpret_cast. + template inline OptionalBorrowedPtr ForceAs() const noexcept { + auto cast = reinterpret_cast(_raw); + return BorrowedPtr(cast); + } + + inline operator T*() const noexcept { return _raw; } + }; +} + +namespace std { + /// @brief Helper class for allowing hashing of BorrowedPtr. + template struct hash> { + /// @brief Returns a hash of for a borrowed Pointer. Effectively just the raw memory address. + /// @param k A borrowed pointer. + /// @return The hash of the borrowed pointer. + std::size_t operator()(const ArbUt::OptionalBorrowedPtr& k) const { return (size_t)k.GetValue(); } + }; +} + +#endif // ARBUTILS_OPTIONALBORROWEDPTR_HPP diff --git a/src/Memory/OptionalUniquePtr.hpp b/src/Memory/OptionalUniquePtr.hpp new file mode 100644 index 0000000..60d61eb --- /dev/null +++ b/src/Memory/OptionalUniquePtr.hpp @@ -0,0 +1,75 @@ +#ifndef ARBUTILS_OPTIONALOptionalUniquePtr_HPP +#define ARBUTILS_OPTIONALOptionalUniquePtr_HPP + +#include "../Assert.hpp" + +namespace ArbUt { + /// @brief An optional unique pointer is used to indicate a pointer that is owned by its holder, and will be deleted + /// when its owner is deleted. + /// @details A unique pointer is used to indicate a pointer that is owned by an object, and that needs to be deleted + /// when its owner is deleted. + template class OptionalUniquePtr { + private: + T* _raw; + + public: + /// @brief Initialise a OptionalUniquePtr with a specific raw pointer. + inline OptionalUniquePtr(__attribute__((nonnull)) T* ptr) : _raw(ptr){}; + /// @brief Initialise a OptionalUniquePtr from a copy. + inline OptionalUniquePtr(const OptionalUniquePtr& other) : _raw(other._raw){}; + /// @brief Initialise a OptionalUniquePtr with a std unique_ptr. + inline OptionalUniquePtr(const std::unique_ptr& other) : _raw(other.get()){}; + + ~OptionalUniquePtr() noexcept { delete _raw; } + + /// @brief Copy operator. + inline OptionalUniquePtr& operator=(const OptionalUniquePtr& rhs) { + if (this == &rhs) + return *this; + _raw = rhs._raw; + return *this; + } + + inline OptionalUniquePtr& operator=(__attribute__((nonnull)) T* rhs) { + if (_raw == &rhs) + return *this; + AssertNotNull(rhs); + _raw = rhs; + return *this; + } + + /// @brief Operator for access into underlying pointer. + /// @warning Note that this asserts that the underlying pointer is not null first, to prevent segfaults. + inline T* operator->() const noexcept { return _raw; } + + /// @brief Get the raw underlying pointer. + inline T* GetRaw() const noexcept { return _raw; } + + /// @brief Check equality of two OptionalUniquePtr objects + inline bool operator==(const OptionalUniquePtr& rhs) const noexcept { return _raw == rhs._raw; } + /// @brief Check equality of pointers + inline bool operator==(T* rhs) const noexcept { return _raw == rhs; } + /// @brief Check equality of two OptionalUniquePtr objects + inline bool operator!=(const OptionalUniquePtr& rhs) const noexcept { return _raw != rhs._raw; } + /// @brief Check equality of pointers + inline bool operator!=(T* rhs) const noexcept { return _raw == rhs; } + + /// @brief Implicit cast to retrieve raw pointer. + inline operator T*() const noexcept { + AssertNotNull(_raw); + return _raw; + } + }; +} + +namespace std { + /// @brief Helper class for allowing hashing of OptionalUniquePtr. + template struct hash> { + /// @brief Returns a hash of for a borrowed Pointer. Effectively just the raw memory address. + /// @param k A borrowed pointer. + /// @return The hash of the borrowed pointer. + std::size_t operator()(const ArbUt::OptionalUniquePtr& k) const { return (size_t)k.GetRaw(); } + }; +} + +#endif // ARBUTILS_OPTIONALOptionalUniquePtr_HPP diff --git a/src/Memory/ScopedPtr.hpp b/src/Memory/ScopedPtr.hpp new file mode 100644 index 0000000..65139a2 --- /dev/null +++ b/src/Memory/ScopedPtr.hpp @@ -0,0 +1,73 @@ +#ifndef ARBUTILS_SCOPEDPTR_HPP +#define ARBUTILS_SCOPEDPTR_HPP + +#include "../Assert.hpp" + +namespace ArbUt { + /// @brief An optional unique pointer is used to indicate a pointer that is owned by its holder, and will be deleted + /// when its owner is deleted. + /// @details A unique pointer is used to indicate a pointer that is owned by an object, and that needs to be deleted + /// when its owner is deleted. + template class ScopedPtr { + private: + T* _raw; + + public: + /// @brief Initialise a ScopedPtr with a specific raw pointer. + inline ScopedPtr(__attribute__((nonnull)) T* ptr) : _raw(ptr){}; + /// @brief Initialise a ScopedPtr from a copy. + inline ScopedPtr(const ScopedPtr& other) : _raw(other._raw){}; + /// @brief Initialise a ScopedPtr with a std unique_ptr. + inline ScopedPtr(const std::unique_ptr& other) : _raw(other.get()){}; + + ~ScopedPtr() noexcept { delete _raw; } + + /// @brief Copy operator. + inline ScopedPtr& operator=(const ScopedPtr& rhs) { + if (this == &rhs) + return *this; + _raw = rhs._raw; + return *this; + } + + inline ScopedPtr& operator=(__attribute__((nonnull)) T* rhs) { + if (_raw == &rhs) + return *this; + AssertNotNull(rhs); + _raw = rhs; + return *this; + } + + /// @brief Operator for access into underlying pointer. + /// @warning Note that this asserts that the underlying pointer is not null first, to prevent segfaults. + inline T* operator->() const noexcept { return _raw; } + + /// @brief Get the raw underlying pointer. + inline T* TakeOwnership() const noexcept { + auto raw = _raw; + _raw = nullptr; + return raw; + } + + /// @brief Check equality of two ScopedPtr objects + inline bool operator==(const ScopedPtr& rhs) const noexcept { return _raw == rhs._raw; } + /// @brief Check equality of pointers + inline bool operator==(T* rhs) const noexcept { return _raw == rhs; } + /// @brief Check equality of two ScopedPtr objects + inline bool operator!=(const ScopedPtr& rhs) const noexcept { return _raw != rhs._raw; } + /// @brief Check equality of pointers + inline bool operator!=(T* rhs) const noexcept { return _raw == rhs; } + }; +} + +namespace std { + /// @brief Helper class for allowing hashing of ScopedPtr. + template struct hash> { + /// @brief Returns a hash of for a borrowed Pointer. Effectively just the raw memory address. + /// @param k A borrowed pointer. + /// @return The hash of the borrowed pointer. + std::size_t operator()(const ArbUt::ScopedPtr& k) const { return (size_t)k.GetRaw(); } + }; +} + +#endif // ARBUTILS_SCOPEDPTR_HPP diff --git a/src/Memory/UniquePtr.hpp b/src/Memory/UniquePtr.hpp new file mode 100644 index 0000000..7cc48b4 --- /dev/null +++ b/src/Memory/UniquePtr.hpp @@ -0,0 +1,71 @@ +#ifndef ARBUTILS_UNIQUEPTR_HPP +#define ARBUTILS_UNIQUEPTR_HPP + +#include "../Assert.hpp" + +namespace ArbUt { + /// @brief A unique pointer is used to indicate a pointer that is owned by its holder, and will be deleted when its + /// owner is deleted. As with all Arbutils pointers, this cannot be assigned null. Use an OptionalUniquePtr for pointers that can be null. + /// @details A unique pointer is used to indicate a pointer that is owned by an object, and that needs to be deleted + /// when its owner is deleted. + template class UniquePtr { + private: + T* _raw; + + public: + /// @brief Initialise a UniquePtr with a specific raw pointer. + inline UniquePtr(__attribute__((nonnull)) T* ptr) : _raw(ptr) { AssertNotNull(ptr); }; + /// @brief Initialise a UniquePtr from a copy. + inline UniquePtr(const UniquePtr& other) : _raw(other._raw){}; + /// @brief Initialise a UniquePtr with a std unique_ptr. + inline UniquePtr(const std::unique_ptr& other) : _raw(other.get()){}; + + ~UniquePtr() noexcept{ + delete _raw; + } + + /// @brief Copy operator. + inline UniquePtr& operator=(const UniquePtr& rhs) { + if (this == &rhs) + return *this; + _raw = rhs._raw; + return *this; + } + + inline UniquePtr& operator=(__attribute__((nonnull)) T* rhs) { + if (_raw == &rhs) + return *this; + AssertNotNull(rhs); + _raw = rhs; + return *this; + } + + /// @brief Operator for access into underlying pointer. + /// @warning Note that this asserts that the underlying pointer is not null first, to prevent segfaults. + inline T* operator->() const noexcept { return _raw; } + + /// @brief Get the raw underlying pointer. + inline T* GetRaw() const noexcept { return _raw; } + + /// @brief Check equality of two UniquePtr objects + inline bool operator==(const UniquePtr& rhs) const noexcept { return _raw == rhs._raw; } + /// @brief Check equality of pointers + inline bool operator==(T* rhs) const noexcept { return _raw == rhs; } + /// @brief Check equality of two UniquePtr objects + inline bool operator!=(const UniquePtr& rhs) const noexcept { return _raw != rhs._raw; } + /// @brief Check equality of pointers + inline bool operator!=(T* rhs) const noexcept { return _raw == rhs; } + }; +} + +namespace std { + /// @brief Helper class for allowing hashing of UniquePtr. + template struct hash> { + /// @brief Returns a hash of for a borrowed Pointer. Effectively just the raw memory address. + /// @param k A borrowed pointer. + /// @return The hash of the borrowed pointer. + std::size_t operator()(const ArbUt::UniquePtr& k) const { return (size_t)k.GetRaw(); } + }; +} + +#endif // ARBUTILS_UNIQUEPTR_HPP