C++ bindings
Header-only C++17 bindings for the consumer side: #include "fznso.hpp", add c/ and cpp/ to
your include path, and link nothing.
Implementing a solver in C++ is fznso_export.hpp instead.
23 classs
Classes
Section titled “Classes”fznso::AnnotationRef
Section titled “fznso::AnnotationRef”class fznso::AnnotationRefsourceAn annotation attached to a decision, constraint or objective.
AnnotationRef(FznsoAnnotationRef raw)AnnotationRef(const A &source)Borrow an AnnotationSource.
The source must outlive this reference.
Dispatch is static: the vtable is specialised to A, so A’s own methods are called directly.
std::string_view ident() constThe annotation’s identifier.
std::size_t size() constThe number of arguments.
`Value` operator[](std::size_t index) constThe argument at index.
const FznsoAnnotationRef & raw() constThe underlying handle, for passing back across the interface.
fznso::AnnotationSource
Section titled “fznso::AnnotationSource”class fznso::AnnotationSourcesourceProduce an AnnotationRef from a type of your own.
The annotation counterpart to ValueSource: implement this to present a downstream annotation type across the interface, and borrow it with AnnotationRef{source}. The reference borrows the source, which must outlive it.
~AnnotationSource()=defaultstd::string_view ident() const =The annotation’s identifier.
std::size_t size() const =The number of arguments.
`Value` argument(std::size_t index) const =The argument at index.
fznso::Constraint
Section titled “fznso::Constraint”struct fznso::ConstraintsourceThe index of a constraint within a model.
std::size_t indexfznso::Decision
Section titled “fznso::Decision”struct fznso::DecisionsourceThe index of a decision variable within a model.
std::size_t indexfznso::DynSolver
Section titled “fznso::DynSolver”class fznso::DynSolversourceA solver instance created from a loaded Library.
DynSolver(const DynSolver &)=delete`DynSolver` & operator=(const DynSolver &)=deleteDynSolver(DynSolver &&other) noexcept~DynSolver()`Value` option_get(std::string_view name) constThe current value of a named option.
std::optional< std::string > option_set(std::string_view name, const Value &value)Set a named option. Returns the solver’s message on failure.
`Value` statistic(std::string_view name) constThe current value of a named solver-level statistic, or absent if unknown.
Only statistics the library declares with the solver flag set are readable here; those carrying only the solution flag are read from a Solution instead.
`Status` run(const M &model, OnSolution &&on_solution, OnMessage &&on_message, ShouldStop &&should_stop)Run the solver over model, reporting solutions and messages, and polling should_stop to decide whether to keep going.
model may be any Model; passing a concrete type lets ref() be resolved statically. The handlers are called directly, not through a std::function.
should_stop returns true to abandon the search, which yields Status::Kind::Incomplete. It is how a caller ends a run it has already started: return true from inside on_solution for “one solution is
enough”, or flip an atomic from another thread to cancel a long search. Unlike the handlers it may be polled concurrently from several threads, so it must be thread-safe — reading a std::atomic<bool>, the usual implementation, already is.
`Status` run(const M &model, OnSolution &&on_solution, OnMessage &&on_message)Run the solver to completion, reporting solutions and messages.
Passes no stop predicate, so the solver is told it will never be cancelled.
`Status` run(const M &model, OnSolution &&on_solution)Run the solver to completion, ignoring any messages.
Passes neither a message sink nor a stop predicate, so the solver knows to skip building diagnostics and to skip polling.
fznso::FloatRanges
Section titled “fznso::FloatRanges”class fznso::FloatRangessourceThe ranges of a float set, borrowed from the value that produced them.
FloatRanges(Value value)std::size_t size() constbool empty() const`Range`< double > operator[](std::size_t index) constfznso::IntRanges
Section titled “fznso::IntRanges”class fznso::IntRangessourceThe ranges of an integer set, borrowed from the value that produced them.
IntRanges(Value value)std::size_t size() constbool empty() const`Range`< std::int64_t > operator[](std::size_t index) constfznso::LayeredModel
Section titled “fznso::LayeredModel”class fznso::LayeredModelsourceAn in-memory Model, built up in layers.
Decisions and constraints are added to the top layer, which can be pushed and popped until it is marked permanent.
LayeredModel()LayeredModel(const LayeredModel &)=delete`LayeredModel` & operator=(const LayeredModel &)=delete`Decision` add_decision(FznsoType type, OwnedValue domain, std::optional< std::string > name=std::nullopt, bool defined=false, bool in_solution=true, std::vector< OwnedAnnotation > annotations={})Add a decision variable to the top layer.
type says what the variable is — build one with decision_type — and domain which values it may take, which may be absent.
`Constraint` add_constraint(std::string ident, std::vector< OwnedValue > arguments, std::optional< Decision > defines=std::nullopt, std::vector< OwnedAnnotation > annotations={})Add a constraint to the top layer.
void set_objective(std::string ident, OwnedValue argument={}, std::vector< OwnedAnnotation > annotations={})Set the objective. Pass an empty identifier for a satisfaction problem.
void push_layer()Push a new, empty layer.
void pop_layer()Pop the top layer. Throws if it is permanent.
void mark_permanent()Mark every current layer as permanent, so it can never be popped.
void mark_redundant(std::size_t layer)Mark a permanent layer as redundant, letting the solver discard it.
void set_unchanged(std::size_t count)Declare how many layers are unchanged since the last run.
std::size_t layer_count() const overrideThe number of layers currently in the model.
std::size_t layer_permanent() const overrideHow many layers are permanently committed, and so can never be popped.
std::size_t layer_unchanged() const overrideHow many layers are unchanged since the last run.
std::size_t layer_redundant_count() const overrideHow many permanent layers have been marked redundant.
std::size_t layer_redundant_index(std::size_t n) const overrideThe layer index of the n-th redundant layer.
std::size_t decision_count() const overrideThe total number of decision variables.
std::size_t decision_layer_end(std::size_t layer) const overrideOne past the last decision index belonging to layers 0..=layer.
FznsoType decision_type(Decision d) const overrideThe type of a decision variable.
What the variable is, as opposed to decision_domain, which says which values it may take: an absent domain is equally a var bool and an unbounded var int, and an integer range list is equally a var int and the upper bound of a var set of int. Build one with decision_type.
`Value` decision_domain(Decision d) const overrideThe domain of a decision variable.
std::optional< std::string_view > decision_name(Decision d) const overrideThe name of a decision variable, if it has one.
bool decision_defined(Decision d) const overrideWhether a decision variable is functionally defined by a constraint.
bool decision_in_solution(Decision d) const overrideWhether a solution may be asked for a decision variable’s value.
A solver must give every such variable a value in every solution it reports, and is free to leave the others open. Having a name does not make a variable needed: names exist only for debugging.
std::size_t decision_annotation_count(Decision d) const overrideThe number of annotations on a decision variable.
`AnnotationRef` decision_annotation(Decision d, std::size_t index) const overrideThe index-th annotation on a decision variable.
std::size_t constraint_count() const overrideThe total number of constraints.
std::size_t constraint_layer_end(std::size_t layer) const overrideOne past the last constraint index belonging to layers 0..=layer.
std::string_view constraint_ident(Constraint c) const overrideThe identifier of a constraint.
std::size_t constraint_argument_count(Constraint c) const overrideThe number of arguments of a constraint.
`Value` constraint_argument(Constraint c, std::size_t index) const overrideThe index-th argument of a constraint.
std::optional< `Decision` > constraint_defines(Constraint c) const overrideThe decision variable this constraint functionally defines, if any.
std::size_t constraint_annotation_count(Constraint c) const overrideThe number of annotations on a constraint.
`AnnotationRef` constraint_annotation(Constraint c, std::size_t index) const overrideThe index-th annotation on a constraint.
std::string_view objective_ident() const overrideThe objective identifier, or empty for a satisfaction problem.
`Value` objective_arg() const overrideThe objective’s argument.
std::size_t objective_annotation_count() const overrideThe number of annotations on the objective.
`AnnotationRef` objective_annotation(std::size_t index) const overrideThe index-th annotation on the objective.
fznso::Library
Section titled “fznso::Library”class fznso::LibrarysourceA dynamically loaded solver library.
The library owns every symbol a DynSolver created from it uses, so it must outlive them.
std::vector< std::filesystem::path > search_paths()The directories searched for solver libraries, in search order: $FZNSO_SOLVER_PATH, then the per-user directory, then the system ones.
Solvers live in their own fznso directory rather than on the normal library path: a shim is usually named after the solver it wraps, so libgecode.so would otherwise collide with real Gecode, and a dedicated directory is what makes discover possible at all.
std::vector< `Discovered` > discover()List the solver libraries on the search path, without loading any.
Directories are visited in search_paths order and, within a directory, the highest version of a solver comes first. Nothing is opened, so the ABI version is not checked here — find skips a candidate built for another ABI.
std::unique_ptr< `Library` > find(std::string_view name)Load a solver by name from the search path, choosing the newest version.
Candidates are tried in discover order: directory precedence first (a solver in $FZNSO_SOLVER_PATH or the per-user directory overrides a system one even if older), then newest version among equals. A candidate built for a different ABI is skipped and the search continues. Throws std::runtime_error if no matching solver loads.
std::unique_ptr< `Library` > find_version(std::string_view name, std::string_view version)Load a solver by name and version from the search path.
version selects by whole dotted components, so "6" matches 6.2.1; an empty string behaves like find. The newest match is chosen.
Library(const char *path)Dynamically load a solver library, resolving every entry point it must export.
The entry points are fznso_<name>_..., where <name> is recovered from the file name by stripping a leading lib and everything from the first .; this is the only supported naming, so the file name and the exported symbols must agree.
A solver’s name has to satisfy both C and the platform’s library naming at once, so:
- It must be a valid C identifier: ASCII letters, digits and underscores, not starting with a digit. Lowercase is the convention. No
-, no., nothing non-ASCII — those cannot appear in a symbol. - It must not begin with
lib, which could not be told apart from the platform prefix:libssatreads back aslibssatfromliblibssat.sobut asssatfromlibssat.dll. - The file’s base name must be
<name>, optionally prefixed withlib, followed by any version and extension components. Everything from the first.is ignored, so<name>must not contain a..
The version goes between the name and the extension on every platform (libgecode.6.2.1.so, libgecode.6.2.1.dylib, gecode.6.2.1.dll), rather than following each platform’s native library convention, so one rule covers all three. Nothing links against a solver — it is opened by path from a directory off the linker search path — so the ELF libfoo.so.MAJOR soname scheme buys nothing here; the native form is still parsed, so a distribution-packaged libgecode.so.6 also loads.
Several versions of one solver can sit side by side (libgecode.6.so, libgecode.7.so). They export the same symbols, but libraries are opened privately (RTLD_LOCAL, and Windows resolves per module), so several can be loaded at once; pass the exact path, or use find_version, to choose one.
Throws std::runtime_error if the file name yields an unusable name, or if the library cannot be opened or is missing a symbol.
Library(const Library &)=delete`Library` & operator=(const Library &)=delete~Library()`DynSolver` create_solver() constCreate a solver instance.
FznsoConstraintList constraint_types() constFznsoTypeList decision_types() constFznsoObjectiveList objectives() constFznsoOptionList options() constFznsoStatisticList statistics() constfznso::Library::AbiMismatch
Section titled “fznso::Library::AbiMismatch”struct fznso::Library::AbiMismatchsourceThrown when a solver reports an ABI version this header cannot use.
A subclass of std::runtime_error, so existing handlers still catch it.
fznso::Library::Discovered
Section titled “fznso::Library::Discovered”struct fznso::Library::DiscoveredsourceA solver library found on the search path, reported without loading it.
std::string namestd::string versionParsed from the file name; empty if none.
std::filesystem::path pathfznso::Model
Section titled “fznso::Model”class fznso::ModelsourceThe read-only view of a model that a solver is given.
This is the interface, not an implementation: subclass it to expose a model you already hold in some other form, or use LayeredModel to build one. A model is organised into layers, matching the incremental-solving concept in the interface.
~Model()=defaultstd::size_t layer_count() const =The number of layers currently in the model.
std::size_t layer_permanent() const =How many layers are permanently committed, and so can never be popped.
std::size_t layer_unchanged() const =How many layers are unchanged since the last run.
std::size_t layer_redundant_count() const =How many permanent layers have been marked redundant.
std::size_t layer_redundant_index(std::size_t n) const =The layer index of the n-th redundant layer.
std::size_t decision_count() const =The total number of decision variables.
std::size_t decision_layer_end(std::size_t layer) const =One past the last decision index belonging to layers 0..=layer.
FznsoType decision_type(Decision decision) const =The type of a decision variable.
What the variable is, as opposed to decision_domain, which says which values it may take: an absent domain is equally a var bool and an unbounded var int, and an integer range list is equally a var int and the upper bound of a var set of int. Build one with decision_type.
`Value` decision_domain(Decision decision) const =The domain of a decision variable.
std::optional< std::string_view > decision_name(Decision decision) const =The name of a decision variable, if it has one.
bool decision_defined(Decision decision) const =Whether a decision variable is functionally defined by a constraint.
bool decision_in_solution(Decision decision) const =Whether a solution may be asked for a decision variable’s value.
A solver must give every such variable a value in every solution it reports, and is free to leave the others open. Having a name does not make a variable needed: names exist only for debugging.
std::size_t decision_annotation_count(Decision decision) const =The number of annotations on a decision variable.
`AnnotationRef` decision_annotation(Decision decision, std::size_t index) const =The index-th annotation on a decision variable.
std::size_t constraint_count() const =The total number of constraints.
std::size_t constraint_layer_end(std::size_t layer) const =One past the last constraint index belonging to layers 0..=layer.
std::string_view constraint_ident(Constraint constraint) const =The identifier of a constraint.
std::size_t constraint_argument_count(Constraint constraint) const =The number of arguments of a constraint.
`Value` constraint_argument(Constraint constraint, std::size_t index) const =The index-th argument of a constraint.
std::optional< `Decision` > constraint_defines(Constraint constraint) const =The decision variable this constraint functionally defines, if any.
std::size_t constraint_annotation_count(Constraint constraint) const =The number of annotations on a constraint.
`AnnotationRef` constraint_annotation(Constraint constraint, std::size_t index) const =The index-th annotation on a constraint.
std::string_view objective_ident() const =The objective identifier, or empty for a satisfaction problem.
`Value` objective_arg() const =The objective’s argument.
std::size_t objective_annotation_count() const =The number of annotations on the objective.
`AnnotationRef` objective_annotation(std::size_t index) const =The index-th annotation on the objective.
fznso::ModelRefAdapter
Section titled “fznso::ModelRefAdapter”class fznso::ModelRefAdaptersourcePresents a model received across the interface as a Model.
This is what a solver implemented in C++ reads its input through.
ModelRefAdapter(FznsoModelRef raw)std::size_t layer_count() const overrideThe number of layers currently in the model.
std::size_t layer_permanent() const overrideHow many layers are permanently committed, and so can never be popped.
std::size_t layer_unchanged() const overrideHow many layers are unchanged since the last run.
std::size_t layer_redundant_count() const overrideHow many permanent layers have been marked redundant.
std::size_t layer_redundant_index(std::size_t n) const overrideThe layer index of the n-th redundant layer.
std::size_t decision_count() const overrideThe total number of decision variables.
std::size_t decision_layer_end(std::size_t layer) const overrideOne past the last decision index belonging to layers 0..=layer.
FznsoType decision_type(Decision d) const overrideThe type of a decision variable.
What the variable is, as opposed to decision_domain, which says which values it may take: an absent domain is equally a var bool and an unbounded var int, and an integer range list is equally a var int and the upper bound of a var set of int. Build one with decision_type.
`Value` decision_domain(Decision d) const overrideThe domain of a decision variable.
std::optional< std::string_view > decision_name(Decision d) const overrideThe name of a decision variable, if it has one.
bool decision_defined(Decision d) const overrideWhether a decision variable is functionally defined by a constraint.
bool decision_in_solution(Decision d) const overrideWhether a solution may be asked for a decision variable’s value.
A solver must give every such variable a value in every solution it reports, and is free to leave the others open. Having a name does not make a variable needed: names exist only for debugging.
std::size_t decision_annotation_count(Decision d) const overrideThe number of annotations on a decision variable.
`AnnotationRef` decision_annotation(Decision d, std::size_t index) const overrideThe index-th annotation on a decision variable.
std::size_t constraint_count() const overrideThe total number of constraints.
std::size_t constraint_layer_end(std::size_t layer) const overrideOne past the last constraint index belonging to layers 0..=layer.
std::string_view constraint_ident(Constraint c) const overrideThe identifier of a constraint.
std::size_t constraint_argument_count(Constraint c) const overrideThe number of arguments of a constraint.
`Value` constraint_argument(Constraint c, std::size_t index) const overrideThe index-th argument of a constraint.
std::optional< `Decision` > constraint_defines(Constraint c) const overrideThe decision variable this constraint functionally defines, if any.
std::size_t constraint_annotation_count(Constraint c) const overrideThe number of annotations on a constraint.
`AnnotationRef` constraint_annotation(Constraint c, std::size_t index) const overrideThe index-th annotation on a constraint.
std::string_view objective_ident() const overrideThe objective identifier, or empty for a satisfaction problem.
`Value` objective_arg() const overrideThe objective’s argument.
std::size_t objective_annotation_count() const overrideThe number of annotations on the objective.
`AnnotationRef` objective_annotation(std::size_t index) const overrideThe index-th annotation on the objective.
fznso::OwnedAnnotation
Section titled “fznso::OwnedAnnotation”struct fznso::OwnedAnnotationsourceAn owned annotation: the counterpart to AnnotationRef, which only borrows.
Its arguments are OwnedValues.
It is itself an AnnotationSource, so an AnnotationRef borrowing it is just AnnotationRef{owned}.
std::string ident_std::vector< `OwnedValue` > arguments_OwnedAnnotation()=defaultOwnedAnnotation(std::string ident, std::vector< OwnedValue > arguments)std::string_view ident() const overrideThe annotation’s identifier.
std::size_t size() const overrideThe number of arguments.
`Value` argument(std::size_t index) const overrideThe argument at index.
fznso::OwnedValue
Section titled “fznso::OwnedValue”struct fznso::OwnedValuesourceAn owned value: the counterpart to Value, which only borrows.
Holds any of the shapes a value can take. Because it owns its storage, it can outlive whatever it was built from — which is what a model needs, since it is queried long after it is built. Construct one from a Value to copy a borrowed value into owned storage.
It is itself a ValueSource, so a Value borrowing it is just Value{owned}.
std::variant< `Absent`, bool, std::int64_t, double, std::string, `Decision`, `Constraint`, std::vector< `Range`< std::int64_t > >, std::vector< `Range`< double > >, std::vector< `OwnedValue` > > payloadOwnedValue()OwnedValue(bool v)OwnedValue(std::int64_t v)OwnedValue(double v)OwnedValue(std::string v)OwnedValue(const char *v)OwnedValue(Decision v)OwnedValue(Constraint v)OwnedValue(std::vector< Range< std::int64_t > > v)OwnedValue(std::vector< Range< double > > v)OwnedValue(std::vector< OwnedValue > v)OwnedValue(std::optional< T > v)An optional value: std::nullopt is absent, a present value takes the kind of T.
OwnedValue(const Value &value)Copy a borrowed Value into owned storage, recursively.
FznsoValueKind kind() const overrideWhich payload this value holds. Every other method must agree with it.
bool as_bool() const overridestd::int64_t as_int() const overridedouble as_float() const overridestd::string_view as_string() const overrideThe string payload; the returned view must outlive the value.
`Decision` as_decision() const override`Constraint` as_constraint() const overridestd::size_t size() const overrideThe number of list elements or set ranges; zero for anything else.
A string’s length is taken from as_string, so a string source need not implement this — only list and set sources do.
`Range`< std::int64_t > int_range(std::size_t i) const override`Range`< double > float_range(std::size_t i) const override`Value` element(std::size_t i) const overrideThe list element at index; the returned value must outlive this one.
`OwnedValue` int_range(std::int64_t min, std::int64_t max)An integer set covering a single inclusive range.
`OwnedValue` float_range(double min, double max)A float set covering a single inclusive range.
fznso::OwnedValue::Absent
Section titled “fznso::OwnedValue::Absent”struct fznso::OwnedValue::AbsentsourceThe absent value.
fznso::Range
Section titled “fznso::Range”struct fznso::RangesourceAn inclusive [min, max] range.
T minT maxfznso::Solution
Section titled “fznso::Solution”class fznso::SolutionsourceA solution reported by a solver.
Solution(FznsoSolutionRef raw)`Value` operator[](Decision decision) constThe value assigned to a decision variable.
`Value` statistic(std::string_view name) constA named statistic for this solution.
fznso::Status
Section titled “fznso::Status”struct fznso::StatussourceHow a run finished.
enum KindCompleteThe solver explored the whole search space.
IncompleteThe solver stopped early; better solutions may exist.
ErrorThe solver failed; error explains why.
`Kind` kindstd::string errorSet only when kind is Error.
bool complete() constbool failed() constfznso::Type
Section titled “fznso::Type”class fznso::TypesourceBuilds a FznsoType from a base type and the qualifiers you name.
FznsoType is a C struct, so it cannot carry the builder methods itself; this holds one and converts back implicitly, so it can be used anywhere a FznsoType is expected, including the constexpr capability tables a solver declares. Every flag starts clear and is only set by the method that names it, which is what keeps positional bools out of the call:
// `list of var int`
FznsoType arg = `fznso::Type`{FznsoTypeBaseInt}.`list`(true).`decision`(true);
// `var set of int`, or plain `var int`, depending on `of_sets`
FznsoType var = `fznso::Type`{FznsoTypeBaseInt}.`decision`(true).`set`(of_sets);constexpr Type(FznsoTypeBase base)constexpr `Type` list(bool list_of) constWhether this type is a list of its element type.
constexpr `Type` decision(bool decision) constWhether this type is a decision variable rather than a parameter.
constexpr `Type` set(bool set_of) constWhether this type is over sets of its base type rather than single values.
constexpr `Type` opt(bool opt) constWhether this type also permits the absent value.
constexpr operator FznsoType() constfznso::Value
Section titled “fznso::Value”class fznso::ValuesourceA borrowed value handed across the interface.
The typed accessors are only valid for the matching kind(); prefer variant(), which resolves the kind and the payload together.
The converting constructors borrow their argument — the value points at it and reads it back on demand, without copying — so the argument must outlive the value. This is how a value already held elsewhere is handed across the interface. A default-constructed value is absent.
A type that decides its shape at runtime is handed over by deriving from ValueSource and constructing a Value from it. To build an owned value instead — one that outlives the storage it came from — use OwnedValue.
Value()The absent value.
Value(FznsoValueRef raw)Value(const bool &value)Borrow a boolean.
Value(const std::int64_t &value)Borrow a 64-bit integer.
Value(const double &value)Borrow a 64-bit float.
Value(const std::string &value)Borrow a string.
Value(Decision value)Reference a decision variable (carried in the handle, nothing borrowed).
Value(Constraint value)Reference a constraint (carried in the handle, nothing borrowed).
Value(const std::vector< Range< std::int64_t > > &ranges)Borrow an integer set as an ordered list of inclusive ranges.
Value(const std::vector< Range< double > > &ranges)Borrow a float set as an ordered list of inclusive ranges.
Value(const std::vector< T > &items)Borrow a list, whose elements are themselves scalars or ValueSources.
Value(const V &source)Borrow a ValueSource, deciding the value’s shape at runtime.
Dispatch is static: the vtable is specialised to V, so V’s own kind() and accessors are called directly.
FznsoValueKind kind() constWhich payload this value holds.
bool as_bool() conststd::int64_t as_int() constdouble as_float() const`Decision` as_decision() const`Constraint` as_constraint() conststd::string_view as_string() constThe string payload. Not null-terminated; the length comes from len.
std::size_t size() constThe number of list elements, set ranges, or string bytes.
bool empty() const`Value` operator[](std::size_t index) constThe list element at index.
Indexing a value means list indexing; the ranges of a set are reached through int_range/float_range instead, so that [] has one meaning.
`Range`< std::int64_t > int_range(std::size_t index) constThe integer-set range at index.
`Range`< double > float_range(std::size_t index) constThe float-set range at index.
`ValueVariant` variant() constResolve this value into its payload as a variant.
const FznsoValueRef & raw() constThe underlying handle, for passing back across the interface.
fznso::ValueList
Section titled “fznso::ValueList”class fznso::ValueListsourceThe elements of a list value, borrowed from the value that produced them.
ValueList(Value value)std::size_t size() constbool empty() const`Value` operator[](std::size_t index) constfznso::ValueSource
Section titled “fznso::ValueSource”class fznso::ValueSourcesourceProduce a Value from a type that decides its shape at runtime.
Implement this when a single downstream type can hold any kind — an interpreter’s expression, a variant AST node — and you want to hand it across the interface without copying its payload into a OwnedValue. Construct a Value from it; the value borrows this source, which must outlive it.
Implement kind() and the accessors your kinds use; the rest abort if called, since a well-formed value only has its matching accessor invoked.
~ValueSource()=defaultFznsoValueKind kind() const =Which payload this value holds. Every other method must agree with it.
bool as_bool() conststd::int64_t as_int() constdouble as_float() conststd::string_view as_string() constThe string payload; the returned view must outlive the value.
`Decision` as_decision() const`Constraint` as_constraint() conststd::size_t size() constThe number of list elements or set ranges; zero for anything else.
A string’s length is taken from as_string, so a string source need not implement this — only list and set sources do.
`Range`< std::int64_t > int_range(std::size_t) const`Range`< double > float_range(std::size_t) const`Value` element(std::size_t) constThe list element at index; the returned value must outlive this one.