// file : build/variable.ixx -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Ltd // license : MIT; see accompanying LICENSE file namespace build { // value // template <typename T> inline void assign (value& v, const variable& var) { auto t (&value_traits<T>::value_type); if (v.type != t) assign (v, t, var); } template <typename T> inline typename value_traits<T>::type as (value& v) { return value_traits<T>::as (v); } template <typename T> inline typename value_traits<T>::const_type as (const value& v) { return value_traits<T>::as (v); } template <typename T> inline bool assign (name& n) { return value_traits<T>::assign (n); } template <typename T> inline typename value_traits<T>::type as (name& n) { return value_traits<T>::as (n); } template <typename T> inline typename value_traits<T>::const_type as (const name& n) { return value_traits<T>::as (n); } template <typename T> inline value& value:: operator= (T v) { value_traits<T>::assign (*this, std::move (v)); return *this; } template <typename T> inline value& value:: operator+= (T v) { value_traits<T>::append (*this, std::move (v)); return *this; } inline void value:: assign (names v, const variable& var) { data_ = std::move (v); state_ = (type != nullptr && type->assign != nullptr ? type->assign (data_, var) : !data_.empty ()) ? state_type::filled : state_type::empty; } // bool value // inline bool_value<name> value_traits<bool>:: as (value& v) { assert (v.type == bool_type); return bool_value<name> (v.data_.front ()); } inline bool_value<const name> value_traits<bool>:: as (const value& v) { assert (v.type == bool_type); return bool_value<const name> (v.data_.front ()); } inline void value_traits<bool>:: assign (value& v, bool x) { if (v.null ()) { if (v.type == nullptr) v.type = bool_type; v.data_.emplace_back (name ()); v.state_ = value::state_type::empty; } as (v) = x; v.state_ = value::state_type::filled; } inline void value_traits<bool>:: append (value& v, bool x) { if (v.null ()) assign (v, x); else as (v) += x; // Cannot be empty. } // string value // inline std::string& value_traits<std::string>:: as (value& v) { assert (v.type == string_type); return v.data_.front ().value; } inline const std::string& value_traits<std::string>:: as (const value& v) { assert (v.type == string_type); return v.data_.front ().value; } inline void value_traits<std::string>:: assign (value& v, std::string x) { if (v.null ()) { if (v.type == nullptr) v.type = string_type; v.data_.emplace_back (name ()); v.state_ = value::state_type::empty; } v.state_ = (as (v) = std::move (x)).empty () ? value::state_type::empty : value::state_type::filled; } inline void value_traits<std::string>:: append (value& v, std::string x) { if (v.null ()) assign (v, std::move (x)); else v.state_ = (as (v) += std::move (x)).empty () ? value::state_type::empty : value::state_type::filled; } // dir_path value // inline dir_path& value_traits<dir_path>:: as (value& v) { assert (v.type == dir_path_type); return v.data_.front ().dir; } inline const dir_path& value_traits<dir_path>:: as (const value& v) { assert (v.type == dir_path_type); return v.data_.front ().dir; } inline void value_traits<dir_path>:: assign (value& v, dir_path x) { if (v.null ()) { if (v.type == nullptr) v.type = dir_path_type; v.data_.emplace_back (name ()); v.state_ = value::state_type::empty; } v.state_ = (as (v) = std::move (x)).empty () ? value::state_type::empty : value::state_type::filled; } inline void value_traits<dir_path>:: append (value& v, dir_path x) { if (v.null ()) assign (v, std::move (x)); else v.state_ = (as (v) /= std::move (x)).empty () ? value::state_type::empty : value::state_type::filled; } // name value // inline name& value_traits<name>:: as (value& v) { assert (v.type == name_type); return v.data_.front (); } inline const name& value_traits<name>:: as (const value& v) { assert (v.type == name_type); return v.data_.front (); } inline void value_traits<name>:: assign (value& v, name x) { if (v.null ()) { if (v.type == nullptr) v.type = name_type; v.data_.emplace_back (name ()); v.state_ = value::state_type::empty; } v.state_ = (as (v) = std::move (x)).empty () ? value::state_type::empty : value::state_type::filled; } // vector<T> value // template <typename T, typename D> inline vector_value<T, D>& vector_value<T, D>:: assign (std::vector<T> v) { d->clear (); d->insert (d->end (), std::make_move_iterator (v.begin ()), std::make_move_iterator (v.end ())); return *this; } template <typename T, typename D> template <typename D1> inline vector_value<T, D>& vector_value<T, D>:: assign (const vector_value<T, D1>& v) { d->clear (); d->insert (d->end (), v.begin (), v.end ()); return *this; } template <typename T, typename D> template <typename D1> inline vector_value<T, D>& vector_value<T, D>:: append (const vector_value<T, D1>& v) { d->insert (d->end (), v.begin (), v.end ()); return *this; } template <typename T> inline vector_value<T, names> value_traits<std::vector<T>>:: as (value& v) { assert (v.type == &value_traits<std::vector<T>>::value_type); return vector_value<T, names> (v.data_); } template <typename T> inline vector_value<T, const names> value_traits<std::vector<T>>:: as (const value& v) { assert (v.type == &value_traits<std::vector<T>>::value_type); return vector_value<T, const names> (v.data_); } template <typename T> template <typename V> inline void value_traits<std::vector<T>>:: assign (value& v, V x) { if (v.null ()) { if (v.type == nullptr) v.type = &value_traits<std::vector<T>>::value_type; v.state_ = value::state_type::empty; } v.state_ = (as (v).assign (std::move (x))).empty () ? value::state_type::empty : value::state_type::filled; } template <typename T> template <typename V> inline void value_traits<std::vector<T>>:: append (value& v, V x) { if (v.null ()) assign (v, std::move (x)); else v.state_ = (as (v).append (std::move (x))).empty () ? value::state_type::empty : value::state_type::filled; } // map<K, V> value // template <typename K, typename V> inline map_value<K, V, names> value_traits<std::map<K, V>>:: as (value& v) { assert ((v.type == &value_traits<std::map<K, V>>::value_type)); return map_value<K, V, names> (v.data_); } template <typename K, typename V> inline map_value<K, V, const names> value_traits<std::map<K, V>>:: as (const value& v) { assert ((v.type == &value_traits<std::map<K, V>>::value_type)); return map_value<K, V, const names> (v.data_); } template <typename K, typename V> template <typename M> inline void value_traits<std::map<K, V>>:: assign (value& v, M x) { if (v.null ()) { if (v.type == nullptr) v.type = &value_traits<std::map<K, V>>::value_type; v.state_ = value::state_type::empty; } v.state_ = (as (v).assign (std::move (x))).empty () ? value::state_type::empty : value::state_type::filled; } template <typename K, typename V> template <typename M> inline void value_traits<std::map<K, V>>:: append (value& v, M x) { if (v.null ()) assign (v, std::move (x)); else v.state_ = (as (v).append (std::move (x))).empty () ? value::state_type::empty : value::state_type::filled; } // 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); auto& val (r.second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) build::assign (const_cast<value&> (val), var.type, 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); auto& val (p->second); // First access after being assigned a type? // if (var.type != nullptr && val.type != var.type) build::assign (const_cast<value&> (val), var.type, var); return p; } }