libacfutils
A general purpose library of utility functions designed to make it easier to develop addons for the X-Plane flight simulator.
Loading...
Searching...
No Matches
Data Structures | Macros | Typedefs | Enumerations | Functions
optional.h File Reference
#include <math.h>
#include <string.h>
#include <stdbool.h>
#include <stdint.h>
#include "assert.h"
#include "log.h"
#include "geom.h"
#include "sysmacros.h"
Include dependency graph for optional.h:

Go to the source code of this file.

Data Structures

struct  opt_int8_t
 An optional type for wrapping an int8_t value. More...
 
struct  opt_uint8_t
 An optional type for wrapping a uint8_t value. More...
 
struct  opt_int16_t
 An optional type for wrapping an int16_t value. More...
 
struct  opt_uint16_t
 An optional type for wrapping a uint16_t value. More...
 
struct  opt_int32_t
 An optional type for wrapping an int32_t value. More...
 
struct  opt_uint32_t
 An optional type for wrapping a uint32_t value. More...
 
struct  opt_int64_t
 An optional type for wrapping an int64_t value. More...
 
struct  opt_uint64_t
 An optional type for wrapping a uint64_t value. More...
 
struct  opt_float
 An optional type for wrapping a non-NAN float value. More...
 
struct  opt_double
 An optional type for wrapping a non-NAN double value. More...
 
struct  opt_str
 An optional type for wrapping a non-NULL char * value. More...
 
struct  opt_str_const
 An optional type for wrapping a non-NULL char const * value. More...
 
struct  opt_vect2_t
 An optional type for wrapping a non-NULL vect2_t value. More...
 
struct  opt_vect3_t
 An optional type for wrapping a non-NULL vect3_t value. More...
 
struct  opt_vect3l_t
 An optional type for wrapping a non-NULL vect3l_t value. More...
 
struct  opt_geo_pos2_t
 An optional type for wrapping a non-NULL geo_pos2_t value. More...
 
struct  opt_geo_pos3_t
 An optional type for wrapping a non-NULL geo_pos3_t value. More...
 
struct  opt_geo_pos2_32_t
 An optional type for wrapping a non-NULL geo_pos2_32_t value. More...
 
struct  opt_geo_pos3_32_t
 An optional type for wrapping a non-NULL geo_pos3_32_t value. More...
 

Macros

#define IMPL_OPTIONAL_EXPLICIT(type_name, c_type)
 Declares a custom optional type with explicit NONE encoding.
 
#define IMPL_OPTIONAL_IMPLICIT(type_name, c_type, none_value, none_check)
 Declares a custom optional type with implicit NONE encoding.
 
#define IMPL_OPTIONAL_ALIAS(orig_type_name, alias_type_name, alias_c_type)
 Declares a type alias for an existing optional type.
 
#define OPTIONAL_TYPE_LIST_ADD(type_name, c_type, op_name)    c_type: op_name ## type_name
 Appends a new entry to the definition of the OPTIONAL_TYPE_LIST() macro.
 
#define OPTIONAL_TYPE_LIST(op_name)    default: _unknown_optional_type_you_need_to_include_your_custom_optional_h_
 Overridable list of custom optional types provided by your code.
 
#define SIZE_T_OPTIONAL_LIST_ENTRY(op_name)
 
#define SOME(expr)   OPTIONAL_TYPE_SELECTOR(opt_some_, expr)(expr)
 Constructs a new optional value in the SOME state.
 
#define NONE(type_name)   opt_none_ ## type_name()
 Constructs a new optional value in the NONE state.
 
#define IS_SOME(opt)    OPTIONAL_TYPE_SELECTOR(opt_is_some_, (opt).value)(opt)
 Returns true if the optional is in the SOME state.
 
#define IS_NONE(x)   (!IS_SOME(x))
 Returns true if the optional is in the NONE state.
 
#define MATCH(opt, out_value)    OPTIONAL_TYPE_SELECTOR(opt_match_, (opt).value)((opt), (out_value))
 Extracts the value embedded in the optional and returns the optional_state_t enum corresponding to the state.
 
#define MATCH_AS_REF(opt, out_value_p)
 Extracts an immutable reference to the value embedded in the optional and returns the optional_state_t enum corresponding to the state.
 
#define MATCH_AS_MUT(opt, out_value_p)
 Extracts a reference to the value embedded in the optional and returns the optional_state_t enum corresponding to the state.
 
#define UNWRAP(opt)
 Extracts the value of the optional unconditionally.
 
#define UNWRAP_AS_REF(opt)
 Extracts an immutable reference to the value of the optional unconditionally.
 
#define UNWRAP_AS_MUT(opt)
 Extracts a mutable reference to the value of the optional unconditionally.
 
#define UNWRAP_OR(opt, dfl_value)    OPTIONAL_TYPE_SELECTOR(opt_unwrap_or_, (opt).value)((opt), (dfl_value))
 Extracts the value of the optional, or evaluates to a fallback value.
 
#define UNWRAP_OR_ELSE(opt, dfl_func, dfl_arg)
 Extracts the value of the optional, or yields a fallback value with lazy evaluation.
 
#define UNWRAP_OR_RET(opt, ...)
 Unwraps a SOME value, or in case of a NONE value, returns from the current function.
 
#define UNWRAP_OR_GOTO(opt, label)
 Unwraps a SOME value, or in case of a NONE value, goes to the label.
 
#define UNWRAP_OR_BREAK(opt)
 Unwraps a SOME value, or in case of a NONE value, breaks out of the current loop or switch case (invokes the break keyword).
 
#define UNWRAP_OR_CONTINUE(opt)
 Unwraps a SOME value, or in case of a NONE value, restarts the current loop iteration (invokes the continue keyword).
 
#define OPT_OR(a, b)    OPTIONAL_TYPE_SELECTOR(opt_or_, (a).value)((a), (b))
 Selects between two optional values based on whether the first optional is in the SOME state.
 
