/* * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you 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. */ #ifndef _OPTIONAL_HPP_ #define _OPTIONAL_HPP_ // This is a simplistic substitute for std::optional until we require C++17 #if (__cplusplus >= 201703L || (defined(_MSVC_LANG) && _MSVC_LANG >= 201703L)) #include using std::optional; #else #include namespace datasketches { template class optional { public: optional() noexcept: initialized_(false) {} optional(const T& value) noexcept(std::is_nothrow_copy_constructible::value) { new (&value_) T(value); initialized_ = true; } optional(T&& value) noexcept(std::is_nothrow_move_constructible::value) { new (&value_) T(std::move(value)); initialized_ = true; } // conversion from compatible types template optional(const optional& other) noexcept(std::is_nothrow_constructible::value): initialized_(false) { if (other.initialized_) { new (&value_) T(other.value_); initialized_ = true; } } optional(const optional& other) noexcept(std::is_nothrow_copy_constructible::value): initialized_(false) { if (other.initialized_) { new (&value_) T(other.value_); initialized_ = true; } } optional(optional&& other) noexcept(std::is_nothrow_move_constructible::value): initialized_(false) { if (other.initialized_) { new (&value_) T(std::move(other.value_)); initialized_ = true; } } ~optional() noexcept(std::is_nothrow_destructible::value) { if (initialized_) value_.~T(); } explicit operator bool() const noexcept { return initialized_; } optional& operator=(const optional& other) noexcept(std::is_nothrow_copy_constructible::value && std::is_nothrow_copy_assignable::value) { if (initialized_) { if (other.initialized_) { value_ = other.value_; } else { reset(); } } else { if (other.initialized_) { new (&value_) T(other.value_); initialized_ = true; } } return *this; } optional& operator=(optional&& other) noexcept(std::is_nothrow_move_constructible::value && std::is_nothrow_move_assignable::value) { if (initialized_) { if (other.initialized_) { value_ = std::move(other.value_); } else { reset(); } } else { if (other.initialized_) { new (&value_) T(std::move(other.value_)); initialized_ = true; } } return *this; } template void emplace(Args&&... args) noexcept(std::is_nothrow_constructible::value) { new (&value_) T(args...); initialized_ = true; } T& operator*() & noexcept { return value_; } const T& operator*() const & noexcept { return value_; } T&& operator*() && noexcept { return std::move(value_); } const T&& operator*() const && noexcept { return std::move(value_); } T* operator->() noexcept { return &value_; } const T* operator->() const noexcept { return &value_; } void reset() noexcept(std::is_nothrow_destructible::value) { if (initialized_) value_.~T(); initialized_ = false; } private: union { T value_; }; bool initialized_; // for converting constructor template friend class optional; }; } // namespace #endif // C++17 #endif // _OPTIONAL_HPP_