You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
548 lines
16 KiB
548 lines
16 KiB
// Copyright 2015-2016 The Android Open Source Project
|
|
//
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
// you may not use this file except in compliance with the License.
|
|
// You may obtain a copy of the License at
|
|
//
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
//
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
// See the License for the specific language governing permissions and
|
|
// limitations under the License.
|
|
|
|
#pragma once
|
|
|
|
#include "android/base/TypeTraits.h"
|
|
|
|
#include <log/log.h>
|
|
|
|
#include <cassert>
|
|
#include <initializer_list>
|
|
#include <type_traits>
|
|
#include <utility>
|
|
|
|
#include <cstddef>
|
|
|
|
// Optional<T> - a template class to store an optional value of type T.
|
|
//
|
|
// Usage examples:
|
|
//
|
|
// Initialization and construction:
|
|
// Optional<Foo> foo; // |foo| doesn't contain a value.
|
|
// Optional<Foo> foo(Foo(10)); // |foo| contains a copy-constructed value.
|
|
// Optional<Foo> foo2(foo); // |foo2| contains a copy of |foo|'s value.
|
|
// Optional<Foo> foo3(std::move(foo2)); // Guess what?
|
|
//
|
|
// Assignment:
|
|
// Foo foo_value(0);
|
|
// Optional<Foo> foo; // |foo| is empty.
|
|
// Optional<Foo> foo2; // |foo2| is empty.
|
|
// foo2 = foo; // |foo2| is still empty.
|
|
// foo = foo_value; // set value of |foo| to a copy of |foo_value|
|
|
// foo = std::move(foo_value); // move |foo_value| into |foo|.
|
|
// foo2 = foo; // now |foo2| has a copy of |foo|'s value.
|
|
// foo = kNullopt; // unset |foo|, it has no value.
|
|
//
|
|
// Checking and accessing value:
|
|
// if (foo) {
|
|
// // |foo| has a value.
|
|
// doStuff(*foo); // |*foo| is the value inside |foo|.
|
|
// foo->callMethod(); // Same as (*foo).callMethod().
|
|
// } else {
|
|
// // |foo| is empty.
|
|
// }
|
|
//
|
|
// foo.value() // Same as *foo
|
|
// foo.valueOr(<default>) // Return <default> is |foo| has no value.
|
|
//
|
|
// In-place construction:
|
|
//
|
|
// Optional<Foo> foo; // |foo| is empty.
|
|
// foo.emplace(20); // |foo| now contains a value constructed as Foo(20)
|
|
//
|
|
// Optional<Foo> foo(kInplace, 20); // |foo| is initialized with a value
|
|
// // that is constructed in-place as
|
|
// // Foo(20).
|
|
//
|
|
// return makeOptional<Foo>(20); // Takes Foo constructor arguments
|
|
// // directly.
|
|
//
|
|
// Returning values:
|
|
//
|
|
// Optional<Foo> myFunc(...) {
|
|
// if (someCondition) {
|
|
// return Foo(10); // call Optional<Foo>(Foo&) constructor.
|
|
// } else {
|
|
// return {}; // call Optional<Foo>() constructor, which
|
|
// // builds an empty value.
|
|
// }
|
|
// }
|
|
//
|
|
// Memory layout:
|
|
// Optional<Foo> is equivalent to:
|
|
//
|
|
// struct {
|
|
// bool flag;
|
|
// Foo value;
|
|
// };
|
|
//
|
|
// in terms of memory layout. This means it *doubles* the size of integral
|
|
// types. Also:
|
|
//
|
|
// - Optional<Foo> can be constructed from anything that constructs a Foo.
|
|
//
|
|
// - Same with Optional<Foo>(kInplace, Args...) where Args... matches any
|
|
// arguments that can be passed to a Foo constructor.
|
|
//
|
|
// - Comparison operators are provided. Beware: an empty Optional<Foo>
|
|
// is always smaller than any Foo value.
|
|
|
|
namespace android {
|
|
namespace base {
|
|
|
|
namespace details {
|
|
|
|
// Base classes to reduce the number of instantiations of the Optional's
|
|
// internal members.
|
|
class OptionalFlagBase {
|
|
public:
|
|
void setConstructed(bool constructed) { mConstructed = constructed; }
|
|
constexpr bool constructed() const { return mConstructed; }
|
|
constexpr operator bool() const { return constructed(); }
|
|
bool hasValue() const { return constructed(); }
|
|
|
|
constexpr OptionalFlagBase(bool constructed = false)
|
|
: mConstructed(constructed) {}
|
|
|
|
private:
|
|
bool mConstructed = false;
|
|
};
|
|
|
|
template <size_t Size, size_t Align>
|
|
class OptionalStorageBase {
|
|
protected:
|
|
using StoreT = typename std::aligned_storage<Size, Align>::type;
|
|
StoreT mStorage = {};
|
|
};
|
|
|
|
} // namespace details
|
|
|
|
// A tag type for empty optional construction
|
|
struct NulloptT {
|
|
constexpr explicit NulloptT(int) {}
|
|
};
|
|
|
|
// A tag type for inplace value construction
|
|
struct InplaceT {
|
|
constexpr explicit InplaceT(int) {}
|
|
};
|
|
|
|
// Tag values for null optional and inplace construction
|
|
constexpr NulloptT kNullopt{1};
|
|
constexpr InplaceT kInplace{1};
|
|
|
|
// Forward declaration for an early use
|
|
template <class T>
|
|
class Optional;
|
|
|
|
// A type trait for checking if a type is an optional instantiation
|
|
// Note: if you want to refer to the template name inside the template,
|
|
// you need to declare this alias outside of it - because the
|
|
// class name inside of the template stands for an instantiated template
|
|
// E.g, for template <T> class Foo if you say 'Foo' inside the class, it
|
|
// actually means Foo<T>;
|
|
template <class U>
|
|
using is_any_optional =
|
|
is_template_instantiation_of<typename std::decay<U>::type, Optional>;
|
|
|
|
template <class T>
|
|
class Optional
|
|
: private details::OptionalFlagBase,
|
|
private details::OptionalStorageBase<sizeof(T),
|
|
std::alignment_of<T>::value> {
|
|
// make sure all optionals are buddies - this is needed to implement
|
|
// conversion from optionals of other types
|
|
template <class U>
|
|
friend class Optional;
|
|
|
|
template <class U>
|
|
using self = Optional<U>;
|
|
|
|
using base_flag = details::OptionalFlagBase;
|
|
using base_storage =
|
|
details::OptionalStorageBase<sizeof(T),
|
|
std::alignment_of<T>::value>;
|
|
|
|
public:
|
|
// std::optional will have this, so let's provide it
|
|
using value_type = T;
|
|
|
|
// make sure we forbid some Optional instantiations where things may get
|
|
// really messy
|
|
static_assert(!std::is_same<typename std::decay<T>::type, NulloptT>::value,
|
|
"Optional of NulloptT is not allowed");
|
|
static_assert(!std::is_same<typename std::decay<T>::type, InplaceT>::value,
|
|
"Optional of InplaceT is not allowed");
|
|
static_assert(!std::is_reference<T>::value,
|
|
"Optional references are not allowed: use a pointer instead");
|
|
|
|
// constructors
|
|
constexpr Optional() {}
|
|
constexpr Optional(NulloptT) {}
|
|
|
|
Optional(const Optional& other) : base_flag(other.constructed()) {
|
|
if (this->constructed()) {
|
|
new (&get()) T(other.get());
|
|
}
|
|
}
|
|
Optional(Optional&& other) : base_flag(other.constructed()) {
|
|
if (this->constructed()) {
|
|
new (&get()) T(std::move(other.get()));
|
|
}
|
|
}
|
|
|
|
// Conversion constructor from optional of similar type
|
|
template <class U,
|
|
class = enable_if_c<!is_any_optional<U>::value &&
|
|
std::is_constructible<T, U>::value>>
|
|
Optional(const Optional<U>& other) : base_flag(other.constructed()) {
|
|
if (this->constructed()) {
|
|
new (&get()) T(other.get());
|
|
}
|
|
}
|
|
|
|
// Move-conversion constructor
|
|
template <class U,
|
|
class = enable_if_c<!is_any_optional<U>::value &&
|
|
std::is_constructible<T, U>::value>>
|
|
Optional(Optional<U>&& other) : base_flag(other.constructed()) {
|
|
if (this->constructed()) {
|
|
new (&get()) T(std::move(other.get()));
|
|
}
|
|
}
|
|
|
|
// Construction from a raw value
|
|
Optional(const T& value) : base_flag(true) { new (&get()) T(value); }
|
|
// Move construction from a raw value
|
|
Optional(T&& value) : base_flag(true) { new (&get()) T(std::move(value)); }
|
|
|
|
// Inplace construction from a list of |T|'s ctor arguments
|
|
template <class... Args>
|
|
Optional(InplaceT, Args&&... args) : base_flag(true) {
|
|
new (&get()) T(std::forward<Args>(args)...);
|
|
}
|
|
|
|
// Inplace construction from an initializer list passed into |T|'s ctor
|
|
template <class U,
|
|
class = enable_if<
|
|
std::is_constructible<T, std::initializer_list<U>>>>
|
|
Optional(InplaceT, std::initializer_list<U> il) : base_flag(true) {
|
|
new (&get()) T(il);
|
|
}
|
|
|
|
// direct assignment
|
|
Optional& operator=(const Optional& other) {
|
|
if (&other == this) {
|
|
return *this;
|
|
}
|
|
|
|
if (this->constructed()) {
|
|
if (other.constructed()) {
|
|
get() = other.get();
|
|
} else {
|
|
destruct();
|
|
this->setConstructed(false);
|
|
}
|
|
} else {
|
|
if (other.constructed()) {
|
|
new (&get()) T(other.get());
|
|
this->setConstructed(true);
|
|
} else {
|
|
; // we're good
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// move assignment
|
|
Optional& operator=(Optional&& other) {
|
|
if (this->constructed()) {
|
|
if (other.constructed()) {
|
|
get() = std::move(other.get());
|
|
} else {
|
|
destruct();
|
|
this->setConstructed(false);
|
|
}
|
|
} else {
|
|
if (other.constructed()) {
|
|
new (&get()) T(std::move(other.get()));
|
|
this->setConstructed(true);
|
|
} else {
|
|
; // we're good
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// conversion assignment
|
|
template <class U,
|
|
class = enable_if_convertible<typename std::decay<U>::type, T>>
|
|
Optional& operator=(const Optional<U>& other) {
|
|
if (this->constructed()) {
|
|
if (other.constructed()) {
|
|
get() = other.get();
|
|
} else {
|
|
destruct();
|
|
this->setConstructed(false);
|
|
}
|
|
} else {
|
|
if (other.constructed()) {
|
|
new (&get()) T(other.get());
|
|
this->setConstructed(true);
|
|
} else {
|
|
; // we're good
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// conversion move assignment
|
|
template <class U,
|
|
class = enable_if_convertible<typename std::decay<U>::type, T>>
|
|
Optional& operator=(Optional<U>&& other) {
|
|
if (this->constructed()) {
|
|
if (other.constructed()) {
|
|
get() = std::move(other.get());
|
|
} else {
|
|
destruct();
|
|
this->setConstructed(false);
|
|
}
|
|
} else {
|
|
if (other.constructed()) {
|
|
new (&get()) T(std::move(other.get()));
|
|
this->setConstructed(true);
|
|
} else {
|
|
; // we're good
|
|
}
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// the most complicated one: forwarding constructor for anything convertible
|
|
// to |T|, excluding the stuff implemented above explicitly
|
|
template <class U,
|
|
class = enable_if_c<
|
|
!is_any_optional<typename std::decay<U>::type>::value &&
|
|
std::is_convertible<typename std::decay<U>::type,
|
|
T>::value>>
|
|
Optional& operator=(U&& other) {
|
|
if (this->constructed()) {
|
|
get() = std::forward<U>(other);
|
|
} else {
|
|
new (&get()) T(std::forward<U>(other));
|
|
this->setConstructed(true);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
// Adopt value checkers from the parent
|
|
using base_flag::operator bool;
|
|
using base_flag::hasValue;
|
|
|
|
T& value() {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return get();
|
|
}
|
|
constexpr const T& value() const {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return get();
|
|
}
|
|
|
|
T* ptr() {
|
|
return this->constructed() ? &get() : nullptr;
|
|
}
|
|
constexpr const T* ptr() const {
|
|
return this->constructed() ? &get() : nullptr;
|
|
}
|
|
|
|
// Value getter with fallback
|
|
template <class U = T,
|
|
class = enable_if_convertible<typename std::decay<U>::type, T>>
|
|
constexpr T valueOr(U&& defaultValue) const {
|
|
return this->constructed() ? get() : std::move(defaultValue);
|
|
}
|
|
|
|
// Pointer-like operators
|
|
T& operator*() {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return get();
|
|
}
|
|
constexpr const T& operator*() const {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return get();
|
|
}
|
|
|
|
T* operator->() {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return &get();
|
|
}
|
|
constexpr const T* operator->() const {
|
|
if (!constructed()) {
|
|
ALOGE("Optional not constructed");
|
|
abort();
|
|
}
|
|
return &get();
|
|
}
|
|
|
|
~Optional() {
|
|
if (this->constructed()) {
|
|
destruct();
|
|
}
|
|
}
|
|
|
|
void clear() {
|
|
if (this->constructed()) {
|
|
destruct();
|
|
this->setConstructed(false);
|
|
}
|
|
}
|
|
|
|
template <class U,
|
|
class = enable_if_convertible<typename std::decay<U>::type, T>>
|
|
void reset(U&& u) {
|
|
*this = std::forward<U>(u);
|
|
}
|
|
|
|
// In-place construction with possible destruction of the old value
|
|
template <class... Args>
|
|
void emplace(Args&&... args) {
|
|
if (this->constructed()) {
|
|
destruct();
|
|
}
|
|
new (&get()) T(std::forward<Args>(args)...);
|
|
this->setConstructed(true);
|
|
}
|
|
|
|
// In-place construction with possible destruction of the old value
|
|
// initializer-list version
|
|
template <class U,
|
|
class = enable_if<
|
|
std::is_constructible<T, std::initializer_list<U>>>>
|
|
void emplace(std::initializer_list<U> il) {
|
|
if (this->constructed()) {
|
|
destruct();
|
|
}
|
|
new (&get()) T(il);
|
|
this->setConstructed(true);
|
|
}
|
|
|
|
private:
|
|
// A helper function to convert the internal raw storage to T&
|
|
constexpr const T& get() const {
|
|
return *reinterpret_cast<const T*>(
|
|
reinterpret_cast<const char*>(&this->mStorage));
|
|
}
|
|
|
|
// Same thing, mutable
|
|
T& get() {
|
|
return const_cast<T&>(const_cast<const Optional*>(this)->get());
|
|
}
|
|
|
|
// Shortcut for a destructor call for the stored object
|
|
void destruct() { get().T::~T(); }
|
|
};
|
|
|
|
template <class T>
|
|
Optional<typename std::decay<T>::type> makeOptional(T&& t) {
|
|
return Optional<typename std::decay<T>::type>(std::forward<T>(t));
|
|
}
|
|
|
|
template <class T, class... Args>
|
|
Optional<typename std::decay<T>::type> makeOptional(Args&&... args) {
|
|
return Optional<typename std::decay<T>::type>(kInplace,
|
|
std::forward<Args>(args)...);
|
|
}
|
|
|
|
template <class T>
|
|
bool operator==(const Optional<T>& l, const Optional<T>& r) {
|
|
return l.hasValue() ? r.hasValue() && *l == *r : !r.hasValue();
|
|
}
|
|
template <class T>
|
|
bool operator==(const Optional<T>& l, NulloptT) {
|
|
return !l;
|
|
}
|
|
template <class T>
|
|
bool operator==(NulloptT, const Optional<T>& r) {
|
|
return !r;
|
|
}
|
|
template <class T>
|
|
bool operator==(const Optional<T>& l, const T& r) {
|
|
return bool(l) && *l == r;
|
|
}
|
|
template <class T>
|
|
bool operator==(const T& l, const Optional<T>& r) {
|
|
return bool(r) && l == *r;
|
|
}
|
|
|
|
template <class T>
|
|
bool operator!=(const Optional<T>& l, const Optional<T>& r) {
|
|
return !(l == r);
|
|
}
|
|
template <class T>
|
|
bool operator!=(const Optional<T>& l, NulloptT) {
|
|
return bool(l);
|
|
}
|
|
template <class T>
|
|
bool operator!=(NulloptT, const Optional<T>& r) {
|
|
return bool(r);
|
|
}
|
|
template <class T>
|
|
bool operator!=(const Optional<T>& l, const T& r) {
|
|
return !l || !(*l == r);
|
|
}
|
|
template <class T>
|
|
bool operator!=(const T& l, const Optional<T>& r) {
|
|
return !r || !(l == *r);
|
|
}
|
|
|
|
template <class T>
|
|
bool operator<(const Optional<T>& l, const Optional<T>& r) {
|
|
return !r ? false : (!l ? true : *l < *r);
|
|
}
|
|
template <class T>
|
|
bool operator<(const Optional<T>&, NulloptT) {
|
|
return false;
|
|
}
|
|
template <class T>
|
|
bool operator<(NulloptT, const Optional<T>& r) {
|
|
return bool(r);
|
|
}
|
|
template <class T>
|
|
bool operator<(const Optional<T>& l, const T& r) {
|
|
return !l || *l < r;
|
|
}
|
|
template <class T>
|
|
bool operator<(const T& l, const Optional<T>& r) {
|
|
return bool(r) && l < *r;
|
|
}
|
|
|
|
} // namespace base
|
|
} // namespace android
|