diff options
Diffstat (limited to 'libbuild2/types.hxx')
-rw-r--r-- | libbuild2/types.hxx | 246 |
1 files changed, 175 insertions, 71 deletions
diff --git a/libbuild2/types.hxx b/libbuild2/types.hxx index 60101b3..ea84701 100644 --- a/libbuild2/types.hxx +++ b/libbuild2/types.hxx @@ -13,8 +13,12 @@ # include <libbuild2/config.hxx> #endif +#include <map> +#include <set> +#include <list> #include <array> #include <tuple> +#include <regex> #include <vector> #include <string> #include <memory> // unique_ptr, shared_ptr @@ -26,14 +30,22 @@ #include <functional> // hash, function, reference_wrapper #include <initializer_list> -#include <mutex> #include <atomic> -#include <thread> -#include <condition_variable> -#include <libbutl/ft/shared_mutex.hxx> -#if defined(__cpp_lib_shared_mutex) || defined(__cpp_lib_shared_timed_mutex) -# include <shared_mutex> +#ifndef LIBBUTL_MINGW_STDTHREAD +# include <mutex> +# include <thread> +# include <condition_variable> + +# include <libbutl/ft/shared_mutex.hxx> +# if defined(__cpp_lib_shared_mutex) || defined(__cpp_lib_shared_timed_mutex) +# include <shared_mutex> +# endif +#else +# include <libbutl/mingw-mutex.hxx> +# include <libbutl/mingw-thread.hxx> +# include <libbutl/mingw-condition_variable.hxx> +# include <libbutl/mingw-shared_mutex.hxx> #endif #include <ios> // ios_base::failure @@ -41,20 +53,22 @@ #include <stdexcept> // logic_error, invalid_argument, runtime_error #include <system_error> -#include <libbutl/path.mxx> -#include <libbutl/path-map.mxx> -#include <libbutl/sha256.mxx> -#include <libbutl/process.mxx> -#include <libbutl/fdstream.mxx> -#include <libbutl/optional.mxx> -#include <libbutl/const-ptr.mxx> -#include <libbutl/timestamp.mxx> -#include <libbutl/vector-view.mxx> -#include <libbutl/small-vector.mxx> -#include <libbutl/project-name.mxx> -#include <libbutl/target-triplet.mxx> -#include <libbutl/semantic-version.mxx> -#include <libbutl/standard-version.mxx> +#include <libbutl/path.hxx> +#include <libbutl/path-map.hxx> +#include <libbutl/regex.hxx> +#include <libbutl/sha256.hxx> +#include <libbutl/process.hxx> +#include <libbutl/fdstream.hxx> +#include <libbutl/optional.hxx> +#include <libbutl/const-ptr.hxx> +#include <libbutl/timestamp.hxx> +#include <libbutl/vector-view.hxx> +#include <libbutl/small-vector.hxx> +#include <libbutl/project-name.hxx> +#include <libbutl/target-triplet.hxx> +#include <libbutl/semantic-version.hxx> +#include <libbutl/standard-version.hxx> +#include <libbutl/move-only-function.hxx> #include <libbuild2/export.hxx> @@ -78,9 +92,12 @@ namespace build2 using std::pair; using std::tuple; using std::string; - using std::function; using std::reference_wrapper; + using std::function; + using butl::move_only_function; + using butl::move_only_function_ex; + using strings = std::vector<string>; using cstrings = std::vector<const char*>; @@ -92,16 +109,30 @@ namespace build2 using std::shared_ptr; using std::weak_ptr; + using std::map; + using std::multimap; + using std::set; + using std::multiset; using std::array; using std::vector; - using butl::vector_view; // <libbutl/vector-view.mxx> - using butl::small_vector; // <libbutl/small-vector.mxx> + using std::list; + using butl::vector_view; // <libbutl/vector-view.hxx> + using butl::small_vector; // <libbutl/small-vector.hxx> using std::istream; using std::ostream; using std::endl; using std::streamsize; // C++'s ssize_t. + // Regex. + // + // Note that <libbutl/regex.hxx> includes an ostream insertion operator for + // regex_error which prints cleaned up message, if any. + // + using std::regex; + using std::regex_error; + using regex_match_results = std::match_results<string::const_iterator>; + // Concurrency. // using std::atomic; @@ -168,20 +199,27 @@ namespace build2 } #endif +#ifndef LIBBUTL_MINGW_STDTHREAD using std::mutex; using mlock = std::unique_lock<mutex>; using std::condition_variable; -#if defined(__cpp_lib_shared_mutex) + using std::defer_lock; + using std::adopt_lock; + + using std::thread; + namespace this_thread = std::this_thread; + +# if defined(__cpp_lib_shared_mutex) using shared_mutex = std::shared_mutex; using ulock = std::unique_lock<shared_mutex>; using slock = std::shared_lock<shared_mutex>; -#elif defined(__cpp_lib_shared_timed_mutex) +# elif defined(__cpp_lib_shared_timed_mutex) using shared_mutex = std::shared_timed_mutex; using ulock = std::unique_lock<shared_mutex>; using slock = std::shared_lock<shared_mutex>; -#else +# else // Because we have this fallback, we need to be careful not to create // multiple shared locks in the same thread. // @@ -196,13 +234,57 @@ namespace build2 using ulock = std::unique_lock<shared_mutex>; using slock = ulock; -#endif +# endif +#else // LIBBUTL_MINGW_STDTHREAD + using mingw_stdthread::mutex; + using mlock = mingw_stdthread::unique_lock<mutex>; - using std::defer_lock; - using std::adopt_lock; + using mingw_stdthread::condition_variable; - using std::thread; - namespace this_thread = std::this_thread; + using mingw_stdthread::defer_lock; + using mingw_stdthread::adopt_lock; + + using mingw_stdthread::thread; + namespace this_thread = mingw_stdthread::this_thread; + + using shared_mutex = mingw_stdthread::shared_mutex; + using ulock = mingw_stdthread::unique_lock<shared_mutex>; + using slock = mingw_stdthread::shared_lock<shared_mutex>; +#endif + + // Global, MT-safe information cache. Normally used for caching information + // (versions, target triplets, search paths, etc) extracted from other + // programs (compilers, etc). + // + // The key is normally a hash of all the inputs that can affect the output. + // + // Note that insertion is racy and it's possible the cache entry already + // exists, in which case we ignore our value assuming it is the same. + // + template <typename T, typename K = string> + class global_cache + { + public: + const T* + find (const K& k) const + { + mlock l (mutex_); + auto i (cache_.find (k)); + return i != cache_.end () ? &i->second : nullptr; + } + + const T& + insert (K k, T v) + { + mlock l (mutex_); + return cache_.insert (std::make_pair (std::move (k), + std::move (v))).first->second; + } + + private: + map<K, T> cache_; + mutable mutex mutex_; + }; // Exceptions. // @@ -215,17 +297,17 @@ namespace build2 using std::system_error; using io_error = std::ios_base::failure; - // <libbutl/optional.mxx> + // <libbutl/optional.hxx> // using butl::optional; using butl::nullopt; - // <libbutl/const-ptr.mxx> + // <libbutl/const-ptr.hxx> // using butl::const_ptr; - // <libbutl/path.mxx> - // <libbutl/path-map.mxx> + // <libbutl/path.hxx> + // <libbutl/path-map.hxx> // using butl::path; using path_traits = path::traits_type; @@ -241,6 +323,8 @@ namespace build2 using butl::path_map; using butl::dir_path_map; + using butl::path_multimap; + using butl::dir_path_multimap; // Absolute directory path. Note that for now we don't do any checking that // the path is in fact absolute. @@ -264,7 +348,21 @@ namespace build2 using paths = std::vector<path>; using dir_paths = std::vector<dir_path>; - // <libbutl/timestamp.mxx> + // Path printing potentially relative with trailing slash for directories. + // + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const path&); // utility.cxx + + inline ostream& + operator<< (ostream& os, const dir_path& d) // For overload resolution. + { + return build2::operator<< (os, static_cast<const path&> (d)); + } + + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const path_name_view&); // utility.cxx + + // <libbutl/timestamp.hxx> // using butl::system_clock; using butl::timestamp; @@ -276,13 +374,15 @@ namespace build2 using butl::to_string; using butl::operator<<; - // <libbutl/sha256.mxx> + // <libbutl/sha256.hxx> // using butl::sha256; - // <libbutl/process.mxx> + // <libbutl/process.hxx> + // using butl::process; using butl::process_env; + using butl::process_exit; using butl::process_path; using butl::process_error; @@ -290,28 +390,52 @@ namespace build2 // // See also {import,export}.metadata. // + // Note that the environment checksum is calculated in the (potentially + // hermetic) project environment which makes instances of process_path_ex + // project-specific. (We could potentially store the original list of + // environment variables and calculate the checksum on the fly in the + // current context thus making it project-independent. But this will + // complicate things without, currently, much real benefit since all our + // use-cases fit well with the project-specific restriction. We could + // probably even support both variants if desirable.) + // struct process_path_ex: process_path { - optional<string> name; // Stable name for diagnostics. - optional<string> checksum; // Checksum for change tracking. + optional<string> name; // Stable name for diagnostics. + optional<string> checksum; // Executable checksum for change tracking. + optional<string> env_checksum; // Environment checksum for change tracking. using process_path::process_path; - process_path_ex (const process_path& p, string n, optional<string> c = {}) + process_path_ex (const process_path& p, + string n, + optional<string> c = {}, + optional<string> ec = {}) : process_path (p, false /* init */), name (std::move (n)), - checksum (std::move (c)) {} + checksum (std::move (c)), + env_checksum (std::move (ec)) {} - process_path_ex (process_path&& p, string n, optional<string> c = {}) + process_path_ex (process_path&& p, + string n, + optional<string> c = {}, + optional<string> ec = {}) : process_path (std::move (p)), name (std::move (n)), - checksum (std::move (c)) {} + checksum (std::move (c)), + env_checksum (std::move (ec)) {} process_path_ex () = default; }; - // <libbutl/fdstream.mxx> + // Print as recall[@effect]. // + LIBBUILD2_SYMEXPORT ostream& + operator<< (ostream&, const process_path&); // utility.cxx + + // <libbutl/fdstream.hxx> + // + using butl::nullfd; using butl::auto_fd; using butl::fdpipe; using butl::ifdstream; @@ -321,21 +445,21 @@ namespace build2 using butl::fdselect_state; using butl::fdselect_set; - // <libbutl/target-triplet.mxx> + // <libbutl/target-triplet.hxx> // using butl::target_triplet; - // <libbutl/semantic-version.mxx> + // <libbutl/semantic-version.hxx> // using butl::semantic_version; using butl::parse_semantic_version; - // <libbutl/standard-version.mxx> + // <libbutl/standard-version.hxx> // using butl::standard_version; using butl::standard_version_constraint; - // <libbutl/project-name.mxx> + // <libbutl/project-name.hxx> // using butl::project_name; @@ -393,9 +517,9 @@ namespace build2 location_value (const location&); - location_value (location_value&&); + location_value (location_value&&) noexcept; location_value (const location_value&); - location_value& operator= (location_value&&); + location_value& operator= (location_value&&) noexcept; location_value& operator= (const location_value&); }; @@ -407,26 +531,6 @@ namespace build2 operator<< (ostream&, run_phase); // utility.cxx } -// In order to be found (via ADL) these have to be either in std:: or in -// butl::. The latter is a bad idea since libbutl includes the default -// implementation. They are defined in utility.cxx. -// -namespace std -{ - // Path printing potentially relative with trailing slash for directories. - // - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::path&); - - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::path_name_view&); - - // Print as recall[@effect]. - // - LIBBUILD2_SYMEXPORT ostream& - operator<< (ostream&, const ::butl::process_path&); -} - // <libbuild2/name.hxx> // #include <libbuild2/name.hxx> |