{"id":13729769,"url":"https://github.com/mpusz/opt","last_synced_at":"2025-07-10T16:34:28.495Z","repository":{"id":139725292,"uuid":"87110405","full_name":"mpusz/opt","owner":"mpusz","description":"Class template designed to express optionality without having to sacrifice memory to store additional bool flag","archived":false,"fork":false,"pushed_at":"2023-09-19T08:23:44.000Z","size":65,"stargazers_count":12,"open_issues_count":0,"forks_count":1,"subscribers_count":5,"default_branch":"master","last_synced_at":"2025-06-03T00:28:57.224Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/mpusz.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2017-04-03T19:04:01.000Z","updated_at":"2024-07-13T03:23:40.000Z","dependencies_parsed_at":"2024-01-07T16:32:00.785Z","dependency_job_id":"315f4b00-3966-4891-806f-913da8737499","html_url":"https://github.com/mpusz/opt","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/mpusz/opt","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpusz%2Fopt","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpusz%2Fopt/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpusz%2Fopt/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpusz%2Fopt/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/mpusz","download_url":"https://codeload.github.com/mpusz/opt/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/mpusz%2Fopt/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264608135,"owners_count":23636684,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-03T02:01:04.949Z","updated_at":"2025-07-10T16:34:28.468Z","avatar_url":"https://github.com/mpusz.png","language":"C++","readme":"[![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg?maxAge=3600)](https://raw.githubusercontent.com/mpusz/opt/master/LICENSE)\n[![Travis CI](https://img.shields.io/travis/mpusz/opt/master.svg?label=Travis%20CI)](https://travis-ci.org/mpusz/opt)\n[![AppVeyor](https://img.shields.io/appveyor/ci/mpusz/opt/master.svg?label=AppVeyor)](https://ci.appveyor.com/project/mpusz/opt)\n[![Codecov](https://img.shields.io/codecov/c/github/mpusz/opt/master.svg)](https://codecov.io/github/mpusz/opt?branch=master)\n\n# `mp::opt\u003cT, Policy\u003e`\n\n`mp::opt\u003cT, Policy\u003e` is a class template designed to express optionality.\n\nIt has interface similar to `std::optional\u003cT\u003e` ([see here](http://en.cppreference.com/w/cpp/utility/optional))\nbut it does not use additional storage space for boolean flag needed to keep information if\nthe value is set or not. On the other hand type `T` should be a type that does not use all\nvalues from its underlying representation thus leaving a possibly to use one of them as a _Null_\nvalue that express emptiness of type `T`.\n\n## Dependencies\n\n`mp::opt\u003cT, Policy\u003e` library depends on C++14 constexpr features and `std::optional\u003cT\u003e` existence so\na fairly modern compiler is needed. \n\n## Installation\n\n`mp::opt\u003cT, Policy\u003e` is a header-only library. Its implementation was split to:\n - `opt.h` that contains the most important implementation and is intended to be included by the user with\n   `#include \u003copt.h\u003e` in the code\n - `opt_bits.h` that contains less important implementation details and is already included by `opt.h` header file\n\n## Usage\n\nHere is a simple example of how to use `mp::opt\u003cT, Policy\u003e` for some artificial type `price`:\n\n```cpp\n  using namespace mp;\n  using price = int;\n  using opt_price = opt\u003cprice, opt_null_value_policy\u003cprice, -1\u003e\u003e;\n  static_assert(sizeof(opt_price) == sizeof(int));\n\n  opt_price o1;\n  assert(static_cast\u003cbool\u003e(o1) == false);\n  assert(o1.has_value() == false);\n  assert(o1.value_or(123) == 123);\n\n  constexpr opt_price o2{99};\n  assert(static_cast\u003cbool\u003e(o2) == true);\n  assert(o2.has_value() == true);\n  assert(*o2 == 99);\n  assert(o2.value() == 99);\n  assert(o2.value_or(123) == 99);\n\n  opt_price o3{o2};\n  assert(o3.has_value() == true);\n  assert(*o3 == 99);\n\n  o3 = o1;\n  assert(o3.has_value() == false);\n\n  o3 = o2;\n  assert(o3.has_value() == true);\n  assert(*o3 == 99);\n\n  o3 = nullopt;\n  assert(o3.has_value() == false);\n```\n\n### `Policy` basic interface\n\n`mp::opt\u003cT, Policy\u003e` uses `Policy` class to provide all necessary information needed for proper class operation. The\nsimplest interface of `Policy` class for type `my_type` that uses `my_type_null_value` as _Null_ value contains\nonly one member function:\n```cpp\nstruct my_opt_policy {\n  static constexpr my_type null_value() noexcept { return my_type_null_value; }\n};\nmp::opt\u003cmy_type, my_opt_policy\u003e my_opt_val;\n```\n- `null_value()` member function returns (by value or reference) special value of type `my_type` that should be\n   used by `mp::opt\u003cT, Policy\u003e` as a special _Null_ value to mark emptiness.\n\n`mp::opt\u003cT, Policy\u003e` by default uses `mp::opt_default_policy\u003cT\u003e` that can be specialized for user's type `T` so above\nexample may be refactored in the following way:\n```cpp\nnamespace mp {\n  template\u003c\u003e\n  struct opt_default_policy\u003cmy_type\u003e {\n    static constexpr my_type null_value() noexcept { return my_type_null_value; }\n  };\n}\nmp::opt\u003cmy_type\u003e my_opt_val;\n```\n\nThe latter solution is suggested for user's types that will always have the same special value used as _Null_ while\nthe former should be used for builtin types like 'int' where the type can express different quantities thus having\ndifferent _Null_ special values (e.g. age, price, month, etc).\n\n### `Policy` types provided with the library\n\nBeside already mentioned `mp::opt_default_policy\u003cT\u003e` that can be specialized by the user for his/her type `my_type`,\nthe library provides 2 additional policy types:\n - `mp::opt_null_value_policy\u003cT, NullValue\u003e`\n   may be used to provide _Null_ value for integral type right in the class type definition. For example:\n   ```cpp\n   mp::opt\u003cint, mp::opt_null_value_policy\u003cint, -1\u003e\u003e opt_int;\n   ```\n\n - `mp::opt_null_type_policy\u003cT, NullType\u003e` may be used for types which values cannot be used as template argument\n   (e.g. `float`). That policy type assumes that `NullType::null_value` will represent _Null_ value. For example:\n   ```cpp\n   struct my_null_float { static constexpr float null_value = 0.0f; };\n   mp::opt\u003cfloat, mp::opt_null_type_policy\u003cfloat, my_null_float\u003e\u003e opt_float;\n   ```\n\n### What if `my_type` does not provide equality comparison?\n\n`mp::opt\u003cT, Policy\u003e` needs to compare contained value with special _Null_ value provided by the _Policy_ type. By default\nit tries to use `operator==()`. If the equality comparison  is not provided for `my_type` than either:\n- `operator==()` should be provided, or\n- additional `has_value(const T\u0026 value)` member function should be provided in the `Policy` type and it should return\n  `false` if `value == null_value()` or `true` otherwise:\n```cpp\nstruct my_opt_policy {\n  static constexpr my_type null_value() noexcept { return my_type_null_value; }\n  static constexpr bool has_value(const T\u0026 value) noexcept { return value != null_value(); }\n};\nmp::opt\u003cmy_type, my_opt_policy\u003e my_opt_val;\n```\n\n### What if `my_type` prevents me from setting value out of allowed range?\n\nSometimes `my_type` has some non-trivial logic or validation in its contructors or assignment operators that prevents\none to set special out-of-range value as _Null_ value for the type. In such case it is possible to extend `Policy`\nclass with following additional `storage_type` public member type. Such `storage_type` type:\n- should be of the same size as `my_type` type\n- should be constructible and assignable in the same way as `my_type`\n- when storing not _Null_ value should have exactly the same memory representation as if the value was stored by\n  `my_type` type\n- should be used in `null_value()` and `has_value()` member functions instead of `my_type`. \n\nBelow is an example of how `opt\u003cbool\u003e` could be implemented:\n```cpp\nnamepace mp {\n  template\u003c\u003e\n  struct opt_default_policy\u003cbool\u003e {\n  private:\n    union storage {\n      bool value;\n      std::int8_t null_value = -1;\n      storage() = default;\n      constexpr storage(bool v) noexcept : value{v} {}\n    };\n  public:\n    using storage_type = storage;\n    static constexpr storage_type null_value() noexcept      { return storage_type{}; }\n    static constexpr bool has_value(storage_type s) noexcept { return s.null_value != -1; }\n  };\n}\n```\n\nHere is another a bit more complicated example for some (not too smart ;-) ) `weekday` class:\n```cpp\nclass weekday {\npublic:\n  using underlying_type = std::int8_t;\n  constexpr explicit weekday(underlying_type v) : value_{v}\n  {\n    if(v \u003c 0 || v \u003e 6) throw std::out_of_range{\"weekday value outside of allowed range\"};\n  }\n  constexpr weekday\u0026 operator=(underlying_type v)\n  {\n    if(v \u003c 0 || v \u003e 6) throw std::out_of_range{\"weekday value outside of allowed range\"};\n    value_ = v;\n    return *this;\n  }\n  constexpr underlying_type get() const noexcept { return value_; }\nprivate:\n  underlying_type value_;  // 0 - 6\n};\nconstexpr bool operator==(weekday lhs, weekday rhs) noexcept { return lhs.get() == rhs.get(); }\nconstexpr bool operator==(weekday::underlying_type lhs, weekday rhs) noexcept { return lhs == rhs.get(); }\nconstexpr bool operator==(weekday lhs, weekday::underlying_type rhs) noexcept { return lhs.get() == rhs; }\n\nnamespace mp {\n  template\u003c\u003e\n  struct opt_default_policy\u003cweekday\u003e {\n    union storage_type {\n      weekday value;\n      weekday::underlying_type null_value = std::numeric_limits\u003cweekday::underlying_type\u003e::max();\n  \n      constexpr storage_type() noexcept {};\n      constexpr storage_type(weekday v) : value{v} {}\n      constexpr storage_type(weekday::underlying_type v) : value{v} {}\n      storage_type\u0026 operator=(weekday v)\n      {\n        value = v;\n        return *this;\n      }\n    };\n  \n  public:\n    static storage_type null_value() noexcept { return storage_type{}; }\n    static bool has_value(storage_type value) noexcept\n    {\n      return value.null_value != std::numeric_limits\u003cweekday::underlying_type\u003e::max();\n    }\n  };\n}\n```\n","funding_links":[],"categories":["C++"],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpusz%2Fopt","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmpusz%2Fopt","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmpusz%2Fopt/lists"}