From 977d07a3ae47ef204665d1eda2d642e5064724f3 Mon Sep 17 00:00:00 2001 From: Boris Kolpackov Date: Mon, 24 Jun 2019 12:01:19 +0200 Subject: Split build system into library and driver --- libbuild2/variable.ixx | 812 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 812 insertions(+) create mode 100644 libbuild2/variable.ixx (limited to 'libbuild2/variable.ixx') diff --git a/libbuild2/variable.ixx b/libbuild2/variable.ixx new file mode 100644 index 0000000..f0bde09 --- /dev/null +++ b/libbuild2/variable.ixx @@ -0,0 +1,812 @@ +// file : libbuild2/variable.ixx -*- C++ -*- +// copyright : Copyright (c) 2014-2019 Code Synthesis Ltd +// license : MIT; see accompanying LICENSE file + +#include // is_same + +#include + +namespace build2 +{ + // value + // + inline bool value:: + empty () const + { + assert (!null); + return type == nullptr + ? as ().empty () + : type->empty == nullptr ? false : type->empty (*this); + } + + inline value:: + value (names ns) + : type (nullptr), null (false), extra (0) + { + new (&data_) names (move (ns)); + } + + inline value:: + value (optional ns) + : type (nullptr), null (!ns), extra (0) + { + if (!null) + new (&data_) names (move (*ns)); + } + + template + inline value:: + value (T v) + : type (&value_traits::value_type), null (true), extra (0) + { + value_traits::assign (*this, move (v)); + null = false; + } + + template + inline value:: + value (optional v) + : type (&value_traits::value_type), null (true), extra (0) + { + if (v) + { + value_traits::assign (*this, move (*v)); + null = false; + } + } + + inline value& value:: + operator= (reference_wrapper v) + { + return *this = v.get (); + } + + inline value& value:: + operator= (reference_wrapper v) + { + return *this = v.get (); + } + + template + inline value& value:: + operator= (T v) + { + assert (type == &value_traits::value_type || type == nullptr); + + // Prepare the receiving value. + // + if (type == nullptr) + { + *this = nullptr; + type = &value_traits::value_type; + } + + value_traits::assign (*this, move (v)); + null = false; + return *this; + } + + template + inline value& value:: + operator+= (T v) + { + assert (type == &value_traits::value_type || (type == nullptr && null)); + + // Prepare the receiving value. + // + if (type == nullptr) + type = &value_traits::value_type; + + value_traits::append (*this, move (v)); + null = false; + return *this; + } + + inline void value:: + assign (name&& n, const variable* var) + { + names ns; + ns.push_back (move (n)); + assign (move (ns), var); + } + + inline bool + operator!= (const value& x, const value& y) + { + return !(x == y); + } + + inline bool + operator<= (const value& x, const value& y) + { + return !(x > y); + } + + inline bool + operator>= (const value& x, const value& y) + { + return !(x < y); + } + + template <> + inline const names& + cast (const value& v) + { + assert (v && v.type == nullptr); + return v.as (); + } + + template <> + inline names& + cast (value& v) + { + assert (v && v.type == nullptr); + return v.as (); + } + + template + inline const T& + cast (const value& v) + { + assert (v); + + // Find base if any. + // + // Note that here we use the value type address as type identity. + // + const value_type* b (v.type); + for (; + b != nullptr && b != &value_traits::value_type; + b = b->base_type) ; + assert (b != nullptr); + + return *static_cast (v.type->cast == nullptr + ? static_cast (&v.data_) + : v.type->cast (v, b)); + } + + template + inline T& + cast (value& v) + { + // Forward to const T&. + // + return const_cast (cast (static_cast (v))); + } + + template + inline T&& + cast (value&& v) + { + return move (cast (v)); // Forward to T&. + } + + template + inline const T& + cast (const lookup& l) + { + return cast (*l); + } + + template + inline T* + cast_null (value& v) + { + return v ? &cast (v) : nullptr; + } + + template + inline const T* + cast_null (const value& v) + { + return v ? &cast (v) : nullptr; + } + + template + inline const T* + cast_null (const lookup& l) + { + return l ? &cast (*l) : nullptr; + } + + template + inline const T& + cast_empty (const value& v) + { + return v ? cast (v) : value_traits::empty_instance; + } + + template + inline const T& + cast_empty (const lookup& l) + { + return l ? cast (l) : value_traits::empty_instance; + } + + template + inline T + cast_default (const value& v, const T& d) + { + return v ? cast (v) : d; + } + + template + inline T + cast_default (const lookup& l, const T& d) + { + return l ? cast (l) : d; + } + + template + inline T + cast_false (const value& v) + { + return v && cast (v); + } + + template + inline T + cast_false (const lookup& l) + { + return l && cast (l); + } + + template + inline T + cast_true (const value& v) + { + return !v || cast (v); + } + + template + inline T + cast_true (const lookup& l) + { + return !l || cast (l); + } + + template + inline void + typify (value& v, const variable* var) + { + const value_type& t (value_traits::value_type); + + if (v.type != &t) + typify (v, t, var); + } + + LIBBUILD2_SYMEXPORT void + typify (value&, const value_type&, const variable*, memory_order); + + inline void + typify (value& v, const value_type& t, const variable* var) + { + typify (v, t, var, memory_order_relaxed); + } + + inline vector_view + reverse (const value& v, names& storage) + { + assert (v && + storage.empty () && + (v.type == nullptr || v.type->reverse != nullptr)); + return v.type == nullptr ? v.as () : v.type->reverse (v, storage); + } + + inline vector_view + reverse (value& v, names& storage) + { + names_view cv (reverse (static_cast (v), storage)); + return vector_view (const_cast (cv.data ()), cv.size ()); + } + + // value_traits + // + template + inline T + convert (name&& n) + { + return value_traits::convert (move (n), nullptr); + } + + template + inline T + convert (name&& l, name&& r) + { + return value_traits::convert (move (l), &r); + } + + // This one will be SFINAE'd out unless T is a container. + // + template + inline auto + convert (names&& ns) -> decltype (value_traits::convert (move (ns))) + { + return value_traits::convert (move (ns)); + } + + // bool value + // + inline void value_traits:: + assign (value& v, bool x) + { + if (v) + v.as () = x; + else + new (&v.data_) bool (x); + } + + inline void value_traits:: + append (value& v, bool x) + { + // Logical OR. + // + if (v) + v.as () = v.as () || x; + else + new (&v.data_) bool (x); + } + + inline int value_traits:: + compare (bool l, bool r) + { + return l < r ? -1 : (l > r ? 1 : 0); + } + + // uint64_t value + // + inline void value_traits:: + assign (value& v, uint64_t x) + { + if (v) + v.as () = x; + else + new (&v.data_) uint64_t (x); + } + + inline void value_traits:: + append (value& v, uint64_t x) + { + // ADD. + // + if (v) + v.as () += x; + else + new (&v.data_) uint64_t (x); + } + + inline int value_traits:: + compare (uint64_t l, uint64_t r) + { + return l < r ? -1 : (l > r ? 1 : 0); + } + + // string value + // + inline void value_traits:: + assign (value& v, string&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) string (move (x)); + } + + inline void value_traits:: + append (value& v, string&& x) + { + if (v) + { + string& s (v.as ()); + + if (s.empty ()) + s.swap (x); + else + s += x; + } + else + new (&v.data_) string (move (x)); + } + + inline void value_traits:: + prepend (value& v, string&& x) + { + if (v) + { + string& s (v.as ()); + + if (!s.empty ()) + x += s; + + s.swap (x); + } + else + new (&v.data_) string (move (x)); + } + + inline int value_traits:: + compare (const string& l, const string& r) + { + return l.compare (r); + } + + // path value + // + inline void value_traits:: + assign (value& v, path&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) path (move (x)); + } + + inline void value_traits:: + append (value& v, path&& x) + { + if (v) + { + path& p (v.as ()); + + if (p.empty ()) + p.swap (x); + else + p /= x; + } + else + new (&v.data_) path (move (x)); + } + + inline void value_traits:: + prepend (value& v, path&& x) + { + if (v) + { + path& p (v.as ()); + + if (!p.empty ()) + x /= p; + + p.swap (x); + } + else + new (&v.data_) path (move (x)); + } + + inline int value_traits:: + compare (const path& l, const path& r) + { + return l.compare (r); + } + + // dir_path value + // + inline void value_traits:: + assign (value& v, dir_path&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) dir_path (move (x)); + } + + inline void value_traits:: + append (value& v, dir_path&& x) + { + if (v) + { + dir_path& p (v.as ()); + + if (p.empty ()) + p.swap (x); + else + p /= x; + } + else + new (&v.data_) dir_path (move (x)); + } + + inline void value_traits:: + prepend (value& v, dir_path&& x) + { + if (v) + { + dir_path& p (v.as ()); + + if (!p.empty ()) + x /= p; + + p.swap (x); + } + else + new (&v.data_) dir_path (move (x)); + } + + inline int value_traits:: + compare (const dir_path& l, const dir_path& r) + { + return l.compare (r); + } + + // abs_dir_path value + // + inline void value_traits:: + assign (value& v, abs_dir_path&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) abs_dir_path (move (x)); + } + + inline void value_traits:: + append (value& v, abs_dir_path&& x) + { + if (v) + { + abs_dir_path& p (v.as ()); + + if (p.empty ()) + p.swap (x); + else + p /= x; + } + else + new (&v.data_) abs_dir_path (move (x)); + } + + inline int value_traits:: + compare (const abs_dir_path& l, const abs_dir_path& r) + { + return l.compare (static_cast (r)); + } + + // name value + // + inline void value_traits:: + assign (value& v, name&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) name (move (x)); + } + + // name_pair value + // + inline void value_traits:: + assign (value& v, name_pair&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) name_pair (move (x)); + } + + inline int value_traits:: + compare (const name_pair& x, const name_pair& y) + { + int r (x.first.compare (y.first)); + + if (r == 0) + r = x.second.compare (y.second); + + return r; + } + + // process_path value + // + inline void value_traits:: + assign (value& v, process_path&& x) + { + // Convert the value to its "self-sufficient" form. + // + if (x.recall.empty ()) + x.recall = path (x.initial); + + x.initial = x.recall.string ().c_str (); + + if (v) + v.as () = move (x); + else + new (&v.data_) process_path (move (x)); + } + + inline int value_traits:: + compare (const process_path& x, const process_path& y) + { + int r (x.recall.compare (y.recall)); + + if (r == 0) + r = x.effect.compare (y.effect); + + return r; + } + + // target_triplet value + // + inline void value_traits:: + assign (value& v, target_triplet&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) target_triplet (move (x)); + } + + // project_name value + // + inline void value_traits:: + assign (value& v, project_name&& x) + { + if (v) + v.as () = move (x); + else + new (&v.data_) project_name (move (x)); + } + + inline name value_traits:: + reverse (const project_name& x) + { + // Make work for the special unnamed subproject representation (see + // find_subprojects() in file.cxx for details). + // + const string& s (x.string ()); + return name (s.empty () || path::traits_type::is_separator (s.back ()) + ? empty_string + : s); + } + + // vector value + // + template + inline void value_traits>:: + assign (value& v, vector&& x) + { + if (v) + v.as> () = move (x); + else + new (&v.data_) vector (move (x)); + } + + template + inline void value_traits>:: + append (value& v, vector&& x) + { + if (v) + { + vector& p (v.as> ()); + + if (p.empty ()) + p.swap (x); + else + p.insert (p.end (), + make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); + } + else + new (&v.data_) vector (move (x)); + } + + template + inline void value_traits>:: + prepend (value& v, vector&& x) + { + if (v) + { + vector& p (v.as> ()); + + if (!p.empty ()) + x.insert (x.end (), + make_move_iterator (p.begin ()), + make_move_iterator (p.end ())); + + p.swap (x); + } + else + new (&v.data_) vector (move (x)); + } + + // map value + // + template + inline void value_traits>:: + assign (value& v, map&& x) + { + if (v) + v.as> () = move (x); + else + new (&v.data_) map (move (x)); + } + + template + inline void value_traits>:: + append (value& v, map&& x) + { + if (v) + { + map& m (v.as> ()); + + if (m.empty ()) + m.swap (x); + else + // Note that this will only move values. Keys (being const) are still + // copied. + // + m.insert (make_move_iterator (x.begin ()), + make_move_iterator (x.end ())); + } + else + new (&v.data_) map (move (x)); + } + + // variable_pool + // + inline const variable& variable_pool:: + operator[] (const string& n) const + { + const variable* r (find (n)); + assert (r != nullptr); + return *r; + } + + inline const variable* variable_pool:: + find (const string& n) const + { + auto i (map_.find (&n)); + return i != map_.end () ? &i->second : nullptr; + } + + // variable_map + // + inline void variable_map:: + typify (const value_data& v, const variable& var) const + { + // We assume typification is not modification so no version increment. + // + if (phase == run_phase::load) + { + if (v.type != var.type) + build2::typify (const_cast (v), *var.type, &var); + } + else + { + if (v.type.load (memory_order_acquire) != var.type) + build2::typify_atomic (const_cast (v), *var.type, &var); + } + } + + // variable_map::iterator_adapter + // + template + inline typename I::reference variable_map::iterator_adapter:: + operator* () const + { + auto& r (I::operator* ()); + const variable& var (r.first); + const value_data& val (r.second); + + // Check if this is the first access after being assigned a type. + // + if (var.type != nullptr) + m_->typify (val, var); + + return r; + } + + template + inline typename I::pointer variable_map::iterator_adapter:: + operator-> () const + { + auto p (I::operator-> ()); + const variable& var (p->first); + const value_data& val (p->second); + + // Check if this is the first access after being assigned a type. + // + if (var.type != nullptr) + m_->typify (val, var); + + return p; + } +} -- cgit v1.1