Commit 9bf9af2f authored by Dominik Charousset's avatar Dominik Charousset

Merge branch 'topic/cow-ptr-redesign'

parents 0df7fab1 aee597a7
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
// -- overridden observers of message_data ----------------------------------- // -- overridden observers of message_data -----------------------------------
cow_ptr copy() const override; concatenated_tuple* copy() const override;
// -- overridden modifiers of type_erased_tuple ------------------------------ // -- overridden modifiers of type_erased_tuple ------------------------------
......
...@@ -50,7 +50,7 @@ public: ...@@ -50,7 +50,7 @@ public:
// -- overridden observers of message_data ----------------------------------- // -- overridden observers of message_data -----------------------------------
cow_ptr copy() const override; message_data* copy() const override;
// -- overridden modifiers of type_erased_tuple ------------------------------ // -- overridden modifiers of type_erased_tuple ------------------------------
......
...@@ -45,7 +45,7 @@ public: ...@@ -45,7 +45,7 @@ public:
// -- overridden observers of message_data ----------------------------------- // -- overridden observers of message_data -----------------------------------
cow_ptr copy() const override; dynamic_message_data* copy() const override;
// -- overridden modifiers of type_erased_tuple ------------------------------ // -- overridden modifiers of type_erased_tuple ------------------------------
...@@ -84,6 +84,12 @@ private: ...@@ -84,6 +84,12 @@ private:
uint32_t type_token_; uint32_t type_token_;
}; };
void intrusive_ptr_add_ref(const dynamic_message_data*);
void intrusive_ptr_release(const dynamic_message_data*);
dynamic_message_data* intrusive_cow_ptr_unshare(dynamic_message_data*&);
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -46,7 +46,7 @@ public: ...@@ -46,7 +46,7 @@ public:
// -- overridden observers of message_data ----------------------------------- // -- overridden observers of message_data -----------------------------------
cow_ptr copy() const override; merged_tuple* copy() const override;
// -- overridden modifiers of type_erased_tuple ------------------------------ // -- overridden modifiers of type_erased_tuple ------------------------------
......
...@@ -50,7 +50,7 @@ public: ...@@ -50,7 +50,7 @@ public:
// -- pure virtual observers ------------------------------------------------- // -- pure virtual observers -------------------------------------------------
virtual cow_ptr copy() const = 0; virtual message_data* copy() const = 0;
// -- observers -------------------------------------------------------------- // -- observers --------------------------------------------------------------
......
...@@ -220,8 +220,8 @@ public: ...@@ -220,8 +220,8 @@ public:
using super::copy; using super::copy;
message_data::cow_ptr copy() const override { message_data* copy() const override {
return message_data::cow_ptr(new tuple_vals(*this), false); return new tuple_vals(*this);
} }
}; };
......
...@@ -248,9 +248,14 @@ class message_data; ...@@ -248,9 +248,14 @@ class message_data;
class private_thread; class private_thread;
class uri_impl; class uri_impl;
void intrusive_ptr_add_ref(const uri_impl* p); // enable intrusive_ptr<uri_impl> with forward declaration only
void intrusive_ptr_add_ref(const uri_impl*);
void intrusive_ptr_release(const uri_impl* p); void intrusive_ptr_release(const uri_impl*);
// enable intrusive_cow_ptr<dynamic_message_data> with forward declaration only
void intrusive_ptr_add_ref(const dynamic_message_data*);
void intrusive_ptr_release(const dynamic_message_data*);
dynamic_message_data* intrusive_cow_ptr_unshare(dynamic_message_data*&);
} // namespace detail } // namespace detail
......
...@@ -19,11 +19,29 @@ ...@@ -19,11 +19,29 @@
#pragma once #pragma once
#include <cstddef> #include <cstddef>
#include <cstdint>
#include "caf/intrusive_ptr.hpp" #include "caf/intrusive_ptr.hpp"
namespace caf { namespace caf {
/// Default implementation for unsharing values.
/// @relates intrusive_cow_ptr
template <class T>
T* default_intrusive_cow_ptr_unshare(T*& ptr) {
if (!ptr->unique())
ptr = ptr->copy();
return ptr;
}
/// Customization point for allowing intrusive_cow_ptr<T> with a forward
/// declared T.
/// @relates intrusive_cow_ptr
template <class T>
T* intrusive_cow_ptr_unshare(T*& ptr) {
return default_intrusive_cow_ptr_unshare(ptr);
}
/// An intrusive, reference counting smart pointer implementation with /// An intrusive, reference counting smart pointer implementation with
/// copy-on-write optimization. /// copy-on-write optimization.
/// @relates ref_counted /// @relates ref_counted
...@@ -49,7 +67,7 @@ public: ...@@ -49,7 +67,7 @@ public:
using counting_pointer = intrusive_ptr<T>; using counting_pointer = intrusive_ptr<T>;
// -- constructors, destructors, and assignment operators ------------------ // -- constructors, destructors, and assignment operators --------------------
intrusive_cow_ptr() noexcept = default; intrusive_cow_ptr() noexcept = default;
...@@ -57,6 +75,12 @@ public: ...@@ -57,6 +75,12 @@ public:
intrusive_cow_ptr(const intrusive_cow_ptr&) noexcept = default; intrusive_cow_ptr(const intrusive_cow_ptr&) noexcept = default;
template <class Y>
intrusive_cow_ptr(intrusive_cow_ptr<Y> other) noexcept
: ptr_(other.detach(), false) {
// nop
}
explicit intrusive_cow_ptr(counting_pointer p) noexcept : ptr_(std::move(p)) { explicit intrusive_cow_ptr(counting_pointer p) noexcept : ptr_(std::move(p)) {
// nop // nop
} }
...@@ -75,14 +99,14 @@ public: ...@@ -75,14 +99,14 @@ public:
return *this; return *this;
} }
// -- comparison ----------------------------------------------------------- // -- comparison -------------------------------------------------------------
ptrdiff_t compare(std::nullptr_t) const noexcept { ptrdiff_t compare(std::nullptr_t) const noexcept {
return reinterpret_cast<ptrdiff_t>(get()); return reinterpret_cast<ptrdiff_t>(get());
} }
ptrdiff_t compare(const_pointer ptr) const noexcept { ptrdiff_t compare(const_pointer ptr) const noexcept {
return static_cast<ptrdiff_t>(get() - ptr); return reinterpret_cast<intptr_t>(get()) - reinterpret_cast<intptr_t>(ptr);
} }
ptrdiff_t compare(const counting_pointer& other) const noexcept { ptrdiff_t compare(const counting_pointer& other) const noexcept {
...@@ -93,7 +117,7 @@ public: ...@@ -93,7 +117,7 @@ public:
return compare(other.get()); return compare(other.get());
} }
// -- modifiers ------------------------------------------------------------ // -- modifiers --------------------------------------------------------------
/// Swaps the managed object with `other`. /// Swaps the managed object with `other`.
void swap(intrusive_cow_ptr& other) noexcept { void swap(intrusive_cow_ptr& other) noexcept {
...@@ -121,30 +145,20 @@ public: ...@@ -121,30 +145,20 @@ public:
/// count of exactly 1. /// count of exactly 1.
void unshare() { void unshare() {
if (ptr_ != nullptr) if (ptr_ != nullptr)
static_cast<void>(get_unshared()); static_cast<void>(unshared());
} }
/// Returns a mutable pointer to the managed object. /// Returns a mutable pointer to the managed object.
pointer operator->() { pointer unshared_ptr() {
return get_unshared(); return intrusive_cow_ptr_unshare(ptr_.ptr_);
} }
/// Returns a mutable reference to the managed object. /// Returns a mutable reference to the managed object.
reference operator*() { reference unshared() {
return *get_unshared(); return *unshared_ptr();
} }
/// Returns a mutable pointer to the managed object. // -- observers --------------------------------------------------------------
pointer get_unshared() {
auto p = ptr_.get();
if (!p->unique()) {
copy_reset(p->copy());
return ptr_.get();
}
return p;
}
// -- observers ------------------------------------------------------------
/// Returns a read-only pointer to the managed object. /// Returns a read-only pointer to the managed object.
const_pointer get() const noexcept { const_pointer get() const noexcept {
...@@ -171,21 +185,6 @@ public: ...@@ -171,21 +185,6 @@ public:
} }
private: private:
// -- allow T::copy to return raw, intrusive, or COW pointer -----------------
void copy_reset(pointer x) {
// Reference counted objects start with a reference count of 1.
reset(x, false);
}
void copy_reset(counting_pointer x) {
ptr_.swap(x);
}
void copy_reset(intrusive_cow_ptr x) {
swap(x);
}
// -- member vairables ------------------------------------------------------- // -- member vairables -------------------------------------------------------
counting_pointer ptr_; counting_pointer ptr_;
......
...@@ -27,6 +27,7 @@ ...@@ -27,6 +27,7 @@
#include "caf/detail/append_hex.hpp" #include "caf/detail/append_hex.hpp"
#include "caf/detail/comparable.hpp" #include "caf/detail/comparable.hpp"
#include "caf/detail/type_traits.hpp" #include "caf/detail/type_traits.hpp"
#include "caf/fwd.hpp"
namespace caf { namespace caf {
...@@ -35,15 +36,30 @@ namespace caf { ...@@ -35,15 +36,30 @@ namespace caf {
template <class T> template <class T>
class intrusive_ptr { class intrusive_ptr {
public: public:
// -- friends ----------------------------------------------------------------
template <class>
friend class intrusive_cow_ptr;
// -- member types -----------------------------------------------------------
using pointer = T*; using pointer = T*;
using const_pointer = const T*; using const_pointer = const T*;
using element_type = T; using element_type = T;
using reference = T&; using reference = T&;
using const_reference = const T&; using const_reference = const T&;
// -- constants --------------------------------------------------------------
// tell actor_cast which semantic this type uses // tell actor_cast which semantic this type uses
static constexpr bool has_weak_ptr_semantics = false; static constexpr bool has_weak_ptr_semantics = false;
// -- constructors, destructors, and assignment operators --------------------
constexpr intrusive_ptr() noexcept : ptr_(nullptr) { constexpr intrusive_ptr() noexcept : ptr_(nullptr) {
// nop // nop
} }
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright 2011-2018 Dominik Charousset *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#pragma once
#include "caf/intrusive_cow_ptr.hpp"
namespace caf {
/// Constructs an object of type `T` in an `intrusive_cow_ptr`.
/// @relates ref_counted
/// @relates intrusive_cow_ptr
template <class T, class... Ts>
intrusive_cow_ptr<T> make_copy_on_write(Ts&&... xs) {
return intrusive_cow_ptr<T>(new T(std::forward<Ts>(xs)...), false);
}
} // namespace caf
...@@ -258,7 +258,7 @@ public: ...@@ -258,7 +258,7 @@ public:
/// @pre `!empty()` /// @pre `!empty()`
inline type_erased_tuple& content() { inline type_erased_tuple& content() {
CAF_ASSERT(vals_ != nullptr); CAF_ASSERT(vals_ != nullptr);
return *vals_; return vals_.unshared();
} }
inline const type_erased_tuple& content() const { inline const type_erased_tuple& content() const {
......
...@@ -133,11 +133,7 @@ private: ...@@ -133,11 +133,7 @@ private:
message_builder& emplace(type_erased_value_ptr); message_builder& emplace(type_erased_value_ptr);
detail::dynamic_message_data* data(); intrusive_cow_ptr<detail::dynamic_message_data> data_;
const detail::dynamic_message_data* data() const;
intrusive_ptr<ref_counted> data_; // hide dynamic_message_data implementation
}; };
} // namespace caf } // namespace caf
......
...@@ -53,8 +53,8 @@ auto concatenated_tuple::make(std::initializer_list<cow_ptr> xs) -> cow_ptr { ...@@ -53,8 +53,8 @@ auto concatenated_tuple::make(std::initializer_list<cow_ptr> xs) -> cow_ptr {
return cow_ptr{make_counted<concatenated_tuple>(xs)}; return cow_ptr{make_counted<concatenated_tuple>(xs)};
} }
message_data::cow_ptr concatenated_tuple::copy() const { concatenated_tuple* concatenated_tuple::copy() const {
return cow_ptr(new concatenated_tuple(*this), false); return new concatenated_tuple(*this);
} }
void* concatenated_tuple::get_mutable(size_t pos) { void* concatenated_tuple::get_mutable(size_t pos) {
...@@ -114,7 +114,7 @@ std::pair<message_data*, size_t> concatenated_tuple::select(size_t pos) { ...@@ -114,7 +114,7 @@ std::pair<message_data*, size_t> concatenated_tuple::select(size_t pos) {
if (idx >= s) if (idx >= s)
idx -= s; idx -= s;
else else
return {m.get_unshared(), idx}; return {m.unshared_ptr(), idx};
} }
CAF_RAISE_ERROR(std::out_of_range, "concatenated_tuple::select out of range"); CAF_RAISE_ERROR(std::out_of_range, "concatenated_tuple::select out of range");
} }
......
...@@ -49,18 +49,18 @@ decorated_tuple::cow_ptr decorated_tuple::make(cow_ptr d, vector_type v) { ...@@ -49,18 +49,18 @@ decorated_tuple::cow_ptr decorated_tuple::make(cow_ptr d, vector_type v) {
return decorated_tuple::cow_ptr{res}; return decorated_tuple::cow_ptr{res};
} }
message_data::cow_ptr decorated_tuple::copy() const { message_data* decorated_tuple::copy() const {
return cow_ptr(new decorated_tuple(*this), false); return new decorated_tuple(*this);
} }
void* decorated_tuple::get_mutable(size_t pos) { void* decorated_tuple::get_mutable(size_t pos) {
CAF_ASSERT(pos < size()); CAF_ASSERT(pos < size());
return decorated_->get_mutable(mapping_[pos]); return decorated_.unshared().get_mutable(mapping_[pos]);
} }
error decorated_tuple::load(size_t pos, deserializer& source) { error decorated_tuple::load(size_t pos, deserializer& source) {
CAF_ASSERT(pos < size()); CAF_ASSERT(pos < size());
return decorated_->load(mapping_[pos], source); return decorated_.unshared().load(mapping_[pos], source);
} }
size_t decorated_tuple::size() const noexcept { size_t decorated_tuple::size() const noexcept {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include "caf/detail/dynamic_message_data.hpp" #include "caf/detail/dynamic_message_data.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/intrusive_cow_ptr.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
namespace caf { namespace caf {
...@@ -48,8 +49,8 @@ dynamic_message_data::~dynamic_message_data() { ...@@ -48,8 +49,8 @@ dynamic_message_data::~dynamic_message_data() {
// nop // nop
} }
message_data::cow_ptr dynamic_message_data::copy() const { dynamic_message_data* dynamic_message_data::copy() const {
return message_data::cow_ptr{make_counted<dynamic_message_data>(*this)}; return new dynamic_message_data(*this);
} }
void* dynamic_message_data::get_mutable(size_t pos) { void* dynamic_message_data::get_mutable(size_t pos) {
...@@ -109,5 +110,17 @@ void dynamic_message_data::add_to_type_token(uint16_t typenr) { ...@@ -109,5 +110,17 @@ void dynamic_message_data::add_to_type_token(uint16_t typenr) {
type_token_ = (type_token_ << 6) | typenr; type_token_ = (type_token_ << 6) | typenr;
} }
void intrusive_ptr_add_ref(const dynamic_message_data* ptr) {
intrusive_ptr_add_ref(static_cast<const ref_counted*>(ptr));
}
void intrusive_ptr_release(const dynamic_message_data* ptr) {
intrusive_ptr_release(static_cast<const ref_counted*>(ptr));
}
dynamic_message_data* intrusive_cow_ptr_unshare(dynamic_message_data*& ptr) {
return default_intrusive_cow_ptr_unshare(ptr);
}
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -53,20 +53,20 @@ merged_tuple::merged_tuple(data_type xs, mapping_type ys) ...@@ -53,20 +53,20 @@ merged_tuple::merged_tuple(data_type xs, mapping_type ys)
} }
} }
merged_tuple::cow_ptr merged_tuple::copy() const { merged_tuple* merged_tuple::copy() const {
return cow_ptr{make_counted<merged_tuple>(data_, mapping_)}; return new merged_tuple(data_, mapping_);
} }
void* merged_tuple::get_mutable(size_t pos) { void* merged_tuple::get_mutable(size_t pos) {
CAF_ASSERT(pos < mapping_.size()); CAF_ASSERT(pos < mapping_.size());
auto& p = mapping_[pos]; auto& p = mapping_[pos];
return data_[p.first]->get_mutable(p.second); return data_[p.first].unshared().get_mutable(p.second);
} }
error merged_tuple::load(size_t pos, deserializer& source) { error merged_tuple::load(size_t pos, deserializer& source) {
CAF_ASSERT(pos < mapping_.size()); CAF_ASSERT(pos < mapping_.size());
auto& p = mapping_[pos]; auto& p = mapping_[pos];
return data_[p.first]->load(p.second, source); return data_[p.first].unshared().load(p.second, source);
} }
size_t merged_tuple::size() const noexcept { size_t merged_tuple::size() const noexcept {
......
...@@ -60,13 +60,13 @@ message::~message() { ...@@ -60,13 +60,13 @@ message::~message() {
void* message::get_mutable(size_t p) { void* message::get_mutable(size_t p) {
CAF_ASSERT(vals_ != nullptr); CAF_ASSERT(vals_ != nullptr);
return vals_->get_mutable(p); return vals_.unshared().get_mutable(p);
} }
error message::load(size_t pos, deserializer& source) { error message::load(size_t pos, deserializer& source) {
CAF_ASSERT(vals_ != nullptr); CAF_ASSERT(vals_ != nullptr);
return vals_->load(pos, source); return vals_.unshared().load(pos, source);
} }
size_t message::size() const noexcept { size_t message::size() const noexcept {
......
...@@ -16,12 +16,13 @@ ...@@ -16,12 +16,13 @@
* http://www.boost.org/LICENSE_1_0.txt. * * http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/ ******************************************************************************/
#include <vector>
#include "caf/message_builder.hpp" #include "caf/message_builder.hpp"
#include "caf/message_handler.hpp"
#include <vector>
#include "caf/detail/dynamic_message_data.hpp" #include "caf/detail/dynamic_message_data.hpp"
#include "caf/make_copy_on_write.hpp"
#include "caf/message_handler.hpp"
namespace caf { namespace caf {
...@@ -37,15 +38,18 @@ void message_builder::init() { ...@@ -37,15 +38,18 @@ void message_builder::init() {
// this should really be done by delegating // this should really be done by delegating
// constructors, but we want to support // constructors, but we want to support
// some compilers without that feature... // some compilers without that feature...
data_ = make_counted<detail::dynamic_message_data>(); data_ = make_copy_on_write<detail::dynamic_message_data>();
} }
void message_builder::clear() { void message_builder::clear() {
data()->clear(); if (data_->unique())
data_.unshared().clear();
else
init();
} }
size_t message_builder::size() const { size_t message_builder::size() const {
return data()->size(); return data_->size();
} }
bool message_builder::empty() const { bool message_builder::empty() const {
...@@ -53,23 +57,16 @@ bool message_builder::empty() const { ...@@ -53,23 +57,16 @@ bool message_builder::empty() const {
} }
message_builder& message_builder::emplace(type_erased_value_ptr x) { message_builder& message_builder::emplace(type_erased_value_ptr x) {
data()->append(std::move(x)); data_.unshared().append(std::move(x));
return *this; return *this;
} }
message message_builder::to_message() const { message message_builder::to_message() const {
// this const_cast is safe, because the message is return message{data_};
// guaranteed to detach its data before modifying it
detail::message_data::cow_ptr ptr;
ptr.reset(const_cast<detail::dynamic_message_data*>(data()));
return message{std::move(ptr)};
} }
message message_builder::move_to_message() { message message_builder::move_to_message() {
message result; return message{std::move(data_)};
using pointer = detail::dynamic_message_data*;
result.vals().reset(static_cast<pointer>(data_.detach()), false);
return result;
} }
message message_builder::extract(message_handler f) const { message message_builder::extract(message_handler f) const {
...@@ -77,29 +74,13 @@ message message_builder::extract(message_handler f) const { ...@@ -77,29 +74,13 @@ message message_builder::extract(message_handler f) const {
} }
optional<message> message_builder::apply(message_handler handler) { optional<message> message_builder::apply(message_handler handler) {
// avoid detaching of data_ by moving the data to a message object, // Avoid detaching of data_ by moving the data to a message object,
// calling message::apply and moving the data back // calling message::apply and moving the data back.
message::data_ptr ptr; auto msg = move_to_message();
ptr.reset(static_cast<detail::dynamic_message_data*>(data_.detach()), false);
message msg{std::move(ptr)};
auto res = msg.apply(std::move(handler)); auto res = msg.apply(std::move(handler));
data_.reset(msg.vals().release(), false); data_.reset(static_cast<detail::dynamic_message_data*>(msg.vals().release()),
false);
return res; return res;
} }
detail::dynamic_message_data* message_builder::data() {
// detach if needed, i.e., assume further non-const
// operations on data_ can cause race conditions if
// someone else holds a reference to data_
if (!data_->unique()) {
auto tmp = static_cast<detail::dynamic_message_data*>(data_.get())->copy();
data_.reset(tmp.release(), false);
}
return static_cast<detail::dynamic_message_data*>(data_.get());
}
const detail::dynamic_message_data* message_builder::data() const {
return static_cast<const detail::dynamic_message_data*>(data_.get());
}
} // namespace caf } // namespace caf
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment