diff --git a/include/xo/facet/facet.hpp b/include/xo/facet/facet.hpp index 47abae4..b1a420a 100644 --- a/include/xo/facet/facet.hpp +++ b/include/xo/facet/facet.hpp @@ -70,7 +70,7 @@ namespace xo { "Abstract facet expected to have trivial dtor since no state"); static_assert (requires(T & facet) { - { facet._typeseq() } -> std::convertible_to; }, + { facet._typeseq().seqno() } -> std::convertible_to; }, "Abstract facet must provide a _typeseq() method for safe downcasting"); return true; }; diff --git a/include/xo/facet/typeseq.hpp b/include/xo/facet/typeseq.hpp index d54ac98..b108874 100644 --- a/include/xo/facet/typeseq.hpp +++ b/include/xo/facet/typeseq.hpp @@ -5,6 +5,7 @@ #pragma once +#include #include namespace xo { @@ -15,6 +16,8 @@ namespace xo { */ template struct typeseq_impl { + explicit typeseq_impl(int32_t s) : seqno_{s} {} + /** Can't have this be constexpr. * We need ids in shared libraries to be generated * at load time to avoid false positives @@ -28,7 +31,7 @@ namespace xo { * when using clang. **/ template - static int32_t id() { + static typeseq_impl id() { static bool armed = true; static int32_t id = 0; @@ -37,15 +40,40 @@ namespace xo { id = ++s_next_id; } - return id; + return typeseq_impl(id); + } + int32_t seqno() const { return seqno_; } + + private: static int32_t s_next_id; + + int32_t seqno_; }; template int32_t typeseq_impl::s_next_id = 0; + template + inline bool + operator==(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() == rhs.seqno(); + } + + template + inline bool + operator!=(const typeseq_impl & lhs, const typeseq_impl & rhs) { + return lhs.seqno() != rhs.seqno(); + } + + template + inline std::ostream & + operator<<(std::ostream & s, const typeseq_impl & x) { + s << x.seqno(); + return s; + } + using typeseq = typeseq_impl<>; } } /*namespace xo*/ diff --git a/utest/objectmodel.test.cpp b/utest/objectmodel.test.cpp index fbeb944..57a80c5 100644 --- a/utest/objectmodel.test.cpp +++ b/utest/objectmodel.test.cpp @@ -34,7 +34,7 @@ namespace xo { using TypeErasedIface = struct IComplex_Any; /** RTTI: reports unique id# for actual runtime data representation **/ - virtual int32_t _typeseq() const = 0; + virtual typeseq _typeseq() const = 0; virtual double xcoord(void * data) const = 0; virtual double ycoord(void * data) const = 0; @@ -61,7 +61,7 @@ namespace xo { // from AComplex - virtual int32_t _typeseq() const final override { return s_typeseq; } + virtual typeseq _typeseq() const final override { return s_typeseq; } virtual double xcoord(void * data) const final override { return Impl::xcoord(*(DRepr*)data); } virtual double ycoord(void * data) const final override { return Impl::ycoord(*(DRepr*)data); } @@ -70,12 +70,12 @@ namespace xo { virtual void destruct_data(void * data) const final override { Impl::destruct_data(*(DRepr*)data); } - static int32_t s_typeseq; + static typeseq s_typeseq; static bool _valid; }; template - int32_t + typeseq IComplex_Xfer::s_typeseq = typeseq::id(); template @@ -96,7 +96,7 @@ namespace xo { * such as IComplex_RectCoords or IComplex_PolarCoords. **/ struct IComplex_Any : public AComplex { - virtual int32_t _typeseq() const final override { return s_typeseq; } + virtual typeseq _typeseq() const final override { return s_typeseq; } virtual double xcoord(void *) const final override { assert(false); return 0.0; } virtual double ycoord(void *) const final override { assert(false); return 0.0; } @@ -105,11 +105,11 @@ namespace xo { virtual void destruct_data(void *) const final override { assert(false); } - static int32_t s_typeseq; + static typeseq s_typeseq; static bool _valid; }; - int32_t + typeseq IComplex_Any::s_typeseq = typeseq::id(); bool @@ -190,7 +190,7 @@ namespace xo { RComplex() {} RComplex(Object::DataPtr data) : Object{std::move(data)} {} - int32_t _typeseq() const { return Object::iface()->_typeseq(); } + typeseq _typeseq() const { return Object::iface()->_typeseq(); } double xcoord() const { return Object::iface()->xcoord(Object::data()); } double ycoord() const { return Object::iface()->ycoord(Object::data()); } double argument() const { return Object::iface()->argument(Object::data()); }