#define OPT_OR_ELSE(a, func_b, arg_b)    OPTIONAL_TYPE_SELECTOR(opt_or_else_, (a).value)((a), (func_b), (arg_b))
 Selects between two optional values based on whether the first optional is in the SOME state. Provides lazy evaluation.
 
#define IF_LET(vartype, varname, opt)
 Allows constructing Rust-like if-let statements in C.
 
#define IF_LET_AS_REF(vartype, varname, opt)
 Same as IF_LET() macro, but returns reference to the value.
 
#define OPT_INTO(value)   OPTIONAL_TYPE_SELECTOR(opt_into_, (value))(value)
 Allows wrapping an implicitly representable value into a suitable optional.
 

Typedefs

typedef opt_uint64_t opt_size_t
 An optional type for wrapping a size_t value.
 
typedef opt_int8_t opt_i8
 Alias for opt_int8_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_uint8_t opt_u8
 Alias for opt_uint8_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_int16_t opt_i16
 Alias for opt_int16_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_uint16_t opt_u16
 Alias for opt_uint16_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_int32_t opt_i32
 Alias for opt_int32_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_uint32_t opt_u32
 Alias for opt_uint32_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_int64_t opt_i64
 Alias for opt_int64_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_uint64_t opt_u64
 Alias for opt_uint64_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_size_t opt_usize
 Alias for opt_size_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_float opt_f32
 Alias for opt_float available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 
typedef opt_double opt_f64
 Alias for opt_double available if OPTIONALS_WITH_RUSTY_NAMES is defined.
 

Enumerations

enum  optional_state_t { OPT_NONE , OPT_SOME }
 

Functions

opt_int8_t opt_into_int8_t (int8_t)
 
opt_uint8_t opt_into_uint8_t (uint8_t)
 
opt_int16_t opt_into_int16_t (int16_t)
 
opt_uint16_t opt_into_uint16_t (uint16_t)
 
opt_int32_t opt_into_int32_t (int32_t)
 
opt_uint32_t opt_into_uint32_t (uint32_t)
 
opt_int64_t opt_into_int64_t (int64_t)
 
opt_uint64_t opt_into_uint64_t (uint64_t)
 
static opt_size_t opt_into_size_t (size_t value)
 
static opt_float opt_into_float (float x)
 
static opt_double opt_into_double (double x)
 
static opt_i8 opt_into_i8 (int8_t value)
 
static opt_u8 opt_into_u8 (uint8_t value)
 
static opt_i16 opt_into_i16 (int16_t value)
 
static opt_u16 opt_into_u16 (uint16_t value)
 
static opt_i32 opt_into_i32 (int32_t value)
 
static opt_u32 opt_into_u32 (uint32_t value)
 
static opt_i64 opt_into_i64 (int64_t value)
 
static opt_u64 opt_into_u64 (uint64_t value)
 
static opt_usize opt_into_usize (size_t value)
 
static opt_f32 opt_into_f32 (float value)
 
static opt_f64 opt_into_f64 (double value)
 
static opt_str opt_into_str (char *x)
 
static opt_str_const opt_into_str_const (const char *x)
 
static opt_vect2_t opt_into_vect2_t (vect2_t x)
 
static opt_vect3_t opt_into_vect3_t (vect3_t x)
 
static opt_vect3l_t opt_into_vect3l_t (vect3l_t x)
 
static opt_geo_pos2_t opt_into_geo_pos2_t (geo_pos2_t x)
 
static opt_geo_pos3_t opt_into_geo_pos3_t (geo_pos3_t x)
 
static opt_geo_pos2_32_t opt_into_geo_pos2_32_t (geo_pos2_32_t x)
 
static opt_geo_pos3_32_t opt_into_geo_pos3_32_t (geo_pos3_32_t x)
 

Detailed Description

Optional Types

This file provides a simplified Rust-like optional type machinery for C11 code. In Rust, the Option<T> type allows expressing the concept of a value being optionally present, with support from the type checker. This helps avoid inadvertently using uninitialized or invalid data without employing proper checks.

Principles of Operation

An optional type is a structure which wraps an underlying type and enforces explicit checks for value presence at compile time. Rather than relying on checking the value of a variable at runtime for validity (e.g. checking a pointer for NULL), the validity check is enforced by preventing access to the wrapped value without first performing a validity-checking unwrapping operation. We refer to the state of the value being valid as the "SOME" state, whereas the invalid state is called "NONE."

For example, to wrap an int32_t as an optional type, we declare a structure of type opt_int32_t and store both the integer value as well as the validity state in the structure (don't worry, you don't need declare this structure yourself, optional.h provides lots of canned types, as well as simple construction macros for your own types, see below). Users of the optional type are then forced to perform one of the several available unwrapping operations on the optional, which perform the validity check.

Constructing Optional Values

Use one of the following two macros to construct new optional values:

  1. SOME(T expr) -> opt_T: returns an optional value of type opt_T in the SOME state from a provided expression argument. Please note that the optional type may perform integrity checks on the value, to make sure that it really conforms to the SOME specification on the type (what constitutes a valid SOME value depends on the type, see below).
  2. NONE(T) -> opt_T: returns an optional value of type opt_T in the NONE state. The argument to this macro is the type name of the optional (the part after the opt_ prefix of the optional type, not necessarily the contained C type).

Manipulating Optional Values

