aboutsummaryrefslogtreecommitdiff
path: root/libbuild2/variable.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'libbuild2/variable.ixx')
-rw-r--r--libbuild2/variable.ixx812
1 files changed, 812 insertions, 0 deletions
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 <type_traits> // is_same
+
+#include <libbuild2/export.hxx>
+
+namespace build2
+{
+ // value
+ //
+ inline bool value::
+ empty () const
+ {
+ assert (!null);
+ return type == nullptr
+ ? as<names> ().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<names> ns)
+ : type (nullptr), null (!ns), extra (0)
+ {
+ if (!null)
+ new (&data_) names (move (*ns));
+ }
+
+ template <typename T>
+ inline value::
+ value (T v)
+ : type (&value_traits<T>::value_type), null (true), extra (0)
+ {
+ value_traits<T>::assign (*this, move (v));
+ null = false;
+ }
+
+ template <typename T>
+ inline value::
+ value (optional<T> v)
+ : type (&value_traits<T>::value_type), null (true), extra (0)
+ {
+ if (v)
+ {
+ value_traits<T>::assign (*this, move (*v));
+ null = false;
+ }
+ }
+
+ inline value& value::
+ operator= (reference_wrapper<value> v)
+ {
+ return *this = v.get ();
+ }
+
+ inline value& value::
+ operator= (reference_wrapper<const value> v)
+ {
+ return *this = v.get ();
+ }
+
+ template <typename T>
+ inline value& value::
+ operator= (T v)
+ {
+ assert (type == &value_traits<T>::value_type || type == nullptr);
+
+ // Prepare the receiving value.
+ //
+ if (type == nullptr)
+ {
+ *this = nullptr;
+ type = &value_traits<T>::value_type;
+ }
+
+ value_traits<T>::assign (*this, move (v));
+ null = false;
+ return *this;
+ }
+
+ template <typename T>
+ inline value& value::
+ operator+= (T v)
+ {
+ assert (type == &value_traits<T>::value_type || (type == nullptr && null));
+
+ // Prepare the receiving value.
+ //
+ if (type == nullptr)
+ type = &value_traits<T>::value_type;
+
+ value_traits<T>::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<names> ();
+ }
+
+ template <>
+ inline names&
+ cast (value& v)
+ {
+ assert (v && v.type == nullptr);
+ return v.as<names> ();
+ }
+
+ template <typename T>
+ 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<T>::value_type;
+ b = b->base_type) ;
+ assert (b != nullptr);
+
+ return *static_cast<const T*> (v.type->cast == nullptr
+ ? static_cast<const void*> (&v.data_)
+ : v.type->cast (v, b));
+ }
+
+ template <typename T>
+ inline T&
+ cast (value& v)
+ {
+ // Forward to const T&.
+ //
+ return const_cast<T&> (cast<T> (static_cast <const value&> (v)));
+ }
+
+ template <typename T>
+ inline T&&
+ cast (value&& v)
+ {
+ return move (cast<T> (v)); // Forward to T&.
+ }
+
+ template <typename T>
+ inline const T&
+ cast (const lookup& l)
+ {
+ return cast<T> (*l);
+ }
+
+ template <typename T>
+ inline T*
+ cast_null (value& v)
+ {
+ return v ? &cast<T> (v) : nullptr;
+ }
+
+ template <typename T>
+ inline const T*
+ cast_null (const value& v)
+ {
+ return v ? &cast<T> (v) : nullptr;
+ }
+
+ template <typename T>
+ inline const T*
+ cast_null (const lookup& l)
+ {
+ return l ? &cast<T> (*l) : nullptr;
+ }
+
+ template <typename T>
+ inline const T&
+ cast_empty (const value& v)
+ {
+ return v ? cast<T> (v) : value_traits<T>::empty_instance;
+ }
+
+ template <typename T>
+ inline const T&
+ cast_empty (const lookup& l)
+ {
+ return l ? cast<T> (l) : value_traits<T>::empty_instance;
+ }
+
+ template <typename T>
+ inline T
+ cast_default (const value& v, const T& d)
+ {
+ return v ? cast<T> (v) : d;
+ }
+
+ template <typename T>
+ inline T
+ cast_default (const lookup& l, const T& d)
+ {
+ return l ? cast<T> (l) : d;
+ }
+
+ template <typename T>
+ inline T
+ cast_false (const value& v)
+ {
+ return v && cast<T> (v);
+ }
+
+ template <typename T>
+ inline T
+ cast_false (const lookup& l)
+ {
+ return l && cast<T> (l);
+ }
+
+ template <typename T>
+ inline T
+ cast_true (const value& v)
+ {
+ return !v || cast<T> (v);
+ }
+
+ template <typename T>
+ inline T
+ cast_true (const lookup& l)
+ {
+ return !l || cast<T> (l);
+ }
+
+ template <typename T>
+ inline void
+ typify (value& v, const variable* var)
+ {
+ const value_type& t (value_traits<T>::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<const name>
+ reverse (const value& v, names& storage)
+ {
+ assert (v &&
+ storage.empty () &&
+ (v.type == nullptr || v.type->reverse != nullptr));
+ return v.type == nullptr ? v.as<names> () : v.type->reverse (v, storage);
+ }
+
+ inline vector_view<name>
+ reverse (value& v, names& storage)
+ {
+ names_view cv (reverse (static_cast<const value&> (v), storage));
+ return vector_view<name> (const_cast<name*> (cv.data ()), cv.size ());
+ }
+
+ // value_traits
+ //
+ template <typename T>
+ inline T
+ convert (name&& n)
+ {
+ return value_traits<T>::convert (move (n), nullptr);
+ }
+
+ template <typename T>
+ inline T
+ convert (name&& l, name&& r)
+ {
+ return value_traits<T>::convert (move (l), &r);
+ }
+
+ // This one will be SFINAE'd out unless T is a container.
+ //
+ template <typename T>
+ inline auto
+ convert (names&& ns) -> decltype (value_traits<T>::convert (move (ns)))
+ {
+ return value_traits<T>::convert (move (ns));
+ }
+
+ // bool value
+ //
+ inline void value_traits<bool>::
+ assign (value& v, bool x)
+ {
+ if (v)
+ v.as<bool> () = x;
+ else
+ new (&v.data_) bool (x);
+ }
+
+ inline void value_traits<bool>::
+ append (value& v, bool x)
+ {
+ // Logical OR.
+ //
+ if (v)
+ v.as<bool> () = v.as<bool> () || x;
+ else
+ new (&v.data_) bool (x);
+ }
+
+ inline int value_traits<bool>::
+ compare (bool l, bool r)
+ {
+ return l < r ? -1 : (l > r ? 1 : 0);
+ }
+
+ // uint64_t value
+ //
+ inline void value_traits<uint64_t>::
+ assign (value& v, uint64_t x)
+ {
+ if (v)
+ v.as<uint64_t> () = x;
+ else
+ new (&v.data_) uint64_t (x);
+ }
+
+ inline void value_traits<uint64_t>::
+ append (value& v, uint64_t x)
+ {
+ // ADD.
+ //
+ if (v)
+ v.as<uint64_t> () += x;
+ else
+ new (&v.data_) uint64_t (x);
+ }
+
+ inline int value_traits<uint64_t>::
+ compare (uint64_t l, uint64_t r)
+ {
+ return l < r ? -1 : (l > r ? 1 : 0);
+ }
+
+ // string value
+ //
+ inline void value_traits<string>::
+ assign (value& v, string&& x)
+ {
+ if (v)
+ v.as<string> () = move (x);
+ else
+ new (&v.data_) string (move (x));
+ }
+
+ inline void value_traits<string>::
+ append (value& v, string&& x)
+ {
+ if (v)
+ {
+ string& s (v.as<string> ());
+
+ if (s.empty ())
+ s.swap (x);
+ else
+ s += x;
+ }
+ else
+ new (&v.data_) string (move (x));
+ }
+
+ inline void value_traits<string>::
+ prepend (value& v, string&& x)
+ {
+ if (v)
+ {
+ string& s (v.as<string> ());
+
+ if (!s.empty ())
+ x += s;
+
+ s.swap (x);
+ }
+ else
+ new (&v.data_) string (move (x));
+ }
+
+ inline int value_traits<string>::
+ compare (const string& l, const string& r)
+ {
+ return l.compare (r);
+ }
+
+ // path value
+ //
+ inline void value_traits<path>::
+ assign (value& v, path&& x)
+ {
+ if (v)
+ v.as<path> () = move (x);
+ else
+ new (&v.data_) path (move (x));
+ }
+
+ inline void value_traits<path>::
+ append (value& v, path&& x)
+ {
+ if (v)
+ {
+ path& p (v.as<path> ());
+
+ if (p.empty ())
+ p.swap (x);
+ else
+ p /= x;
+ }
+ else
+ new (&v.data_) path (move (x));
+ }
+
+ inline void value_traits<path>::
+ prepend (value& v, path&& x)
+ {
+ if (v)
+ {
+ path& p (v.as<path> ());
+
+ if (!p.empty ())
+ x /= p;
+
+ p.swap (x);
+ }
+ else
+ new (&v.data_) path (move (x));
+ }
+
+ inline int value_traits<path>::
+ compare (const path& l, const path& r)
+ {
+ return l.compare (r);
+ }
+
+ // dir_path value
+ //
+ inline void value_traits<dir_path>::
+ assign (value& v, dir_path&& x)
+ {
+ if (v)
+ v.as<dir_path> () = move (x);
+ else
+ new (&v.data_) dir_path (move (x));
+ }
+
+ inline void value_traits<dir_path>::
+ append (value& v, dir_path&& x)
+ {
+ if (v)
+ {
+ dir_path& p (v.as<dir_path> ());
+
+ if (p.empty ())
+ p.swap (x);
+ else
+ p /= x;
+ }
+ else
+ new (&v.data_) dir_path (move (x));
+ }
+
+ inline void value_traits<dir_path>::
+ prepend (value& v, dir_path&& x)
+ {
+ if (v)
+ {
+ dir_path& p (v.as<dir_path> ());
+
+ if (!p.empty ())
+ x /= p;
+
+ p.swap (x);
+ }
+ else
+ new (&v.data_) dir_path (move (x));
+ }
+
+ inline int value_traits<dir_path>::
+ compare (const dir_path& l, const dir_path& r)
+ {
+ return l.compare (r);
+ }
+
+ // abs_dir_path value
+ //
+ inline void value_traits<abs_dir_path>::
+ assign (value& v, abs_dir_path&& x)
+ {
+ if (v)
+ v.as<abs_dir_path> () = move (x);
+ else
+ new (&v.data_) abs_dir_path (move (x));
+ }
+
+ inline void value_traits<abs_dir_path>::
+ append (value& v, abs_dir_path&& x)
+ {
+ if (v)
+ {
+ abs_dir_path& p (v.as<abs_dir_path> ());
+
+ if (p.empty ())
+ p.swap (x);
+ else
+ p /= x;
+ }
+ else
+ new (&v.data_) abs_dir_path (move (x));
+ }
+
+ inline int value_traits<abs_dir_path>::
+ compare (const abs_dir_path& l, const abs_dir_path& r)
+ {
+ return l.compare (static_cast<const dir_path&> (r));
+ }
+
+ // name value
+ //
+ inline void value_traits<name>::
+ assign (value& v, name&& x)
+ {
+ if (v)
+ v.as<name> () = move (x);
+ else
+ new (&v.data_) name (move (x));
+ }
+
+ // name_pair value
+ //
+ inline void value_traits<name_pair>::
+ assign (value& v, name_pair&& x)
+ {
+ if (v)
+ v.as<name_pair> () = move (x);
+ else
+ new (&v.data_) name_pair (move (x));
+ }
+
+ inline int value_traits<name_pair>::
+ 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<process_path>::
+ 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<process_path> () = move (x);
+ else
+ new (&v.data_) process_path (move (x));
+ }
+
+ inline int value_traits<process_path>::
+ 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<target_triplet>::
+ assign (value& v, target_triplet&& x)
+ {
+ if (v)
+ v.as<target_triplet> () = move (x);
+ else
+ new (&v.data_) target_triplet (move (x));
+ }
+
+ // project_name value
+ //
+ inline void value_traits<project_name>::
+ assign (value& v, project_name&& x)
+ {
+ if (v)
+ v.as<project_name> () = move (x);
+ else
+ new (&v.data_) project_name (move (x));
+ }
+
+ inline name value_traits<project_name>::
+ 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<T> value
+ //
+ template <typename T>
+ inline void value_traits<vector<T>>::
+ assign (value& v, vector<T>&& x)
+ {
+ if (v)
+ v.as<vector<T>> () = move (x);
+ else
+ new (&v.data_) vector<T> (move (x));
+ }
+
+ template <typename T>
+ inline void value_traits<vector<T>>::
+ append (value& v, vector<T>&& x)
+ {
+ if (v)
+ {
+ vector<T>& p (v.as<vector<T>> ());
+
+ 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<T> (move (x));
+ }
+
+ template <typename T>
+ inline void value_traits<vector<T>>::
+ prepend (value& v, vector<T>&& x)
+ {
+ if (v)
+ {
+ vector<T>& p (v.as<vector<T>> ());
+
+ 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<T> (move (x));
+ }
+
+ // map<K, V> value
+ //
+ template <typename K, typename V>
+ inline void value_traits<std::map<K, V>>::
+ assign (value& v, map<K, V>&& x)
+ {
+ if (v)
+ v.as<map<K, V>> () = move (x);
+ else
+ new (&v.data_) map<K, V> (move (x));
+ }
+
+ template <typename K, typename V>
+ inline void value_traits<std::map<K, V>>::
+ append (value& v, map<K, V>&& x)
+ {
+ if (v)
+ {
+ map<K, V>& m (v.as<map<K, V>> ());
+
+ 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<K, V> (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<value_data&> (v), *var.type, &var);
+ }
+ else
+ {
+ if (v.type.load (memory_order_acquire) != var.type)
+ build2::typify_atomic (const_cast<value_data&> (v), *var.type, &var);
+ }
+ }
+
+ // variable_map::iterator_adapter
+ //
+ template <typename I>
+ inline typename I::reference variable_map::iterator_adapter<I>::
+ 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 <typename I>
+ inline typename I::pointer variable_map::iterator_adapter<I>::
+ 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;
+ }
+}