1*99e0aae7SDavid Rees // Copyright 2019 Google LLC 2*99e0aae7SDavid Rees // 3*99e0aae7SDavid Rees // Licensed under the Apache License, Version 2.0 (the "License"); 4*99e0aae7SDavid Rees // you may not use this file except in compliance with the License. 5*99e0aae7SDavid Rees // You may obtain a copy of the License at 6*99e0aae7SDavid Rees // 7*99e0aae7SDavid Rees // https://www.apache.org/licenses/LICENSE-2.0 8*99e0aae7SDavid Rees // 9*99e0aae7SDavid Rees // Unless required by applicable law or agreed to in writing, software 10*99e0aae7SDavid Rees // distributed under the License is distributed on an "AS IS" BASIS, 11*99e0aae7SDavid Rees // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12*99e0aae7SDavid Rees // See the License for the specific language governing permissions and 13*99e0aae7SDavid Rees // limitations under the License. 14*99e0aae7SDavid Rees 15*99e0aae7SDavid Rees // Definition of the Maybe<T> template class. 16*99e0aae7SDavid Rees #ifndef EMBOSS_RUNTIME_CPP_EMBOSS_MAYBE_H_ 17*99e0aae7SDavid Rees #define EMBOSS_RUNTIME_CPP_EMBOSS_MAYBE_H_ 18*99e0aae7SDavid Rees 19*99e0aae7SDavid Rees #include <utility> 20*99e0aae7SDavid Rees 21*99e0aae7SDavid Rees #include "runtime/cpp/emboss_defines.h" 22*99e0aae7SDavid Rees 23*99e0aae7SDavid Rees namespace emboss { 24*99e0aae7SDavid Rees // TODO(bolms): Should Maybe be a public type (i.e., live in ::emboss)? 25*99e0aae7SDavid Rees namespace support { 26*99e0aae7SDavid Rees 27*99e0aae7SDavid Rees // Maybe<T> is similar to, but much more restricted than, C++17's std::optional. 28*99e0aae7SDavid Rees // It is intended for use in Emboss's expression system, wherein a non-Known() 29*99e0aae7SDavid Rees // Maybe<T> will usually (but not always) poison the result of an operation. 30*99e0aae7SDavid Rees // 31*99e0aae7SDavid Rees // As such, Maybe<> is intended for use with small, copyable T's: specifically, 32*99e0aae7SDavid Rees // integers, enums, and booleans. It may not perform well with other types. 33*99e0aae7SDavid Rees template <typename T> 34*99e0aae7SDavid Rees class Maybe final { 35*99e0aae7SDavid Rees public: Maybe()36*99e0aae7SDavid Rees constexpr Maybe() : value_(), known_(false) {} Maybe(T value)37*99e0aae7SDavid Rees constexpr explicit Maybe(T value) 38*99e0aae7SDavid Rees : value_(::std::move(value)), known_(true) {} 39*99e0aae7SDavid Rees constexpr Maybe(const Maybe<T> &) = default; 40*99e0aae7SDavid Rees ~Maybe() = default; 41*99e0aae7SDavid Rees Maybe &operator=(const Maybe &) = default; 42*99e0aae7SDavid Rees Maybe &operator=(T value) { 43*99e0aae7SDavid Rees value_ = ::std::move(value); 44*99e0aae7SDavid Rees known_ = true; 45*99e0aae7SDavid Rees return *this; 46*99e0aae7SDavid Rees } 47*99e0aae7SDavid Rees Maybe &operator=(const T &value) { 48*99e0aae7SDavid Rees value_ = value; 49*99e0aae7SDavid Rees known_ = true; 50*99e0aae7SDavid Rees return *this; 51*99e0aae7SDavid Rees } 52*99e0aae7SDavid Rees Known()53*99e0aae7SDavid Rees constexpr bool Known() const { return known_; } Value()54*99e0aae7SDavid Rees T Value() const { 55*99e0aae7SDavid Rees EMBOSS_CHECK(Known()); 56*99e0aae7SDavid Rees return value_; 57*99e0aae7SDavid Rees } ValueOr(T default_value)58*99e0aae7SDavid Rees constexpr T ValueOr(T default_value) const { 59*99e0aae7SDavid Rees return known_ ? value_ : default_value; 60*99e0aae7SDavid Rees } 61*99e0aae7SDavid Rees // A non-Ok() Maybe value-initializes value_ to a default (by explicitly 62*99e0aae7SDavid Rees // calling the nullary constructor on value_ in the initializer list), so it 63*99e0aae7SDavid Rees // is safe to just return value_ here. For integral types and enums, value_ 64*99e0aae7SDavid Rees // will be 0, for bool it will be false, and for other types it depends on the 65*99e0aae7SDavid Rees // constructor's behavior. ValueOrDefault()66*99e0aae7SDavid Rees constexpr T ValueOrDefault() const { return value_; } 67*99e0aae7SDavid Rees 68*99e0aae7SDavid Rees private: 69*99e0aae7SDavid Rees T value_; 70*99e0aae7SDavid Rees bool known_; 71*99e0aae7SDavid Rees }; 72*99e0aae7SDavid Rees 73*99e0aae7SDavid Rees } // namespace support 74*99e0aae7SDavid Rees } // namespace emboss 75*99e0aae7SDavid Rees 76*99e0aae7SDavid Rees #endif // EMBOSS_RUNTIME_CPP_EMBOSS_MAYBE_H_ 77