// 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 value:: value (names&& ns) : type (nullptr), state (ns.empty () ? value_state::empty : value_state::filled), extra (0) { new (&data_) names (move (ns)); } 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; } state = value_traits::assign (*this, move (v)) ? value_state::filled : value_state::empty; 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; state = value_traits::append (*this, move (v)) ? value_state::filled : value_state::empty; return *this; } inline bool operator!= (const value& x, const value& y) { return !(x == y); } template <> inline const names& cast (const value& v) { // Note that it can still be a typed vector. // assert (!v.null () && (v.type == nullptr || v.type == &value_traits::value_type)); return v.as (); } template <> inline names& cast (value& v) { assert (!v.null () && (v.type == nullptr || v.type == &value_traits::value_type)); return v.as (); } template inline const T& cast (const value& v) { assert (!v.null ()); // 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) { assert (!v.null () && v.type == &value_traits::value_type); return *static_cast (v.type->cast == nullptr ? static_cast (&v.data_) : const_cast (v.type->cast (v, v.type))); } 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 void typify (value& v, const variable& var) { value_type& t (value_traits::value_type); if (v.type != &t) typify (v, t, &var); } inline names_view reverse (const value& v, names& storage) { assert (!v.null () && 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); } // bool value // inline bool value_traits:: assign (value& v, bool x) { if (v.null ()) new (&v.data_) bool (x); else v.as () = x; return true; } inline bool value_traits:: append (value& v, bool x) { // Logical OR. // if (v.null ()) new (&v.data_) bool (x); else v.as () = v.as () || x; return true; } inline int value_traits:: compare (bool l, bool r) { return l < r ? -1 : (l > r ? 1 : 0); } // uint64_t value // inline bool value_traits:: assign (value& v, uint64_t x) { if (v.null ()) new (&v.data_) uint64_t (x); else v.as () = x; return true; } inline bool value_traits:: append (value& v, uint64_t x) { // ADD. // if (v.null ()) new (&v.data_) uint64_t (x); else v.as () += x; return true; } inline int value_traits:: compare (uint64_t l, uint64_t r) { return l < r ? -1 : (l > r ? 1 : 0); } // string value // inline bool value_traits:: assign (value& v, string&& x) { string* p; if (v.null ()) p = new (&v.data_) string (move (x)); else p = &(v.as () = move (x)); return !p->empty (); } inline bool value_traits:: append (value& v, string&& x) { string* p; if (v.null ()) p = new (&v.data_) string (move (x)); else { p = &v.as (); if (p->empty ()) p->swap (x); else *p += x; } return !p->empty (); } inline bool value_traits:: prepend (value& v, string&& x) { string* p; if (v.null ()) new (&v.data_) string (move (x)); else { p = &v.as (); if (!p->empty ()) x += *p; p->swap (x); } return !p->empty (); } inline int value_traits:: compare (const string& l, const string& r) { return l.compare (r); } // path value // inline bool value_traits:: assign (value& v, path&& x) { path* p; if (v.null ()) p = new (&v.data_) path (move (x)); else p = &(v.as () = move (x)); return !p->empty (); } inline bool value_traits:: append (value& v, path&& x) { path* p; if (v.null ()) p = new (&v.data_) path (move (x)); else { p = &v.as (); if (p->empty ()) p->swap (x); else *p /= x; } return !p->empty (); } inline bool value_traits:: prepend (value& v, path&& x) { path* p; if (v.null ()) new (&v.data_) path (move (x)); else { p = &v.as (); if (!p->empty ()) x /= *p; p->swap (x); } return !p->empty (); } inline int value_traits:: compare (const path& l, const path& r) { return l.compare (r); } // dir_path value // inline bool value_traits:: assign (value& v, dir_path&& x) { dir_path* p; if (v.null ()) p = new (&v.data_) dir_path (move (x)); else p = &(v.as () = move (x)); return !p->empty (); } inline bool value_traits:: append (value& v, dir_path&& x) { dir_path* p; if (v.null ()) p = new (&v.data_) dir_path (move (x)); else { p = &v.as (); if (p->empty ()) p->swap (x); else *p /= x; } return !p->empty (); } inline bool value_traits:: prepend (value& v, dir_path&& x) { dir_path* p; if (v.null ()) new (&v.data_) dir_path (move (x)); else { p = &v.as (); if (!p->empty ()) x /= *p; p->swap (x); } return !p->empty (); } inline int value_traits:: compare (const dir_path& l, const dir_path& r) { return l.compare (r); } // abs_dir_path value // inline bool value_traits:: assign (value& v, abs_dir_path&& x) { abs_dir_path* p; if (v.null ()) p = new (&v.data_) abs_dir_path (move (x)); else p = &(v.as () = move (x)); return !p->empty (); } inline bool value_traits:: append (value& v, abs_dir_path&& x) { abs_dir_path* p; if (v.null ()) p = new (&v.data_) abs_dir_path (move (x)); else { p = &v.as (); if (p->empty ()) p->swap (x); else *p /= x; } return !p->empty (); } inline int value_traits:: compare (const abs_dir_path& l, const abs_dir_path& r) { return l.compare (static_cast (r)); } // name value // inline bool value_traits:: assign (value& v, name&& x) { name* p; if (v.null ()) p = new (&v.data_) name (move (x)); else p = &(v.as () = move (x)); return !p->empty (); } inline int value_traits:: compare (const name& l, const name& r) { return l.compare (r); } // vector value // template inline bool value_traits>:: assign (value& v, vector&& x) { vector* p; if (v.null ()) p = new (&v.data_) vector (move (x)); else p = &(v.as> () = move (x)); return !p->empty (); } template inline bool value_traits>:: append (value& v, vector&& x) { vector* p; if (v.null ()) p = new (&v.data_) vector (move (x)); else { p = &v.as> (); if (p->empty ()) p->swap (x); else p->insert (p->end (), make_move_iterator (x.begin ()), make_move_iterator (x.end ())); } return !p->empty (); } template inline bool value_traits>:: prepend (value& v, vector&& x) { vector* p; if (v.null ()) new (&v.data_) vector (move (x)); else { p = &v.as> (); if (!p->empty ()) x.insert (x.end (), make_move_iterator (p->begin ()), make_move_iterator (p->end ())); p->swap (x); } return !p->empty (); } // map value // template inline bool value_traits>:: assign (value& v, map&& x) { map* p; if (v.null ()) p = new (&v.data_) map (move (x)); else p = &(v.as> () = move (x)); return !p->empty (); } template inline bool value_traits>:: append (value& v, map&& x) { map* p; if (v.null ()) p = new (&v.data_) map (move (x)); else { p = &v.as> (); if (p->empty ()) p->swap (x); else // Note that this will only move values. Keys (being const) are still // copied. // p->insert (p->end (), make_move_iterator (x.begin ()), make_move_iterator (x.end ())); } return !p->empty (); } // variable_pool // inline const variable& variable_pool:: find (const string& n) { auto p (variable_pool_base::insert ( variable {n, nullptr, nullptr, variable_visibility::normal})); return *p.first; } // 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; } }