228 lines
5.7 KiB
C
228 lines
5.7 KiB
C
|
/*------------------------------------------------------------------------------*
|
||
|
* Architecture & Implementation of DBMS *
|
||
|
*------------------------------------------------------------------------------*
|
||
|
* Copyright 2022 Databases and Information Systems Group TU Dortmund *
|
||
|
* Visit us at *
|
||
|
* http://dbis.cs.tu-dortmund.de/cms/en/home/ *
|
||
|
* *
|
||
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
|
||
|
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, *
|
||
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL *
|
||
|
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR *
|
||
|
* OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, *
|
||
|
* ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR *
|
||
|
* OTHER DEALINGS IN THE SOFTWARE. *
|
||
|
* *
|
||
|
* Authors: *
|
||
|
* Maximilian Berens <maximilian.berens@tu-dortmund.de> *
|
||
|
* Roland Kühn <roland.kuehn@cs.tu-dortmund.de> *
|
||
|
* Jan Mühlig <jan.muehlig@tu-dortmund.de> *
|
||
|
*------------------------------------------------------------------------------*
|
||
|
*/
|
||
|
|
||
|
#pragma once
|
||
|
#include <array>
|
||
|
#include <cstddef>
|
||
|
#include <cstdint>
|
||
|
#include <new>
|
||
|
|
||
|
namespace beedb::util
|
||
|
{
|
||
|
/**
|
||
|
* Implementation of an optional data container.
|
||
|
* Inspired by std::optional (https://en.cppreference.com/w/cpp/utility/optional).
|
||
|
* In contrast to std::optional, the value is moved on assignment.
|
||
|
*/
|
||
|
template <typename T> class optional
|
||
|
{
|
||
|
public:
|
||
|
optional() = default;
|
||
|
|
||
|
~optional() noexcept
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
explicit optional(const T &t) : _is_empty(false)
|
||
|
{
|
||
|
new (_storage.data()) T(t);
|
||
|
}
|
||
|
|
||
|
explicit optional(const T &&) = delete;
|
||
|
|
||
|
explicit optional(T &t) : _is_empty(false)
|
||
|
{
|
||
|
new (_storage.data()) T(t);
|
||
|
}
|
||
|
|
||
|
explicit optional(T &&t) : _is_empty(false)
|
||
|
{
|
||
|
new (_storage.data()) T(std::move(t));
|
||
|
}
|
||
|
|
||
|
optional(const optional<T> &o) : _is_empty(o._is_empty)
|
||
|
{
|
||
|
if (o._is_empty == false)
|
||
|
{
|
||
|
new (_storage.data()) T(o.value());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
optional(const optional<T> &&) = delete;
|
||
|
|
||
|
optional(optional<T> &o) : _is_empty(o._is_empty)
|
||
|
{
|
||
|
if (o._is_empty == false)
|
||
|
{
|
||
|
new (_storage.data()) T(o.value());
|
||
|
}
|
||
|
}
|
||
|
|
||
|
optional(optional<T> &&o) noexcept : _is_empty(o._is_empty)
|
||
|
{
|
||
|
if (o._is_empty == false)
|
||
|
{
|
||
|
new (_storage.data()) T(std::move(o.value()));
|
||
|
}
|
||
|
o._is_empty = true;
|
||
|
}
|
||
|
|
||
|
optional<T> &operator=(const T &t)
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = false;
|
||
|
new (_storage.data()) T(t);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
optional<T> &operator=(T &t)
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = false;
|
||
|
new (_storage.data()) T(t);
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
optional<T> &operator=(T &&t)
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = false;
|
||
|
new (_storage.data()) T(std::move(t));
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
optional<T> &operator=(const optional<T> &o)
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = o._is_empty;
|
||
|
if (o._is_empty == false)
|
||
|
{
|
||
|
new (_storage.data()) T(o.value());
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
optional<T> &operator=(optional<T> &&o) noexcept
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = o._is_empty;
|
||
|
if (o._is_empty == false)
|
||
|
{
|
||
|
new (_storage.data()) T(std::move(o.value()));
|
||
|
o._is_empty = true;
|
||
|
}
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
[[nodiscard]] bool has_value() const noexcept
|
||
|
{
|
||
|
return _is_empty == false;
|
||
|
}
|
||
|
T &value() noexcept
|
||
|
{
|
||
|
return *pointer();
|
||
|
}
|
||
|
const T &value() const noexcept
|
||
|
{
|
||
|
return *pointer();
|
||
|
}
|
||
|
|
||
|
void clear() noexcept
|
||
|
{
|
||
|
if (_is_empty == false)
|
||
|
{
|
||
|
pointer()->~T();
|
||
|
}
|
||
|
_is_empty = true;
|
||
|
}
|
||
|
|
||
|
T *operator->() noexcept
|
||
|
{
|
||
|
return pointer();
|
||
|
}
|
||
|
operator T *() noexcept
|
||
|
{
|
||
|
return pointer();
|
||
|
}
|
||
|
operator T &() noexcept
|
||
|
{
|
||
|
return value();
|
||
|
}
|
||
|
operator const T &() const noexcept
|
||
|
{
|
||
|
return value();
|
||
|
}
|
||
|
bool operator==(const bool b) const noexcept
|
||
|
{
|
||
|
return has_value() == b;
|
||
|
}
|
||
|
bool operator!=(const bool b) const noexcept
|
||
|
{
|
||
|
return has_value() != b;
|
||
|
}
|
||
|
bool operator==(const std::nullptr_t) const noexcept
|
||
|
{
|
||
|
return has_value() == false;
|
||
|
}
|
||
|
bool operator!=(const std::nullptr_t) const noexcept
|
||
|
{
|
||
|
return has_value() == true;
|
||
|
}
|
||
|
operator bool() const noexcept
|
||
|
{
|
||
|
return has_value();
|
||
|
}
|
||
|
|
||
|
private:
|
||
|
std::array<std::byte, sizeof(T)> _storage;
|
||
|
bool _is_empty = true;
|
||
|
|
||
|
T *pointer() noexcept
|
||
|
{
|
||
|
return reinterpret_cast<T *>(_storage.data());
|
||
|
}
|
||
|
};
|
||
|
|
||
|
template <typename T> optional<T> make_optional(T &&t)
|
||
|
{
|
||
|
return optional{std::forward(t)};
|
||
|
}
|
||
|
} // namespace beedb::util
|