mirror of
https://github.com/cculianu/Fulcrum.git
synced 2026-08-13 12:33:27 +02:00
121 lines
6.2 KiB
C++
121 lines
6.2 KiB
C++
//
|
|
// Fulcrum - A fast & nimble SPV Server for Bitcoin Cash
|
|
// Copyright (C) 2019-2025 Calin A. Culianu <calin.culianu@gmail.com>
|
|
//
|
|
// This program is free software: you can redistribute it and/or modify
|
|
// it under the terms of the GNU General Public License as published by
|
|
// the Free Software Foundation, either version 3 of the License, or
|
|
// (at your option) any later version.
|
|
//
|
|
// This program is distributed in the hope that it will be useful,
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
// GNU General Public License for more details.
|
|
//
|
|
// You should have received a copy of the GNU General Public License
|
|
// along with this program (see LICENSE.txt). If not, see
|
|
// <https://www.gnu.org/licenses/>.
|
|
//
|
|
#pragma once
|
|
|
|
#include <functional> // for std::equal_to, etc
|
|
#include <memory>
|
|
#include <utility>
|
|
|
|
namespace bitcoin {
|
|
/// An optional that stores its value on the heap, rather than in-line, in
|
|
/// order to save memory. This is implemented using a std::unique_ptr. This
|
|
/// optional is intended to be a drop-in replacement for a std::optional
|
|
/// but with the in-line cost of a unique_ptr. Like an optional but unlike a
|
|
/// unique_ptr, it can be treated as a value type. It is copy-constructible
|
|
/// and copy-assignable (does a deep copy). It also can be
|
|
/// copy/move-constructed or copy/move-assigned from a T.
|
|
///
|
|
/// Intended to be used for "heavy" optional data members that are null in the
|
|
/// common case, but take non-trivial amounts of memory when they are not
|
|
/// null. In this way, the common-case ends up using less memory than a normal
|
|
/// in-lined optional would.
|
|
template <typename T>
|
|
class HeapOptional {
|
|
std::unique_ptr<T> p{};
|
|
public:
|
|
using element_type = T;
|
|
|
|
constexpr HeapOptional() noexcept = default;
|
|
explicit HeapOptional(const T & t) { *this = t; }
|
|
explicit HeapOptional(T && t) noexcept { *this = std::move(t); }
|
|
|
|
/// Construct the HeapOptional in-place using argument forwarding
|
|
template <typename ...Args>
|
|
explicit HeapOptional(Args && ...args) { emplace(std::forward<Args>(args)...); }
|
|
|
|
HeapOptional(const HeapOptional & o) { *this = o; }
|
|
HeapOptional(HeapOptional && o) = default;
|
|
|
|
/// Create the new object in-place. Deletes previous object (if any) first.
|
|
template <typename ...Args>
|
|
void emplace(Args && ...args) { p = std::make_unique<T>(std::forward<Args>(args)...); }
|
|
|
|
HeapOptional & operator=(const HeapOptional & o) {
|
|
if (o.p) p = std::make_unique<T>(*o.p);
|
|
else p.reset();
|
|
return *this;
|
|
}
|
|
HeapOptional & operator=(HeapOptional && o) noexcept = default;
|
|
|
|
HeapOptional & operator=(const T & t) { p = std::make_unique<T>(t); return *this; }
|
|
HeapOptional & operator=(T && t) { p = std::make_unique<T>(std::move(t)); return *this; }
|
|
|
|
operator bool() const { return static_cast<bool>(p); }
|
|
T & operator*() { return *p; }
|
|
const T & operator*() const { return *p; }
|
|
T * get() { return p.get(); }
|
|
const T * get() const { return p.get(); }
|
|
T * operator->() { return p.operator->(); }
|
|
const T * operator->() const { return p.operator->(); }
|
|
|
|
void reset(T * t = nullptr) { p.reset(t); }
|
|
T * release() { return p.release(); }
|
|
|
|
|
|
//--- Comparison operators: ==, !=, <, does deep compare of pointed-to T values
|
|
// (only SFINAE-enabled if underlying type T supports these ops)
|
|
|
|
auto operator==(const HeapOptional & o) const -> decltype(std::declval<std::equal_to<T>>()(std::declval<T>(),
|
|
std::declval<T>())) {
|
|
if (p && o.p) return std::equal_to{}(*p, *o.p); // compare by pointed-to value if both are not null
|
|
return std::equal_to{}(p, o.p); // compare the unique_ptr's if either are null
|
|
}
|
|
// compare to a value directly
|
|
auto operator==(const T & t) const -> decltype(std::declval<std::equal_to<T>>()(std::declval<T>(),
|
|
std::declval<T>())) {
|
|
if (!p) return false; // we never compare equal to a real value if we are null
|
|
return std::equal_to{}(*p, t); // compare by pointed-to value if we not null
|
|
}
|
|
|
|
#if __cplusplus < 202000L /* C++20 auto-gens these so we don't need to bother to compile them in */
|
|
auto operator!=(const HeapOptional & o) const -> decltype(std::declval<std::not_equal_to<T>>()(std::declval<T>(),
|
|
std::declval<T>())) {
|
|
if (p && o.p) return std::not_equal_to{}(*p, *o.p); // compare by pointed-to value if both are not null
|
|
return std::not_equal_to{}(p, o.p); // compare the unique_ptr's if either are null
|
|
}
|
|
// compare to a value directly
|
|
auto operator!=(const T & t) const -> decltype(std::declval<std::not_equal_to<T>>()(std::declval<T>(),
|
|
std::declval<T>())) {
|
|
if (!p) return true; // we are not equal to t if we are nullptr
|
|
return std::not_equal_to{}(*p, t); // compare by pointed-to value
|
|
}
|
|
#endif
|
|
|
|
auto operator<(const HeapOptional & o) const -> decltype(std::declval<std::less<T>>()(std::declval<T>(),
|
|
std::declval<T>())) {
|
|
if (p && o.p) return std::less{}(*p, *o.p); // compare by pointed-to value if both are not null
|
|
return std::less{}(p, o.p); // compare the unique_ptr's if either are null
|
|
}
|
|
// compare to a value directly
|
|
auto operator<(const T & t) const -> decltype(std::declval<std::less<T>>()(std::declval<T>(), std::declval<T>())) {
|
|
if (!p) return true; // if we are null we are always less
|
|
return std::less{}(*p, t); // compare to the pointed-to value
|
|
}
|
|
};
|
|
} // namespace bitcoin
|