Add 'xo-flatstring/' from commit 'ebbe45e5e7'

git-subtree-dir: xo-flatstring
git-subtree-mainline: 1eb4114722
git-subtree-split: ebbe45e5e7
This commit is contained in:
Roland Conybeare 2025-05-10 19:15:08 -05:00
commit 852dbe66dd
30 changed files with 2464 additions and 0 deletions

View file

@ -0,0 +1,5 @@
# xo-flatstring/docs/CMakeLists.txt
xo_doxygen_collect_deps()
xo_docdir_doxygen_config()
xo_docdir_sphinx_config(index.rst install.rst lessons.rst flatstring-reference.rst flatstring-class.rst)

1
xo-flatstring/docs/_static/README vendored Normal file
View file

@ -0,0 +1 @@
add any static {.html, .js, ..} files for sphinx to pickup here

Binary file not shown.

After

Width:  |  Height:  |  Size: 302 KiB

77
xo-flatstring/docs/_static/img/icon.svg vendored Normal file
View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="108.32474mm"
height="108.39381mm"
viewBox="0 0 108.32474 108.39382"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="icon.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="157"
inkscape:cy="322.5"
inkscape:window-width="1607"
inkscape:window-height="1085"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1"
fit-margin-top="9.8"
fit-margin-left="8"
fit-margin-right="10"
fit-margin-bottom="9.8" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-47.453609,-27.112369)">
<circle
style="fill:#ff0000;fill-rule:evenodd;stroke-width:0.264583"
id="path31"
cx="68.211342"
cy="87.603088"
r="12.757732" />
<circle
style="fill:#ffcf00;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
id="path31-3"
cx="122.47422"
cy="49.670101"
r="12.757732" />
<circle
style="fill:#6b6bff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
id="path31-3-6"
cx="133.02061"
cy="112.94845"
r="12.757732" />
<path
style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 73.144329,75.525772 C 85.051544,48.309278 109.54639,49.670102 109.54639,49.670102"
id="path589" />
<path
style="fill:none;stroke:#000000;stroke-width:2.44548;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 76.544292,96.598799 C 95.429921,116.11457 120.4897,113.37017 120.4897,113.37017"
id="path593" />
<path
style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 132,58.175257 c 17.01031,17.350515 7.14433,43.886603 7.14433,43.886603"
id="path788" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,77 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
width="108.32474mm"
height="108.39381mm"
viewBox="0 0 108.32474 108.39382"
version="1.1"
id="svg5"
inkscape:version="1.1.2 (0a00cf5339, 2022-02-04)"
sodipodi:docname="xo-icon.svg"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns="http://www.w3.org/2000/svg"
xmlns:svg="http://www.w3.org/2000/svg">
<sodipodi:namedview
id="namedview7"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageshadow="2"
inkscape:pageopacity="0.0"
inkscape:pagecheckerboard="0"
inkscape:document-units="mm"
showgrid="false"
inkscape:zoom="1"
inkscape:cx="157"
inkscape:cy="322.5"
inkscape:window-width="1607"
inkscape:window-height="1085"
inkscape:window-x="26"
inkscape:window-y="23"
inkscape:window-maximized="0"
inkscape:current-layer="layer1"
fit-margin-top="9.8"
fit-margin-left="8"
fit-margin-right="10"
fit-margin-bottom="9.8" />
<defs
id="defs2" />
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-47.453609,-27.112369)">
<circle
style="fill:#ff0000;fill-rule:evenodd;stroke-width:0.264583"
id="path31"
cx="68.211342"
cy="87.603088"
r="12.757732" />
<circle
style="fill:#ffcf00;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
id="path31-3"
cx="122.47422"
cy="49.670101"
r="12.757732" />
<circle
style="fill:#6b6bff;fill-opacity:1;fill-rule:evenodd;stroke-width:0.264583"
id="path31-3-6"
cx="133.02061"
cy="112.94845"
r="12.757732" />
<path
style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 73.144329,75.525772 C 85.051544,48.309278 109.54639,49.670102 109.54639,49.670102"
id="path589" />
<path
style="fill:none;stroke:#000000;stroke-width:2.44548;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="M 76.544292,96.598799 C 95.429921,116.11457 120.4897,113.37017 120.4897,113.37017"
id="path593" />
<path
style="fill:none;stroke:#000000;stroke-width:2.5;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-opacity:1"
d="m 132,58.175257 c 17.01031,17.350515 7.14433,43.886603 7.14433,43.886603"
id="path788" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 2.7 KiB

