fish-shell/src/null_terminated_array.h
Aaron Gyes 14d2a6d8ff IWYU-guided #include rejiggering.
Let's hope this doesn't causes build failures for e.g. musl: I just
know it's good on macOS and our Linux CI.

It's been a long time.

One fix this brings, is I discovered we #include assert.h or cassert
in a lot of places. If those ever happen to be in a file that doesn't
include common.h, or we are before common.h gets included, we're
unawaringly working with the system 'assert' macro again, which
may get disabled for debug builds or at least has different
behavior on crash. We undef 'assert' and redefine it in common.h.

Those were all eliminated, except in one catch-22 spot for
maybe.h: it can't include common.h. A fix might be to
make a fish_assert.h that *usually* common.h exports.
2022-08-20 23:55:18 -07:00

76 lines
2.9 KiB
C++

// Support for null-terminated arrays like char**.
#ifndef FISH_NULL_TERMINATED_ARRAY_H
#define FISH_NULL_TERMINATED_ARRAY_H
#include "config.h" // IWYU pragma: keep
#include <cstddef>
#include <string>
#include <utility>
#include <vector>
#include "common.h"
/// This supports the null-terminated array of NUL-terminated strings consumed by exec.
/// Given a list of strings, construct a vector of pointers to those strings contents.
/// This is used for building null-terminated arrays of null-terminated strings.
/// *Important*: the vector stores pointers into the interior of the input strings, which may be
/// subject to the small-string optimization. This means that pointers will be left dangling if any
/// input string is deallocated *or moved*. This class should only be used in transient calls.
template <typename T>
class null_terminated_array_t : noncopyable_t, nonmovable_t {
public:
/// \return the list of pointers, appropriate for envp or argv.
/// Note this returns a mutable array of const strings. The caller may rearrange the strings but
/// not modify their contents.
const T **get() {
assert(!pointers_.empty() && pointers_.back() == nullptr && "Should have null terminator");
return &pointers_[0];
}
// Construct from a list of strings (std::string or wcstring).
// This holds pointers into the strings.
explicit null_terminated_array_t(const std::vector<std::basic_string<T>> &strs) {
pointers_.reserve(strs.size() + 1);
for (const auto &s : strs) {
pointers_.push_back(s.c_str());
}
pointers_.push_back(nullptr);
}
private:
std::vector<const T *> pointers_{};
};
/// A container which exposes a null-terminated array of pointers to strings that it owns.
/// This is useful for persisted null-terminated arrays, e.g. the exported environment variable
/// list. This assumes char, since we don't need this for wchar_t.
/// Note this class is not movable or copyable as it embeds a null_terminated_array_t.
class owning_null_terminated_array_t {
public:
// Access the null-terminated array of nul-terminated strings, appropriate for execv().
const char **get() { return pointers_.get(); }
// Construct, taking ownership of a list of strings.
explicit owning_null_terminated_array_t(std::vector<std::string> &&strings)
: strings_(std::move(strings)), pointers_(strings_) {}
private:
const std::vector<std::string> strings_;
null_terminated_array_t<char> pointers_;
};
/// Helper to convert a list of wcstring to a list of std::string.
std::vector<std::string> wide_string_list_to_narrow(const wcstring_list_t &strs);
/// \return the length of a null-terminated array of pointers to something.
template <typename T>
size_t null_terminated_array_length(const T *const *arr) {
size_t idx = 0;
while (arr[idx] != nullptr) {
idx++;
}
return idx;
}
#endif // FISH_NULL_TERMINATED_ARRAY_H