// file : build2/variable.ixx -*- C++ -*- // copyright : Copyright (c) 2014-2016 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file #include // is_same 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)); } template inline value:: value (T v) : type (&value_traits::value_type), null (true), extra (0) { 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. // const value_type* b (v.type); for (; b != nullptr && b != &value_traits::value_type; b = b->base) ; 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 T cast_false (const value& v) {return v && cast (v);} template inline T cast_false (const lookup& l) {return l && cast (l);} template inline void typify (value& v, const variable& var) { value_type& t (value_traits::value_type); if (v.type != &t) typify (v, t, &var); } 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)); } inline int value_traits:: compare (const name& l, const name& r) { return l.compare (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; } // 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 (m.end (), make_move_iterator (x.begin ()), make_move_iterator (x.end ())); } else new (&v.data_) map (move (x)); } // variable_pool // inline const variable* variable_pool:: find (const string& n) { auto i (map_.find (&n)); return i != map_.end () ? &i->second : nullptr; } inline const variable& variable_pool:: insert (string n) { // We are not overriding anything so skip the custom insert() checks. // auto p ( insert ( variable {move (n), nullptr, nullptr, variable_visibility::normal})); return p.first->second; } inline const variable& variable_pool:: operator[] (const string& n) { if (const variable* v = find (n)) return *v; else return insert (n); } // variable_map::iterator_adapter // template inline typename I::reference variable_map::iterator_adapter:: operator* () const { auto& r (I::operator* ()); const variable& var (r.first); auto& val (r.second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) typify (const_cast (val), *var.type, &var); return r; } template inline typename I::pointer variable_map::iterator_adapter:: operator-> () const { auto p (I::operator-> ()); const variable& var (p->first); auto& val (p->second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) typify (const_cast (val), *var.type, &var); return p; } }