To manipulate an optional value, use one of the following macros:

  1. IS_SOME(opt_T opt) -> bool: returns true if the optional opt is in the SOME state.
  2. IS_NONE(opt_T opt) -> bool: returns true if the optional opt is in the NONE state.
  3. MATCH(opt_T opt, T &out_value) -> optional_state_t: this operation checks the state of the optional opt. If it is in the SOME state, the wrapped value is written to &out_value and the entire MATCH operation returns the OPT_SOME enumeration. If the optional is in the NONE state, the &out_value reference is filled with an invalid value and the MATCH operation returns OPT_NONE.
  4. UNWRAP(opt_T opt) -> T: this operation returns the wrapped value contained within the optional type, if the optional is in the SOME state. If the state is NONE, then attempting this operation causes a runtime assertion failure and panic. UNWRAP() should only be used for testing, or for cases where another check has already been performed, guaranteeing that the value is the SOME state.
  5. UNWRAP_OR(opt_T opt, T dfl_value) -> T: if the optional opt is in the SOME state, this operation returns the wrapped value of type T. If the optional value is in the NONE state, this operation returns dfl_value instead.
  6. UNWRAP_OR_ELSE(opt_T opt, T (*func), void *arg) -> T: if the optional opt is in the SOME state, returns the wrapped value of type T. If the optional value is in the NONE state, lazily calls func with arg and returns its return value.
  7. OPT_OR(opt_T a, opt_T b) -> opt_T: if the state of the optional a is SOME, returns a. Otherwise, returns b.
  8. OPT_OR_ELSE(opt_T a, opt_T (*func), void *arg) -> opt_T: if the state of a is SOME, returns a. Otherwise, lazily calls func with arg and returns its return value.

Interoperating with C++ Code

While the optional.h functionality is primarily designed for C11 code, optional values can be both manipulated as well as constructed from C++ code. This bridge is primarily provided for compatibility in heterogeneous codebases.

C++ doesn't have the same kind of type-matching mechanism as C11's _Generic statement has, so when called from C++ code, the above macros need an explicit type name argument. For example, for a optional value of type opt_float, you must modify the macro invocations from C++ code as follows:

  1. SOME(x) becomes SOME(float, x)
  2. MATCH(opt, out_val) becomes MATCH(float, opt, out_val)
  3. (etc.)

Available Built-In Optional Types

This list summarizes all automatically provided optional types directly from libacfutils. See the next section on how to add extra custom optional types for your own needs.

  1. Most sized standard C integer types: opt_int8_t, opt_uint8_t, etc. through to opt_uint64_t. The type opt_size_t is a type alias, which can be used for wrapping a size_t (except on macOS, where it is a full type, same as uint64_t and friends).
  2. Single-precision and double-precision floating point types: opt_float and opt_double. These types are explicitly disallow NAN values in the SOME state.
  3. Vector types from geom.h: opt_vect2_t, opt_vect3_t and opt_vect3l_t. These types explicitly disallow the matching NULL_VECT* values in the SOME state.
  4. Geographic coordinate types from geom.h: opt_geo_pos2_t, opt_geo_pos3_t, opt_geo_pos2_32_t and opt_geo_pos3_32_t. These types explicitly disallow the matching NULL_GEO_POS* values in the SOME state.
  5. C string types opt_str (containing a char *) and opt_str_const (containing a char const *). These types explicitly disallow passing a NULL pointer in the SOME state.

Adding Your Own Custom Optional Types

Due to the preprocessor-driven nature of the optional.h machinery, adding custom optional types is a bit tricky, but possible. To do so, you must first create your header file, which will #include <acfutils/optional.h> at the start. It should then include any headers for declarations of the types you wish to wrap into new optional types. Any code that wants to use these new optional types must then include this custom header, to allow for properly selecting the implementation using the standard SOME, MATCH and similar macros. Example header template so far:

#ifndef _my_optional_h_
#define _my_optional_h_
#include "my_type_1.h"
#include "my_type_2.h"
#endif // _my_optional_h_

With the headers included, we can proceed to implement each optional type using the IMPL_OPTIONAL_IMPLICIT() or IMPL_OPTIONAL_EXPLICIT() macros. See each macro for details on what they do.

#ifndef _my_optional_h_
#define _my_optional_h_
#include "my_type_1.h"
#include "my_type_2.h"
IMPL_OPTIONAL_EXPLICIT(my_type_1, my_type_1, my_1_none_value)
IMPL_OPTIONAL_IMPLICIT(my_type_2, my_type_2, my_2_none_value,
check_type_2_is_none(x))
#endif // _my_optional_h_
#define IMPL_OPTIONAL_EXPLICIT(type_name, c_type)
Declares a custom optional type with explicit NONE encoding.
Definition optional.h:310
#define IMPL_OPTIONAL_IMPLICIT(type_name, c_type, none_value, none_check)
Declares a custom optional type with implicit NONE encoding.
Definition optional.h:491

We have now constructed all of the necessary typedefs and inline functions to manipulate each optional type. Lastly, we need to link these new types into the master auto-selection macro inside of optional.h. We do this by simply redefining the OPTIONAL_TYPE_LIST macro, filling it with our types:

#ifndef _my_optional_h_
#define _my_optional_h_
#include "my_type_1.h"
#include "my_type_2.h"
IMPL_OPTIONAL_EXPLICIT(my_type_1, my_type_1, my_1_none_value)
IMPL_OPTIONAL_IMPLICIT(my_type_2, my_type_2, my_2_none_value,
check_type_2_is_none(x))
#undef OPTIONAL_TYPE_LIST
#define OPTIONAL_TYPE_LIST(op_name) \
OPTIONAL_TYPE_LIST_ADD(my_type_1, my_type_1, op_name), \
OPTIONAL_TYPE_LIST_ADD(my_type_2, my_type_2, op_name)
#endif // _my_optional_h_

Please note that the OPTIONAL_TYPE_LIST() macro must be defined to take an op_name argument and must pass it through to the OPTIONAL_TYPE_LIST_ADD() macro invocations within. This is required to correctly construct the invoked function names when an optional operation macro is instantiated.

We have now extended the optional list with our new custom optional types, opt_my_type_1 and opt_my_type_2 (containing values of type my_type_1 and my_type_2 respectively). All the standard optional types from libacfutils remain available as well.

There are some important caveats to consider when adding custom optional types:

Definition in file optional.h.

Macro Definition Documentation

◆ IF_LET

