From 5f7e03ccf493ad3b3f48d707f043a6b8aa971587 Mon Sep 17 00:00:00 2001 From: ridiculousfish Date: Thu, 22 Jul 2021 10:43:25 -0700 Subject: [PATCH] Introduce noncopyable_t and nonmovable_t These are little helper types that allow us to get rid of lots of '=delete' declarations. --- src/ast.h | 28 +++++------------------ src/builtin_string.cpp | 5 +---- src/common.h | 23 +++++++++++++------ src/env.cpp | 7 +----- src/fds.cpp | 1 - src/fds.h | 7 ++---- src/fish_tests.cpp | 4 +--- src/global_safety.h | 16 ++----------- src/history.h | 9 +------- src/history_file.cpp | 7 +----- src/history_file.h | 6 ++--- src/io.h | 26 +++++---------------- src/iothread.cpp | 21 +++-------------- src/lru.h | 11 +++------ src/null_terminated_array.h | 8 +------ src/parse_execution.h | 6 +---- src/parse_tree.h | 7 +----- src/postfork.h | 7 +----- src/proc.h | 12 ++-------- src/redirection.h | 45 ++++++++++++++++--------------------- src/screen.h | 5 +---- src/tokenizer.h | 6 +---- src/topic_monitor.h | 8 +------ src/wait_handle.h | 6 +---- 24 files changed, 72 insertions(+), 209 deletions(-) diff --git a/src/ast.h b/src/ast.h index 2cd8bcd44..cc9bc0129 100644 --- a/src/ast.h +++ b/src/ast.h @@ -215,7 +215,7 @@ void accept_field_visitor(FieldVisitor &v, bool reverse, Field &field, Rest &... /// node_t is the base node of all AST nodes. /// It is not a template: it is possible to work concretely with this type. -struct node_t { +struct node_t : noncopyable_t { /// The parent node, or null if this is root. const node_t *parent{nullptr}; @@ -227,12 +227,6 @@ struct node_t { constexpr explicit node_t(type_t t, category_t c) : type(t), category(c) {} - /// Disallow copying, etc. - node_t(const node_t &) = delete; - node_t(node_t &&) = delete; - void operator=(const node_t &) = delete; - void operator=(node_t &&) = delete; - /// Cast to a concrete node type, aborting on failure. /// Example usage: /// if (node->type == type_t::job_list) node->as()->... @@ -349,8 +343,9 @@ struct leaf_t : public node_t { }; // A simple fixed-size array, possibly empty. +// Disallow moving as we own a raw pointer. template -struct list_t : public node_t { +struct list_t : public node_t, nonmovable_t { static constexpr type_t AstType = ListType; static constexpr category_t Category = category_t::list; @@ -404,10 +399,6 @@ struct list_t : public node_t { list_t() : node_t(ListType, Category) {} ~list_t() { delete[] contents; } - - // Disallow moving as we own a raw pointer. - list_t(list_t &&) = delete; - void operator=(list_t &&) = delete; }; // Fully define all list types, as they are very uniform. @@ -825,7 +816,7 @@ union_ptr_t::union_ptr_t(std::unique_ptr n) : contents(n.release * }; */ template -class node_visitation_t { +class node_visitation_t : noncopyable_t { public: explicit node_visitation_t(NodeVisitor &v, bool reverse = false) : v_(v), reverse_(reverse) {} @@ -890,13 +881,6 @@ class node_visitation_t { void will_visit_fields_of(node_t &) {} void did_visit_fields_of(node_t &) {} - node_visitation_t(node_visitation_t &&) = default; - - // We cannot be copied. - node_visitation_t(const node_visitation_t &) = delete; - void operator=(const node_visitation_t &) = delete; - void operator=(node_visitation_t &&) = delete; - private: // Our adapted visitor. NodeVisitor &v_; @@ -959,7 +943,7 @@ class traversal_t { }; /// The ast type itself. -class ast_t { +class ast_t : noncopyable_t { public: using source_range_list_t = std::vector; @@ -1036,8 +1020,6 @@ class ast_t { ast_t(ast_t &&) = default; ast_t &operator=(ast_t &&) = default; - ast_t(const ast_t &) = delete; - void operator=(const ast_t &) = delete; private: ast_t() = default; diff --git a/src/builtin_string.cpp b/src/builtin_string.cpp index ead8e9ce6..fe6ecce49 100644 --- a/src/builtin_string.cpp +++ b/src/builtin_string.cpp @@ -813,7 +813,7 @@ static wcstring pcre2_strerror(int err_code) { return buf; } -struct compiled_regex_t { +struct compiled_regex_t : noncopyable_t { pcre2_code *code{nullptr}; pcre2_match_data *match{nullptr}; @@ -919,9 +919,6 @@ struct compiled_regex_t { bool is_valid() const { return this->valid_; } - compiled_regex_t(const compiled_regex_t &) = delete; - void operator=(const compiled_regex_t &) = delete; - private: bool valid_{false}; }; diff --git a/src/common.h b/src/common.h index f006762eb..c596926e6 100644 --- a/src/common.h +++ b/src/common.h @@ -238,6 +238,21 @@ extern const wcstring g_empty_string; /// See https://developer.gnome.org/glib/stable/glib-I18N.html#N-:CAPS #define N_(wstr) wstr +/// An empty struct which may be embedded (or inherited from) to prevent copying. +struct [[gnu::unused]] noncopyable_t { + noncopyable_t() = default; + noncopyable_t(noncopyable_t &&) = default; + noncopyable_t &operator=(noncopyable_t &&) = default; + noncopyable_t(const noncopyable_t &) = delete; + noncopyable_t &operator=(const noncopyable_t &) = delete; +}; + +struct [[gnu::unused]] nonmovable_t { + nonmovable_t() = default; + nonmovable_t(nonmovable_t &&) = delete; + nonmovable_t &operator=(nonmovable_t &&) = delete; +}; + /// Test if a collection contains a value. template bool contains(const Col &col, const T2 &val) { @@ -332,7 +347,7 @@ using scoped_lock = std::lock_guard; // name.acquire().value = "derp" // template -class acquired_lock { +class acquired_lock : noncopyable_t { template friend class owning_lock; @@ -346,12 +361,6 @@ class acquired_lock { Data *value; public: - // No copying, move construction only - acquired_lock &operator=(const acquired_lock &) = delete; - acquired_lock(const acquired_lock &) = delete; - acquired_lock(acquired_lock &&) = default; - acquired_lock &operator=(acquired_lock &&) = default; - Data *operator->() { return value; } const Data *operator->() const { return value; } Data &operator*() { return *value; } diff --git a/src/env.cpp b/src/env.cpp index 0bbe27fb4..5d41b1fff 100644 --- a/src/env.cpp +++ b/src/env.cpp @@ -547,7 +547,7 @@ class env_node_t { } // namespace using env_node_ref_t = std::shared_ptr; -class env_scoped_impl_t : public environment_t { +class env_scoped_impl_t : public environment_t, noncopyable_t { /// A struct wrapping up parser-local variables. These are conceptually variables that differ in /// different fish internal processes. struct perproc_data_t { @@ -573,11 +573,6 @@ class env_scoped_impl_t : public environment_t { std::shared_ptr export_array(); - env_scoped_impl_t(env_scoped_impl_t &&) = delete; - env_scoped_impl_t(const env_scoped_impl_t &) = delete; - void operator=(env_scoped_impl_t &&) = delete; - void operator=(const env_scoped_impl_t &) = delete; - protected: // A linked list of scopes. env_node_ref_t locals_{}; diff --git a/src/fds.cpp b/src/fds.cpp index cfa1600fd..2ead1ebfe 100644 --- a/src/fds.cpp +++ b/src/fds.cpp @@ -10,7 +10,6 @@ #include -#include "common.h" #include "flog.h" #include "wutil.h" diff --git a/src/fds.h b/src/fds.h index c01ed8228..1b136b046 100644 --- a/src/fds.h +++ b/src/fds.h @@ -13,10 +13,9 @@ #include #include +#include "common.h" #include "maybe.h" -using wcstring = std::wstring; - /// Pipe redirection error message. #define PIPE_ERROR _(L"An error occurred while setting up pipe") @@ -25,7 +24,7 @@ using wcstring = std::wstring; extern const int k_first_high_fd; /// A helper class for managing and automatically closing a file descriptor. -class autoclose_fd_t { +class autoclose_fd_t : noncopyable_t { int fd_; public: @@ -52,8 +51,6 @@ class autoclose_fd_t { // \return if this has a valid fd. bool valid() const { return fd_ >= 0; } - autoclose_fd_t(const autoclose_fd_t &) = delete; - void operator=(const autoclose_fd_t &) = delete; autoclose_fd_t(autoclose_fd_t &&rhs) : fd_(rhs.fd_) { rhs.fd_ = -1; } void operator=(autoclose_fd_t &&rhs) { diff --git a/src/fish_tests.cpp b/src/fish_tests.cpp index 2306e5f47..cf7f3da32 100644 --- a/src/fish_tests.cpp +++ b/src/fish_tests.cpp @@ -821,7 +821,7 @@ static void test_fd_monitor() { say(L"Testing fd_monitor"); // Helper to make an item which counts how many times its callback is invoked. - struct item_maker_t { + struct item_maker_t : public noncopyable_t { std::atomic did_timeout{false}; std::atomic length_read{0}; std::atomic pokes{0}; @@ -858,8 +858,6 @@ static void test_fd_monitor() { item = fd_monitor_item_t(std::move(pipes.read), std::move(callback), timeout_usec); } - item_maker_t(const item_maker_t &) = delete; - // Write 42 bytes to our write end. void write42() const { char buff[42] = {0}; diff --git a/src/global_safety.h b/src/global_safety.h index e97033508..cc19f2f59 100644 --- a/src/global_safety.h +++ b/src/global_safety.h @@ -13,21 +13,9 @@ // may therefore lead to data races. Use the following types to characterize and enforce correct // access patterns. -namespace detail { -// An empty value type that cannot be copied or moved. -// Include this as an instance variable to prevent globals from being copied or moved. -struct fixed_t { - fixed_t(const fixed_t &) = delete; - fixed_t(fixed_t &&) = delete; - fixed_t &operator=(fixed_t &&) = delete; - fixed_t &operator=(const fixed_t &) = delete; - fixed_t() = default; -}; -} // namespace detail - /// A mainthread_t variable may only be accessed on the main thread. template -class mainthread_t : detail::fixed_t { +class mainthread_t : noncopyable_t { T value_{}; public: @@ -58,7 +46,7 @@ class mainthread_t : detail::fixed_t { /// A latch variable may only be set once, on the main thread. /// The value is a immortal. template -class latch_t : detail::fixed_t { +class latch_t : noncopyable_t, nonmovable_t { T *value_{}; public: diff --git a/src/history.h b/src/history.h index 3bcb8a48f..6778d84fd 100644 --- a/src/history.h +++ b/src/history.h @@ -128,18 +128,11 @@ typedef std::deque history_item_list_t; struct history_impl_t; -class history_t { +class history_t : noncopyable_t, nonmovable_t { friend class history_tests_t; struct impl_wrapper_t; const std::unique_ptr wrap_; - // No copying or moving. - history_t() = delete; - history_t(const history_t &) = delete; - history_t(history_t &&) = delete; - history_t &operator=(const history_t &) = delete; - history_t &operator=(history_t &&) = delete; - acquired_lock impl(); acquired_lock impl() const; diff --git a/src/history_file.cpp b/src/history_file.cpp index 0114f25df..f2cb69cfc 100644 --- a/src/history_file.cpp +++ b/src/history_file.cpp @@ -96,7 +96,7 @@ static void unescape_yaml_fish_2_0(std::string *str) { } // A type wrapping up a region allocated via mmap(). -struct history_file_contents_t::mmap_region_t { +struct history_file_contents_t::mmap_region_t : noncopyable_t, nonmovable_t { void *const ptr; const size_t len; @@ -128,11 +128,6 @@ struct history_file_contents_t::mmap_region_t { if (ptr == MAP_FAILED) return nullptr; return make_unique(ptr, len); } - - mmap_region_t(mmap_region_t &&rhs) = delete; - void operator=(mmap_region_t &&rhs) = delete; - mmap_region_t(const mmap_region_t &) = delete; - void operator=(const mmap_region_t &) = delete; }; history_file_contents_t::~history_file_contents_t() = default; diff --git a/src/history_file.h b/src/history_file.h index 8a10aa5fb..198ee11f1 100644 --- a/src/history_file.h +++ b/src/history_file.h @@ -9,6 +9,7 @@ #include #include +#include "common.h" #include "maybe.h" class history_item_t; @@ -18,7 +19,7 @@ class history_tests_t; enum history_file_type_t { history_type_fish_2_0, history_type_fish_1_x }; /// history_file_contents_t holds the read-only contents of a file. -class history_file_contents_t { +class history_file_contents_t : noncopyable_t, nonmovable_t { public: /// Construct a history file contents from a file descriptor. The file descriptor is not closed. static std::unique_ptr create(int fd); @@ -74,9 +75,6 @@ class history_file_contents_t { // Try to infer the file type to populate type_. // \return true on success, false on error. bool infer_file_type(); - - history_file_contents_t(history_file_contents_t &&) = delete; - void operator=(history_file_contents_t &&) = delete; }; /// Append a history item to a buffer, in preparation for outputting it to the history file. diff --git a/src/io.h b/src/io.h index 6ce2605a6..e99e891fb 100644 --- a/src/io.h +++ b/src/io.h @@ -38,7 +38,7 @@ enum class separation_type_t { /// A separated_buffer_t contains a list of elements, some of which may be separated explicitly and /// others which must be separated further by the user (e.g. via IFS). -class separated_buffer_t { +class separated_buffer_t : noncopyable_t { public: struct element_t { std::string contents; @@ -50,11 +50,7 @@ class separated_buffer_t { bool is_explicitly_separated() const { return separation == separation_type_t::explicitly; } }; - /// separated_buffer_t may not be copied. - separated_buffer_t(const separated_buffer_t &) = delete; - void operator=(const separated_buffer_t &) = delete; - - /// We may be moved. + /// We not be copied but may be moved. /// Note this leaves the moved-from value in a bogus state until clear() is called on it. separated_buffer_t(separated_buffer_t &&) = default; separated_buffer_t &operator=(separated_buffer_t &&) = default; @@ -163,11 +159,7 @@ class separated_buffer_t { enum class io_mode_t { file, pipe, fd, close, bufferfill }; /// Represents an FD redirection. -class io_data_t { - // No assignment or copying allowed. - io_data_t(const io_data_t &rhs) = delete; - void operator=(const io_data_t &rhs) = delete; - +class io_data_t : noncopyable_t, nonmovable_t { protected: io_data_t(io_mode_t m, int fd, int source_fd) : io_mode(m), fd(fd), source_fd(source_fd) {} @@ -358,7 +350,7 @@ class io_chain_t : public std::vector { /// Base class representing the output that a builtin can generate. /// This has various subclasses depending on the ultimate output destination. -class output_stream_t { +class output_stream_t : noncopyable_t, nonmovable_t { public: /// Required override point. The output stream receives a string \p s with \p amt chars. virtual void append(const wchar_t *s, size_t amt) = 0; @@ -401,10 +393,6 @@ class output_stream_t { void append_formatv(const wchar_t *format, va_list va) { append(vformat_string(format, va)); } - // No copying. - output_stream_t(const output_stream_t &s) = delete; - void operator=(const output_stream_t &s) = delete; - output_stream_t() = default; virtual ~output_stream_t() = default; }; @@ -463,7 +451,7 @@ class buffered_output_stream_t final : public output_stream_t { std::shared_ptr buffer_; }; -struct io_streams_t { +struct io_streams_t : noncopyable_t { // Streams for out and err. output_stream_t &out; output_stream_t &err; @@ -495,10 +483,6 @@ struct io_streams_t { // FIXME: this is awkwardly placed. std::shared_ptr job_group{}; - // io_streams_t cannot be copied. - io_streams_t(const io_streams_t &) = delete; - void operator=(const io_streams_t &) = delete; - io_streams_t(output_stream_t &out, output_stream_t &err) : out(out), err(err) {} }; diff --git a/src/iothread.cpp b/src/iothread.cpp index 121645631..2f2d31281 100644 --- a/src/iothread.cpp +++ b/src/iothread.cpp @@ -44,19 +44,12 @@ using void_function_t = std::function; -struct work_request_t { +struct work_request_t : noncopyable_t { void_function_t handler; - explicit work_request_t(void_function_t &&f) : handler(std::move(f)) {} - - // Move-only - work_request_t &operator=(const work_request_t &) = delete; - work_request_t &operator=(work_request_t &&) = default; - work_request_t(const work_request_t &) = delete; - work_request_t(work_request_t &&) = default; }; -struct thread_pool_t { +struct thread_pool_t : noncopyable_t, nonmovable_t { struct data_t { /// The queue of outstanding, unclaimed requests. std::queue request_queue{}; @@ -108,12 +101,6 @@ struct thread_pool_t { /// Attempt to spawn a new pthread. bool spawn() const; - - /// No copying or moving. - thread_pool_t(const thread_pool_t &) = delete; - thread_pool_t(thread_pool_t &&) = delete; - void operator=(const thread_pool_t &) = delete; - void operator=(thread_pool_t &&) = delete; }; /// The thread pool for "iothreads" which are used to lift I/O off of the main thread. @@ -122,7 +109,7 @@ struct thread_pool_t { static thread_pool_t &s_io_thread_pool = *(new thread_pool_t(1, IO_MAX_THREADS)); /// A queue of "things to do on the main thread." -struct main_thread_queue_t { +struct main_thread_queue_t : noncopyable_t { // Functions to invoke as the completion callback from debounce. std::vector completions; @@ -143,8 +130,6 @@ struct main_thread_queue_t { main_thread_queue_t() = default; main_thread_queue_t(main_thread_queue_t &&) = default; main_thread_queue_t &operator=(main_thread_queue_t &&) = default; - main_thread_queue_t(const main_thread_queue_t &) = delete; - void operator=(const main_thread_queue_t &) = delete; }; static owning_lock s_main_thread_queue; diff --git a/src/lru.h b/src/lru.h index d010d2c34..3df78ed59 100644 --- a/src/lru.h +++ b/src/lru.h @@ -21,20 +21,15 @@ template class lru_cache_t { struct lru_node_t; - struct lru_link_t { - // Our doubly linked list - // The base class is used for the mouth only + struct lru_link_t : noncopyable_t { + // Our doubly linked list. + // The base class is used for the mouth only. lru_link_t *prev = nullptr; lru_link_t *next = nullptr; }; // The node type in our LRU cache struct lru_node_t : public lru_link_t { - // No copying - lru_node_t(const lru_node_t &) = delete; - lru_node_t &operator=(const lru_node_t &) = delete; - lru_node_t(lru_node_t &&) = default; - // Our key in the map. This is owned by the map itself. const wcstring *key = nullptr; diff --git a/src/null_terminated_array.h b/src/null_terminated_array.h index 406eb6d5d..c8dd93ac4 100644 --- a/src/null_terminated_array.h +++ b/src/null_terminated_array.h @@ -17,7 +17,7 @@ /// 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 -class null_terminated_array_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 @@ -37,12 +37,6 @@ class null_terminated_array_t { pointers_.push_back(nullptr); } - // Because this class holds unowned pointers, it should not be copied or moved. - null_terminated_array_t(const null_terminated_array_t &) = delete; - null_terminated_array_t(null_terminated_array_t &&) = delete; - void operator=(const null_terminated_array_t &) = delete; - void operator=(null_terminated_array_t &&) = delete; - private: std::vector pointers_{}; }; diff --git a/src/parse_execution.h b/src/parse_execution.h index 5220d7937..572db7e14 100644 --- a/src/parse_execution.h +++ b/src/parse_execution.h @@ -33,7 +33,7 @@ enum class end_execution_reason_t { error, }; -class parse_execution_context_t { +class parse_execution_context_t : noncopyable_t { private: parsed_source_ref_t pstree; parser_t *const parser; @@ -51,10 +51,6 @@ class parse_execution_context_t { /// For example, in `begin; foo ; end < file.txt` this would have the 'file.txt' IO. io_chain_t block_io{}; - // No copying allowed. - parse_execution_context_t(const parse_execution_context_t &) = delete; - parse_execution_context_t &operator=(const parse_execution_context_t &) = delete; - // Check to see if we should end execution. // \return the eval result to end with, or none() to continue on. // This will never return end_execution_reason_t::ok. diff --git a/src/parse_tree.h b/src/parse_tree.h index 187c54b0b..dae6c8cd1 100644 --- a/src/parse_tree.h +++ b/src/parse_tree.h @@ -60,17 +60,12 @@ class ast_t; } /// A type wrapping up a parse tree and the original source behind it. -struct parsed_source_t { +struct parsed_source_t : noncopyable_t, nonmovable_t { wcstring src; ast::ast_t ast; parsed_source_t(wcstring &&s, ast::ast_t &&ast); ~parsed_source_t(); - - parsed_source_t(const parsed_source_t &) = delete; - void operator=(const parsed_source_t &) = delete; - parsed_source_t(parsed_source_t &&) = delete; - parsed_source_t &operator=(parsed_source_t &&) = delete; }; /// Return a shared pointer to parsed_source_t, or null on failure. diff --git a/src/postfork.h b/src/postfork.h index 2a72dcc29..785cb54ba 100644 --- a/src/postfork.h +++ b/src/postfork.h @@ -55,7 +55,7 @@ void safe_report_exec_error(int err, const char *actual_cmd, const char *const * #if FISH_USE_POSIX_SPAWN /// A RAII type which wraps up posix_spawn's data structures. -class posix_spawner_t { +class posix_spawner_t : noncopyable_t, nonmovable_t { public: /// Attempt to construct from a job and dup2 list. /// The caller must check the error function, as this may fail. @@ -71,11 +71,6 @@ class posix_spawner_t { ~posix_spawner_t(); - posix_spawner_t(const posix_spawner_t &) = delete; - void operator=(const posix_spawner_t &) = delete; - void operator=(posix_spawner_t &&) = delete; - posix_spawner_t(posix_spawner_t &&) = delete; - private: bool check_fail(int err); posix_spawnattr_t *attr() { return &*attr_; } diff --git a/src/proc.h b/src/proc.h index 44367f777..cfd6bcc95 100644 --- a/src/proc.h +++ b/src/proc.h @@ -198,7 +198,7 @@ enum { INVALID_PID = -2 }; /// If the process is of type process_type_t::function, argv is the argument vector, and argv[0] is /// the name of the shellscript function. class parser_t; -class process_t { +class process_t : noncopyable_t { public: process_t(); @@ -283,10 +283,6 @@ class process_t { /// Number of jiffies spent in process at last cpu time check. unsigned long last_jiffies{0}; - // No copying. - process_t(const process_t &rhs) = delete; - void operator=(const process_t &rhs) = delete; - private: wcstring_list_t argv_; redirection_spec_list_t proc_redirection_specs_; @@ -299,7 +295,7 @@ using process_ptr_t = std::unique_ptr; using process_list_t = std::vector; /// A struct representing a job. A job is a pipeline of one or more processes. -class job_t { +class job_t : noncopyable_t { public: /// A set of jobs properties. These are immutable: they do not change for the lifetime of the /// job. @@ -331,10 +327,6 @@ class job_t { /// messages about job status on the terminal. const wcstring command_str; - // No copying. - job_t(const job_t &rhs) = delete; - void operator=(const job_t &) = delete; - public: job_t(const properties_t &props, wcstring command_str); ~job_t(); diff --git a/src/redirection.h b/src/redirection.h index b5c1ba10d..fe1f9bb66 100644 --- a/src/redirection.h +++ b/src/redirection.h @@ -49,7 +49,7 @@ struct redirection_spec_t { using redirection_spec_list_t = std::vector; /// A class representing a sequence of basic redirections. -class dup2_list_t { +class dup2_list_t : noncopyable_t { public: /// A type that represents the action dup2(src, target). /// If target is negative, this represents close(src). @@ -59,6 +59,24 @@ class dup2_list_t { int target; }; + dup2_list_t() = default; + dup2_list_t(dup2_list_t &&) = default; + dup2_list_t &operator=(dup2_list_t &&) = default; + ~dup2_list_t(); + + /// \return the list of dup2 actions. + const std::vector &get_actions() const { return actions_; } + + /// Produce a dup_fd_list_t from an io_chain. This may not be called before fork(). + /// The result contains the list of fd actions (dup2 and close), as well as the list + /// of fds opened. + static dup2_list_t resolve_chain(const io_chain_t &); + + /// \return the fd ultimately dup'd to a target fd, or -1 if the target is closed. + /// For example, if target fd is 1, and we have a dup2 chain 5->3 and 3->1, then we will + /// return 5. If the target is not referenced in the chain, returns target. + int fd_for_target_fd(int target) const; + private: /// The list of actions. std::vector actions_; @@ -76,31 +94,6 @@ class dup2_list_t { assert(fd >= 0 && "Invalid fd in add_close"); actions_.push_back(action_t{fd, -1}); } - - dup2_list_t() = default; - - public: - ~dup2_list_t(); - - /// Disable copying. - dup2_list_t(const dup2_list_t &) = delete; - void operator=(const dup2_list_t &) = delete; - - dup2_list_t(dup2_list_t &&) = default; - dup2_list_t &operator=(dup2_list_t &&) = default; - - /// \return the list of dup2 actions. - const std::vector &get_actions() const { return actions_; } - - /// Produce a dup_fd_list_t from an io_chain. This may not be called before fork(). - /// The result contains the list of fd actions (dup2 and close), as well as the list - /// of fds opened. - static dup2_list_t resolve_chain(const io_chain_t &); - - /// \return the fd ultimately dup'd to a target fd, or -1 if the target is closed. - /// For example, if target fd is 1, and we have a dup2 chain 5->3 and 3->1, then we will - /// return 5. If the target is not referenced in the chain, returns target. - int fd_for_target_fd(int target) const; }; #endif diff --git a/src/screen.h b/src/screen.h index a3b214be5..e7cf672ed 100644 --- a/src/screen.h +++ b/src/screen.h @@ -219,7 +219,7 @@ struct prompt_layout_t { }; // Maintain a mapping of escape sequences to their widths for fast lookup. -class layout_cache_t { +class layout_cache_t : noncopyable_t { private: // Cached escape sequences we've already detected in the prompt and similar strings, ordered // lexicographically. @@ -283,9 +283,6 @@ class layout_cache_t { static layout_cache_t shared; layout_cache_t() = default; - layout_cache_t(const layout_cache_t &) = delete; - void operator=(const layout_cache_t &) = delete; - private: // Add a cache entry. void add_prompt_layout(prompt_cache_entry_t entry); diff --git a/src/tokenizer.h b/src/tokenizer.h index 3b6b3717f..efe614eb3 100644 --- a/src/tokenizer.h +++ b/src/tokenizer.h @@ -87,11 +87,7 @@ struct tok_t { }; /// The tokenizer struct. -class tokenizer_t { - // No copying, etc. - tokenizer_t(const tokenizer_t &) = delete; - void operator=(const tokenizer_t &) = delete; - +class tokenizer_t : noncopyable_t { /// A pointer into the original string, showing where the next token begins. const wchar_t *token_cursor; /// The start of the original string. diff --git a/src/topic_monitor.h b/src/topic_monitor.h index 2f1be0900..cacb8564f 100644 --- a/src/topic_monitor.h +++ b/src/topic_monitor.h @@ -171,7 +171,7 @@ class binary_semaphore_t { /// up. If if failed, then either a post() call updated the status values (so perhaps there is a /// new topic post) or some other thread won the race and called wait() on the semaphore. Here our /// thread will wait on the data_notifier_ queue. -class topic_monitor_t { +class topic_monitor_t : noncopyable_t, nonmovable_t { private: using topic_bitmask_t = uint8_t; @@ -236,12 +236,6 @@ class topic_monitor_t { topic_monitor_t(); ~topic_monitor_t(); - /// topic_monitors should not be copied, and there should be no reason to move one. - void operator=(const topic_monitor_t &) = delete; - topic_monitor_t(const topic_monitor_t &) = delete; - void operator=(topic_monitor_t &&) = delete; - topic_monitor_t(topic_monitor_t &&) = delete; - /// The principal topic_monitor. This may be fetched from a signal handler. static topic_monitor_t &principal(); diff --git a/src/wait_handle.h b/src/wait_handle.h index f36b890f2..ffc480fc9 100644 --- a/src/wait_handle.h +++ b/src/wait_handle.h @@ -41,7 +41,7 @@ using wait_handle_ref_t = std::shared_ptr; /// Support for storing a list of wait handles, with a max limit set at initialization. /// Note this class is not safe for concurrent access. -class wait_handle_store_t { +class wait_handle_store_t : noncopyable_t { public: // Our wait handles are arranged in a linked list for its iterator invalidation semantics: we // may remove one without needing to update the map from pid -> handle. @@ -72,10 +72,6 @@ class wait_handle_store_t { /// Convenience to return the size, for testing. size_t size() const { return handles_.size(); } - /// No copying allowed. - wait_handle_store_t(const wait_handle_store_t &) = delete; - void operator=(const wait_handle_store_t &) = delete; - private: using list_node_t = typename wait_handle_list_t::iterator;