aboutsummaryrefslogtreecommitdiff
path: root/build/variable.ixx
diff options
context:
space:
mode:
Diffstat (limited to 'build/variable.ixx')
-rw-r--r--build/variable.ixx403
1 files changed, 345 insertions, 58 deletions
diff --git a/build/variable.ixx b/build/variable.ixx
index b97815e..16ea7c0 100644
--- a/build/variable.ixx
+++ b/build/variable.ixx
@@ -4,108 +4,395 @@
namespace build
{
- // value_proxy
+ // value
//
- inline bool value_proxy::
- empty () const {return as<const list_value&> ().empty ();}
+ 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);
+ }
- inline const value_proxy& value_proxy::
- operator= (value_ptr v) const
+ template <typename T>
+ inline typename value_traits<T>::const_type
+ as (const name& n)
{
- *p = std::move (v);
+ 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 const value_proxy& value_proxy::
- operator= (const value_proxy& v) const
+ 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)
{
- if (this != &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)
- *p = v.as<const value&> ().clone ();
- else
- p->reset ();
+ if (v.type == nullptr)
+ v.type = bool_type;
+ v.data_.emplace_back (name ());
+ v.state_ = value::state_type::empty;
}
- return *this;
+ as (v) = x;
+ v.state_ = value::state_type::filled;
}
- inline const value_proxy& value_proxy::
- operator= (list_value v) const
+ inline void value_traits<bool>::
+ append (value& v, bool x)
{
- if (*p == nullptr)
- p->reset (new list_value (std::move (v)));
+ if (v.null ())
+ assign (v, x);
else
- //@@ Assuming it is a list_value.
- //
- as<list_value&> () = std::move (v);
+ as (v) += x; // Cannot be empty.
+ }
- return *this;
+ // string value
+ //
+ inline std::string& value_traits<std::string>::
+ as (value& v)
+ {
+ assert (v.type == string_type);
+ return v.data_.front ().value;
}
- inline const value_proxy& value_proxy::
- operator= (std::string v) const
+ inline const std::string& value_traits<std::string>::
+ as (const value& v)
{
- // In most cases this is used to initialize a new variable, so
- // don't bother trying to optimize for the case where p is not
- // NULL.
- //
- p->reset (new list_value (std::move (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;
}
- inline const value_proxy& value_proxy::
- operator= (dir_path v) const
+ template <typename T, typename D>
+ template <typename D1>
+ inline vector_value<T, D>& vector_value<T, D>::
+ assign (const vector_value<T, D1>& v)
{
- p->reset (new list_value (std::move (v)));
+ d->clear ();
+ d->insert (d->end (), v.begin (), v.end ());
return *this;
}
- inline const value_proxy& value_proxy::
- operator= (std::nullptr_t) const
+ template <typename T, typename D>
+ template <typename D1>
+ inline vector_value<T, D>& vector_value<T, D>::
+ append (const vector_value<T, D1>& v)
{
- p->reset ();
+ d->insert (d->end (), v.begin (), v.end ());
return *this;
}
- inline const value_proxy& value_proxy::
- operator+= (const value_proxy& v) const
+ 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)
{
- if (v && this != &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 (*p == nullptr)
- *this = v;
- else
- //@@ Assuming it is a list_value.
- //
- *this += v.as<const list_value&> ();
+ if (v.type == nullptr)
+ v.type = &value_traits<std::vector<T>>::value_type;
+ v.state_ = value::state_type::empty;
}
- return *this;
+ v.state_ = (as (v).assign (std::move (x))).empty ()
+ ? value::state_type::empty
+ : value::state_type::filled;
}
- inline const value_proxy& value_proxy::
- operator+= (const list_value& v) const
+ template <typename T>
+ template <typename V>
+ inline void value_traits<std::vector<T>>::
+ append (value& v, V x)
{
- if (*p == nullptr)
- *this = v;
+ 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 ())
{
- list_value& lv (as<list_value&> ());
- lv.insert (lv.end (), v.begin (), v.end ());
+ if (v.type == nullptr)
+ v.type = &value_traits<std::map<K, V>>::value_type;
+ v.state_ = value::state_type::empty;
}
- return *this;
+ v.state_ = (as (v).assign (std::move (x))).empty ()
+ ? value::state_type::empty
+ : value::state_type::filled;
}
- inline const value_proxy& value_proxy::
- operator+= (std::string v) const
+ template <typename K, typename V>
+ template <typename M>
+ inline void value_traits<std::map<K, V>>::
+ append (value& v, M x)
{
- if (*p == nullptr)
- *this = v;
+ if (v.null ())
+ assign (v, std::move (x));
else
- as<list_value&> ().emplace_back (std::move (v));
+ v.state_ = (as (v).append (std::move (x))).empty ()
+ ? value::state_type::empty
+ : value::state_type::filled;
+ }
- return *this;
+ // 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;
}
}