#define IF_LET (   vartype,
  varname,
  opt 
)
Value:
{ \
vartype __if_let_tmp_##varname; \
/* \
* The void pointer cast here gets rid of a C language quirk \
* where const and non-const pointers aren't technically \
* compatible for referencing. Thus to avoid having to force \
* the caller to use a mutable reference when all they want \
* is an immutable reference, we perform type erasure here. \
*/ \
if (MATCH((opt), (void *)&__if_let_tmp_##varname) == \
OPT_SOME) { \
vartype varname = __if_let_tmp_##varname;
#define MATCH(opt, out_value)
Extracts the value embedded in the optional and returns the optional_state_t enum corresponding to th...
Definition optional.h:1057
@ OPT_SOME
State denoting that the optional contains a valid value.
Definition optional.h:277

Allows constructing Rust-like if-let statements in C.

This macro helps in assembling Rust-like if-let statements, which scope their variables to prevent inadvertently leaking them outside of the properly matched scope (as might otherwise happen with the MATCH() macro).

This macro, along with its accompanying IF_LET_END and IF_LET_ELSE macros replaces the normal control flow constructs, to provide automatic scoping.

opt_float my_option;
IF_LET(float, foo, my_option)
// place your condition-met code into this block
// `foo' is available here (and only here) to contain the
// SOME state value of `my_option'
use_foo(foo);
IF_LET_END
#define IF_LET(vartype, varname, opt)
Allows constructing Rust-like if-let statements in C.
Definition optional.h:1507
An optional type for wrapping a non-NAN float value.
Definition optional.h:755

In the above example, foo is prevented from leaking outside of the if block scope, thus stopping accidentally using it when no value was contained in the optional type. To add an else block to this kind of block, use:

IF_LET(float, foo, my_option)
use_foo(foo);
IF_LET_ELSE
// `foo' doesn't exist here
do_something_else();
IF_LET_END

Definition at line 1507 of file optional.h.

◆ IF_LET_AS_REF

#define IF_LET_AS_REF (   vartype,
  varname,
  opt 
)
Value:
{ \
vartype __if_let_tmp_##varname; \
if (MATCH_AS_REF((opt), (void *)&__if_let_tmp_##varname) == \
OPT_SOME) { \
vartype varname = __if_let_tmp_##varname;
#define MATCH_AS_REF(opt, out_value_p)
Extracts an immutable reference to the value embedded in the optional and returns the optional_state_...
Definition optional.h:1099

Same as IF_LET() macro, but returns reference to the value.

This macro works in a similar manner as IF_LET(), but instead returning the optional in the SOME case by value, the optional is returned by reference (as in MATCH_AS_REF()). Example:

opt_object_t maybe_obj;
IF_LET_AS_REF(object_t *, obj, maybe_obj)
// `obj' points into `maybe_obj'
use_obj_ref(obj);
IF_LET_END
#define IF_LET_AS_REF(vartype, varname, opt)
Same as IF_LET() macro, but returns reference to the value.
Definition optional.h:1529

Definition at line 1529 of file optional.h.

◆ IMPL_OPTIONAL_ALIAS

#define IMPL_OPTIONAL_ALIAS (   orig_type_name,
  alias_type_name,
  alias_c_type 
)

Declares a type alias for an existing optional type.

This function constructs a typedef, as well as support functions to make the new type name function equally to the old one.

Parameters
orig_type_nameThe type name of the original type. The type name is the part following the opt_ prefix in the optional type and need not exactly correspond to the C type of the embedded value.
alias_type_nameThe new aliased type name for the optional type. This can subsequently be used in any place where the original type name would have been.
alias_c_typeThe C type of the aliased type. This type must be directly compatible to the embedded type of the original optional type.

Definition at line 651 of file optional.h.

◆ IMPL_OPTIONAL_EXPLICIT

#define IMPL_OPTIONAL_EXPLICIT (   type_name,
  c_type 
)

Declares a custom optional type with explicit NONE encoding.

This macro constructs all the necessary typedefs and inline functions for your custom optional type, allowing it to be linked into the optional type selection logic in macros such as SOME(x) or MATCH(x, out). The "explicit" nature of this optional means that the SOME/NONE state of the value cannot be inferred and checked from the value itself, but rather must be stored directly in the optional state. This inflates the stored type by an extra 32 bits on most platforms, because the value of the optional_state_t enum must be embedded. If your value supports implicit SOME/NONE distinction (such as a floating point number with NAN, or a pointer being NULL), then you can use the IMPL_OPTIONAL_IMPLICIT() macro instead. This provides additional integrity checking, to make sure the caller doesn't attempt to embed an invalid value when constructing the optional type using the SOME() macro.

Note
Don't forget to also add the type to your OPTIONAL_TYPE_LIST().
Parameters
type_nameThe type name of the optional type. This will be the name which will appear after the opt_ prefix. For example, passing foobar here will result in an optional type named opt_foobar. This string must constitute a well-formed C identifier, as it is used as part of the typedef name, as well as manipulation function names.
c_typeThe actual C type being wrapped by the optional type. This can be any valid C type.

Definition at line 310 of file optional.h.

◆ IMPL_OPTIONAL_IMPLICIT

#define IMPL_OPTIONAL_IMPLICIT (   type_name,
  c_type,
  none_value,
  none_check 
)

Declares a custom optional type with implicit NONE encoding.

This macro constructs all the necessary typedefs and inline functions for your custom optional type, allowing it to be linked into the optional type selection logic in macros such as SOME(x) or MATCH(x, out). The "implicit" nature of this optional means that the SOME/NONE state of the value is encoded directly in the value itself and can be checked at runtime. This also saves a bit of storage space, since the optional_state_t enum doesn't have to be embedded in the resultant optional type. If the type you want to embed has no specific "NONE" encoded in its representation (for example, integers do not have any specific numerical value which could be considered per-se "invalid"), use the IMPL_OPTIONAL_EXPLICIT() macro instead.

Note
Don't forget to also add the type to your OPTIONAL_TYPE_LIST().
Parameters
type_nameThe type name of the optional type. This will be the name which will appear after the opt_ prefix. For example, passing foobar here will result in an optional type named opt_foobar. This string must constitute a well-formed C identifier, as it is used as part of the typedef name, as well as manipulation function names.
c_typeThe actual C type being wrapped by the optional type. This can be any valid C type.
none_valueThe actual value of the C type which denotes a NONE state.
none_checkAn expression which must return true if the value is NONE. The expression must be formed using a variable named "x", which holds the value to be tested. For example, for floating point numbers, this argument is isnan(x). For pointers, a good none_check is x == NULL.

Definition at line 491 of file optional.h.

◆ IS_NONE

#define IS_NONE (   x)    (!IS_SOME(x))

Returns true if the optional is in the NONE state.

Definition at line 1018 of file optional.h.

◆ IS_SOME

#define IS_SOME (   opt)     OPTIONAL_TYPE_SELECTOR(opt_is_some_, (opt).value)(opt)

Returns true if the optional is in the SOME state.

Definition at line 1005 of file optional.h.

◆ MATCH

#define MATCH (   opt,
  out_value 
)     OPTIONAL_TYPE_SELECTOR(opt_match_, (opt).value)((opt), (out_value))

Extracts the value embedded in the optional and returns the optional_state_t enum corresponding to the state.

If the optional is in the SOME state, the wrapped value is written to the out_value argument. If the optional is in the NONE state, the out_value argument is filled with an invalid value.

Note
The out_value argument is mandatory and may not be NULL.

This macro is intended to be used in one of the following ways:

  1. As a switch condition, which is similar to the Rust match value destructuring pattern:
    float my_value;
    switch (MATCH(my_opt_float, &my_value)) {
    case OPT_SOME:
    operate_with(my_value);
    break;
    case OPT_NONE:
    operate_without_any_value();
    break;
    }
    @ OPT_NONE
    State denoting that the optional contains no valid value.
    Definition optional.h:276
  2. As an if condition, which is similar to a Rust "if-let" statement:
    float my_value;
    if (MATCH(my_opt_float, &my_value)) {
    operate_with(my_value);
    }

Definition at line 1057 of file optional.h.

◆ MATCH_AS_MUT

#define MATCH_AS_MUT (   opt,
  out_value_p 
)
Value:
OPTIONAL_TYPE_SELECTOR(opt_match_as_mut_, (*(opt)).value)\
((opt), (out_value_p))

