#include #include "common/util/Assert.h" /* template std::unique_ptr make_unique(Args&&... args) { return std::unique_ptr(new T(std::forward(args)...)); } */ /*! * The CopyOnWrite class acts like a value, but internally uses references to avoid copying * when it is possible to avoid it. * * It is used like a shared pointer. * But, if you try to modify an existing object with multiple owners, it will make a copy * so the other owners don't see any changes. In this way, it does not act like a reference. * * To construct a new object, use CopyOnWrite(args...). This is different from the usual smart * pointer pattern. * * Like shared pointers, a CopyOnWrite can be null. Doing mut() just gives you a null pointer. * * The default .get(), ->, and * operators give you const references. If you need to modify, * use .mut(). It will create a copy if needed, then give you a mutable reference. */ template class CopyOnWrite { private: // we store the object and its reference count in the same heap allocation. struct ObjectAndCount { T object; // construct the object in-place, or copy construct from an existing. template explicit ObjectAndCount(Args&&... args) : object(std::forward(args)...) {} explicit ObjectAndCount(const T& existing) : object(existing) {} // in case we ever want this to have locks. void add_ref() { m_count++; } void remove_ref() { m_count--; } bool unique() { return m_count == 1; } bool dead() { return m_count == 0; } private: int m_count = 0; }; public: CopyOnWrite() = default; // allow nulls. /*! * Construct a new object. */ template explicit CopyOnWrite(Args&&... args) { auto obj = new ObjectAndCount(std::forward(args)...); acquire_object(obj); } /*! * Copy an object. */ CopyOnWrite(const CopyOnWrite& other) { acquire_object(other.m_data); } CopyOnWrite& operator=(const CopyOnWrite& other) { if (this == &other) { return *this; } if (m_data != other.m_data) { clear_my_object(); acquire_object(other.m_data); } return *this; } ~CopyOnWrite() { clear_my_object(); } // constant access const T* get() const { return &m_data->object; } const T* operator->() const { return &m_data->object; } const T& operator*() const { return m_data->object; } explicit operator bool() const { return m_data; } T* mut() { if (!m_data) { return nullptr; } if (!m_data->unique()) { ASSERT(!m_data->dead()); m_data->remove_ref(); // don't need to check for dead here, there's another ref somewhere. ASSERT(!m_data->dead()); m_data = new ObjectAndCount(m_data->object); m_data->add_ref(); } return &m_data->object; } private: void clear_my_object() { if (m_data) { m_data->remove_ref(); if (m_data->dead()) { delete m_data; } } m_data = nullptr; } void acquire_object(ObjectAndCount* obj) { ASSERT(!m_data); m_data = obj; if (obj) { m_data->add_ref(); } } ObjectAndCount* m_data = nullptr; };