View file

@ -0,0 +1,36 @@
# Configuration file for the Sphinx documentation builder.
#
# For the full list of built-in configuration values, see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#project-information
project = 'xo flatstring documentation'
copyright = '2024, Roland Conybeare'
author = 'Roland Conybeare'
# -- General configuration ---------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#general-configuration
#extensions = []
extensions = [ "breathe",
"sphinx.ext.autodoc" # generate info from docstrings
]
# note: breathe requires doxygen xml output -> must have GENERATE_XML = YES in Doxyfile.in
# match project name in Doxyfile.in
breathe_default_project = "xodoxxml"
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
pygments_style = 'sphinx'
# -- Options for HTML output -------------------------------------------------
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output
#html_theme = 'alabaster'
html_theme = 'sphinx_rtd_theme'
html_static_path = ['_static']
html_favicon = '_static/img/favicon.ico'

View file

@ -0,0 +1,65 @@
.. _flatstring-class:
Flatstring
==========
.. code-block:: cpp
#include <xo/flatstring/flatstring.hpp>
A ``flatstring`` is a thin wrapper around a character array.
.. doxygenclass:: xo::flatstring
Instance Variables
------------------
.. doxygengroup:: flatstring-instance-variables
:content-only:
Types
-----
.. doxygengroup:: flatstring-types
Constants
---------
.. doxygengroup:: flatstring-constants
:content-only:
Constructors
------------
.. doxygengroup:: flatstring-ctor
:content-only:
Properties
----------
.. doxygengroup:: flatstring-properties
:content-only:
Access Methods
--------------
.. doxygengroup:: flatstring-access
:content-only:
Iterators
---------
.. doxygengroup:: flatstring-iterators
:content-only:
Assignment
----------
.. doxygengroup:: flatstring-assign
:content-only:
Conversion
----------
.. doxygengroup:: flatstring-conversion-operators
:content-only:

View file

@ -0,0 +1,16 @@
.. _flatstring_functions:
.. toctree::
:maxdepth: 2
Flatstring Functions
====================
.. code-block:: cpp
#include <xo/flatstring/flatstring.hpp>
.. doxygenfunction:: xo::flatstring_concat
.. doxygengroup:: flatstring-3way-compare
:content-only:

View file

@ -0,0 +1,11 @@
.. _flatstring-reference:
Flatstring Reference
====================
.. toctree::
:maxdepth: 2
:caption: Flatstring Reference
flatstring-class
flatstring-functions

View file

@ -0,0 +1,38 @@
xo-flatstring documentation master file
xo-flatstring documentation
===========================
xo-flatstring is a lightweight header-only library that provides a constexpr
fixed-size no-allocation string implementation.
Why ``flatstring``?
1. ``flatstring`` instances can be used as template arguments. [1]_
2. ``flatstring`` operations (construction, concatenation, ...) are ``constexpr``, so can be done at compile time. [2]_
3. a ``flatstring`` expression can occupy both compile-time and runtime roles. [3]_
.. [1] A fixed-size char array *can* be used as a template
argument, but char* pointers cannot. Automatic conversion of char arrays to pointers in various contexts
makes them difficult to work with in c++ templates.
.. [2] Although allocation is permitted in constexpr code, it's subject to several restrictions.
it's not yet possible (as of c++23) to use ``std::string`` at compile time.
.. [3] contrast with a solution relying on template arguments, which must then be compile-time-only.
.. toctree::
:maxdepth: 2
:caption: xo-flatstring contents:
install
lessons
flatstring-reference
Indices and Tables
------------------
* :ref:`genindex`
* :ref:`search`

View file