Extracts a reference to the value embedded in the optional and returns the optional_state_t enum corresponding to the state.

This is similar to MATCH(), except the second argument is a reference to a pointer. If the optional value is OPT_SOME, the pointer is filled with a reference to the value contained internally in the optional value. If the optional value is OPT_NONE, the pointer is set to NULL.

The purpose of this macro is to facilitate returning an internal value by reference. This may be necessary, in case a stack-allocated copy of the object cannot be returned from the calling function.

float *my_value_ptr;
switch (MATCH(my_opt_float, &my_value)) {
case OPT_SOME:
printf("my_value is %f\n", *my_value_ptr);
break;
case OPT_NONE:
// my_value_ptr is now NULL
break;
}

Definition at line 1136 of file optional.h.

◆ MATCH_AS_REF

#define MATCH_AS_REF (   opt,
  out_value_p 
)
Value:
OPTIONAL_TYPE_SELECTOR(opt_match_as_ref_, (*(opt)).value)\
((opt), (out_value_p))

Extracts an immutable reference to the value embedded in the optional and returns the optional_state_t enum corresponding to the state.

This is similar to MATCH(), except the second argument is a reference to an immutable pointer. If the optional value is OPT_SOME, the pointer is filled with a reference to the value contained internally in the optional value. If the optional value is OPT_NONE, the pointer is set to NULL.

The purpose of this macro is to facilitate returning an internal value by immutable reference. This may be necessary, in case a stack-allocated copy of the object cannot be returned from the calling function.

Note
If you need a mutable reference to the value contained inside of the optional, use MATCH_AS_MUT() instead.
float *my_value_ptr;
switch (MATCH(my_opt_float, &my_value)) {
case OPT_SOME:
printf("my_value is %f\n", *my_value_ptr);
break;
case OPT_NONE:
// my_value_ptr is now NULL
break;
}
See also
MATCH_AS_MUT()

Definition at line 1099 of file optional.h.

◆ NONE

#define NONE (   type_name)    opt_none_ ## type_name()

Constructs a new optional value in the NONE state.

Due to C's lack of type inference support from return values, you must provide an explicit type name annotation in the type_name argument. This is the latter part of the name of the optional type, e.g. for an opt_str the type name is str and not necessarily the C type designator (which is char * in the case of opt_str).

Example usage:

opt_float my_func(void) {
if (some_condition()) {
return SOME(5.0f);
} else {
return NONE(float);
}
}
#define NONE(type_name)
Constructs a new optional value in the NONE state.
Definition optional.h:996
#define SOME(expr)
Constructs a new optional value in the SOME state.
Definition optional.h:967

Definition at line 996 of file optional.h.

◆ OPT_INTO

#define OPT_INTO (   value)    OPTIONAL_TYPE_SELECTOR(opt_into_, (value))(value)

Allows wrapping an implicitly representable value into a suitable optional.

This macro works by performing a NONE-check on the value itself, to then determine whether the value should be wrapped in a SOME variant, or a NONE variant.

Note
This only works for values which can be implicitly represented in an optional (i.e. they are defined using IMPL_OPTIONAL_IMPLICIT). This is because we rely on the value itself containing enough information to convey its state. Only the following types implemented in libacfutils support implicit conversion into an optional type:

Example usage:

float foo(); // may return NAN to indicate an invalid value
IF_LET(float, valid_value, OPT_INTO(foo()))
// valid_value is guaranteed to be non-NAN here
IF_LET_END
#define OPT_INTO(value)
Allows wrapping an implicitly representable value into a suitable optional.
Definition optional.h:1568

Definition at line 1568 of file optional.h.

◆ OPT_OR

#define OPT_OR (   a,
 
)     OPTIONAL_TYPE_SELECTOR(opt_or_, (a).value)((a), (b))

