aboutsummaryrefslogtreecommitdiff
path: root/butl
diff options
context:
space:
mode:
authorBoris Kolpackov <boris@codesynthesis.com>2017-02-07 08:08:43 +0200
committerBoris Kolpackov <boris@codesynthesis.com>2017-02-07 08:08:43 +0200
commit0b383b72841e4af2890d082e4caed3119484fe95 (patch)
tree7b09b6cc4d73828a51063a4f6f38c411fb449c30 /butl
parentbfae9dab4b2e3ddaf13e82a6c24c0684de9e0d48 (diff)
Add const_ptr, const-propagating smart pointer
Diffstat (limited to 'butl')
-rw-r--r--butl/buildfile1
-rw-r--r--butl/const-ptr77
2 files changed, 78 insertions, 0 deletions
diff --git a/butl/buildfile b/butl/buildfile
index 734195e..090f9ed 100644
--- a/butl/buildfile
+++ b/butl/buildfile
@@ -5,6 +5,7 @@
lib{butl}: \
{hxx cxx}{ base64 } \
{hxx cxx}{ char-scanner } \
+ {hxx }{ const-ptr } \
{hxx cxx}{ diagnostics } \
{hxx }{ export } \
{hxx ixx cxx}{ fdstream } \
diff --git a/butl/const-ptr b/butl/const-ptr
new file mode 100644
index 0000000..23686bc
--- /dev/null
+++ b/butl/const-ptr
@@ -0,0 +1,77 @@
+// file : butl/const-ptr -*- C++ -*-
+// copyright : Copyright (c) 2014-2017 Code Synthesis Ltd
+// license : MIT; see accompanying LICENSE file
+
+#ifndef BUTL_CONST_PTR
+#define BUTL_CONST_PTR
+
+#include <cstddef> // nullptr_t
+
+namespace butl
+{
+ // Const-propagating pointer.
+ //
+ // It has the semantics of a raw pointer except that it passes on its own
+ // const-ness to the pointed-to object. In other words, if you have a const
+ // instance of this pointer, then you can only obtain a const raw pointer to
+ // the underlying object. It is normally used as a data member, for example:
+ //
+ // struct tree
+ // {
+ // const_ptr<tree> left;
+ // const_ptr<tree> right;
+ //
+ // void modify ();
+ // };
+ //
+ // tree* x = ...;
+ // const tree* y = ...;
+ //
+ // x.left->modify (); // Ok.
+ // y.left->modify (); // Error.
+ //
+ // Note that due to this semantics, copy construction/assignment requires
+ // a non-const instance of const_ptr.
+ //
+ // Known drawbacks/issues:
+ //
+ // 1. Cannot do static_cast<mytree*> (x.left).
+ //
+ template <typename T>
+ class const_ptr
+ {
+ public:
+ const_ptr () = default;
+ explicit const_ptr (T* p): p_ (p) {}
+ const_ptr (std::nullptr_t): p_ (nullptr) {}
+
+ const_ptr& operator= (T* p) {p_ = p; return *this;}
+ const_ptr& operator= (std::nullptr_t) {p_ = nullptr; return *this;}
+
+ template <class T1> explicit const_ptr (T1* p): p_ (p) {}
+ template <class T1> const_ptr (const_ptr<T1>& p): p_ (p.p_) {}
+
+ template <class T1> const_ptr& operator= (T1* p) {p_ = p; return *this;}
+ template <class T1> const_ptr& operator= (const_ptr<T1>& p) {
+ p_ = p.p_; return *this;}
+
+ T* operator-> () {return p_;}
+ const T* operator-> () const {return p_;}
+
+ T& operator* () {return *p_;}
+ const T& operator* () const {return *p_;}
+
+ operator T* () {return p_;}
+ operator const T* () const {return p_;}
+
+ explicit operator bool () const {return p_ != nullptr;}
+
+ T* get () {return p_;}
+ const T* get () const {return p_;}
+
+ private:
+ T* p_;
+ };
+};
+
+#endif // BUTL_CONST_PTR