Files
lix/lix/libutil/types.hh
T

192 lines
5.1 KiB
C++

#pragma once
///@file
#include <list>
#include <optional>
#include <set>
#include <string>
#include <string_view>
#include <map>
#include <vector>
#include <span>
#include <stdint.h> // IWYU pragma: keep (this is used literally everywhere)
// NOTE: This check is load-bearing, c.f.
// https://git.lix.systems/lix-project/lix/commit/96a36833084f66b79ba778e719862b8219557773
// It is put here so that every consumer of our headers are prohibited from
// compiling with NDEBUG as some asserts are used in inline code
#ifdef NDEBUG
#error "Lix may not be built with assertions disabled (i.e. with -DNDEBUG)."
#endif
namespace nix {
typedef std::list<std::string> Strings;
typedef std::set<std::string> StringSet;
typedef std::map<std::string, std::string> StringMap;
typedef std::map<std::string, std::string> StringPairs;
// TODO this should be a std::byte span, but too much of the
// current codebase predates std::byte and uses char instead
using Bytes = std::span<const char>;
/**
* Paths are just strings.
*/
typedef std::string Path;
typedef std::string_view PathView;
typedef std::list<Path> Paths;
typedef std::set<Path> PathSet;
typedef std::vector<std::pair<std::string, std::string>> Headers;
/**
* Wrap bools to prevent string literals (i.e. 'char *') from being
* cast to a bool in Attr.
*/
template<typename T>
struct Explicit {
T t;
bool operator ==(const Explicit<T> & other) const
{
return t == other.t;
}
};
/**
* Get a value for the specified key from an associate container.
*/
template <class T>
const typename T::mapped_type * get(const T & map, const typename T::key_type & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
return &i->second;
}
template <class T>
typename T::mapped_type * get(T & map, const typename T::key_type & key)
{
auto i = map.find(key);
if (i == map.end()) return nullptr;
return &i->second;
}
/**
* Get a value for the specified key from an associate container, or a default value if the key isn't present.
*/
template<class T>
const typename T::mapped_type & getOr(
T & map [[clang::lifetimebound]],
const typename T::key_type & key,
const typename T::mapped_type & defaultValue [[clang::lifetimebound]]
)
{
auto i = map.find(key);
if (i == map.end()) {
/* FIXME(Raito): `[[clang::lifetimebound]]` has no effect on `defaultValue` warning. */
// NOLINTNEXTLINE(bugprone-return-const-ref-from-parameter)
return defaultValue;
}
return i->second;
}
/**
* Remove and return the first item from a container.
*/
template <class T>
std::optional<typename T::value_type> remove_begin(T & c)
{
auto i = c.begin();
if (i == c.end()) return {};
auto v = std::move(*i);
c.erase(i);
return v;
}
/**
* Remove and return the first item from a container.
*/
template <class T>
std::optional<typename T::value_type> pop(T & c)
{
if (c.empty()) return {};
auto v = std::move(c.front());
c.pop();
return v;
}
/**
* A RAII helper that increments a counter on construction and
* decrements it on destruction.
*/
template<typename T>
struct MaintainCount
{
T & counter;
long delta;
MaintainCount(T & counter, long delta = 1) : counter(counter), delta(delta) { counter += delta; }
~MaintainCount() { counter -= delta; }
};
/**
* A Rust/Python-like enumerate() iterator adapter.
*
* Borrowed from http://reedbeta.com/blog/python-like-enumerate-in-cpp17.
*
* FIXME(jade): remove once P2164R9 is implemented in libc++ and replace with
* std::views::enumerate: https://libcxx.llvm.org/Status/Cxx23.html
*/
template <typename T,
typename TIter = decltype(std::begin(std::declval<T>())),
typename = decltype(std::end(std::declval<T>()))>
constexpr auto enumerate(T && iterable)
{
struct iterator
{
size_t i;
TIter iter;
constexpr bool operator != (const iterator & other) const { return iter != other.iter; }
constexpr void operator ++ () { ++i; ++iter; }
constexpr auto operator * () { return std::tie(i, *iter); }
};
struct iterable_wrapper
{
T iterable;
constexpr auto begin() { return iterator{ 0, std::begin(iterable) }; }
constexpr auto end() { return iterator{ 0, std::end(iterable) }; }
};
return iterable_wrapper{ std::forward<T>(iterable) };
}
/**
* C++17 std::visit boilerplate
*/
template<class... Ts> struct overloaded : Ts... { using Ts::operator()...; };
template<class... Ts> overloaded(Ts...) -> overloaded<Ts...>;
/**
* marker type for things that should never be called from async code.
* add a defaulted argument of this type to a method or constructor to
* have our linter check that marked code is never called by accident.
*/
struct NeverAsync {};
/**
* Escape hatch to allow calling NeverAsync-marked code from functions
* that aren't themselves NeverAsync. this should only be used when no
* typelevel proof can be given for a call that's dynamically known to
* not block. using this is still forbidden in promises since blocking
* an executor, even on something known to complete, impedes progress.
*/
constexpr inline NeverAsync always_progresses;
}