xo-facet: + doc scaffold + begin include scaffold
This commit is contained in:
parent
7117a8d9e5
commit
a4e88b674e
12 changed files with 181 additions and 3 deletions
|
|
@ -75,6 +75,7 @@ set(DOX_EXCLUDE_PATTERNS [=[
|
|||
# in reverse topological order i.e. dependencies first
|
||||
|
||||
add_subdirectory(xo-cmake)
|
||||
add_subdirectory(xo-facet)
|
||||
add_subdirectory(xo-indentlog)
|
||||
add_subdirectory(xo-allocutil)
|
||||
add_subdirectory(xo-refcnt)
|
||||
|
|
|
|||
2
conf.py
2
conf.py
|
|
@ -17,7 +17,7 @@ author = 'Roland Conybeare'
|
|||
extensions = [ "breathe",
|
||||
"sphinx.ext.mathjax", # inline math
|
||||
"sphinx.ext.autodoc", # generate info from docstrings
|
||||
"sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||
# "sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||
"sphinxcontrib.plantuml", # text -> uml diagrams
|
||||
]
|
||||
|
||||
|
|
|
|||
|
|
@ -421,6 +421,7 @@ in
|
|||
pkgs = pkgs;
|
||||
xo = {
|
||||
cmake = pkgs.xo-cmake;
|
||||
# facet = pkgs.xo-facet;
|
||||
indentlog = pkgs.xo-indentlog;
|
||||
refcnt = pkgs.xo-refcnt;
|
||||
subsys = pkgs.xo-subsys;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,7 @@ Some features: kalman filters, stochastic processes, complex event processing, s
|
|||
:caption: XO contents
|
||||
|
||||
docs/install
|
||||
xo-facet/docs/index
|
||||
xo-alloc/docs/index
|
||||
xo-indentlog/docs/index
|
||||
xo-flatstring/docs/index
|
||||
|
|
|
|||
|
|
@ -261,7 +261,7 @@ namespace xo {
|
|||
};
|
||||
|
||||
bool
|
||||
IComplex_Any::_valid = valid_interface_implementation<AComplex, IComplex_Any>;
|
||||
IComplex_Any::_valid = valid_interface_implementation<AComplex, IComplex_Any>();
|
||||
|
||||
// ----------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
1
xo-facet/docs/_static/README
vendored
Normal file
1
xo-facet/docs/_static/README
vendored
Normal file
|
|
@ -0,0 +1 @@
|
|||
add any static {.html, .js, ..} files for sphinx to pickup here
|
||||
BIN
xo-facet/docs/_static/favicon.ico
vendored
Normal file
BIN
xo-facet/docs/_static/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 303 KiB |
BIN
xo-facet/docs/_static/img/favicon.ico
vendored
Normal file
BIN
xo-facet/docs/_static/img/favicon.ico
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 303 KiB |
|
|
@ -4,7 +4,46 @@ xo-facet documentation
|
|||
======================
|
||||
|
||||
xo-facet provides an object model that supports runtime polymorphism with interfaces and data kept separate.
|
||||
Similar to rust traits, haskell type clases, go interfaces.
|
||||
Design operates on similar lines to rust traits, haskell type clases, and go interfaces.
|
||||
|
||||
Principles
|
||||
----------
|
||||
|
||||
* Keep interfaces and data structures separate.
|
||||
An object is represented using a combination of exactly two pointers:
|
||||
an interface pointer and a data pointer.
|
||||
|
||||
* An interface pointer implements an abstract facet.
|
||||
A facet has only abstract methods, and no state.
|
||||
|
||||
* An interface pointer is analogous to a vtable pointer in a regular
|
||||
c++ object. It identifies a suite of related functions that operate
|
||||
on a particular data type.
|
||||
|
||||
* A data pointer is like a pointer to a c struct.
|
||||
Data objects are passive, except for necessary ctors/dtors.
|
||||
Runtime polymorphism works seamlessly across different data types
|
||||
without requiring any prearrangement such as sharing a common
|
||||
base class.
|
||||
|
||||
* We make 'familiar c++ objects', on demand, by pairing an interface pointer
|
||||
with a data pointer. Unlike usual c++ practice, we expect such objects
|
||||
to be transient. To represent persistent state, we rely
|
||||
solely on data pointers.
|
||||
|
||||
* Since interface+data are separate,
|
||||
we can easily swap out one interface for another.
|
||||
|
||||
This gives us several benefits:
|
||||
|
||||
* A data type can easily particpate in polymorphism across different facets,
|
||||
without complicating object representation. To convert an object to use a
|
||||
different facet, we just swap out the interface pointer.
|
||||
|
||||
* Interface and data pointers can arrive at the doorstep of a computation
|
||||
by different pathways. Often the pathway for an interface pointer is
|
||||
simpler that the pathway for a data pointer. This increases scope for
|
||||
devirtualization.
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 2
|
||||
|
|
|
|||
68
xo-facet/include/xo/facet/AFacet.hpp
Normal file
68
xo-facet/include/xo/facet/AFacet.hpp
Normal file
|
|
@ -0,0 +1,68 @@
|
|||
/** @file AFacet.hpp
|
||||
*
|
||||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <concepts>
|
||||
#include <type_traits>
|
||||
|
||||
namespace xo {
|
||||
namespace facet {
|
||||
namespace detail {
|
||||
struct PlaceholderAbstractInterface {
|
||||
virtual double foo(void * data) const = 0;
|
||||
};
|
||||
|
||||
static_assert(sizeof(PlaceholderAbstractInterface) == sizeof(void*));
|
||||
}
|
||||
|
||||
/** Concept: abstract interface requirements
|
||||
* Use: when inheriting an abstract interface
|
||||
* (see also valid_abstract_interface() below)
|
||||
**/
|
||||
template <typename T>
|
||||
concept abstract_facet = requires {
|
||||
std::is_abstract_v<T>,
|
||||
std::is_polymorphic_v<T>;
|
||||
/** require no state, just a single vtable pointer **/
|
||||
sizeof(T) == sizeof(detail::PlaceholderAbstractInterface);
|
||||
!std::has_virtual_destructor_v<T>;
|
||||
std::is_trivially_destructible_v<T>;
|
||||
};
|
||||
|
||||
/** Use: when defining an abstract facet AMyFacet
|
||||
*
|
||||
* struct AMyFacet {
|
||||
* virtual void foo(void * data) const = 0;
|
||||
* };
|
||||
*
|
||||
* static_assert(valid_abstract_facet<AMyFacet>());
|
||||
*
|
||||
**/
|
||||
template <typename T>
|
||||
consteval bool valid_abstract_facet()
|
||||
{
|
||||
static_assert
|
||||
(std::is_abstract_v<T>,
|
||||
"Abstract facet is expected to have all-abstract methods");
|
||||
static_assert
|
||||
(std::is_polymorphic_v<T>,
|
||||
"Abstract facet is expected to have vtable");
|
||||
static_assert
|
||||
(sizeof(T) == sizeof(detail::PlaceholderAbstractInterface),
|
||||
"Abstract facet is expected to have no state except for a single vtable pointer");
|
||||
static_assert
|
||||
(!std::has_virtual_destructor_v<T>,
|
||||
"Abstract facet does not benefit from virtual dtor since no state");
|
||||
static_assert
|
||||
(std::is_trivially_destructible_v<T>,
|
||||
"Abstract facet expected to have trivial dtor since no state");
|
||||
return true;
|
||||
};
|
||||
|
||||
} /*namespace facet*/
|
||||
} /*namespace xo*/
|
||||
|
||||
/* end AFacet.hpp **/
|
||||
6
xo-facet/utest/facet_utest_main.cpp
Normal file
6
xo-facet/utest/facet_utest_main.cpp
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
/* file facet_utest_main.cpp */
|
||||
|
||||
#define CATCH_CONFIG_MAIN
|
||||
#include "catch2/catch.hpp"
|
||||
|
||||
/* end facet_utest_main.cpp */
|
||||
61
xo-facet/utest/objectmodel.test.cpp
Normal file
61
xo-facet/utest/objectmodel.test.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
/** @file objectmodel.test.cpp
|
||||
*
|
||||
* @author Roland Conybeare, Dec 2025
|
||||
**/
|
||||
|
||||
#include "xo/facet/AFacet.hpp"
|
||||
#include <catch2/catch.hpp>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <cstring>
|
||||
|
||||
namespace xo {
|
||||
using xo::facet::valid_abstract_facet;
|
||||
|
||||
namespace ut {
|
||||
// ------ AComplex -----
|
||||
|
||||
/** abstract interface for a complex number **/
|
||||
struct AComplex {
|
||||
using TypeErasedIface = struct IComplex_Any;
|
||||
|
||||
virtual double xcoord(void * data) const = 0;
|
||||
virtual double ycoord(void * data) const = 0;
|
||||
virtual double argument(void * data) const = 0;
|
||||
virtual double magnitude(void * data) const = 0;
|
||||
|
||||
virtual void destruct_data(void * data) const = 0;
|
||||
|
||||
private:
|
||||
static bool _valid;
|
||||
};
|
||||
|
||||
bool
|
||||
AComplex::_valid = valid_abstract_facet<AComplex>();
|
||||
|
||||
// ----- IComplex_Any -----
|
||||
|
||||
/** type-erased implementation of AComplex, for runtime polymorphism
|
||||
* Usable by (and only by) overwriting with a typed implementation,
|
||||
* such as IComplex_RectCoords or IComplex_PolarCoords.
|
||||
**/
|
||||
struct IComplex_Any : public AComplex {
|
||||
virtual double xcoord(void *) const final override { assert(false); return 0.0; }
|
||||
virtual double ycoord(void *) const final override { assert(false); return 0.0; }
|
||||
virtual double argument(void *) const final override { assert(false); return 0.0; }
|
||||
virtual double magnitude(void *) const final override { assert(false); return 0.0; }
|
||||
|
||||
virtual void destruct_data(void *) const final override { assert(false); }
|
||||
|
||||
private:
|
||||
static bool _valid;
|
||||
};
|
||||
|
||||
bool
|
||||
IComplex_Any::_valid = true; //valid_interface_implementation<AComplex, IComplex_Any>();
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
/* end objectmodel.test.cpp */
|
||||
Loading…
Add table
Add a link
Reference in a new issue