2012-07-18 18:59:03 +00:00
|
|
|
#pragma once
|
2006-09-04 21:06:23 +00:00
|
|
|
|
2016-02-23 12:53:31 +00:00
|
|
|
#include "ref.hh"
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
#include <list>
|
|
|
|
#include <set>
|
2020-06-29 21:21:27 +00:00
|
|
|
#include <string>
|
2022-03-04 18:31:59 +00:00
|
|
|
#include <limits>
|
2017-04-13 13:55:38 +00:00
|
|
|
#include <map>
|
2022-01-21 15:20:54 +00:00
|
|
|
#include <variant>
|
2020-05-14 18:28:18 +00:00
|
|
|
#include <vector>
|
2014-10-20 16:15:50 +00:00
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
namespace nix {
|
|
|
|
|
2022-02-21 15:37:25 +00:00
|
|
|
typedef std::list<std::string> Strings;
|
|
|
|
typedef std::set<std::string> StringSet;
|
|
|
|
typedef std::map<std::string, std::string> StringMap;
|
2022-02-25 15:00:00 +00:00
|
|
|
typedef std::map<std::string, std::string> StringPairs;
|
2006-09-04 21:06:23 +00:00
|
|
|
|
|
|
|
/* Paths are just strings. */
|
2022-02-21 15:37:25 +00:00
|
|
|
typedef std::string Path;
|
2022-01-12 15:02:29 +00:00
|
|
|
typedef std::string_view PathView;
|
2022-02-21 15:25:12 +00:00
|
|
|
typedef std::list<Path> Paths;
|
2022-02-21 15:28:23 +00:00
|
|
|
typedef std::set<Path> PathSet;
|
2006-09-04 21:06:23 +00:00
|
|
|
|
2022-02-21 15:37:25 +00:00
|
|
|
typedef std::vector<std::pair<std::string, std::string>> Headers;
|
2020-06-17 19:08:59 +00:00
|
|
|
|
2020-03-30 14:04:18 +00:00
|
|
|
/* Helper class to run code at startup. */
|
|
|
|
template<typename T>
|
|
|
|
struct OnStartup
|
|
|
|
{
|
|
|
|
OnStartup(T && t) { t(); }
|
|
|
|
};
|
|
|
|
|
2020-10-26 15:58:58 +00:00
|
|
|
/* 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;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2022-01-21 15:20:54 +00:00
|
|
|
|
|
|
|
/* This wants to be a little bit like rust's Cow type.
|
|
|
|
Some parts of the evaluator benefit greatly from being able to reuse
|
|
|
|
existing allocations for strings, but have to be able to also use
|
|
|
|
newly allocated storage for values.
|
|
|
|
|
|
|
|
We do not define implicit conversions, even with ref qualifiers,
|
|
|
|
since those can easily become ambiguous to the reader and can degrade
|
|
|
|
into copying behaviour we want to avoid. */
|
|
|
|
class BackedStringView {
|
|
|
|
private:
|
|
|
|
std::variant<std::string, std::string_view> data;
|
|
|
|
|
|
|
|
/* Needed to introduce a temporary since operator-> must return
|
|
|
|
a pointer. Without this we'd need to store the view object
|
|
|
|
even when we already own a string. */
|
|
|
|
class Ptr {
|
|
|
|
private:
|
|
|
|
std::string_view view;
|
|
|
|
public:
|
|
|
|
Ptr(std::string_view view): view(view) {}
|
|
|
|
const std::string_view * operator->() const { return &view; }
|
|
|
|
};
|
|
|
|
|
|
|
|
public:
|
|
|
|
BackedStringView(std::string && s): data(std::move(s)) {}
|
|
|
|
BackedStringView(std::string_view sv): data(sv) {}
|
|
|
|
template<size_t N>
|
|
|
|
BackedStringView(const char (& lit)[N]): data(std::string_view(lit)) {}
|
|
|
|
|
|
|
|
BackedStringView(const BackedStringView &) = delete;
|
|
|
|
BackedStringView & operator=(const BackedStringView &) = delete;
|
|
|
|
|
|
|
|
/* We only want move operations defined since the sole purpose of
|
|
|
|
this type is to avoid copies. */
|
|
|
|
BackedStringView(BackedStringView && other) = default;
|
|
|
|
BackedStringView & operator=(BackedStringView && other) = default;
|
|
|
|
|
|
|
|
bool isOwned() const
|
|
|
|
{
|
|
|
|
return std::holds_alternative<std::string>(data);
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string toOwned() &&
|
|
|
|
{
|
|
|
|
return isOwned()
|
|
|
|
? std::move(std::get<std::string>(data))
|
|
|
|
: std::string(std::get<std::string_view>(data));
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string_view operator*() const
|
|
|
|
{
|
|
|
|
return isOwned()
|
|
|
|
? std::get<std::string>(data)
|
|
|
|
: std::get<std::string_view>(data);
|
|
|
|
}
|
|
|
|
Ptr operator->() const { return Ptr(**this); }
|
|
|
|
};
|
|
|
|
|
2022-03-04 18:31:59 +00:00
|
|
|
/* Provides an indexable container like vector<> with memory overhead
|
|
|
|
guarantees like list<> by allocating storage in chunks of ChunkSize
|
|
|
|
elements instead of using a contiguous memory allocation like vector<>
|
|
|
|
does. Not using a single vector that is resized reduces memory overhead
|
|
|
|
on large data sets by on average (growth factor)/2, mostly
|
|
|
|
eliminates copies within the vector during resizing, and provides stable
|
|
|
|
references to its elements. */
|
|
|
|
template<typename T, size_t ChunkSize>
|
|
|
|
class ChunkedVector {
|
|
|
|
private:
|
|
|
|
uint32_t size_ = 0;
|
|
|
|
std::vector<std::vector<T>> chunks;
|
|
|
|
|
|
|
|
/* keep this out of the ::add hot path */
|
|
|
|
[[gnu::noinline]]
|
|
|
|
auto & addChunk()
|
|
|
|
{
|
|
|
|
if (size_ >= std::numeric_limits<uint32_t>::max() - ChunkSize)
|
|
|
|
abort();
|
|
|
|
chunks.emplace_back();
|
|
|
|
chunks.back().reserve(ChunkSize);
|
|
|
|
return chunks.back();
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
|
|
|
ChunkedVector(uint32_t reserve)
|
|
|
|
{
|
|
|
|
chunks.reserve(reserve);
|
|
|
|
addChunk();
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t size() const { return size_; }
|
|
|
|
|
|
|
|
std::pair<T &, uint32_t> add(T value)
|
|
|
|
{
|
|
|
|
const auto idx = size_++;
|
|
|
|
auto & chunk = [&] () -> auto & {
|
|
|
|
if (auto & back = chunks.back(); back.size() < ChunkSize)
|
|
|
|
return back;
|
|
|
|
return addChunk();
|
|
|
|
}();
|
|
|
|
auto & result = chunk.emplace_back(std::move(value));
|
|
|
|
return {result, idx};
|
|
|
|
}
|
|
|
|
|
|
|
|
const T & operator[](uint32_t idx) const
|
|
|
|
{
|
|
|
|
return chunks[idx / ChunkSize][idx % ChunkSize];
|
|
|
|
}
|
2022-03-05 13:40:24 +00:00
|
|
|
|
|
|
|
template<typename Fn>
|
|
|
|
void forEach(Fn fn) const
|
|
|
|
{
|
|
|
|
for (const auto & c : chunks)
|
|
|
|
for (const auto & e : c)
|
|
|
|
fn(e);
|
|
|
|
}
|
2022-03-04 18:31:59 +00:00
|
|
|
};
|
|
|
|
|
2006-09-04 21:06:23 +00:00
|
|
|
}
|