diff options
Diffstat (limited to 'nihil/argv.ccm')
| -rw-r--r-- | nihil/argv.ccm | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/nihil/argv.ccm b/nihil/argv.ccm new file mode 100644 index 0000000..a9c254e --- /dev/null +++ b/nihil/argv.ccm @@ -0,0 +1,107 @@ +/* + * This source code is released into the public domain. + */ + +module; + +#include <memory> +#include <ranges> +#include <string> +#include <vector> + +export module nihil:argv; + +namespace nihil { + +/* + * argv: stores a null-terminated array of nul-terminated C strings. + * argv::data() is suitable for passing to ::execv(). + * + * Create an argv using argv::from_range(), which takes a range of + * string-like objects. + */ + +export struct argv { + /* + * Create a new argv from a range. + */ + static auto from_range(std::ranges::range auto &&args) -> argv + { + auto ret = argv{}; + + for (auto &&arg : args) + ret._add_arg(std::string_view(arg)); + + ret._args.push_back(nullptr); + return ret; + } + + template<typename T> + static auto from_args(std::initializer_list<T> &&args) + { + return from_range(std::move(args)); + } + + argv(argv &&) noexcept = default; + auto operator=(this argv &, argv &&other) -> argv& = default; + + // Not copyable. TODO: for completeness, it probably should be. + argv(argv const &) = delete; + auto operator=(this argv &, argv const &other) -> argv& = delete; + + ~argv() + { + for (auto *arg : _args) + delete[] arg; + } + + // Access the stored arguments. + auto data(this argv const &self) -> char const * const * + { + return self._args.data(); + } + + auto data(this argv &self) -> char * const * + { + return self._args.data(); + } + + auto size(this argv const &self) + { + return self._args.size(); + } + + // Range access + auto begin(this argv const &self) + { + return self._args.begin(); + } + + auto end(this argv const &self) + { + return self._args.end(); + } + +private: + // Use the from_range() factory method to create new instances. + argv() = default; + + // The argument pointers, including the null terminator. + std::vector<char *> _args; + + // Add a new argument to the array. + auto _add_arg(this argv &self, std::string_view arg) -> void + { + // Create a nul-terminated C string. + auto ptr = std::make_unique<char[]>(arg.size() + 1); + std::ranges::copy(arg, ptr.get()); + ptr[arg.size()] = '\0'; + + // Ensure we won't throw when emplacing the pointer. + self._args.reserve(self._args.size() + 1); + self._args.emplace_back(ptr.release()); + } +}; + +} // namespace nihil + |
