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
|
# in reverse topological order i.e. dependencies first
|
||||||
|
|
||||||
add_subdirectory(xo-cmake)
|
add_subdirectory(xo-cmake)
|
||||||
|
add_subdirectory(xo-facet)
|
||||||
add_subdirectory(xo-indentlog)
|
add_subdirectory(xo-indentlog)
|
||||||
add_subdirectory(xo-allocutil)
|
add_subdirectory(xo-allocutil)
|
||||||
add_subdirectory(xo-refcnt)
|
add_subdirectory(xo-refcnt)
|
||||||
|
|
|
||||||
2
conf.py
2
conf.py
|
|
@ -17,7 +17,7 @@ author = 'Roland Conybeare'
|
||||||
extensions = [ "breathe",
|
extensions = [ "breathe",
|
||||||
"sphinx.ext.mathjax", # inline math
|
"sphinx.ext.mathjax", # inline math
|
||||||
"sphinx.ext.autodoc", # generate info from docstrings
|
"sphinx.ext.autodoc", # generate info from docstrings
|
||||||
"sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
# "sphinxcontrib.ditaa", # diagrams-through-ascii-art
|
||||||
"sphinxcontrib.plantuml", # text -> uml diagrams
|
"sphinxcontrib.plantuml", # text -> uml diagrams
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -421,6 +421,7 @@ in
|
||||||
pkgs = pkgs;
|
pkgs = pkgs;
|
||||||
xo = {
|
xo = {
|
||||||
cmake = pkgs.xo-cmake;
|
cmake = pkgs.xo-cmake;
|
||||||
|
# facet = pkgs.xo-facet;
|
||||||
indentlog = pkgs.xo-indentlog;
|
indentlog = pkgs.xo-indentlog;
|
||||||
refcnt = pkgs.xo-refcnt;
|
refcnt = pkgs.xo-refcnt;
|
||||||
subsys = pkgs.xo-subsys;
|
subsys = pkgs.xo-subsys;
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ Some features: kalman filters, stochastic processes, complex event processing, s
|
||||||
:caption: XO contents
|
:caption: XO contents
|
||||||
|
|
||||||
docs/install
|
docs/install
|
||||||
|
xo-facet/docs/index
|
||||||
xo-alloc/docs/index
|
xo-alloc/docs/index
|
||||||
xo-indentlog/docs/index
|
xo-indentlog/docs/index
|
||||||
xo-flatstring/docs/index
|
xo-flatstring/docs/index
|
||||||
|
|
|
||||||
|
|
@ -261,7 +261,7 @@ namespace xo {
|
||||||
};
|
};
|
||||||
|
|
||||||
bool
|
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.
|
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::
|
.. toctree::
|
||||||
:maxdepth: 2
|
: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