Selects between two optional values based on whether the first optional is in the SOME state.

If the first argument is in the SOME state, returns the first optional. Otherwise returns the second optional. This macro can be used to provide a fallback optional value without actually unwrapping the value contained in the optional.

Example usage:

opt_float result = OPT_OR(my_opt_float, fallback_opt_float);
#define OPT_OR(a, b)
Selects between two optional values based on whether the first optional is in the SOME state.
Definition optional.h:1429
Note
The second argument to this macro is eagerly evaluated, even if the first argument is in the SOME state. You must take care to avoid unintended side effects of the second argument. If you want to force lazy execution, you must use the OPT_OR_ELSE() macro instead.
See also
OPT_OR_ELSE

Definition at line 1429 of file optional.h.

◆ OPT_OR_ELSE

#define OPT_OR_ELSE (   a,
  func_b,
  arg_b 
)     OPTIONAL_TYPE_SELECTOR(opt_or_else_, (a).value)((a), (func_b), (arg_b))

Selects between two optional values based on whether the first optional is in the SOME state. Provides lazy evaluation.

If the a argument is in the SOME state, returns a. Otherwise calls func_b with argument arg_b and returns its return value. The func_b function must conform to this signature:

opt_type func(void *);

where opt_type is the same type as the type of a.

Example usage:

opt_float build_fallback(void *arg);
opt_float result = OPT_OR_ELSE(my_opt_float, build_fallback, foo);
#define OPT_OR_ELSE(a, func_b, arg_b)
Selects between two optional values based on whether the first optional is in the SOME state....
Definition optional.h:1465
Note
The purpose of this macro is to provide a mechanism for lazy evaluation of the fallback case. The func_b argument is not called unless the first argument is in the NONE state. If you want the second argument to be eagerly evaluated (as well as avoid having to write a callback function), use OPT_OR().
See also
OPT_OR

Definition at line 1465 of file optional.h.

◆ OPTIONAL_TYPE_LIST

#define OPTIONAL_TYPE_LIST (   op_name)     default: _unknown_optional_type_you_need_to_include_your_custom_optional_h_

Overridable list of custom optional types provided by your code.

If you want to specify a list of your own custom optional types, you must redefine this macro somewhere in your headers, to add the optional types using the OPTIONAL_TYPE_LIST_ADD() macro.

Example:

#undef OPTIONAL_TYPE_LIST
#define OPTIONAL_TYPE_LIST(op_name) \
OPTIONAL_TYPE_LIST_ADD(my_type_1, my_type_1, op_name), \
OPTIONAL_TYPE_LIST_ADD(my_type_2, my_type_2 *, op_name)
See also
Adding Your Own Custom Optional Types

Definition at line 896 of file optional.h.

◆ OPTIONAL_TYPE_LIST_ADD

#define OPTIONAL_TYPE_LIST_ADD (   type_name,
  c_type,
  op_name 
)     c_type: op_name ## type_name

Appends a new entry to the definition of the OPTIONAL_TYPE_LIST() macro.

Use this macro to append entries to your OPTIONAL_TYPE_LIST() macro, which contains a list of your custom optional types.

See also
Adding Your Own Custom Optional Types

Definition at line 874 of file optional.h.

◆ SIZE_T_OPTIONAL_LIST_ENTRY

#define SIZE_T_OPTIONAL_LIST_ENTRY (   op_name)

Definition at line 901 of file optional.h.

◆ SOME

#define SOME (   expr)    OPTIONAL_TYPE_SELECTOR(opt_some_, expr)(expr)

Constructs a new optional value in the SOME state.

The type of the optional is determined by the result type of the expression in the expr argument.

Example usage:

opt_float my_func(void) {
if (some_condition()) {
return SOME(5.0f);
} else {
return NONE(float);
}
}

Because the type is determined solely by the macro argument expression and not by the overall return type, you must make sure the expression is typed exactly to the desired optional type. This can require an explicit cast. For example SOME(5.0) always results in an opt_double, even if you want assign to or return an opt_float. To force the correct type inference, use SOME(5.0f) or SOME((float)5.0).

Note
C++ doesn't support the C11 _Generic construct and thus automatic type inference cannot be used for the SOME macro. When used from C++ code, you must provide an explicit optional type name in the first argument, such as: SOME(float, 5.0f). The optional type name is the latter part of the name of the optional type, e.g. for an opt_str the type name is str and not necessarily the C type designator (which is char * in the case of opt_str).

Definition at line 967 of file optional.h.

◆ UNWRAP

