Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mapsme/omim.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/base
diff options
context:
space:
mode:
authorYuri Gorshenin <y@maps.me>2016-07-04 16:24:47 +0300
committerYuri Gorshenin <y@maps.me>2016-07-05 12:40:47 +0300
commit7df300bc547e7fbb845ff3cedf95d27b61a7ad73 (patch)
treed058fe814917d70bf9cff3e95f4eb11bd6c15c4e /base
parent36fe4a08508b790a16677465e2e0ed5db70f0414 (diff)
Minor fixes - get rid of redundant copying.
Diffstat (limited to 'base')
-rw-r--r--base/base.pro1
-rw-r--r--base/base_tests/base_tests.pro1
-rw-r--r--base/base_tests/ref_counted_tests.cpp78
-rw-r--r--base/ref_counted.hpp107
4 files changed, 187 insertions, 0 deletions
diff --git a/base/base.pro b/base/base.pro
index 934e3298ac..49052f5b1a 100644
--- a/base/base.pro
+++ b/base/base.pro
@@ -57,6 +57,7 @@ HEADERS += \
object_tracker.hpp \
observer_list.hpp \
range_iterator.hpp \
+ ref_counted.hpp \
regexp.hpp \
rolling_hash.hpp \
scope_guard.hpp \
diff --git a/base/base_tests/base_tests.pro b/base/base_tests/base_tests.pro
index c447870577..7624cc052f 100644
--- a/base/base_tests/base_tests.pro
+++ b/base/base_tests/base_tests.pro
@@ -28,6 +28,7 @@ SOURCES += \
mem_trie_test.cpp \
observer_list_test.cpp \
range_iterator_test.cpp \
+ ref_counted_tests.cpp \
regexp_test.cpp \
rolling_hash_test.cpp \
scope_guard_test.cpp \
diff --git a/base/base_tests/ref_counted_tests.cpp b/base/base_tests/ref_counted_tests.cpp
new file mode 100644
index 0000000000..de27a7c01f
--- /dev/null
+++ b/base/base_tests/ref_counted_tests.cpp
@@ -0,0 +1,78 @@
+#include "testing/testing.hpp"
+
+#include "base/ref_counted.hpp"
+
+using namespace my;
+
+namespace
+{
+struct Resource : public RefCounted
+{
+ Resource(bool & destroyed) : m_destroyed(destroyed) {}
+ ~Resource() override { m_destroyed = true; }
+
+ bool & m_destroyed;
+};
+
+UNIT_TEST(RefCounted_Smoke)
+{
+ {
+ RefCountPtr<Resource> p;
+ }
+
+ {
+ bool destroyed = false;
+ {
+ RefCountPtr<Resource> p(new Resource(destroyed));
+ TEST_EQUAL(1, p->NumRefs(), ());
+ TEST(!destroyed, ());
+ }
+ TEST(destroyed, ());
+ }
+
+ {
+ bool destroyed = false;
+ {
+ RefCountPtr<Resource> a(new Resource(destroyed));
+ TEST_EQUAL(1, a->NumRefs(), ());
+ TEST(!destroyed, ());
+
+ RefCountPtr<Resource> b(a);
+ TEST(a.Get() == b.Get(), ());
+ TEST_EQUAL(2, a->NumRefs(), ());
+ TEST(!destroyed, ());
+
+ {
+ RefCountPtr<Resource> c;
+ TEST(c.Get() == nullptr, ());
+
+ c = b;
+ TEST(a.Get() == b.Get(), ());
+ TEST(b.Get() == c.Get(), ());
+ TEST_EQUAL(3, a->NumRefs(), ());
+ TEST(!destroyed, ());
+ }
+
+ TEST(a.Get() == b.Get(), ());
+ TEST_EQUAL(2, a->NumRefs(), ());
+ TEST(!destroyed, ());
+
+ RefCountPtr<Resource> d(move(b));
+ TEST(b.Get() == nullptr, ());
+ TEST(a.Get() == d.Get(), ());
+ TEST_EQUAL(2, a->NumRefs(), ());
+ TEST(!destroyed, ());
+
+ a = a;
+ TEST_EQUAL(a.Get(), d.Get(), ());
+ TEST_EQUAL(2, a->NumRefs(), ());
+ TEST(!destroyed, ());
+
+ TEST_EQUAL(a.Get(), d.Get(), ());
+ TEST_EQUAL(2, a->NumRefs(), ());
+ TEST(!destroyed, ());
+ }
+ TEST(destroyed, ());
+ }
+}
+} // namespace
diff --git a/base/ref_counted.hpp b/base/ref_counted.hpp
new file mode 100644
index 0000000000..54feffc08b
--- /dev/null
+++ b/base/ref_counted.hpp
@@ -0,0 +1,107 @@
+#pragma once
+
+#include "base/macros.hpp"
+
+#include "std/cstdint.hpp"
+#include "std/unique_ptr.hpp"
+
+namespace my
+{
+class RefCounted
+{
+public:
+ virtual ~RefCounted() = default;
+
+ inline void IncRef() noexcept { ++m_refs; }
+ inline uint64_t DecRef() noexcept { return --m_refs; }
+ inline uint64_t NumRefs() const noexcept { return m_refs; }
+
+protected:
+ RefCounted() noexcept = default;
+
+ uint64_t m_refs = 0;
+
+ DISALLOW_COPY_AND_MOVE(RefCounted);
+};
+
+template <typename T>
+class RefCountPtr
+{
+public:
+ RefCountPtr() noexcept = default;
+
+ explicit RefCountPtr(T * p) noexcept : m_p(p)
+ {
+ if (m_p)
+ m_p->IncRef();
+ }
+
+ explicit RefCountPtr(unique_ptr<T> p) noexcept : RefCountPtr(p.release()) {}
+
+ RefCountPtr(RefCountPtr const & rhs) { *this = rhs; }
+
+ RefCountPtr(RefCountPtr && rhs) { *this = move(rhs); }
+
+ ~RefCountPtr() { Reset(); }
+
+ RefCountPtr & operator=(unique_ptr<T> p)
+ {
+ Reset();
+
+ m_p = p.release();
+ if (m_p)
+ m_p->IncRef();
+
+ return *this;
+ }
+
+ RefCountPtr & operator=(RefCountPtr const & rhs)
+ {
+ if (this == &rhs)
+ return *this;
+
+ Reset();
+ m_p = rhs.m_p;
+ if (m_p)
+ m_p->IncRef();
+
+ return *this;
+ }
+
+ RefCountPtr & operator=(RefCountPtr && rhs)
+ {
+ if (this == &rhs)
+ return *this;
+
+ Reset();
+ m_p = rhs.m_p;
+ rhs.m_p = nullptr;
+
+ return *this;
+ }
+
+ void Reset()
+ {
+ if (!m_p)
+ return;
+
+ if (m_p->DecRef() == 0)
+ delete m_p;
+ m_p = nullptr;
+ }
+
+ T * Get() noexcept { return m_p; }
+ T const * Get() const noexcept { return m_p; }
+
+ T & operator*() { return *m_p; }
+ T const & operator*() const { return *m_p; }
+
+ T * operator->() noexcept { return m_p; }
+ T const * operator->() const noexcept { return m_p; }
+
+ inline operator bool() const noexcept { return m_p != nullptr; }
+
+private:
+ T * m_p = nullptr;
+};
+} // namespace my