xo-facet: typeseq strongly typed

This commit is contained in:
Roland Conybeare 2026-01-02 09:52:16 -05:00
commit 0c06430703
3 changed files with 39 additions and 11 deletions

View file

@ -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<std::int32_t>; },
{ facet._typeseq().seqno() } -> std::convertible_to<std::int32_t>; },
"Abstract facet must provide a _typeseq() method for safe downcasting");
return true;
};

View file

@ -5,6 +5,7 @@
#pragma once
#include <iostream>
#include <cstdint>
namespace xo {
@ -15,6 +16,8 @@ namespace xo {
*/
template<typename Tag = class typeseq_tag>
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 <typename T>
static int32_t id() {
static typeseq_impl<Tag> 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 <typename Tag>
int32_t typeseq_impl<Tag>::s_next_id = 0;
template <typename Tag>
inline bool
operator==(const typeseq_impl<Tag> & lhs, const typeseq_impl<Tag> & rhs) {
return lhs.seqno() == rhs.seqno();
}
template <typename Tag>
inline bool
operator!=(const typeseq_impl<Tag> & lhs, const typeseq_impl<Tag> & rhs) {
return lhs.seqno() != rhs.seqno();
}
template <typename Tag>
inline std::ostream &
operator<<(std::ostream & s, const typeseq_impl<Tag> & x) {
s << x.seqno();
return s;
}
using typeseq = typeseq_impl<>;
}
} /*namespace xo*/

View file

@ -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 <typename DRepr>
int32_t
typeseq
IComplex_Xfer<DRepr>::s_typeseq = typeseq::id<DRepr>();
template <typename DRepr>
@ -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<DVariantPlaceholder>();
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()); }