From: David Howells Date: Wed, 26 Aug 2020 08:57:22 +0000 (+0100) Subject: Implement a magic-pointer X-Git-Url: https://www.infradead.org/git/?a=commitdiff_plain;h=07db9a8f641c04e4e8c595b92c98296a51faf12e;p=users%2Fdhowells%2Fkafs-utils.git Implement a magic-pointer 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 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 This is like 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. (*) 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 --- diff --git a/lib/pointer.H b/lib/pointer.H new file mode 100644 index 0000000..cedb1b4 --- /dev/null +++ b/lib/pointer.H @@ -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 + +namespace rxrpc { + +template class ref; + +/* + * Refcounting base class, for use in objects pointed to by class ref<>. + */ +struct refcount { + template 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 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(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 &p) { set(p.ptr); } + template ref(ref &p) { Q *q = p.get_ptr(); set(q); } + template ref(const ref &p) { Q *q = p.get_ptr(); set(q); } + + void operator=(T *p) { assign(p); } + void operator=(const ref &p) { assign(p.ptr); } + template void operator=(const ref &p) { assign(p); } + template 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 operator ref *() { return dynamic_cast(ptr); } + //template operator Q *() { return dynamic_cast(ptr); } + template Q *cast() { return dynamic_cast(ptr); } +}; + +} /* end namespace rxrpc */ + +#endif /* POINTER_H */