TinyRobotics
Loading...
Searching...
No Matches
Optional.h
1#pragma once
2
3#if __cplusplus >= 201703L
4
5#include <optional>
6
7#else
8
9#include <type_traits>
10#include <utility>
11#include <stdexcept>
12
13namespace std {
14
15/// nullopt_t and nullopt definition
16struct nullopt_t {
17 explicit constexpr nullopt_t(int) {}
18};
19constexpr nullopt_t nullopt{0};
20
21/**
22 * @class optional
23 * @brief Minimal header-only polyfill for std::optional for pre-C++17 environments.
24 *
25 * This implementation provides the basic interface of std::optional, allowing code to use
26 * std::optional<T> and std::nullopt in environments where the standard library version is not available.
27 *
28 * Features:
29 * - Value storage and lifetime management
30 * - Copy/move construction and assignment
31 * - has_value(), value(), value_or(), reset(), and conversion to bool
32 * - Construction and assignment from std::nullopt
33 *
34 * Limitations:
35 * - No emplace or in-place construction
36 * - No support for references or advanced C++17 features
37 *
38 * Usage:
39 * - Use as a drop-in replacement for std::optional<T> in C++11/C++14 code
40 * - When C++17 or later is available, the standard library version is used
41 */
42template <typename T>
43class optional {
44 bool has_value_ = false;
45 alignas(T) unsigned char storage_[sizeof(T)];
46
47 public:
48 optional() noexcept = default;
49 optional(nullopt_t) noexcept {}
50 optional(const T& value) { new (storage_) T(value); has_value_ = true; }
51 optional(T&& value) { new (storage_) T(std::move(value)); has_value_ = true; }
52 optional(const optional& other) {
53 if (other.has_value_) {
54 new (storage_) T(other.value());
55 has_value_ = true;
56 }
57 }
58 optional(optional&& other) noexcept {
59 if (other.has_value_) {
60 new (storage_) T(std::move(other.value()));
61 has_value_ = true;
62 other.reset();
63 }
64 }
65 ~optional() { reset(); }
66
67 optional& operator=(nullopt_t) noexcept {
68 reset();
69 return *this;
70 }
71 optional& operator=(const optional& other) {
72 if (this != &other) {
73 reset();
74 if (other.has_value_) {
75 new (storage_) T(other.value());
76 has_value_ = true;
77 }
78 }
79 return *this;
80 }
81 optional& operator=(optional&& other) noexcept {
82 if (this != &other) {
83 reset();
84 if (other.has_value_) {
85 new (storage_) T(std::move(other.value()));
86 has_value_ = true;
87 other.reset();
88 }
89 }
90 return *this;
91 }
92
93 bool has_value() const noexcept { return has_value_; }
94 explicit operator bool() const noexcept { return has_value_; }
95
96 T& value() {
97 if (!has_value_) throw std::runtime_error("Bad optional access");
98 return *reinterpret_cast<T*>(storage_);
99 }
100 const T& value() const {
101 if (!has_value_) throw std::runtime_error("Bad optional access");
102 return *reinterpret_cast<const T*>(storage_);
103 }
104 T value_or(const T& default_value) const {
105 return has_value_ ? value() : default_value;
106 }
107 void reset() {
108 if (has_value_) {
109 reinterpret_cast<T*>(storage_)->~T();
110 has_value_ = false;
111 }
112 }
113};
114
115} // namespace std
116
117#endif