pyurd 0.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pyurd/__init__.py +95 -0
- pyurd/__main__.py +51 -0
- pyurd/include/urd/bits.hpp +36 -0
- pyurd/include/urd/config.hpp +47 -0
- pyurd/include/urd/cost.hpp +313 -0
- pyurd/include/urd/elements/builder.hpp +12 -0
- pyurd/include/urd/elements/children.hpp +120 -0
- pyurd/include/urd/elements/concepts.hpp +189 -0
- pyurd/include/urd/elements/data.hpp +33 -0
- pyurd/include/urd/elements/equal_to.hpp +183 -0
- pyurd/include/urd/elements/flat.hpp +151 -0
- pyurd/include/urd/elements/hash.hpp +249 -0
- pyurd/include/urd/elements/hash_dynamic_bitset.hpp +26 -0
- pyurd/include/urd/elements/index.hpp +98 -0
- pyurd/include/urd/elements/less.hpp +272 -0
- pyurd/include/urd/elements/prehashed.hpp +68 -0
- pyurd/include/urd/elements/requirements.hpp +148 -0
- pyurd/include/urd/elements/subset_view.hpp +57 -0
- pyurd/include/urd/elements/view.hpp +499 -0
- pyurd/include/urd/format.hpp +174 -0
- pyurd/include/urd/kinds.hpp +467 -0
- pyurd/include/urd/memory.hpp +105 -0
- pyurd/include/urd/property_set.hpp +367 -0
- pyurd/include/urd/python/bindings.hpp +89 -0
- pyurd/include/urd/python/caster.hpp +67 -0
- pyurd/include/urd/python/flat.hpp +136 -0
- pyurd/include/urd/python/maps/flat_map.hpp +14 -0
- pyurd/include/urd/python/maps/index_map.hpp +14 -0
- pyurd/include/urd/python/maps/ordered_map.hpp +14 -0
- pyurd/include/urd/python/maps/parallel_hash_map.hpp +16 -0
- pyurd/include/urd/python/maps/std_map.hpp +16 -0
- pyurd/include/urd/python/maps/unordered_flat_map.hpp +14 -0
- pyurd/include/urd/python/owner.hpp +67 -0
- pyurd/include/urd/python/ranges.hpp +79 -0
- pyurd/include/urd/python/sequences/segmented.hpp +14 -0
- pyurd/include/urd/python/sequences/sequence.hpp +14 -0
- pyurd/include/urd/python/values/dense_set.hpp +14 -0
- pyurd/include/urd/python/values/flat_set.hpp +14 -0
- pyurd/include/urd/python/values/indexed.hpp +14 -0
- pyurd/include/urd/python/values/parallel_hash_set.hpp +16 -0
- pyurd/include/urd/python/values/sparse_set.hpp +14 -0
- pyurd/include/urd/python/values/std_set.hpp +16 -0
- pyurd/include/urd/python/values/unordered_flat_set.hpp +14 -0
- pyurd/include/urd/registry/declaration.hpp +148 -0
- pyurd/include/urd/registry/declarations.hpp +179 -0
- pyurd/include/urd/registry/derived.hpp +65 -0
- pyurd/include/urd/registry/facts.hpp +213 -0
- pyurd/include/urd/registry/scan.hpp +87 -0
- pyurd/include/urd/registry/select.hpp +133 -0
- pyurd/include/urd/registry/table.hpp +24 -0
- pyurd/include/urd/repr/containers/bit.hpp +304 -0
- pyurd/include/urd/repr/containers/bit_rows.hpp +196 -0
- pyurd/include/urd/repr/containers/bitset_span.hpp +631 -0
- pyurd/include/urd/repr/containers/byte_arena.hpp +128 -0
- pyurd/include/urd/repr/containers/detail/geometric_segment_layout.hpp +59 -0
- pyurd/include/urd/repr/containers/detail/segmented_rows.hpp +96 -0
- pyurd/include/urd/repr/containers/detail/threading.hpp +114 -0
- pyurd/include/urd/repr/containers/detail/tracking.hpp +59 -0
- pyurd/include/urd/repr/containers/schema_rows.hpp +324 -0
- pyurd/include/urd/repr/containers/segment_sizes.hpp +40 -0
- pyurd/include/urd/repr/containers/segmented_vector.hpp +384 -0
- pyurd/include/urd/repr/containers/spin_mutex.hpp +143 -0
- pyurd/include/urd/repr/containers/uniform_rows.hpp +210 -0
- pyurd/include/urd/repr/core/boost_memory.hpp +44 -0
- pyurd/include/urd/repr/core/gtl_memory.hpp +61 -0
- pyurd/include/urd/repr/core/gtl_spin_lock.hpp +28 -0
- pyurd/include/urd/repr/core/numbered.hpp +58 -0
- pyurd/include/urd/repr/core/position_iterator.hpp +124 -0
- pyurd/include/urd/repr/core/std_memory.hpp +120 -0
- pyurd/include/urd/repr/maps/bidirectional_csr.hpp +90 -0
- pyurd/include/urd/repr/maps/csr_multimap.hpp +24 -0
- pyurd/include/urd/repr/maps/dense_groups.hpp +117 -0
- pyurd/include/urd/repr/maps/dense_map_fwd.hpp +164 -0
- pyurd/include/urd/repr/maps/dense_multimap.hpp +24 -0
- pyurd/include/urd/repr/maps/flat_map.hpp +31 -0
- pyurd/include/urd/repr/maps/flat_map_fwd.hpp +87 -0
- pyurd/include/urd/repr/maps/grouped_fwd.hpp +183 -0
- pyurd/include/urd/repr/maps/grouped_multimap.hpp +255 -0
- pyurd/include/urd/repr/maps/index_groups.hpp +115 -0
- pyurd/include/urd/repr/maps/index_map.hpp +506 -0
- pyurd/include/urd/repr/maps/ordered_map.hpp +209 -0
- pyurd/include/urd/repr/maps/ordered_map_fwd.hpp +89 -0
- pyurd/include/urd/repr/maps/parallel_hash_map.hpp +135 -0
- pyurd/include/urd/repr/maps/parallel_hash_map_fwd.hpp +98 -0
- pyurd/include/urd/repr/maps/postings.hpp +403 -0
- pyurd/include/urd/repr/maps/std_map.hpp +178 -0
- pyurd/include/urd/repr/maps/unordered_flat_map.hpp +25 -0
- pyurd/include/urd/repr/maps/unordered_flat_map_fwd.hpp +49 -0
- pyurd/include/urd/repr/partitions/disjoint_sets.hpp +115 -0
- pyurd/include/urd/repr/partitions/disjoint_sets_fwd.hpp +48 -0
- pyurd/include/urd/repr/pools/pools.hpp +460 -0
- pyurd/include/urd/repr/pools/pools_fwd.hpp +181 -0
- pyurd/include/urd/repr/pools/tree_bitset.hpp +616 -0
- pyurd/include/urd/repr/pools/tree_vector.hpp +309 -0
- pyurd/include/urd/repr/queues/addressable_heap.hpp +182 -0
- pyurd/include/urd/repr/queues/bucket_queue.hpp +114 -0
- pyurd/include/urd/repr/queues/queue.hpp +129 -0
- pyurd/include/urd/repr/queues/queues_fwd.hpp +203 -0
- pyurd/include/urd/repr/queues/ring_fifo.hpp +156 -0
- pyurd/include/urd/repr/records/arena.hpp +129 -0
- pyurd/include/urd/repr/records/records.hpp +132 -0
- pyurd/include/urd/repr/records/records_fwd.hpp +163 -0
- pyurd/include/urd/repr/sequences/jagged.hpp +323 -0
- pyurd/include/urd/repr/sequences/row_pool.hpp +173 -0
- pyurd/include/urd/repr/sequences/rows_fwd.hpp +180 -0
- pyurd/include/urd/repr/sequences/segmented.hpp +29 -0
- pyurd/include/urd/repr/sequences/segmented_fwd.hpp +81 -0
- pyurd/include/urd/repr/sequences/sequence.hpp +55 -0
- pyurd/include/urd/repr/slots/slots.hpp +249 -0
- pyurd/include/urd/repr/slots/slots_fwd.hpp +86 -0
- pyurd/include/urd/repr/values/dense_set.hpp +362 -0
- pyurd/include/urd/repr/values/dense_set_fwd.hpp +157 -0
- pyurd/include/urd/repr/values/flat_set.hpp +41 -0
- pyurd/include/urd/repr/values/flat_set_fwd.hpp +94 -0
- pyurd/include/urd/repr/values/indexed.hpp +663 -0
- pyurd/include/urd/repr/values/indexed_fwd.hpp +145 -0
- pyurd/include/urd/repr/values/parallel_hash_set.hpp +32 -0
- pyurd/include/urd/repr/values/parallel_hash_set_fwd.hpp +103 -0
- pyurd/include/urd/repr/values/sparse_set.hpp +198 -0
- pyurd/include/urd/repr/values/std_set.hpp +109 -0
- pyurd/include/urd/repr/values/unordered_flat_set.hpp +25 -0
- pyurd/include/urd/repr/values/unordered_flat_set_fwd.hpp +49 -0
- pyurd/include/urd/repr/wrappers/layer.hpp +275 -0
- pyurd/include/urd/repr/wrappers/layered_fwd.hpp +70 -0
- pyurd/include/urd/repr/wrappers/layered_pool.hpp +311 -0
- pyurd/include/urd/repr/wrappers/recycling.hpp +281 -0
- pyurd/include/urd/repr/wrappers/recycling_fwd.hpp +152 -0
- pyurd/include/urd/repr/wrappers/scoped.hpp +227 -0
- pyurd/include/urd/repr/wrappers/scoped_fwd.hpp +122 -0
- pyurd/include/urd/spec.hpp +231 -0
- pyurd/include/urd/store/appending.hpp +85 -0
- pyurd/include/urd/store/assigning.hpp +41 -0
- pyurd/include/urd/store/capacity.hpp +35 -0
- pyurd/include/urd/store/contiguous_data.hpp +40 -0
- pyurd/include/urd/store/ends.hpp +66 -0
- pyurd/include/urd/store/entries.hpp +39 -0
- pyurd/include/urd/store/equality.hpp +40 -0
- pyurd/include/urd/store/grouping.hpp +47 -0
- pyurd/include/urd/store/insertion.hpp +67 -0
- pyurd/include/urd/store/inverse.hpp +30 -0
- pyurd/include/urd/store/iteration.hpp +89 -0
- pyurd/include/urd/store/layers.hpp +97 -0
- pyurd/include/urd/store/lookup.hpp +77 -0
- pyurd/include/urd/store/multi_values.hpp +39 -0
- pyurd/include/urd/store/ordered_lookup.hpp +43 -0
- pyurd/include/urd/store/ordering.hpp +43 -0
- pyurd/include/urd/store/pool.hpp +225 -0
- pyurd/include/urd/store/positions.hpp +137 -0
- pyurd/include/urd/store/queue_access.hpp +101 -0
- pyurd/include/urd/store/records.hpp +126 -0
- pyurd/include/urd/store/removal.hpp +85 -0
- pyurd/include/urd/store/scopes.hpp +53 -0
- pyurd/include/urd/store/set_algebra.hpp +89 -0
- pyurd/include/urd/store/shape.hpp +59 -0
- pyurd/include/urd/store/sizing.hpp +57 -0
- pyurd/include/urd/store/slots.hpp +180 -0
- pyurd/include/urd/store/store_facts.hpp +51 -0
- pyurd/include/urd/store/types.hpp +170 -0
- pyurd/include/urd/store/values_by_key.hpp +110 -0
- pyurd/include/urd/store.hpp +266 -0
- pyurd/include/urd/tags.hpp +1226 -0
- pyurd/include/urd/testing/allocations.cpp +51 -0
- pyurd/include/urd/testing/allocations.hpp +91 -0
- pyurd/include/urd/traits.hpp +70 -0
- pyurd/include/urd/type_traits_of.hpp +200 -0
- pyurd/lib/cmake/urd/urdConfig.cmake +54 -0
- pyurd/lib/cmake/urd/urdConfigVersion.cmake +54 -0
- pyurd/lib/cmake/urd/urdTargets.cmake +118 -0
- pyurd/py.typed +0 -0
- pyurd/repair.py +95 -0
- pyurd/share/urd/complexity.json +85 -0
- pyurd/share/urd/vocabulary.json +78 -0
- pyurd-0.1.0.dist-info/METADATA +122 -0
- pyurd-0.1.0.dist-info/RECORD +176 -0
- pyurd-0.1.0.dist-info/WHEEL +5 -0
- pyurd-0.1.0.dist-info/licenses/LICENSE +674 -0
pyurd/__init__.py
ADDED
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Copyright (C) 2026 Dominik Drexler
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
"""urd's headers and CMake package: the paths of the bundled prefix. The libraries urd's headers include are
|
|
5
|
+
pyurd-native's (``pyurd_native.native_prefix()``)."""
|
|
6
|
+
|
|
7
|
+
import tomllib as _tomllib
|
|
8
|
+
from importlib.metadata import PackageNotFoundError, version
|
|
9
|
+
from pathlib import Path
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _has_urd_headers(path: Path) -> bool:
|
|
13
|
+
return (path / "include" / "urd").is_dir()
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
def source_version() -> str:
|
|
17
|
+
for parent in Path(__file__).resolve().parents:
|
|
18
|
+
pyproject = parent / "pyproject.toml"
|
|
19
|
+
if not pyproject.exists():
|
|
20
|
+
continue
|
|
21
|
+
|
|
22
|
+
project_version = _tomllib.loads(pyproject.read_text(encoding="utf-8")).get("project", {}).get("version")
|
|
23
|
+
if project_version is not None:
|
|
24
|
+
return project_version
|
|
25
|
+
|
|
26
|
+
return "0.0.0"
|
|
27
|
+
|
|
28
|
+
|
|
29
|
+
try:
|
|
30
|
+
__version__ = version("pyurd")
|
|
31
|
+
except PackageNotFoundError:
|
|
32
|
+
__version__ = source_version()
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def native_prefix() -> Path:
|
|
36
|
+
"""Return the directory containing urd's headers and CMake package."""
|
|
37
|
+
package_dir = Path(__file__).resolve().parent
|
|
38
|
+
if _has_urd_headers(package_dir):
|
|
39
|
+
return package_dir
|
|
40
|
+
for parent in package_dir.parents:
|
|
41
|
+
if (parent / "pyproject.toml").exists() and _has_urd_headers(parent):
|
|
42
|
+
return parent
|
|
43
|
+
|
|
44
|
+
return package_dir
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def include_dir() -> Path:
|
|
48
|
+
"""Return the bundled C++ header include directory."""
|
|
49
|
+
return native_prefix() / "include"
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def library_dirs() -> tuple[Path, ...]:
|
|
53
|
+
"""Return existing bundled native library directories."""
|
|
54
|
+
prefix = native_prefix()
|
|
55
|
+
return tuple(path for path in (prefix / "lib", prefix / "lib64") if path.is_dir())
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def cmake_dirs() -> tuple[Path, ...]:
|
|
59
|
+
"""Return existing bundled CMake package directories."""
|
|
60
|
+
return tuple(path / "cmake" for path in library_dirs() if (path / "cmake").is_dir())
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def cmake_prefix() -> Path:
|
|
64
|
+
"""Return the prefix to put on CMAKE_PREFIX_PATH.
|
|
65
|
+
|
|
66
|
+
find_package then finds urd there; its dependencies are under pyurd-native's prefix, which goes on
|
|
67
|
+
CMAKE_PREFIX_PATH too.
|
|
68
|
+
"""
|
|
69
|
+
return native_prefix()
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
def cmake_dir() -> Path:
|
|
73
|
+
"""Return the directory containing urdConfig.cmake."""
|
|
74
|
+
for cmake_packages_dir in cmake_dirs():
|
|
75
|
+
candidate = cmake_packages_dir / "urd"
|
|
76
|
+
if (candidate / "urdConfig.cmake").is_file():
|
|
77
|
+
return candidate
|
|
78
|
+
|
|
79
|
+
msg = (
|
|
80
|
+
"urdConfig.cmake not found under "
|
|
81
|
+
f"{[str(path) for path in cmake_dirs()] or native_prefix()}; "
|
|
82
|
+
"the installed pyurd is too old or incomplete."
|
|
83
|
+
)
|
|
84
|
+
raise FileNotFoundError(msg)
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
__all__ = [
|
|
88
|
+
"__version__",
|
|
89
|
+
"cmake_dir",
|
|
90
|
+
"cmake_dirs",
|
|
91
|
+
"cmake_prefix",
|
|
92
|
+
"include_dir",
|
|
93
|
+
"library_dirs",
|
|
94
|
+
"native_prefix",
|
|
95
|
+
]
|
pyurd/__main__.py
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Copyright (C) 2026 Dominik Drexler
|
|
2
|
+
# SPDX-License-Identifier: GPL-3.0-or-later
|
|
3
|
+
|
|
4
|
+
"""``python -m pyurd``: print where urd's headers and CMake package are."""
|
|
5
|
+
|
|
6
|
+
import argparse
|
|
7
|
+
|
|
8
|
+
import pyurd
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def main() -> None:
|
|
12
|
+
"""Print the requested path or version."""
|
|
13
|
+
parser = argparse.ArgumentParser(
|
|
14
|
+
prog="python -m pyurd",
|
|
15
|
+
description="Print discovery paths for urd's headers and CMake package.",
|
|
16
|
+
)
|
|
17
|
+
group = parser.add_mutually_exclusive_group(required=True)
|
|
18
|
+
group.add_argument(
|
|
19
|
+
"--prefix",
|
|
20
|
+
action="store_true",
|
|
21
|
+
help="Print the prefix to put on CMAKE_PREFIX_PATH.",
|
|
22
|
+
)
|
|
23
|
+
group.add_argument(
|
|
24
|
+
"--include-dir",
|
|
25
|
+
action="store_true",
|
|
26
|
+
help="Print the bundled C++ header include directory.",
|
|
27
|
+
)
|
|
28
|
+
group.add_argument(
|
|
29
|
+
"--cmake-dir",
|
|
30
|
+
action="store_true",
|
|
31
|
+
help="Print the directory containing urdConfig.cmake.",
|
|
32
|
+
)
|
|
33
|
+
group.add_argument(
|
|
34
|
+
"--version",
|
|
35
|
+
action="store_true",
|
|
36
|
+
help="Print the pyurd version.",
|
|
37
|
+
)
|
|
38
|
+
args = parser.parse_args()
|
|
39
|
+
|
|
40
|
+
if args.prefix:
|
|
41
|
+
print(pyurd.cmake_prefix())
|
|
42
|
+
elif args.include_dir:
|
|
43
|
+
print(pyurd.include_dir())
|
|
44
|
+
elif args.cmake_dir:
|
|
45
|
+
print(pyurd.cmake_dir())
|
|
46
|
+
elif args.version:
|
|
47
|
+
print(pyurd.__version__)
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
main()
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// urd's bit vocabulary, for code outside urd: a span over the words of a bitset, its set bits as a range, and the
|
|
4
|
+
// helpers that read and write integers packed into words. These are the names to use; urd::repr is urd's own. (The
|
|
5
|
+
// tag urd::bit is a request's; the helpers are urd::bits.)
|
|
6
|
+
|
|
7
|
+
#include "urd/repr/containers/bit.hpp"
|
|
8
|
+
#include "urd/repr/containers/bitset_span.hpp"
|
|
9
|
+
|
|
10
|
+
namespace urd
|
|
11
|
+
{
|
|
12
|
+
|
|
13
|
+
/// A span over the words of a bitset, a bit per index below its length.
|
|
14
|
+
template<typename Block>
|
|
15
|
+
using bitset_span = repr::BitsetSpan<Block>;
|
|
16
|
+
/// The set bits of a bitset_span, as a range of their indices: what set_bit_indices gives.
|
|
17
|
+
template<typename Block>
|
|
18
|
+
using set_bit_indices_view = repr::SetBitIndices<Block>;
|
|
19
|
+
using repr::for_each_bit;
|
|
20
|
+
using repr::set_bit_indices;
|
|
21
|
+
|
|
22
|
+
namespace bits
|
|
23
|
+
{
|
|
24
|
+
|
|
25
|
+
using repr::bit::bits_needed;
|
|
26
|
+
using repr::bit::bits_per_block_v;
|
|
27
|
+
using repr::bit::ceil_div;
|
|
28
|
+
using repr::bit::for_each_set_bit;
|
|
29
|
+
using repr::bit::int_reference;
|
|
30
|
+
using repr::bit::lo_set;
|
|
31
|
+
using repr::bit::read_int;
|
|
32
|
+
using repr::bit::write_int;
|
|
33
|
+
|
|
34
|
+
} // namespace bits
|
|
35
|
+
|
|
36
|
+
} // namespace urd
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include <cassert>
|
|
4
|
+
#include <cstddef>
|
|
5
|
+
#include <cstdint>
|
|
6
|
+
#include <limits>
|
|
7
|
+
|
|
8
|
+
namespace urd
|
|
9
|
+
{
|
|
10
|
+
|
|
11
|
+
/// urd's word: the unsigned integer that bit-packed storage is made of (rows of a bit width or of column widths, sets
|
|
12
|
+
/// kept as bits), and that a packed value is read and written as.
|
|
13
|
+
using word_t = std::uint64_t;
|
|
14
|
+
|
|
15
|
+
/// Its bits, derived from it: the most a packed value takes. No code spells them as a number.
|
|
16
|
+
inline constexpr std::size_t word_bits = std::numeric_limits<word_t>::digits;
|
|
17
|
+
|
|
18
|
+
} // namespace urd
|
|
19
|
+
|
|
20
|
+
// NOLINTBEGIN(cppcoreguidelines-macro-usage): each must expand at its call site
|
|
21
|
+
/// States an invariant of side-effect free `condition`: asserted in Debug, assumed in Release (undefined
|
|
22
|
+
/// behavior if false, at no cost), and visible to static analysis in both, unlike a plain assert under NDEBUG
|
|
23
|
+
/// (a function would hide the condition from the analysis of optionals).
|
|
24
|
+
#if defined(_MSC_VER)
|
|
25
|
+
#define URD_ASSUME(condition) (assert(condition), (condition) ? void(0) : __assume(0))
|
|
26
|
+
#else
|
|
27
|
+
#define URD_ASSUME(condition) (assert(condition), (condition) ? void(0) : __builtin_unreachable())
|
|
28
|
+
#endif
|
|
29
|
+
|
|
30
|
+
/// Keeps a rarely taken helper out of line, so its size does not count towards the inlined size of its caller.
|
|
31
|
+
#if defined(_MSC_VER)
|
|
32
|
+
#define URD_NOINLINE __declspec(noinline)
|
|
33
|
+
#else
|
|
34
|
+
#define URD_NOINLINE [[gnu::noinline]]
|
|
35
|
+
#endif
|
|
36
|
+
|
|
37
|
+
/// Marks a parameter that the function's result refers to, so the compiler can warn when the result outlives a
|
|
38
|
+
/// temporary argument (Clang); empty where the attribute is unknown.
|
|
39
|
+
#if defined(__has_cpp_attribute)
|
|
40
|
+
#if __has_cpp_attribute(clang::lifetimebound)
|
|
41
|
+
#define URD_LIFETIMEBOUND [[clang::lifetimebound]]
|
|
42
|
+
#endif
|
|
43
|
+
#endif
|
|
44
|
+
#ifndef URD_LIFETIMEBOUND
|
|
45
|
+
#define URD_LIFETIMEBOUND
|
|
46
|
+
#endif
|
|
47
|
+
// NOLINTEND(cppcoreguidelines-macro-usage)
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
// What each operation costs a representation, and the memory it takes: how a cost grows, in which quantity, urd's
|
|
4
|
+
// operations, and a container's table of costs, one entry per operation; its memory in words (urd/memory.hpp tells
|
|
5
|
+
// what it holds). Stated in its declaration (operation_costs, words; urd/registry/declaration.hpp), from which
|
|
6
|
+
// urd/registry/derived.hpp gives container_costs<R>, without defining R. Reading a representation's costs therefore
|
|
7
|
+
// completes nothing and includes no implementation: the registry's own headers suffice. The docs' complexity tables
|
|
8
|
+
// and the benchmarks' judgment of the registry (benchmarks/record.py) read these.
|
|
9
|
+
|
|
10
|
+
#include "urd/traits.hpp"
|
|
11
|
+
|
|
12
|
+
#include <concepts>
|
|
13
|
+
#include <cstdint>
|
|
14
|
+
#include <optional>
|
|
15
|
+
#include <string_view>
|
|
16
|
+
|
|
17
|
+
namespace urd
|
|
18
|
+
{
|
|
19
|
+
|
|
20
|
+
/// How a cost grows, in which quantity.
|
|
21
|
+
enum class growth : std::uint8_t
|
|
22
|
+
{
|
|
23
|
+
one,
|
|
24
|
+
log,
|
|
25
|
+
linear,
|
|
26
|
+
n_log_n,
|
|
27
|
+
n_times, ///< n times the quantity: O(n changes)
|
|
28
|
+
};
|
|
29
|
+
|
|
30
|
+
/// A growth's name: one, log, linear, n_log_n, n_times.
|
|
31
|
+
constexpr std::string_view name(growth of)
|
|
32
|
+
{
|
|
33
|
+
switch (of)
|
|
34
|
+
{
|
|
35
|
+
case growth::one:
|
|
36
|
+
return "one";
|
|
37
|
+
case growth::log:
|
|
38
|
+
return "log";
|
|
39
|
+
case growth::linear:
|
|
40
|
+
return "linear";
|
|
41
|
+
case growth::n_log_n:
|
|
42
|
+
return "n_log_n";
|
|
43
|
+
case growth::n_times:
|
|
44
|
+
return "n_times";
|
|
45
|
+
}
|
|
46
|
+
return {};
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/// What a cost grows in.
|
|
50
|
+
enum class quantity : std::uint8_t
|
|
51
|
+
{
|
|
52
|
+
n, ///< the elements
|
|
53
|
+
keys, ///< U, the key range (dense keys fill it: about n)
|
|
54
|
+
capacity, ///< the slots held (about n over the load factor)
|
|
55
|
+
row, ///< r, a row's length
|
|
56
|
+
delta, ///< k, a delta's changes
|
|
57
|
+
changes, ///< the changes since a scope began, or since the log was cleared
|
|
58
|
+
};
|
|
59
|
+
|
|
60
|
+
/// A quantity's name: n, keys, capacity, row, delta, changes.
|
|
61
|
+
constexpr std::string_view name(quantity of)
|
|
62
|
+
{
|
|
63
|
+
switch (of)
|
|
64
|
+
{
|
|
65
|
+
case quantity::n:
|
|
66
|
+
return "n";
|
|
67
|
+
case quantity::keys:
|
|
68
|
+
return "keys";
|
|
69
|
+
case quantity::capacity:
|
|
70
|
+
return "capacity";
|
|
71
|
+
case quantity::row:
|
|
72
|
+
return "row";
|
|
73
|
+
case quantity::delta:
|
|
74
|
+
return "delta";
|
|
75
|
+
case quantity::changes:
|
|
76
|
+
return "changes";
|
|
77
|
+
}
|
|
78
|
+
return {};
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/// A quantity as a cost writes it: n, U, capacity, r, k, changes.
|
|
82
|
+
constexpr std::string_view symbol(quantity of)
|
|
83
|
+
{
|
|
84
|
+
switch (of)
|
|
85
|
+
{
|
|
86
|
+
case quantity::n:
|
|
87
|
+
return "n";
|
|
88
|
+
case quantity::keys:
|
|
89
|
+
return "U";
|
|
90
|
+
case quantity::capacity:
|
|
91
|
+
return "capacity";
|
|
92
|
+
case quantity::row:
|
|
93
|
+
return "r";
|
|
94
|
+
case quantity::delta:
|
|
95
|
+
return "k";
|
|
96
|
+
case quantity::changes:
|
|
97
|
+
return "changes";
|
|
98
|
+
}
|
|
99
|
+
return {};
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/// Which quantities grow together: the elements, their key range and the capacity are one; a row's length, a delta's
|
|
103
|
+
/// changes and the changes since a scope began each grow on their own.
|
|
104
|
+
enum class scale : std::uint8_t
|
|
105
|
+
{
|
|
106
|
+
n,
|
|
107
|
+
row,
|
|
108
|
+
delta,
|
|
109
|
+
changes,
|
|
110
|
+
};
|
|
111
|
+
/// A scale's name.
|
|
112
|
+
constexpr std::string_view name(scale of)
|
|
113
|
+
{
|
|
114
|
+
switch (of)
|
|
115
|
+
{
|
|
116
|
+
case scale::n:
|
|
117
|
+
return "n";
|
|
118
|
+
case scale::row:
|
|
119
|
+
return "row";
|
|
120
|
+
case scale::delta:
|
|
121
|
+
return "delta";
|
|
122
|
+
case scale::changes:
|
|
123
|
+
return "changes";
|
|
124
|
+
}
|
|
125
|
+
return {};
|
|
126
|
+
}
|
|
127
|
+
constexpr scale scale_of(quantity of)
|
|
128
|
+
{
|
|
129
|
+
switch (of)
|
|
130
|
+
{
|
|
131
|
+
case quantity::n:
|
|
132
|
+
case quantity::keys:
|
|
133
|
+
case quantity::capacity:
|
|
134
|
+
return scale::n;
|
|
135
|
+
case quantity::row:
|
|
136
|
+
return scale::row;
|
|
137
|
+
case quantity::delta:
|
|
138
|
+
return scale::delta;
|
|
139
|
+
case quantity::changes:
|
|
140
|
+
return scale::changes;
|
|
141
|
+
}
|
|
142
|
+
return scale::n;
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
/// One operation's cost: its growth in a quantity, and whether it is amortized or expected.
|
|
146
|
+
struct cost
|
|
147
|
+
{
|
|
148
|
+
growth grows = growth::one;
|
|
149
|
+
quantity of = quantity::n;
|
|
150
|
+
bool amortized = false;
|
|
151
|
+
bool expected = false;
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
/// An operation's words (urd/property_set.hpp, words), and the operation Op (a struct with its name, its description,
|
|
155
|
+
/// and how costs name it). A kind added outside urd adds its own, with costs its containers declare as members named
|
|
156
|
+
/// for it.
|
|
157
|
+
using operation_info = words<struct operation_words>;
|
|
158
|
+
template<typename Op>
|
|
159
|
+
inline constexpr const operation_info* operation_v = &words_of<struct operation_words, Op>;
|
|
160
|
+
|
|
161
|
+
/// A list of operations: what a facet offers.
|
|
162
|
+
template<typename... Ops>
|
|
163
|
+
struct operation_list
|
|
164
|
+
{
|
|
165
|
+
};
|
|
166
|
+
/// urd's operations: each its words, and the key of its entry in a container's costs (cost_table).
|
|
167
|
+
namespace operation
|
|
168
|
+
{
|
|
169
|
+
|
|
170
|
+
struct insert
|
|
171
|
+
{
|
|
172
|
+
static constexpr std::string_view name = "insert";
|
|
173
|
+
static constexpr std::string_view description = "a set's or map's insert, a sequence's push_back";
|
|
174
|
+
};
|
|
175
|
+
struct lookup
|
|
176
|
+
{
|
|
177
|
+
static constexpr std::string_view name = "lookup";
|
|
178
|
+
static constexpr std::string_view description = "find, contains, a map's value by key";
|
|
179
|
+
};
|
|
180
|
+
struct ordered_lookup
|
|
181
|
+
{
|
|
182
|
+
static constexpr std::string_view name = "ordered_lookup";
|
|
183
|
+
static constexpr std::string_view description = "lower_bound";
|
|
184
|
+
};
|
|
185
|
+
struct erase
|
|
186
|
+
{
|
|
187
|
+
static constexpr std::string_view name = "erase";
|
|
188
|
+
static constexpr std::string_view description = "by key, or by position";
|
|
189
|
+
};
|
|
190
|
+
struct clear
|
|
191
|
+
{
|
|
192
|
+
static constexpr std::string_view name = "clear";
|
|
193
|
+
static constexpr std::string_view description = "every element at once";
|
|
194
|
+
};
|
|
195
|
+
struct iterate
|
|
196
|
+
{
|
|
197
|
+
static constexpr std::string_view name = "iterate";
|
|
198
|
+
static constexpr std::string_view description = "every element in turn";
|
|
199
|
+
};
|
|
200
|
+
struct access
|
|
201
|
+
{
|
|
202
|
+
static constexpr std::string_view name = "access";
|
|
203
|
+
static constexpr std::string_view description = "by position or handle";
|
|
204
|
+
};
|
|
205
|
+
struct push
|
|
206
|
+
{
|
|
207
|
+
static constexpr std::string_view name = "push";
|
|
208
|
+
static constexpr std::string_view description = "a queue's";
|
|
209
|
+
};
|
|
210
|
+
struct pop
|
|
211
|
+
{
|
|
212
|
+
static constexpr std::string_view name = "pop";
|
|
213
|
+
static constexpr std::string_view description = "a queue's";
|
|
214
|
+
};
|
|
215
|
+
struct top
|
|
216
|
+
{
|
|
217
|
+
static constexpr std::string_view name = "top";
|
|
218
|
+
static constexpr std::string_view description = "a queue's";
|
|
219
|
+
};
|
|
220
|
+
struct merge
|
|
221
|
+
{
|
|
222
|
+
static constexpr std::string_view name = "merge";
|
|
223
|
+
static constexpr std::string_view description = "a partition's";
|
|
224
|
+
};
|
|
225
|
+
struct insert_row
|
|
226
|
+
{
|
|
227
|
+
static constexpr std::string_view name = "insert_row";
|
|
228
|
+
static constexpr std::string_view description = "a pool's insert";
|
|
229
|
+
};
|
|
230
|
+
struct find_row
|
|
231
|
+
{
|
|
232
|
+
static constexpr std::string_view name = "find_row";
|
|
233
|
+
static constexpr std::string_view description = "a pool's find";
|
|
234
|
+
};
|
|
235
|
+
struct scope
|
|
236
|
+
{
|
|
237
|
+
static constexpr std::string_view name = "scope";
|
|
238
|
+
static constexpr std::string_view description = "push_scope, changes, pop_scope";
|
|
239
|
+
};
|
|
240
|
+
|
|
241
|
+
} // namespace operation
|
|
242
|
+
|
|
243
|
+
/// What operation Op costs in a container: one entry of its costs.
|
|
244
|
+
template<typename Op, cost Cost>
|
|
245
|
+
struct cost_entry
|
|
246
|
+
{
|
|
247
|
+
using operation = Op;
|
|
248
|
+
static constexpr cost value = Cost;
|
|
249
|
+
};
|
|
250
|
+
|
|
251
|
+
/// A container's costs: one entry per operation it offers. `of<Op>()` is Op's cost, or none where it has no entry.
|
|
252
|
+
template<typename... Entries>
|
|
253
|
+
struct cost_table
|
|
254
|
+
{
|
|
255
|
+
template<typename Op>
|
|
256
|
+
static constexpr std::optional<cost> of()
|
|
257
|
+
{
|
|
258
|
+
auto found = std::optional<cost>();
|
|
259
|
+
((std::same_as<Op, typename Entries::operation> ? void(found = Entries::value) : void()), ...);
|
|
260
|
+
return found;
|
|
261
|
+
}
|
|
262
|
+
template<typename Op>
|
|
263
|
+
static constexpr bool passed_on()
|
|
264
|
+
{ return false; }
|
|
265
|
+
};
|
|
266
|
+
|
|
267
|
+
/// A wrapper's costs: its own entries, and for every other operation its part's (Part, a declaration). An operation it
|
|
268
|
+
/// has no entry for is passed on to its part.
|
|
269
|
+
template<typename Part, typename... Entries>
|
|
270
|
+
struct costs_over
|
|
271
|
+
{
|
|
272
|
+
using part = Part;
|
|
273
|
+
template<typename Op>
|
|
274
|
+
static constexpr std::optional<cost> of()
|
|
275
|
+
{
|
|
276
|
+
const auto own = cost_table<Entries...>::template of<Op>();
|
|
277
|
+
return own ? own : Part::operation_costs::template of<Op>();
|
|
278
|
+
}
|
|
279
|
+
template<typename Op>
|
|
280
|
+
static constexpr bool passed_on()
|
|
281
|
+
{ return !cost_table<Entries...>::template of<Op>() && Part::operation_costs::template of<Op>(); }
|
|
282
|
+
};
|
|
283
|
+
|
|
284
|
+
/// The costs of the operations of representation R: its declaration's operation_costs, a cost_table with an entry per
|
|
285
|
+
/// operation R offers (a wrapper's, costs_over its part's declaration). Its memory is the declaration's `words`: at
|
|
286
|
+
/// most so many words per element, or per unit of its `words_per` (a key of its range, a slot of its capacity), an
|
|
287
|
+
/// upper bound the benchmarks judge (benchmarks/record.py); what that memory holds is in words in its synopsis
|
|
288
|
+
/// (urd/registry/derived.hpp, container_synopsis). Declared for every registered representation, derived from its
|
|
289
|
+
/// declaration (urd/registry/derived.hpp); none here.
|
|
290
|
+
template<typename R>
|
|
291
|
+
struct container_costs
|
|
292
|
+
{
|
|
293
|
+
};
|
|
294
|
+
|
|
295
|
+
/// The costs, named: growth, then a for amortized, e for expected.
|
|
296
|
+
namespace costs
|
|
297
|
+
{
|
|
298
|
+
inline constexpr cost one {};
|
|
299
|
+
inline constexpr cost one_a { .amortized = true };
|
|
300
|
+
inline constexpr cost one_e { .expected = true };
|
|
301
|
+
inline constexpr cost one_ae { .amortized = true, .expected = true };
|
|
302
|
+
inline constexpr cost log_n { .grows = growth::log };
|
|
303
|
+
inline constexpr cost log_na { .grows = growth::log, .amortized = true };
|
|
304
|
+
inline constexpr cost lin_n { .grows = growth::linear };
|
|
305
|
+
inline constexpr cost lin_keys { .grows = growth::linear, .of = quantity::keys };
|
|
306
|
+
inline constexpr cost lin_capacity { .grows = growth::linear, .of = quantity::capacity };
|
|
307
|
+
inline constexpr cost lin_row { .grows = growth::linear, .of = quantity::row };
|
|
308
|
+
inline constexpr cost lin_row_e { .grows = growth::linear, .of = quantity::row, .expected = true };
|
|
309
|
+
inline constexpr cost lin_changes { .grows = growth::linear, .of = quantity::changes };
|
|
310
|
+
inline constexpr cost nlog_changes { .grows = growth::n_log_n, .of = quantity::changes };
|
|
311
|
+
} // namespace costs
|
|
312
|
+
|
|
313
|
+
} // namespace urd
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
namespace urd
|
|
4
|
+
{
|
|
5
|
+
|
|
6
|
+
/// The mutable form of a T, filled in place before T is stored or read (a state while it is expanded, a denotation
|
|
7
|
+
/// while it is computed). Specialize it per type; views read it as their record, urd::borrowed_view<T, C, builder<T>>
|
|
8
|
+
/// (or owning_view, shared_view), with the accessors of view_mixin<builder<T>, V>.
|
|
9
|
+
template<typename T>
|
|
10
|
+
struct builder;
|
|
11
|
+
|
|
12
|
+
} // namespace urd
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
#pragma once
|
|
2
|
+
|
|
3
|
+
#include "urd/elements/concepts.hpp"
|
|
4
|
+
#include "urd/elements/flat.hpp"
|
|
5
|
+
#include "urd/elements/index.hpp"
|
|
6
|
+
|
|
7
|
+
#include <boost/mp11/algorithm.hpp>
|
|
8
|
+
#include <concepts>
|
|
9
|
+
#include <tuple>
|
|
10
|
+
#include <type_traits>
|
|
11
|
+
#include <utility>
|
|
12
|
+
|
|
13
|
+
/// The children of a record of element type T: every index<U> with U in the type list Types (a boost::mp11 list),
|
|
14
|
+
/// found anywhere in the record's cista members: directly, in (nested) flat vectors, as a variant's alternative, in an
|
|
15
|
+
/// optional or a pair (std's or cista's, as urd::resolution reads them), or inside a member that names cista members
|
|
16
|
+
/// itself (urd::Serializable). U may be T: an index<T> nested in any of these shapes is a child (an (and (and ...))).
|
|
17
|
+
/// Only a direct member of type index<T> is not: that is the record's own handle. A direct index<T> member that links
|
|
18
|
+
/// to another record of type T (a parent) is therefore not a child either; nest it (an optional, say) to make it one.
|
|
19
|
+
/// They are handed out as the views their context makes, context.view(index) (urd::resolves), so callers never handle
|
|
20
|
+
/// raw indices. urd::map_variant_children instead hands out each variant slot whole (urd::resolve of it), so that a
|
|
21
|
+
/// callback may replace it by another alternative.
|
|
22
|
+
namespace urd
|
|
23
|
+
{
|
|
24
|
+
namespace detail
|
|
25
|
+
{
|
|
26
|
+
/// Calls f with each member of a record whose cista_members() is a Members list.
|
|
27
|
+
template<typename R, typename F>
|
|
28
|
+
void for_each_cista_member(R& record, F f)
|
|
29
|
+
{
|
|
30
|
+
[&]<auto... Ms>(Members<Ms...>) { (f(record.*Ms), ...); }(std::remove_const_t<R>::cista_members());
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
/// A slot of type S that is a child: an index of a type in the list Types.
|
|
34
|
+
template<typename S, typename Types>
|
|
35
|
+
concept child_of = is_index_type<std::remove_const_t<S>> && boost::mp11::mp_contains<Types, typename std::remove_const_t<S>::element_type>::value;
|
|
36
|
+
template<typename Types, typename S>
|
|
37
|
+
inline constexpr bool is_child = child_of<S, Types>;
|
|
38
|
+
|
|
39
|
+
/// Walks member (const or not, as member is) in member order, calling f with each slot f takes (std::invocable) and
|
|
40
|
+
/// not descending into it; any other slot is descended into where it is one of the flat containers a stored record
|
|
41
|
+
/// holds (flat_vector, flat_variant, flat_optional, flat_pair) or a nested record, else skipped. An index f does not
|
|
42
|
+
/// take is skipped too (its own cista member, value, is no slot).
|
|
43
|
+
template<typename M, typename F>
|
|
44
|
+
void walk(M& member, F& f)
|
|
45
|
+
{
|
|
46
|
+
using V = std::remove_const_t<M>;
|
|
47
|
+
if constexpr (std::invocable<F&, M&>)
|
|
48
|
+
f(member);
|
|
49
|
+
else if constexpr (is_index_type<V>)
|
|
50
|
+
return;
|
|
51
|
+
else if constexpr (is_flat_vector<V>)
|
|
52
|
+
for (auto& element : member)
|
|
53
|
+
walk(element, f);
|
|
54
|
+
else if constexpr (is_flat_variant<V>)
|
|
55
|
+
member.apply([&](auto& alternative) { walk(alternative, f); });
|
|
56
|
+
else if constexpr (is_flat_optional<V>)
|
|
57
|
+
{
|
|
58
|
+
if (member.has_value())
|
|
59
|
+
walk(*member, f);
|
|
60
|
+
}
|
|
61
|
+
else if constexpr (is_flat_pair<V>)
|
|
62
|
+
{
|
|
63
|
+
walk(member.first, f);
|
|
64
|
+
walk(member.second, f);
|
|
65
|
+
}
|
|
66
|
+
else if constexpr (Serializable<V>)
|
|
67
|
+
for_each_cista_member(member, [&](auto& nested) { walk(nested, f); });
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/// walk over record's members, but for its own handle: a direct member of type index<T>.
|
|
71
|
+
template<typename T, typename R, typename F>
|
|
72
|
+
void walk_members(R& record, F f)
|
|
73
|
+
{
|
|
74
|
+
for_each_cista_member(record,
|
|
75
|
+
[&]<typename M>(M& member)
|
|
76
|
+
{
|
|
77
|
+
if constexpr (!std::same_as<std::remove_const_t<M>, index<T>>)
|
|
78
|
+
walk(member, f);
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
} // namespace detail
|
|
82
|
+
|
|
83
|
+
/// Calls f(context.view(child)) for every child of record, in member order.
|
|
84
|
+
template<typename Types, typename T, typename R, typename C, typename F>
|
|
85
|
+
void for_each_child(const R& record, const C& context, F f)
|
|
86
|
+
{
|
|
87
|
+
detail::walk_members<T>(record,
|
|
88
|
+
[&]<typename S>(S& child)
|
|
89
|
+
requires detail::is_child<Types, S> { f(context.view(child)); });
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/// record with every child c replaced by urd::to_stored(f(context.view(c))), in member order: f returns an index of
|
|
93
|
+
/// c's type, or a view of one.
|
|
94
|
+
template<typename Types, typename T, typename R, typename C, typename F>
|
|
95
|
+
R map_children(R record, const C& context, F f)
|
|
96
|
+
{
|
|
97
|
+
detail::walk_members<T>(record,
|
|
98
|
+
[&]<typename S>(S& child)
|
|
99
|
+
requires detail::is_child<Types, S> { child = urd::to_stored(f(context.view(child))); });
|
|
100
|
+
return record;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/// map_children, but every flat_variant slot (one not inside another variant; any alternatives, children or not) is
|
|
104
|
+
/// replaced whole: by urd::to_stored(f(urd::resolve(slot, context))), f called with the std::variant of the slot's
|
|
105
|
+
/// alternatives resolved (an empty slot throws std::bad_variant_access). f returns that variant, another of its
|
|
106
|
+
/// alternatives (a view or index of another alternative type), or anything else to_stored makes into the slot's type or
|
|
107
|
+
/// one of its alternatives. The walk does not descend into a slot: the children (and nested variants) inside it are
|
|
108
|
+
/// f's to map. Children outside variants are replaced as map_children replaces them, so f is an overload set (or a
|
|
109
|
+
/// generic callback) taking both the views and the resolved variants.
|
|
110
|
+
template<typename Types, typename T, typename R, typename C, typename F>
|
|
111
|
+
R map_variant_children(R record, const C& context, F f)
|
|
112
|
+
{
|
|
113
|
+
detail::walk_members<T>(record,
|
|
114
|
+
[&]<typename S>(S& slot)
|
|
115
|
+
requires(detail::is_child<Types, S> || is_flat_variant<S>)
|
|
116
|
+
{ slot = urd::to_stored(f(urd::resolve(std::as_const(slot), context))); });
|
|
117
|
+
return record;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
} // namespace urd
|