#define UNWRAP (   opt)
Value:
OPTIONAL_TYPE_SELECTOR(opt_unwrap_, (opt).value)((opt), \
log_basename(__FILE__), __LINE__, #opt)
#define log_basename(f)
Definition log.h:89

Extracts the value of the optional unconditionally.

If the optional was in the SOME state, returns the wrapped value. If the optional was in the NONE state, causes a runtime assertion failure and panic. You should only use this macro during testing, or after you have made sure using other means that the optional is in the SOME state.

Example usage:

float my_value = UNWRAP(my_opt_float);
#define UNWRAP(opt)
Extracts the value of the optional unconditionally.
Definition optional.h:1162

Definition at line 1162 of file optional.h.

◆ UNWRAP_AS_MUT

#define UNWRAP_AS_MUT (   opt)
Value:
OPTIONAL_TYPE_SELECTOR(opt_unwrap_as_mut_, (*(opt)).value)((opt), \
log_basename(__FILE__), __LINE__, #opt)

Extracts a mutable reference to the value of the optional unconditionally.

If the optional was in the SOME state, returns a pointer to the wrapped value. If the optional was in the NONE state, causes a runtime assertion failure and panic. You should only use this macro during testing, or after you have made sure using other means that the optional is in the SOME state.

Example usage:

float *my_value_ref = UNWRAP_AS_REF(&my_opt_float);
#define UNWRAP_AS_REF(opt)
Extracts an immutable reference to the value of the optional unconditionally.
Definition optional.h:1189

Definition at line 1217 of file optional.h.

◆ UNWRAP_AS_REF

#define UNWRAP_AS_REF (   opt)
Value:
OPTIONAL_TYPE_SELECTOR(opt_unwrap_as_ref_, (*(opt)).value)((opt), \
log_basename(__FILE__), __LINE__, #opt)

Extracts an immutable reference to the value of the optional unconditionally.

If the optional was in the SOME state, returns a pointer to the wrapped value. If the optional was in the NONE state, causes a runtime assertion failure and panic. You should only use this macro during testing, or after you have made sure using other means that the optional is in the SOME state.

Example usage:

const float *my_value_ref = UNWRAP_AS_REF(&my_opt_float);

Definition at line 1189 of file optional.h.

◆ UNWRAP_OR

#define UNWRAP_OR (   opt,
  dfl_value 
)     OPTIONAL_TYPE_SELECTOR(opt_unwrap_or_, (opt).value)((opt), (dfl_value))

Extracts the value of the optional, or evaluates to a fallback value.

If opt is in the SOME state, evaluates to the wrapped value. If opt is in the NONE state, evaluates to the dfl_value argument. This can be used to safely unwrap an optional, providing a default value in case the optional was in the NONE state.

Example usage:

float my_value = UNWRAP_OR(my_opt_float, 0.0f);
#define UNWRAP_OR(opt, dfl_value)
Extracts the value of the optional, or evaluates to a fallback value.
Definition optional.h:1249
Note
The second argument to this macro is eagerly evaluated, even if the first argument is in the SOME state. You must take care to avoid unintended side effects of the second argument. If you want to force lazy execution, you must use the UNWRAP_OR_ELSE() macro instead.
See also
UNWRAP_OR_ELSE()

Definition at line 1249 of file optional.h.

◆ UNWRAP_OR_BREAK

#define UNWRAP_OR_BREAK (   opt)
Value:
({ __typeof(opt) __tmp = (opt); \
if (IS_NONE(__tmp)) { break; } UNWRAP(__tmp); })
#define IS_NONE(x)
Returns true if the optional is in the NONE state.
Definition optional.h:1018

Unwraps a SOME value, or in case of a NONE value, breaks out of the current loop or switch case (invokes the break keyword).

This macro helps with flow control when a NONE variant is encountered.

Example usage:

for (int i = 0; i < 10; i++) {
...
// break out of loop if we get a NONE variant here
float need_valid_value_here = UNWRAP_OR_BREAK(this_can_be_NONE());
...
}
#define UNWRAP_OR_BREAK(opt)
Unwraps a SOME value, or in case of a NONE value, breaks out of the current loop or switch case (invo...
Definition optional.h:1377

Definition at line 1377 of file optional.h.

◆ UNWRAP_OR_CONTINUE

#define UNWRAP_OR_CONTINUE (   opt)
Value:
({ __typeof(opt) __tmp = (opt); \
if (IS_NONE(__tmp)) { continue; } UNWRAP(__tmp); })

Unwraps a SOME value, or in case of a NONE value, restarts the current loop iteration (invokes the continue keyword).

This macro helps with flow control when a NONE variant is encountered.

Example usage:

for (int i = 0; i < 10; i++) {
...
// continue to next loop iteration if we get a NONE variant here
float need_valid_value_here = UNWRAP_OR_CONTINUE(this_can_be_NONE());
...
}
#define UNWRAP_OR_CONTINUE(opt)
Unwraps a SOME value, or in case of a NONE value, restarts the current loop iteration (invokes the co...
Definition optional.h:1400

Definition at line 1400 of file optional.h.

◆ UNWRAP_OR_ELSE

#define UNWRAP_OR_ELSE (   opt,
  dfl_func,
  dfl_arg 
)
Value:
OPTIONAL_TYPE_SELECTOR(opt_unwrap_or_else_, (opt).value)\
((opt), (dfl_func), (dfl_arg))

Extracts the value of the optional, or yields a fallback value with lazy evaluation.

If opt is in the SOME state, evaluates to the wrapped value. If opt is in the NONE state, calls dfl_func with dfl_arg in its argument and evaluates to the return value of this call. The function must have a signature conforming to:

c_type func(void *);

where c_type is the native C type wrapped in the optional type. This can be used to safely unwrap an optional, providing a lazily evaluated default value in case the optional was in the NONE state.

Example usage:

float calc_fallback(void *arg);
float my_value = UNWRAP_OR_ELSE(my_opt_float, calc_fallback, foo);
#define UNWRAP_OR_ELSE(opt, dfl_func, dfl_arg)
Extracts the value of the optional, or yields a fallback value with lazy evaluation.
Definition optional.h:1288
Note
The purpose of this macro is to provide a mechanism for lazy evaluation of the default case. The function is not called unless the first argument is in the NONE state. If you want the second argument to be eagerly evaluated (as well as avoid having to write a callback function), use UNWRAP_OR().
See also
UNWRAP_OR()

Definition at line 1288 of file optional.h.

◆ UNWRAP_OR_GOTO

#define UNWRAP_OR_GOTO (   opt,
  label 
)
Value:
({ __typeof(opt) __tmp = (opt); \
if (IS_NONE(__tmp)) { goto label; } UNWRAP(__tmp); })

Unwraps a SOME value, or in case of a NONE value, goes to the label.

This macro helps with unwinding when a NONE variant is encountered, requiring cleanup of the current function.

Example usage:

opt_float foo(void); // can return NONE variant
void bar() {
// setup some resources that need cleanup
...
float need_valid_value_here = UNWRAP_OR_GOTO(foo(), out);
...
// use need_valid_value_here
...
out:
// perform cleanup of resources acquired during setup
}
#define UNWRAP_OR_GOTO(opt, label)
Unwraps a SOME value, or in case of a NONE value, goes to the label.
Definition optional.h:1354

Definition at line 1354 of file optional.h.

◆ UNWRAP_OR_RET

#define UNWRAP_OR_RET (   opt,
  ... 
)
Value:
({ __typeof(opt) __tmp = (opt); \
if (IS_NONE(__tmp)) { return __VA_ARGS__; } \
UNWRAP(__tmp); })

Unwraps a SOME value, or in case of a NONE value, returns from the current function.

This macro lets you emulate the Rust '?' operator.

  1. If the first argument is in the SOME state, the contained value is yielded.
  2. If the first argument is in the NONE state, returns from the current function, optionally with a return value of your choosing.

The way to use this macro is as follows:

bool my_func(opt_float wrapped_value) {
// if `wrapped_value` is NONE, we return from `my_func` with `false`:
float value = UNWRAP_OR_RET(wrapped_value, false);
// ... do something with `value`, it is guaranteed to be valid ...
return true;
}
#define UNWRAP_OR_RET(opt,...)
Unwraps a SOME value, or in case of a NONE value, returns from the current function.
Definition optional.h:1324

To return with no value from the current function, simply invoke the macro with just one argument:

float foo = UNWRAP_OR_RET(wrapped_foo);

Definition at line 1324 of file optional.h.

Typedef Documentation

◆ opt_f32

typedef opt_float opt_f32

Alias for opt_float available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 784 of file optional.h.

◆ opt_f64

Alias for opt_double available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 786 of file optional.h.

◆ opt_i16

Alias for opt_int16_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 770 of file optional.h.

◆ opt_i32

Alias for opt_int32_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 774 of file optional.h.

◆ opt_i64

Alias for opt_int64_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 778 of file optional.h.

◆ opt_i8

typedef opt_int8_t opt_i8

Alias for opt_int8_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 766 of file optional.h.

◆ opt_size_t

An optional type for wrapping a size_t value.

Definition at line 744 of file optional.h.

◆ opt_u16

Alias for opt_uint16_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 772 of file optional.h.

◆ opt_u32

Alias for opt_uint32_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 776 of file optional.h.

◆ opt_u64

Alias for opt_uint64_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 780 of file optional.h.

◆ opt_u8

Alias for opt_uint8_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 768 of file optional.h.

◆ opt_usize

Alias for opt_size_t available if OPTIONALS_WITH_RUSTY_NAMES is defined.

Definition at line 782 of file optional.h.

Enumeration Type Documentation

◆ optional_state_t

Describes the state of an optional type. This enumeration is returned by the MATCH() macro.

Enumerator
OPT_NONE 

State denoting that the optional contains no valid value.

OPT_SOME 

State denoting that the optional contains a valid value.

Definition at line 275 of file optional.h.

Function Documentation

◆ opt_into_double()

static opt_double opt_into_double ( double  x)
static

Definition at line 761 of file optional.h.

◆ opt_into_f32()

static opt_f32 opt_into_f32 ( float  value)
static

Definition at line 784 of file optional.h.

◆ opt_into_f64()

static opt_f64 opt_into_f64 ( double  value)
static

Definition at line 786 of file optional.h.

◆ opt_into_float()

static opt_float opt_into_float ( float  x)
static

Definition at line 755 of file optional.h.

◆ opt_into_geo_pos2_32_t()

static opt_geo_pos2_32_t opt_into_geo_pos2_32_t ( geo_pos2_32_t  x)
static

Definition at line 850 of file optional.h.

◆ opt_into_geo_pos2_t()

static opt_geo_pos2_t opt_into_geo_pos2_t ( geo_pos2_t  x)
static

Definition at line 834 of file optional.h.

◆ opt_into_geo_pos3_32_t()

static opt_geo_pos3_32_t opt_into_geo_pos3_32_t ( geo_pos3_32_t  x)
static

Definition at line 858 of file optional.h.

◆ opt_into_geo_pos3_t()

static opt_geo_pos3_t opt_into_geo_pos3_t ( geo_pos3_t  x)
static

Definition at line 842 of file optional.h.

◆ opt_into_i16()

static opt_i16 opt_into_i16 ( int16_t  value)
static

Definition at line 770 of file optional.h.

◆ opt_into_i32()

static opt_i32 opt_into_i32 ( int32_t  value)
static

Definition at line 774 of file optional.h.

◆ opt_into_i64()

static opt_i64 opt_into_i64 ( int64_t  value)
static

Definition at line 778 of file optional.h.

◆ opt_into_i8()

static opt_i8 opt_into_i8 ( int8_t  value)
static

Definition at line 766 of file optional.h.

◆ opt_into_size_t()

static opt_size_t opt_into_size_t ( size_t  value)
static

Definition at line 744 of file optional.h.

◆ opt_into_str()

static opt_str opt_into_str ( char *  x)
static

Definition at line 796 of file optional.h.

◆ opt_into_str_const()

static opt_str_const opt_into_str_const ( const char *  x)
static

Definition at line 804 of file optional.h.

◆ opt_into_u16()

static opt_u16 opt_into_u16 ( uint16_t  value)
static

Definition at line 772 of file optional.h.

◆ opt_into_u32()

static opt_u32 opt_into_u32 ( uint32_t  value)
static

Definition at line 776 of file optional.h.

◆ opt_into_u64()

static opt_u64 opt_into_u64 ( uint64_t  value)
static

Definition at line 780 of file optional.h.

◆ opt_into_u8()

static opt_u8 opt_into_u8 ( uint8_t  value)
static

Definition at line 768 of file optional.h.

◆ opt_into_usize()

static opt_usize opt_into_usize ( size_t  value)
static

Definition at line 782 of file optional.h.

◆ opt_into_vect2_t()

static opt_vect2_t opt_into_vect2_t ( vect2_t  x)
static

Definition at line 812 of file optional.h.

◆ opt_into_vect3_t()

static opt_vect3_t opt_into_vect3_t ( vect3_t  x)
static

Definition at line 819 of file optional.h.

◆ opt_into_vect3l_t()

static opt_vect3l_t opt_into_vect3l_t ( vect3l_t  x)
static

Definition at line 826 of file optional.h.