Skip to content

bemanproject/indirect

Repository files navigation

beman.indirect: Vocabulary types for composite class design

Library Status Continuous Integration Tests Lint Check (pre-commit) Coverage Standard Target Compiler Explorer Example

beman.indirect implements std::indirect and std::polymorphic, vocabulary types for composite class design. These types provide value semantics for owned heap-allocated objects:

  • indirect<T>: Owns a heap-allocated T with deep-copy semantics and const-propagation.
  • polymorphic<T>: Owns a heap-allocated object derived from T with polymorphic deep-copy via type erasure.

Implements: std::indirect and std::polymorphic proposed in P3019R14.

Status: Under development and not yet ready for production use.

License

beman.indirect is licensed under the Apache License v2.0 with LLVM Exceptions.

Usage

#include <beman/indirect/indirect.hpp>
#include <beman/indirect/polymorphic.hpp>

// indirect: value-semantic heap-allocated int
beman::indirect::indirect<int> i(42);
auto copy = i;    // deep copy
*copy = 100;      // original unchanged

// polymorphic: value-semantic polymorphic ownership
struct Shape { virtual double area() const = 0; virtual ~Shape() = default; /* ... */ };
struct Circle : Shape { double r; double area() const override { return 3.14 * r * r; } /* ... */ };
beman::indirect::polymorphic<Shape> shape(Circle{5.0});
auto shape_copy = shape;  // deep copy preserves dynamic type

Recursive variants

std::variant cannot directly contain itself, so recursive data structures traditionally use std::unique_ptr. But unique_ptr compares by pointer identity (not by value), forces null checks, and doesn't copy. indirect<T> solves all three: it provides value semantics with deep copy, value-based equality, and is never null (outside of moved-from state).

#include <beman/indirect/indirect.hpp>

#include <map>
#include <string>
#include <variant>
#include <vector>

using beman::indirect::indirect;

struct json_value {
    struct null_t {
        bool operator==(const null_t&) const = default;
    };

    using array_t  = indirect<std::vector<json_value>>;
    using object_t = indirect<std::map<std::string, json_value>>;

    std::variant<null_t, bool, double, std::string, array_t, object_t> data;

    json_value() : data(null_t{}) {}
    json_value(double d) : data(d) {}
    json_value(const char* s) : data(std::string(s)) {}
    json_value(std::string s) : data(std::move(s)) {}
    json_value(std::vector<json_value> a) : data(array_t{std::in_place, std::move(a)}) {}
    json_value(std::map<std::string, json_value> o) : data(object_t{std::in_place, std::move(o)}) {}

    bool operator==(const json_value&) const = default;
};

json_value person(std::map<std::string, json_value>{
    {"name", json_value("Alice")},
    {"scores", json_value(std::vector<json_value>{
        json_value(10.0),
        json_value(20.0),
    })},
});

auto copy = person;   // deep copy of the entire tree
assert(person == copy); // value-based equality through the recursive structure

Full runnable examples can be found in examples/.

Dependencies

Build Environment

This project requires at least the following to build:

  • A C++ compiler that conforms to the C++17 standard or greater
  • CMake 3.30 or later
  • (Test Only) GoogleTest

You can disable building tests by setting CMake option BEMAN_INDIRECT_BUILD_TESTS to OFF when configuring the project.

Supported Platforms

Compiler Version C++ Standards Standard Library
GCC 16-13 C++26-C++17 libstdc++
GCC 12-11 C++23-C++17 libstdc++
Clang 22-19 C++26-C++17 libstdc++, libc++
Clang 18 C++26-C++17 libc++
Clang 18 C++23-C++17 libstdc++
Clang 17 C++26-C++17 libc++
Clang 17 C++20, C++17 libstdc++
AppleClang latest C++26-C++17 libc++
MSVC latest C++23, C++17 MSVC STL

Development

See the Contributing Guidelines.

Integrate beman.indirect into your project

Build

You can build indirect using a CMake workflow preset:

cmake --workflow --preset gcc-release

To list available workflow presets, you can invoke:

cmake --list-presets=workflow

For details on building beman.indirect without using a CMake preset, refer to the Contributing Guidelines.

Installation

Vcpkg

The preferred way to install indirect is via vcpkg. To do so, after installing vcpkg itself, you need to add support for the Beman project's vcpkg registry by configuring a vcpkg-configuration.json file (which indirect provides).

Then, simply run vcpkg install beman-indirect.

Manual

To install beman.indirect globally after building with the gcc-release preset, you can run:

sudo cmake --install build/gcc-release

Alternatively, to install to a prefix, for example /opt/beman, you can run:

sudo cmake --install build/gcc-release --prefix /opt/beman

This will generate the following directory structure:

/opt/beman
├── include
│   └── beman
│       └── indirect
│           ├── indirect.hpp
│           └── ...
└── lib
    └── cmake
        └── beman.indirect
            ├── beman.indirect-config-version.cmake
            ├── beman.indirect-config.cmake
            └── beman.indirect-targets.cmake

CMake Configuration

If you installed beman.indirect to a prefix, you can specify that prefix to your CMake project using CMAKE_PREFIX_PATH; for example, -DCMAKE_PREFIX_PATH=/opt/beman.

You need to bring in the beman.indirect package to define the beman::indirect CMake target:

find_package(beman.indirect REQUIRED)

You will then need to add beman::indirect to the link libraries of any libraries or executables that include beman.indirect headers.

target_link_libraries(yourlib PUBLIC beman::indirect)

Using beman.indirect

To use beman.indirect in your C++ project, include an appropriate beman.indirect header from your source code.

#include <beman/indirect/indirect.hpp>

Note

beman.indirect headers are to be included with the beman/indirect/ prefix. Altering include search paths to spell the include target another way (e.g. #include <indirect.hpp>) is unsupported.

About

Vocabulary types for composite class design (std::indirect and std::polymorphic)

Resources

License

Contributing

Stars

Watchers

Forks

Packages

 
 
 

Contributors