From 9da862db50fc8892315b803c17139497780c357b Mon Sep 17 00:00:00 2001 From: Alexis Placet Date: Thu, 4 Apr 2024 12:00:16 +0200 Subject: [PATCH] Add value_ptr --- CMakeLists.txt | 3 +- include/sparrow/memory.hpp | 83 ++++++++++++++++++++++++++++ test/CMakeLists.txt | 1 + test/test_memory.cpp | 109 +++++++++++++++++++++++++++++++++++++ 4 files changed, 195 insertions(+), 1 deletion(-) create mode 100644 include/sparrow/memory.hpp create mode 100644 test/test_memory.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 076713b7..f89bc08b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -52,10 +52,11 @@ OPTION(BUILD_TESTS "sparrow test suite" OFF) set(SPARROW_HEADERS ${SPARROW_INCLUDE_DIR}/sparrow/array_data.hpp ${SPARROW_INCLUDE_DIR}/sparrow/buffer.hpp - ${SPARROW_INCLUDE_DIR}/sparrow/fixed_size_layout.hpp ${SPARROW_INCLUDE_DIR}/sparrow/data_type.hpp ${SPARROW_INCLUDE_DIR}/sparrow/dynamic_bitset.hpp + ${SPARROW_INCLUDE_DIR}/sparrow/fixed_size_layout.hpp ${SPARROW_INCLUDE_DIR}/sparrow/iterator.hpp + ${SPARROW_INCLUDE_DIR}/sparrow/memory.hpp ${SPARROW_INCLUDE_DIR}/sparrow/mp_utils.hpp ${SPARROW_INCLUDE_DIR}/sparrow/sparrow_version.hpp ${SPARROW_INCLUDE_DIR}/sparrow/variable_size_binary_layout.hpp diff --git a/include/sparrow/memory.hpp b/include/sparrow/memory.hpp new file mode 100644 index 00000000..399ffab3 --- /dev/null +++ b/include/sparrow/memory.hpp @@ -0,0 +1,83 @@ +#include +#include + +namespace sparrow { + +template +class value_ptr { +public: + value_ptr() = default; + + explicit value_ptr(T value) + : value_(std::make_unique(std::move(value))) {} + + value_ptr(const value_ptr& other) + : value_(other.value_ ? std::make_unique(*other.value_) : std::unique_ptr()){} + + value_ptr(value_ptr&& other) noexcept + : value_(std::move(other.value_)) { + other.reset(); + } + + value_ptr& operator=(const value_ptr& other) { + if (other.has_value()) { + value_ = std::make_unique(*other.value_); + }else { + value_.reset(); + } + return *this; + } + + value_ptr& operator=(value_ptr&& other) noexcept { + if (this != &other) { + value_ = std::move(other.value_); + other.reset(); + } + return *this; + } + + T& operator*() { + if (!value_) { + throw std::runtime_error("No value stored in value_ptr"); + } + return *value_; + } + + const T& operator*() const { + if (!value_) { + throw std::runtime_error("No value stored in value_ptr"); + } + return *value_; + } + + T* operator->() { + if (!value_) { + throw std::runtime_error("No value stored in value_ptr"); + } + return &*value_; + } + + const T* operator->() const { + if (!value_) { + throw std::runtime_error("No value stored in value_ptr"); + } + return &*value_; + } + + explicit operator bool() const noexcept { + return has_value(); + } + + bool has_value() const noexcept { + return bool(value_); + } + + void reset() noexcept { + value_.reset(); + } + +private: + std::unique_ptr value_; +}; + +} diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index c7b7caca..0a196bf6 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -42,6 +42,7 @@ set(SPARROW_TESTS_SOURCES test_layout.cpp test_variable_size_binary_layout.cpp test_dictionary_encoded_layout.cpp + test_memory.cpp ) set(test_target "test_sparrow_lib") add_executable(${test_target} ${SPARROW_TESTS_SOURCES}) diff --git a/test/test_memory.cpp b/test/test_memory.cpp new file mode 100644 index 00000000..7c15163e --- /dev/null +++ b/test/test_memory.cpp @@ -0,0 +1,109 @@ +#include + +#include "sparrow/memory.hpp" + +#include "doctest/doctest.h" + +using namespace sparrow; + +TEST_SUITE("value_ptr") +{ + TEST_CASE("constructor") + { + value_ptr vp; + CHECK(!vp); + + value_ptr vp1(42); + REQUIRE(vp1); + CHECK(*vp1 == 42); + } + + TEST_CASE("copy constructor") + { + value_ptr vp1(42); + value_ptr vp2(vp1); + REQUIRE(vp1); + REQUIRE(vp2); + CHECK(*vp1 == 42); + CHECK(*vp2 == 42); + } + + TEST_CASE("copy") + { + value_ptr vp1(42); + value_ptr vp2 = vp1; + REQUIRE(vp1); + REQUIRE(vp2); + CHECK(*vp1 == 42); + CHECK(*vp2 == 42); + } + + TEST_CASE("move constructor") + { + value_ptr vp1(42); + value_ptr vp2(std::move(vp1)); + CHECK(!vp1); + REQUIRE(vp2); + CHECK(*vp2 == 42); + } + + TEST_CASE("move assignment") + { + value_ptr vp1(42); + value_ptr vp2; + vp2 = std::move(vp1); + CHECK(!vp1); + REQUIRE(vp2); + CHECK(*vp2 == 42); + + value_ptr vp3; + { + value_ptr vp4(43); + vp3 = std::move(vp4); + } + REQUIRE(vp3); + CHECK(*vp3 == 43); + } + + TEST_CASE("operator*") + { + value_ptr vp(42); + CHECK(*vp == 42); + + *vp = 43; + CHECK(*vp == 43); + } + + TEST_CASE("operator->") + { + value_ptr vp(std::vector{42}); + CHECK(vp.operator->() == &*vp); + CHECK(vp->size() == 1); + } + + TEST_CASE("operator bool") + { + value_ptr vp; + CHECK(!vp); + + value_ptr vp1(42); + CHECK(vp1); + } + + TEST_CASE("has_value") + { + value_ptr vp; + CHECK(!vp.has_value()); + + value_ptr vp1(42); + CHECK(vp1.has_value()); + } + + TEST_CASE("reset") + { + value_ptr vp(42); + REQUIRE(vp); + vp.reset(); + CHECK(!vp); + } +}