From d911ed1130bd79b6e1a8bdbf68aae6d6c334c14d Mon Sep 17 00:00:00 2001 From: Lexi Winter Date: Fri, 27 Jun 2025 12:48:46 +0100 Subject: add more [[nodiscard]] --- nihil.config/option.ccm | 8 ++-- nihil.config/write.ccm | 4 +- nihil/command_map.ccm | 11 +++--- nihil/ctype.ccm | 15 ++++---- nihil/error.ccm | 2 +- nihil/fd.ccm | 42 +++++++++++++-------- nihil/find_in_path.ccm | 3 +- nihil/getenv.ccm | 2 +- nihil/guard.ccm | 12 +++--- nihil/match.ccm | 4 +- nihil/next_word.ccm | 2 +- nihil/open_file.ccm | 4 +- nihil/process.ccm | 17 +++++---- nihil/rename_file.ccm | 7 ++-- nihil/skipws.ccm | 2 +- nihil/spawn.ccm | 23 +++++++++--- nihil/tabulate.ccm | 94 ++++++++++++++++++++++++++++++---------------- nihil/tests/command_map.cc | 4 +- 18 files changed, 160 insertions(+), 96 deletions(-) diff --git a/nihil.config/option.ccm b/nihil.config/option.ccm index c095d34..c6ebcae 100644 --- a/nihil.config/option.ccm +++ b/nihil.config/option.ccm @@ -78,17 +78,17 @@ protected: /* * Get or set this option as a string. */ - virtual auto get_string() const + [[nodiscard]] virtual auto get_string() const -> std::string = 0; - virtual auto set_string(std::string_view) + [[nodiscard]] virtual auto set_string(std::string_view) -> std::expected = 0; /* * Get or set this option as a UCL object. */ - virtual auto get_ucl() const + [[nodiscard]] virtual auto get_ucl() const -> std::expected = 0; - virtual auto set_ucl(ucl::object const &) + [[nodiscard]] virtual auto set_ucl(ucl::object const &) -> std::expected = 0; private: diff --git a/nihil.config/write.ccm b/nihil.config/write.ccm index cb35d76..8fb8151 100644 --- a/nihil.config/write.ccm +++ b/nihil.config/write.ccm @@ -11,12 +11,12 @@ export module nihil.config:write; import nihil; -export namespace nihil::config { +namespace nihil::config { /* * Write all config values (except defaults) to disk. */ -auto write_to(std::filesystem::path const &filename) -> +export [[nodiscard]] auto write_to(std::filesystem::path const &filename) -> std::expected; }; diff --git a/nihil/command_map.ccm b/nihil/command_map.ccm index 979657b..4e55211 100644 --- a/nihil/command_map.ccm +++ b/nihil/command_map.ccm @@ -30,12 +30,13 @@ struct command_base { { } - auto path(this command_base const &self) -> std::string_view + [[nodiscard]] auto path(this command_base const &self) + -> std::string_view { return self._path; } - virtual auto invoke(int argc, char **argv) -> int = 0; + [[nodiscard]] virtual auto invoke(int argc, char **argv) -> int = 0; private: std::string_view _path; @@ -59,7 +60,7 @@ struct command final : command_base { register_command(path, this); } - auto invoke(int argc, char **argv) -> int override + [[nodiscard]] auto invoke(int argc, char **argv) -> int final { return std::invoke(_func, argc, argv); } @@ -69,7 +70,7 @@ private: }; // The public API. -export auto dispatch_command(int argc, char **argv) -> int; -export void print_usage(std::string_view prefix); +export [[nodiscard]] auto dispatch_command(int argc, char **argv) -> int; +export auto print_usage(std::string_view prefix) -> void; } // namespace nihil diff --git a/nihil/ctype.ccm b/nihil/ctype.ccm index cc058cd..5f45703 100644 --- a/nihil/ctype.ccm +++ b/nihil/ctype.ccm @@ -24,20 +24,21 @@ namespace nihil { export struct ctype_is final { ctype_is(std::ctype_base::mask mask_, std::locale const &locale_ = std::locale()) - : mask(mask_) - , locale(locale_) + : m_mask(mask_) + , m_locale(locale_) {} - auto operator()(this ctype_is const &self, std::integral auto c) + [[nodiscard]] auto operator()(this ctype_is const &self, + std::integral auto c) { using ctype = std::ctype; - auto &facet = std::use_facet(self.locale); - return facet.is(self.mask, c); + auto &facet = std::use_facet(self.m_locale); + return facet.is(self.m_mask, c); } private: - std::ctype_base::mask mask; - std::locale locale; + std::ctype_base::mask m_mask; + std::locale m_locale; }; // Predefined tests for the current global locale. diff --git a/nihil/error.ccm b/nihil/error.ccm index 7d220e1..0500f2e 100644 --- a/nihil/error.ccm +++ b/nihil/error.ccm @@ -121,7 +121,7 @@ export struct error : std::exception { [[nodiscard]] auto condition(this error const &) -> std::optional; - auto what() const noexcept -> char const * final; + [[nodiscard]] auto what() const noexcept -> char const * final; private: friend auto operator==(error const &, error const &) -> bool; diff --git a/nihil/fd.ccm b/nihil/fd.ccm index 3503833..3349fbd 100644 --- a/nihil/fd.ccm +++ b/nihil/fd.ccm @@ -68,7 +68,7 @@ private: }; // Create a copy of this fd by calling dup(). -export auto dup(fd const &self) -> std::expected; +export [[nodiscard]] auto dup(fd const &self) -> std::expected; // Create a copy of this fd by calling dup2(). Note that because this results // in the existing fd and the new fd both being managed by an fd instance, @@ -79,47 +79,58 @@ export auto dup(fd const &self) -> std::expected; // // In both of these cases, either use raw_dup() instead, or immediately call // release() on the returned fd to prevent the fd instance from closing it. -export auto dup(fd const &self, int newfd) -> std::expected; +export [[nodiscard]] auto dup(fd const &self, int newfd) + -> std::expected; // Create a copy of this fd by calling dup(). -export auto raw_dup(fd const &self) -> std::expected; +export [[nodiscard]] auto raw_dup(fd const &self) + -> std::expected; // Create a copy of this fd by calling dup2(). -export auto raw_dup(fd const &self, int newfd) -> std::expected; +export [[nodiscard]] auto raw_dup(fd const &self, int newfd) + -> std::expected; // Return the fnctl flags for this fd. -export auto getflags(fd const &self) -> std::expected; +export [[nodiscard]] auto getflags(fd const &self) + -> std::expected; // Replace the fnctl flags for this fd. -export auto replaceflags(fd &self, int newflags) -> std::expected; +export [[nodiscard]] auto replaceflags(fd &self, int newflags) + -> std::expected; // Add bits to the fcntl flags for this fd. Returns the new flags. -export auto setflags(fd &self, int newflags) -> std::expected; +export [[nodiscard]] auto setflags(fd &self, int newflags) + -> std::expected; // Remove bits from the fcntl flags for this fd. Returns the new flags. -export auto clearflags(fd &self, int clrflags) -> std::expected; +export [[nodiscard]] auto clearflags(fd &self, int clrflags) + -> std::expected; // Return the fd flags for this fd. -export auto getfdflags(fd const &self) -> std::expected; +export [[nodiscard]] auto getfdflags(fd const &self) + -> std::expected; // Replace the fd flags for this fd. -export auto replacefdflags(fd &self, int newflags) +export [[nodiscard]] auto replacefdflags(fd &self, int newflags) -> std::expected; // Add bits to the fd flags for this fd. Returns the new flags. -export auto setfdflags(fd &self, int newflags) -> std::expected; +export [[nodiscard]] auto setfdflags(fd &self, int newflags) + -> std::expected; // Remove bits from the fd flags for this fd. Returns the new flags. -export auto clearfdflags(fd &self, int clrflags) -> std::expected; +export [[nodiscard]] auto clearfdflags(fd &self, int clrflags) + -> std::expected; // Create two fds by calling pipe() and return them. -export auto pipe() -> std::expected, error>; +export [[nodiscard]] auto pipe() -> std::expected, error>; /* * Write data to a file descriptor from the provided range. Returns the * number of bytes written. */ -export auto write(fd &file, std::ranges::contiguous_range auto &&range) +export [[nodiscard]] auto write(fd &file, + std::ranges::contiguous_range auto &&range) -> std::expected requires(sizeof(std::ranges::range_value_t) == 1) { @@ -130,7 +141,8 @@ requires(sizeof(std::ranges::range_value_t) == 1) * Read data from a file descriptor into the provided buffer. Returns a * span containing the data that was read. */ -export auto read(fd &file, std::ranges::contiguous_range auto &&range) +export [[nodiscard]] auto read(fd &file, + std::ranges::contiguous_range auto &&range) -> std::expected< std::span>, error> diff --git a/nihil/find_in_path.ccm b/nihil/find_in_path.ccm index 3c02ca5..3983c40 100644 --- a/nihil/find_in_path.ccm +++ b/nihil/find_in_path.ccm @@ -18,6 +18,7 @@ namespace nihil { * If $PATH is not set, uses _PATH_DEFPATH. If the file can't be found * or opened, returns std::nullopt. */ -auto find_in_path(std::filesystem::path const &file) -> std::optional; +export [[nodiscard]] auto find_in_path(std::filesystem::path const &file) + -> std::optional; } // namespace nihil diff --git a/nihil/getenv.ccm b/nihil/getenv.ccm index 25bde77..a7831e0 100644 --- a/nihil/getenv.ccm +++ b/nihil/getenv.ccm @@ -18,7 +18,7 @@ namespace nihil { * Find a variable by the given name in the environment by calling getenv_r(). */ -export auto getenv(std::string_view varname) +export [[nodiscard]] auto getenv(std::string_view varname) -> std::expected; } // namespace nihil diff --git a/nihil/guard.ccm b/nihil/guard.ccm index 92305f2..554f605 100644 --- a/nihil/guard.ccm +++ b/nihil/guard.ccm @@ -20,23 +20,23 @@ namespace nihil { export template struct guard final { // Initialise the guard with a callable we will invoke later. - guard(F func) : _func(std::move(func)) {} + guard(F func) : m_func(std::move(func)) {} /* * We are being destroyed, so call the callable. * If the callable throws, std::terminate() will be called. */ ~guard() { - if (_func) - std::invoke(*_func); + if (m_func) + std::invoke(*m_func); } // Release the guard. This turns the destructor into a no-op. void release() noexcept { - _func.reset(); + m_func.reset(); } - // Not default-constructible or copyable. + // Not default-constructible, movable or copyable. guard() = delete; guard(guard const &) = delete; guard(guard &&) noexcept = delete; @@ -45,7 +45,7 @@ struct guard final { private: // The callable to be invoked when we are destroyed. - std::optional _func; + std::optional m_func; }; } // namespace nihil diff --git a/nihil/match.ccm b/nihil/match.ccm index 9859ea4..f51ce4b 100644 --- a/nihil/match.ccm +++ b/nihil/match.ccm @@ -10,10 +10,10 @@ export module nihil:match; namespace nihil { -template +export template struct match : Ts... { using Ts::operator()...; }; -template +export template constexpr decltype(auto) operator| (std::variant const &v, match const &match) { diff --git a/nihil/next_word.ccm b/nihil/next_word.ccm index b6345bc..6c988a0 100644 --- a/nihil/next_word.ccm +++ b/nihil/next_word.ccm @@ -22,7 +22,7 @@ namespace nihil { * calling this repeatedly will return each word from the string. */ -export template +export template [[nodiscard]] auto next_word(std::basic_string_view text, std::locale const &locale = std::locale()) -> std::pair, diff --git a/nihil/open_file.ccm b/nihil/open_file.ccm index 89af4e6..1333785 100644 --- a/nihil/open_file.ccm +++ b/nihil/open_file.ccm @@ -18,8 +18,8 @@ namespace nihil { /* * Open the given file and return an fd for it. */ -export auto open_file(std::filesystem::path const &filename, - int flags, int mode = 0777) +export [[nodiscard]] auto open_file(std::filesystem::path const &filename, + int flags, int mode = 0777) -> std::expected; } // namespace nihil diff --git a/nihil/process.ccm b/nihil/process.ccm index 83e34b4..6d74513 100644 --- a/nihil/process.ccm +++ b/nihil/process.ccm @@ -23,14 +23,16 @@ namespace nihil { export struct wait_result final { // Return true if the process exited normally with an exit code of // zero, otherwise false. - auto okay(this wait_result const &self) -> bool; - explicit operator bool(this wait_result const &self); + [[nodiscard]] auto okay(this wait_result const &self) -> bool; + [[nodiscard]] explicit operator bool(this wait_result const &self); // Return the exit status, if any. - auto status(this wait_result const &self) -> std::optional; + [[nodiscard]] auto status(this wait_result const &self) + -> std::optional; // Return the exit signal, if any. - auto signal(this wait_result const &self) -> std::optional; + [[nodiscard]] auto signal(this wait_result const &self) + -> std::optional; private: friend struct process; @@ -66,20 +68,21 @@ export struct process final { auto operator=(this process &, process const &) -> process & = delete; // Get the child's process id. - auto pid(this process const &self) noexcept -> ::pid_t; + [[nodiscard]] auto pid(this process const &self) noexcept -> ::pid_t; /* * Wait for this process to exit (by calling waitpid()) and return * its exit status. This destroys the process state, leaving this * object in a moved-from state. */ - auto wait(this process &&self) -> std::expected; + [[nodiscard]] auto wait(this process &&self) + -> std::expected; /* * Release this process so we won't try to wait for it when * destroying this object. */ - auto release(this process &&self) -> ::pid_t; + [[nodiscard]] auto release(this process &&self) -> ::pid_t; private: ::pid_t m_pid; diff --git a/nihil/rename_file.ccm b/nihil/rename_file.ccm index bffb3fa..4abe975 100644 --- a/nihil/rename_file.ccm +++ b/nihil/rename_file.ccm @@ -11,13 +11,14 @@ export module nihil:rename_file; import :error; -export namespace nihil { +namespace nihil { /* * Rename a file (or directory). */ -auto rename_file(std::filesystem::path const &oldp, - std::filesystem::path const &newp) +export [[nodiscard]] auto +rename_file(std::filesystem::path const &oldp, + std::filesystem::path const &newp) -> std::expected; } // namespace nihil diff --git a/nihil/skipws.ccm b/nihil/skipws.ccm index 20f6aa4..3d760a9 100644 --- a/nihil/skipws.ccm +++ b/nihil/skipws.ccm @@ -19,7 +19,7 @@ namespace nihil { * Remove leading whitespace from a string. */ -export template +export template [[nodiscard]] auto skipws(std::basic_string_view text, std::locale const &locale = std::locale()) -> std::basic_string_view diff --git a/nihil/spawn.ccm b/nihil/spawn.ccm index 00c970c..c15ab8d 100644 --- a/nihil/spawn.ccm +++ b/nihil/spawn.ccm @@ -56,9 +56,17 @@ export struct fd_pipe final { auto run_in_child(this fd_pipe &self, process &) -> void { - std::ignore = self.m_parent_fd.close(); + auto err = raw_dup(self.m_child_fd, self.m_fdno); + if (!err) { + std::print("dup: {}\n", err.error()); + _exit(1); + } - raw_dup(self.m_child_fd, self.m_fdno); + /* + * We don't care about errors from close() since the fd + * is still closed. + */ + std::ignore = self.m_parent_fd.close(); std::ignore = self.m_child_fd.close(); } @@ -67,7 +75,7 @@ export struct fd_pipe final { std::ignore = self.m_child_fd.close(); } - auto parent_fd(this fd_pipe &self) -> fd & + [[nodiscard]] auto parent_fd(this fd_pipe &self) -> fd & { return self.m_parent_fd; } @@ -103,7 +111,12 @@ export struct fd_file final { auto run_in_child(this fd_file &self, process &) -> void { - raw_dup(self.m_file_fd, self.m_fdno); + auto err = raw_dup(self.m_file_fd, self.m_fdno); + if (!err) { + std::print("dup: {}\n", err.error()); + _exit(1); + } + std::ignore = self.m_file_fd.close(); } @@ -221,7 +234,7 @@ spawn(executor auto &&executor, auto &&...actions) // try to wait for ourselves, then run child handlers and // exec the process. - std::move(proc).release(); + std::ignore = std::move(proc).release(); (actions.run_in_child(proc), ...); auto err = executor.exec(); diff --git a/nihil/tabulate.ccm b/nihil/tabulate.ccm index 9e2303b..9faf885 100644 --- a/nihil/tabulate.ccm +++ b/nihil/tabulate.ccm @@ -50,43 +50,70 @@ export struct table_spec_error : error { */ template struct field_spec { - std::basic_string_view name; - std::size_t width = 0; - enum { left, right } align = left; + enum align_t { left, right }; + + // Get the name of this field. + auto name(this field_spec const &self) + -> std::basic_string_view + { + return self.m_name; + } + + // Set the name of this field. + auto name(this field_spec &self, + std::basic_string_view new_name) + -> void + { + self.m_name = new_name; + } + + // Set this field's alignment. + auto align(this field_spec &self, align_t new_align) -> void + { + self.m_align = new_align; + } // Ensure the length of this field is at least the given width. - auto ensure_width(std::size_t newwidth) -> void + auto ensure_width(this field_spec &self, std::size_t newwidth) + -> void { - width = std::max(width, newwidth); + self.m_width = std::max(self.m_width, newwidth); } // Format an object to a string based on our field spec. - auto format(auto &&obj) const -> std::basic_string + [[nodiscard]] auto format(this field_spec const &, auto &&obj) + -> std::basic_string { - std::basic_string format_string{'{', '}'}; + auto format_string = std::basic_string{'{', '}'}; return std::format(std::runtime_format(format_string), obj); } // Print a column value to an output iterator according to our field // spec. If is_last is true, this is the last field on the line, so // we won't output any trailling padding. - auto print(std::basic_string_view value, + auto print(this field_spec const &self, + std::basic_string_view value, std::output_iterator auto &out, bool is_last) - const + -> void { - auto padding = width - value.size(); + auto padding = self.m_width - value.size(); - if (align == right) + if (self.m_align == right) for (std::size_t i = 0; i < padding; ++i) *out++ = ' '; std::ranges::copy(value, out); - if (!is_last && align == left) + if (!is_last && self.m_align == left) for (std::size_t i = 0; i < padding; ++i) *out++ = ' '; } + +private: + std::basic_string_view m_name; + std::size_t m_width = 0; + align_t m_align = left; }; /* @@ -95,34 +122,36 @@ struct field_spec { template struct table_spec { // Add a new field spec to this table. - auto add(field_spec field) + auto add(this table_spec &self, field_spec field) -> void { - _fields.emplace_back(std::move(field)); + self.m_fields.emplace_back(std::move(field)); } // Return the field spec for a given field. If the field doesn't // exist, this field and any intermediate fields will be created. - auto field(std::size_t fieldnr) -> field_spec& + [[nodiscard]] auto field(this table_spec &self, std::size_t fieldnr) + -> field_spec & { - if (_fields.size() < fieldnr + 1) - _fields.resize(fieldnr + 1); - return _fields.at(fieldnr); + if (fieldnr >= self.m_fields.size()) + self.m_fields.resize(fieldnr + 1); + return self.m_fields.at(fieldnr); } // The number of columns in this table. - auto columns() const -> std::size_t + [[nodiscard]] auto columns(this table_spec const &self) -> std::size_t { - return _fields.size(); + return self.m_fields.size(); } // Return all the fields in this table. - auto fields() const + [[nodiscard]] auto fields(this table_spec const &self) + -> std::vector> const & { - return _fields; + return self.m_fields; } private: - std::vector> _fields; + std::vector> m_fields; }; // Parse the field flags, e.g. '<'. @@ -134,10 +163,10 @@ auto parse_field_flags(field_spec &field, Iterator &pos, Sentinel end) while (pos < end) { switch (*pos) { case '<': - field.align = field_spec::left; + field.align(field_spec::left); break; case '>': - field.align = field_spec::right; + field.align(field_spec::right); break; case ':': ++pos; @@ -158,7 +187,7 @@ auto parse_field_flags(field_spec &field, Iterator &pos, Sentinel end) // Parse a complete field spec, e.g. "{<:NAME}". template Sentinel> -auto parse_field(Iterator &pos, Sentinel end) +[[nodiscard]] auto parse_field(Iterator &pos, Sentinel end) -> field_spec { auto field = field_spec{}; @@ -180,17 +209,18 @@ auto parse_field(Iterator &pos, Sentinel end) if (brace == end) throw table_spec_error("Invalid table spec: expected '}'"); - field.name = std::basic_string_view(pos, brace); + field.name(std::basic_string_view(pos, brace)); pos = std::next(brace); // The field must be at least as wide as its header. - field.width = field.name.size(); + field.ensure_width(field.name().size()); return field; } template -auto parse_table_spec(std::basic_string_view spec) -> table_spec +[[nodiscard]] auto parse_table_spec(std::basic_string_view spec) + -> table_spec { auto table = table_spec(); @@ -215,8 +245,8 @@ export template Iterator> auto basic_tabulate(std::basic_string_view table_spec, - Range &&range, - Iterator &&out) + Range &&range, + Iterator &&out) -> void { // Parse the table spec. @@ -243,7 +273,7 @@ auto basic_tabulate(std::basic_string_view table_spec, // Add the header row. for (auto &&field : table.fields()) - data.at(0).emplace_back(std::from_range, field.name); + data.at(0).emplace_back(std::from_range, field.name()); // Print the values. for (auto &&row : data) { diff --git a/nihil/tests/command_map.cc b/nihil/tests/command_map.cc index 7d34b33..4490396 100644 --- a/nihil/tests/command_map.cc +++ b/nihil/tests/command_map.cc @@ -25,6 +25,8 @@ TEST_CASE("command_map: basic", "[command_map]") "cmd", "sub1", nullptr }; auto argv = const_cast(args.data()); - nihil::dispatch_command(args.size() - 1, argv); + + int ret = nihil::dispatch_command(args.size() - 1, argv); + REQUIRE(ret == 0); REQUIRE(cmd_sub1_called == true); } -- cgit v1.2.3