@ -0,0 +1,86 @@
.. _install:
.. toctree
:maxdepth: 2
Source
======
Source code lives on github `here`_
.. _here: https://github.com/rconybea/xo-flatstring
To clone from git:
.. code-block:: bash
git clone https://github.com/rconybea/xo-flatstring
Implementation relies on c++20 features (expanded use of constexpr; class-instances as template arguments).
Tested with gcc 13.2
Install
=======
Since xo-flatstring is header-only, can incorporate into another project just by copying the include directories
to somewhere convenient.
Copy includes
-------------
.. code-block:: bash
# For example..
cd myproject
mkdir -p ext/xo-flatstring
rsync -a -v path/to/xo-flatstring/include/ ext/xo-flatstring/
Include as git submodule
------------------------
.. code-block:: bash
cd myproject
git submodule add -b main https://github.com/rconybea/xo-flatstring ext/xo-flatstring
git submodule update --init
This assumes you organize directly-incorporated dependencies under directory ``myproject/ext``.
You would then add ``myproject/ext/xo-flatstring/include`` to your compiler's include path,
and from c++ do something like
.. code-block:: c++
#include <xo/flatstring/flatstring.hpp>
in c++ source files that rely on xo-flatstring
Supported compilers
-------------------
* developed with gcc 13.2.0; github CI using gcc 11.4.0 (asof April 2024)
Building from source
--------------------
Although the xo-flatstring library is header-only, unit tests have some dependencies.
Example instructions (github CI) for build starting from stock ubuntu are in `ubuntu-main.yml`_
.. _ubuntu-main.yml: https://github.com/Rconybea/xo-flatstring/blob/main/.github/workflows/ubuntu-main.yml
Unit test dependencies:
* `catch2`_ header-only unit-test framework
* `xo-cmake`_ cmake macros
* `xo-indentlog`_ logging with call-structure indenting
.. _catch2: https://github.com/catchorg/Catch2
.. _xo-cmake: https://github.com/rconybea/xo-cmake
.. _xo-indentlog: https://github.com/rconybea/indentlog
To build documentation, will also need:
* `doxygen`
* `graphviz`
* `sphinx`
* `breathe`
* `sphinx_rtd_theme`

View file

@ -0,0 +1,98 @@
.. _lessons:
.. toctree
:maxdepth: 2
Lessons
=======
This is a rogue's gallery of experiments, typically unsuccessful.
One hurdle we've created for ourselves, is we need both gcc and clang to agree
that an expression can be computed at compile-time;
otherwise will get false alarms in our IDE (raised by LSP running in the background, which relies on clang).
Must fully initialize memory
----------------------------
Struggled for a while with the implementation of :ref:xo::flatstring_concat
.. code-block:: cpp
template <std::size_t N>
flatstring::flatstring<N>() {
if (N > 0)
value_[0] = '\0';
}
This implementation satisfies gcc, but not clang: in the following snippet, clang doesn't recognize ``tmp`` as constexpr:
.. code-block:: cpp
constexpr n = ...;
flatstring<n> tmp;
static_assert(tmp.size() == ...); // tmp not constexpr!
Correction is to prove to clang that every memory address owned by an empty ``flatstring`` is initialized:
.. code-block:: cpp
template <std::size_t N>
flatstring::flatstring<N>() {
std::fill_n(value_, N, '\0');
}
Still need equality comparison alongside spaceship operator
-----------------------------------------------------------
Had the impression that spaceship operator for :ref:xo::flatstring would be sufficient
to get all six comparison operators:
.. code-block:: cpp
template <std::size_t N1,
std::size_t N2>
constexpr auto
operator<=>(const flatstring<N1> & s1,
const flatstring<N2> & s2) noexcept
{
return (std::string_view(s1) <=> std::string_view(s2));
}
We observe this is not the case, at least with gcc 13.1; need to separately define :ref:xo::operator==
.. code-block:: cpp
template <std::size_t N1,
std::size_t N2>
constexpr bool
operator==(const flatstring<N1> & s1,
const flatstring<N2> & s2) noexcept
{
return ((s1 <=> s2) == std::strong_ordering::equal);
}
Constexpr strict about pointer arithmetic
-----------------------------------------
Initially attempted to implement :ref:xo::flatstring reverse iterators using char pointers.
Notice there's an assymetry between reverse iterators and forward iterators.
We can (and do) implement forward iterators using char pointers.
The natural value of ``flatstring::end()`` is a char pointer referring to just past the end of
the string, i.e. to its null terminator. From the compiler's perspective, this is an ordinary
char pointer, just like other iterator values.
For reverse iterators this isn't the case. The natural value for ``flatstring::rend()`` might
seem to be a char pointer referring to just before the first character in the string.
However this is no longer a valid pointer address -- dereferencing would be undefined behavior.
In particular, with this implementation, gcc demotes ``flatstring::rend()`` to non-constexpr
Workaround is to implement a shim iterator class, where representation is pointer to the
character just after the one the iterator position; iterator's ``operator*`` adjusts pointer before
dereferencing.
This works because gcc can observe that we never dereference a reverse iterator with pointer value
at the beginning of a flatstring.