]> www.infradead.org Git - users/dhowells/kafs-utils.git/commitdiff
Implement a magic-pointer
authorDavid Howells <dhowells@redhat.com>
Wed, 26 Aug 2020 08:57:22 +0000 (09:57 +0100)
committerDavid Howells <dhowells@redhat.com>
Tue, 4 May 2021 13:43:57 +0000 (14:43 +0100)
Implement a magic-pointer that manages objects based on a refcount held in
the pointed-to object.

The following classes are implemented:

 (*) refcount

     This class holds the refcount and is intended to be subclassed by any
     object that will be pointed to.

 (*) ref<to_class>

     This is a template pointer class that pins a reference on the object
     it points to, which must be of or derived from type to_class.
     to_class must be derived from class refcount.

 (*) pointer<to_class>

     This is like ref<to_class> but doesn't pin a reference.  It has no
     copy constructor, thereby allowing it to be passed in a register as an
     argument or a return value.

 (*) opaque_ref

     This class points to any object derived from class refcount and will
     pin a reference on the object.

 (*) opaque_pointer

     This is like class opaque_ref, but doesn't pin a reference.  It has no
     copy constructor, thereby allowing it to be passed in a register as an
     argument or a return value.

Objects can be assigned between any pair of classes.  Assigning from an
opaque ref/pointer to a template-typed ref/pointer will dynamic_cast the
value (if it's not NULL).

Signed-off-by: David Howells <dhowells@redhat.com>
lib/pointer.H [new file with mode: 0644]

diff --git a/lib/pointer.H b/lib/pointer.H
new file mode 100644 (file)
index 0000000..cedb1b4
--- /dev/null
@@ -0,0 +1,97 @@
+/* Automatic refcounter pointer class
+ *
+ * Copyright (C) 2020 Red Hat, Inc. All Rights Reserved.
+ * Written by David Howells (dhowells@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public Licence
+ * as published by the Free Software Foundation; either version
+ * 2 of the Licence, or (at your option) any later version.
+ */
+
+#ifndef POINTER_H
+#define POINTER_H
+
+#include <fmt/core.h>
+
+namespace rxrpc {
+
+template <class T> class ref;
+
+/*
+ * Refcounting base class, for use in objects pointed to by class ref<>.
+ */
+struct refcount {
+       template<class T> friend class ref;
+protected:
+       int usage;
+
+       virtual void get() { usage++; }
+       virtual void put() { if (--usage == 0) { delete this; } }
+public:
+       refcount() { usage = 0; }
+       virtual ~refcount() = 0;
+       inline int get_refcount() const { return usage; }
+};
+
+/*
+ * Typed pointer class.  Holds a reference on an object of type T that's a
+ * subclass of the refcount class.
+ */
+template <class T>
+class ref {
+private:
+       T *ptr;
+       void set(T *p)          { ptr = p; if (p) ptr->refcount::get(); }
+       void clear()            { if (ptr) ptr->refcount::put(); }
+       void assign(T *p)       { clear(); set(p); }
+
+       inline void set_cast(refcount *c)
+               {
+                       if (c) {
+                               T *t = dynamic_cast<T *>(c);
+                               if (!t)
+                                       throw std::logic_error("Type mismatch");
+                               set(t);
+                       } else {
+                               set(NULL);
+                       }
+               }
+public:
+       inline void assign_cast(refcount *c)
+               {
+                       clear();
+                       set_cast(c);
+               }
+       inline T *get_ptr()             const   { return ptr; }
+
+       ~ref()                                          { clear(); }
+       ref()                           : ptr(NULL)     { }
+       ref(T *p)                                       { set(p); }
+       ref(const ref<T> &p)                            { set(p.ptr); }
+       template <class Q> ref(ref<Q> &p)               { Q *q = p.get_ptr(); set(q); }
+       template <class Q> ref(const ref<Q> &p)         { Q *q = p.get_ptr(); set(q); }
+
+       void operator=(T *p)                            { assign(p); }
+       void operator=(const ref<T> &p)                 { assign(p.ptr); }
+       template <class Q> void operator=(const ref<Q> &p) { assign(p); }
+       template <class Q> void operator=(Q *p)         { assign(p); }
+
+       T &operator*()                          { return *(T *)ptr; }
+       const T &operator*()            const   { return *(T *)ptr; }
+       T *operator->()                         { return (T *)ptr; }
+       const T *operator->()           const   { return (T *)ptr; }
+       operator T *()                          { return ptr; }
+       operator const T *()            const   { return ptr; }
+       operator unsigned long()        const   { return (unsigned long)ptr; }
+       operator bool()                 const   { return ptr; }
+       bool operator!()                const   { return !ptr; }
+
+       //template <class Q> operator ref<Q> *() { return dynamic_cast<Q *>(ptr); }
+       //template <class Q> operator Q *() { return dynamic_cast<Q *>(ptr); }
+       template <class Q> Q *cast() { return dynamic_cast<Q *>(ptr); }
+};
+
+} /* end namespace rxrpc */
+
+#endif /* POINTER_H */