Skip to content

Commit

Permalink
Add value_ptr (#59)
Browse files Browse the repository at this point in the history
Implement value_ptr
  • Loading branch information
Alex-PLACET authored Apr 9, 2024
1 parent 8d69576 commit c938478
Show file tree
Hide file tree
Showing 6 changed files with 278 additions and 4 deletions.
3 changes: 2 additions & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -61,11 +61,12 @@ endif()
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/data_traits.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
Expand Down
4 changes: 2 additions & 2 deletions include/sparrow/array_data.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,13 @@

#include <cassert>
#include <compare>
#include <concepts>
#include <optional>
#include <vector>

#include "sparrow/buffer.hpp"
#include "sparrow/data_type.hpp"
#include "sparrow/dynamic_bitset.hpp"
#include "sparrow/memory.hpp"

namespace sparrow
{
Expand All @@ -48,7 +48,7 @@ namespace sparrow
// Other buffers
std::vector<buffer_type> buffers;
std::vector<array_data> child_data;
std::shared_ptr<array_data> dictionary;
value_ptr<array_data> dictionary;
};

/**
Expand Down
123 changes: 123 additions & 0 deletions include/sparrow/memory.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
// Copyright 2024 Man Group Operations Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or mplied.
// See the License for the specific language governing permissions and
// limitations under the License.

#pragma once

#include <cassert>
#include <memory>

namespace sparrow
{

/**
* @brief A value_ptr is a smart pointer that behaves like a value.
* It manages the lifetime of an object of type T which is not stored in the `value_ptr` but a pointer,
* similar to `unique_ptr`. When copied, it copies the managed object.
*
* @tparam T The type of the object managed by the `value_ptr`.
* @todo Make it constexpr.
*/
template <class T>
class value_ptr
{
public:

value_ptr() = default;

explicit value_ptr(T value)
: value_(std::make_unique<T>(std::move(value)))
{
}

explicit value_ptr(T* value)
: value_(value != nullptr ? std::make_unique<T>(*value) : std::unique_ptr<T>())
{
}

value_ptr(const value_ptr& other)
: value_(other.value_ ? std::make_unique<T>(*other.value_) : std::unique_ptr<T>())
{
}

value_ptr(value_ptr&& other) noexcept = default;

~value_ptr() = default;

value_ptr& operator=(const value_ptr& other)
{
if (other.has_value())
{
if (value_)
{
*value_ = *other.value_;
}
else
{
value_ = std::make_unique<T>(*other.value_);
}
}
else
{
value_.reset();
}
return *this;
}

value_ptr& operator=(value_ptr&& other) noexcept = default;

T& operator*()
{
assert(value_);
return *value_;
}

const T& operator*() const
{
assert(value_);
return *value_;
}

T* operator->()
{
assert(value_);
return &*value_;
}

const T* operator->() const
{
assert(value_);
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<T> value_;
};

}
1 change: 1 addition & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ set(SPARROW_TESTS_SOURCES
test_dictionary_encoded_layout.cpp
test_mpl.cpp
test_traits.cpp
test_memory.cpp
)
set(test_target "test_sparrow_lib")
add_executable(${test_target} ${SPARROW_TESTS_SOURCES})
Expand Down
2 changes: 1 addition & 1 deletion test/test_dictionary_encoded_layout.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ namespace sparrow
m_data.buffers.push_back(b);
m_data.length = element_count;
auto dictionary = make_dictionary();
m_data.dictionary = std::make_shared<array_data>(std::move(dictionary));
m_data.dictionary = sparrow::value_ptr<array_data>(std::move(dictionary));
}

static array_data make_dictionary()
Expand Down
149 changes: 149 additions & 0 deletions test/test_memory.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
// Copyright 2024 Man Group Operations Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include <vector>

#include "sparrow/memory.hpp"

#include "doctest/doctest.h"

using namespace sparrow;

TEST_SUITE("value_ptr")
{
TEST_CASE("constructor")
{
value_ptr<int> vp;
CHECK(!vp);

value_ptr vp1(42);
REQUIRE(vp1);
CHECK_EQ(*vp1, 42);
}

TEST_CASE("copy constructor")
{
const value_ptr vp1(42);
const value_ptr vp2(vp1);
REQUIRE(vp1);
REQUIRE(vp2);
CHECK_EQ(*vp1, 42);
CHECK_EQ(*vp2, 42);
}

TEST_CASE("copy constructor with nullptr")
{
const value_ptr<int> vp1;
const value_ptr<int> vp2(vp1);
CHECK(!vp1);
CHECK(!vp2);
}

TEST_CASE("operator=")
{
value_ptr<int> vp1;
value_ptr<int> vp2(42);
vp1 = vp2;
REQUIRE(vp1);
REQUIRE(vp2);
CHECK_EQ(*vp1, 42);
CHECK_EQ(*vp2, 42);

value_ptr<int> vp3;
value_ptr<int> vp4;
vp3 = vp4;
CHECK(!vp3);
CHECK(!vp4);
}

TEST_CASE("copy")
{
const value_ptr vp1(42);
const value_ptr vp2 = vp1;
REQUIRE(vp1);
REQUIRE(vp2);
CHECK_EQ(*vp1, 42);
CHECK_EQ(*vp2, 42);
}

TEST_CASE("move constructor")
{
value_ptr vp1(42);
const value_ptr vp2(std::move(vp1));
CHECK(!vp1);
REQUIRE(vp2);
CHECK_EQ(*vp2, 42);
}

TEST_CASE("move assignment")
{
value_ptr vp1(42);
value_ptr<int> vp2;
vp2 = std::move(vp1);
CHECK(!vp1);
REQUIRE(vp2);
CHECK_EQ(*vp2, 42);

value_ptr<int> vp3;
{
value_ptr vp4(43);
vp3 = std::move(vp4);
}
REQUIRE(vp3);
CHECK_EQ(*vp3, 43);
}

TEST_CASE("operator*")
{
value_ptr vp(42);
CHECK_EQ(*vp, 42);

*vp = 43;
CHECK_EQ(*vp, 43);
}

TEST_CASE("operator->")
{
value_ptr vp(std::vector<int>{42});
CHECK_EQ(vp.operator->(), std::addressof(*vp));
CHECK_EQ(vp->size(), 1);
CHECK_EQ(vp->at(0), 42);
}

TEST_CASE("operator bool")
{
value_ptr<int> vp;
CHECK(!vp);

value_ptr vp1(42);
CHECK(vp1);
}

TEST_CASE("has_value")
{
value_ptr<int> 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);
}
}

0 comments on commit c938478

Please sign in to comment.