blob: 917fc40fae6d80cf24cb6853ecd5c4da59bc936e [file] [log] [blame]
// Copyright Microsoft and CHERIoT Contributors.
// SPDX-License-Identifier: MIT
#pragma once
#include <cdefs.h>
#include <limits>
#include <stddef.h>
#include <stdint.h>
#include <type_traits>
namespace utils
{
constexpr size_t bytes2bits(size_t in)
{
return in * __CHAR_BIT__;
}
template<size_t N>
constexpr size_t log2()
{
static_assert(N > 0 && (N & (N - 1)) == 0);
return 1U + log2<(N >> 1)>();
}
template<>
constexpr size_t log2<1U>()
{
return 0;
}
template<typename T, size_t N>
constexpr size_t array_size(T (&a)[N])
{
return N;
}
class NoCopyNoMove
{
public:
NoCopyNoMove() = default;
NoCopyNoMove(const NoCopyNoMove &) = delete;
NoCopyNoMove &operator=(const NoCopyNoMove &) = delete;
NoCopyNoMove(NoCopyNoMove &&) = delete;
NoCopyNoMove &operator=(NoCopyNoMove &&) = delete;
~NoCopyNoMove() = default;
};
/**
* A helper class modelled on `std::optional` that represents an optional
* `T&`. This is stored as a pointer with `nullptr` representing the
* not-present version.
*
* Unlike `std::optional`, this intentionally omits the APIs that make it
* possible to access the value without checking that it is present.
*
* This is intended to be used as an alternative to using bare pointers to
* represent `T& | None`.
*/
template<typename T>
class OptionalReference
{
/// The pointer to the real value
T *pointer;
public:
/**
* Construct the optional wrapper from a real value.
*/
__always_inline OptionalReference(T &value) : pointer(&value) {}
/**
* Construct the optional wrapper from not-present value.
*/
OptionalReference(std::nullptr_t) : pointer(nullptr) {}
/**
* Returns a copy of the wrapped value if present or the provided
* default value if not.
*/
T value_or(T defaultValue)
{
if (pointer == nullptr)
{
return defaultValue;
}
return *pointer;
}
/**
* Returns a reference to the wrapped value if present or the provided
* default value if not.
*/
T &value_or(T &defaultValue)
{
if (pointer == nullptr)
{
return defaultValue;
}
return *pointer;
}
/**
* If this object holds a value then apply `f` to it and return the
* result, otherwise return the result of converting nullptr to the
* return type of `f`.
*/
__always_inline auto and_then(auto &&f)
{
using Result = decltype(f(std::declval<T &>()));
if constexpr (std::is_same_v<void, Result>)
{
if (pointer != nullptr)
{
f(*pointer);
}
return;
}
else
{
if (pointer != nullptr)
{
return f(*pointer);
}
return Result{nullptr};
}
}
};
} // namespace utils