aboutsummaryrefslogtreecommitdiff
path: root/build/variable
diff options
context:
space:
mode:
Diffstat (limited to 'build/variable')
-rw-r--r--build/variable831
1 files changed, 0 insertions, 831 deletions
diff --git a/build/variable b/build/variable
deleted file mode 100644
index 799a35c..0000000
--- a/build/variable
+++ /dev/null
@@ -1,831 +0,0 @@
-// file : build/variable -*- C++ -*-
-// copyright : Copyright (c) 2014-2015 Code Synthesis Ltd
-// license : MIT; see accompanying LICENSE file
-
-#ifndef BUILD_VARIABLE
-#define BUILD_VARIABLE
-
-#include <map>
-#include <vector>
-#include <cstddef> // nullptr_t
-#include <utility> // pair, make_pair()
-#include <iterator>
-#include <functional> // hash
-#include <type_traits> // conditional, is_reference, remove_reference, etc.
-#include <unordered_set>
-
-#include <butl/prefix-map>
-
-#include <build/types>
-#include <build/utility>
-
-#include <build/target-type>
-
-namespace build
-{
- struct variable;
-
- // If assign is NULL, then the value is assigned as is. If append
- // is NULL, then the names are appended to the end of the value
- // and assign is called, if not NULL. Variable is provided primarily
- // for diagnostics. Return true if the resulting value is not empty.
- //
- struct value_type
- {
- const char* name;
- bool (*const assign) (names&, const variable&);
- bool (*const append) (names&, names, const variable&);
- };
-
- enum class variable_visibility
- {
- scope, // This scope (no outer scopes).
- project, // This project (no outer projects).
- normal // All outer scopes.
- };
-
- // variable
- //
- // The two variables are considered the same if they have the same name.
- //
- struct variable
- {
- std::string name;
- const value_type* type; // If NULL, then not (yet) typed.
- variable_visibility visibility;
- char pairs; // Pair symbold or '\0' if not used.
- };
-
- inline bool
- operator== (const variable& x, const variable& y) {return x.name == y.name;}
-
- typedef std::reference_wrapper<const variable> variable_cref;
-
- // value
- //
- class value
- {
- public:
- // By default we create NULL value.
- //
- explicit value (const value_type* t = nullptr)
- : type (t), state_ (state_type::null) {}
-
- value (value&&) = default;
-
- value&
- operator= (std::nullptr_t)
- {
- data_.clear ();
- state_ = state_type::null;
- return *this;
- }
-
- value&
- operator= (value&&);
-
- value&
- operator= (const value& v)
- {
- if (&v != this)
- *this = value (v);
- return *this;
- }
-
- value&
- operator= (reference_wrapper<value> v) {return *this = v.get ();}
-
- value&
- operator= (reference_wrapper<const value> v) {return *this = v.get ();}
-
- value&
- append (value, const variable&); // Aka operator+=().
-
- value&
- prepend (value, const variable&); // Aka operator=+().
-
- // Forwarded to the representation type's assign()/append() (see below).
- //
- template <typename T> value& operator= (T);
- value& operator= (const char* v) {return *this = std::string (v);}
-
- template <typename T> value& operator+= (T);
- value& operator+= (const char* v) {return *this += std::string (v);}
-
- private:
- explicit value (const value&) = default;
-
- public:
- const value_type* type; // NULL means this value is not (yet) typed.
-
- bool null () const {return state_ == state_type::null;}
- bool empty () const {return state_ == state_type::empty;}
-
- explicit operator bool () const {return !null ();}
- bool operator== (std::nullptr_t) const {return null ();}
- bool operator!= (std::nullptr_t) const {return !null ();}
-
- // Raw data read interface.
- //
- using const_iterator = names::const_iterator;
-
- const_iterator begin () const {return data_.begin ();}
- const_iterator end () const {return data_.end ();}
-
- // Raw data write interface. Note that it triggers callbacks for
- // typed values. Variable is passed for diagnostics.
- //
- void
- assign (names, const variable&);
-
- void
- append (names, const variable&);
-
- void
- prepend (names, const variable&);
-
- public:
- // Don't use directly except in the implementation of representation
- // types, in which case take care to update state.
- //
- enum class state_type {null, empty, filled} state_;
- names data_;
- };
-
- //@@ Right now we assume that for each value type each value has a
- // unique representation. This is currently not the case for map.
- //
- inline bool
- operator== (const value& x, const value& y)
- {
- return x.state_ == y.state_ && x.data_ == y.data_;
- }
-
- inline bool
- operator!= (const value& x, const value& y) {return !(x == y);}
-
- // lookup
- //
- // A variable can be undefined, NULL, or contain a (potentially
- // empty) value.
- //
- struct variable_map;
-
- template <typename V>
- struct lookup
- {
- V* value;
- const variable_map* vars;
-
- bool
- defined () const {return value != nullptr;}
-
- // Note: returns true if defined and not NULL.
- //
- explicit operator bool () const {return defined () && !value->null ();}
-
- V& operator* () const {return *value;}
- V* operator-> () const {return value;}
-
- // Return true if this value belongs to the specified scope or target.
- // Note that it can also be a target type/pattern-specific value.
- //
- template <typename T>
- bool
- belongs (const T& x) const {return vars == &x.vars;}
-
- lookup (): value (nullptr), vars (nullptr) {}
- lookup (V* v, const variable_map* vs)
- : value (v), vars (v != nullptr ? vs : nullptr) {}
-
- template <typename T>
- lookup (V& v, const T& x): lookup (&v, &x.vars) {}
- };
-
- // Representation types.
- //
- template <typename T> struct value_traits;
-
- // Assign value type to the value.
- //
- template <typename T>
- void assign (value&, const variable&);
- void assign (value&, const value_type*, const variable&);
-
- template <typename T> typename value_traits<T>::type as (value&);
- template <typename T> typename value_traits<T>::const_type as (const value&);
-
- // "Assign" simple value type to the value stored in name. Return false
- // if the value is not valid for this type.
- //
- template <typename T> bool assign (name&);
-
- template <typename T> typename value_traits<T>::type as (name&);
- template <typename T> typename value_traits<T>::const_type as (const name&);
-
- // bool
- //
- template <typename D>
- struct bool_value
- {
- explicit
- operator bool () const {return d->value[0] == 't';}
-
- bool_value&
- operator= (bool v)
- {
- d->value = v ? "true" : "false";
- return *this;
- }
-
- bool_value&
- operator+= (bool v)
- {
- if (!*this && v)
- d->value = "true";
- return *this;
- }
-
- // Implementation details.
- //
- public:
- explicit bool_value (D& d): d (&d) {}
-
- bool_value (const bool_value&) = delete;
- bool_value& operator= (const bool_value&) = delete; // Rebind or deep?
-
- bool_value (bool_value&&) = default;
- bool_value& operator= (bool_value&&) = delete;
-
- D* d; // name
- };
-
- template <>
- struct value_traits<bool>
- {
- using type = bool_value<name>;
- using const_type = bool_value<const name>;
-
- static type as (name& n) {return type (n);}
- static const_type as (const name& n) {return const_type (n);}
-
- static type as (value&);
- static const_type as (const value&);
-
- static bool assign (name&);
- static void assign (value&, bool);
- static void append (value&, bool);
-
- static const build::value_type value_type;
- };
-
- extern const value_type* bool_type;
-
- // string
- //
- template <>
- struct value_traits<std::string>
- {
- using type = std::string&;
- using const_type = const std::string&;
-
- static type as (name& n) {return n.value;}
- static const_type as (const name& n) {return n.value;}
-
- static type as (value&);
- static const_type as (const value&);
-
- static bool assign (name&);
- static void assign (value&, std::string);
- static void append (value&, std::string);
-
- static const build::value_type value_type;
- };
-
- extern const value_type* string_type;
-
- // dir_path
- //
- template <>
- struct value_traits<dir_path>
- {
- using type = dir_path&;
- using const_type = const dir_path&;
-
- static type as (name& n) {return n.dir;}
- static const_type as (const name& n) {return n.dir;}
-
- static type as (value&);
- static const_type as (const value&);
-
- static bool assign (name&);
- static void assign (value&, dir_path);
- static void append (value&, dir_path);
-
- static const build::value_type value_type;
- };
-
- extern const value_type* dir_path_type;
-
- // name
- //
- template <>
- struct value_traits<name>
- {
- using type = name&;
- using const_type = const name&;
-
- static type as (name& n) {return n;}
- static const_type as (const name& n) {return n;}
-
- static type as (value&);
- static const_type as (const value&);
-
- static bool assign (name&) {return true;}
- static void assign (value&, name);
- static void append (value&, name) = delete;
-
- static const build::value_type value_type;
- };
-
- extern const value_type* name_type;
-
- // vector<T>
- //
- template <typename T, typename D>
- struct vector_value
- {
- using size_type = typename D::size_type;
-
- using value_type = typename value_traits<T>::type;
- using const_value_type = typename value_traits<T>::const_type;
-
- template <typename I, typename V, typename R>
- struct iterator_impl: I
- {
- using value_type = V;
- using pointer = value_type*;
- using reference = R;
- using difference_type = typename I::difference_type;
-
- iterator_impl () = default;
- iterator_impl (const I& i): I (i) {}
-
- // Note: operator->() is unavailable if R is a value.
- //
- reference operator* () const {return as<T> (I::operator* ());}
- pointer operator-> () const {return &as<T> (I::operator* ());}
- reference operator[] (difference_type n) const
- {
- return as<T> (I::operator[] (n));
- }
- };
-
- // Make iterator the same as const_iterator if our data type is const.
- //
- using const_iterator =
- iterator_impl<names::const_iterator, const T, const_value_type>;
- using iterator = typename std::conditional<
- std::is_const<D>::value,
- const_iterator,
- iterator_impl<names::iterator, T, value_type>>::type;
-
- public:
- vector_value&
- operator= (std::vector<T> v) {assign (std::move (v)); return *this;}
-
- vector_value&
- assign (std::vector<T>);
-
- template <typename D1>
- vector_value&
- assign (const vector_value<T, D1>&);
-
- template <typename D1>
- vector_value&
- append (const vector_value<T, D1>&);
-
- public:
- bool empty () const {return d->empty ();}
- size_type size () const {return d->size ();}
-
- value_type operator[] (size_type i) {return as<T> ((*d)[i]);}
- const_value_type operator[] (size_type i) const {return as<T> ((*d)[i]);}
-
- iterator begin () {return iterator (d->begin ());}
- iterator end () {return iterator (d->end ());}
-
- const_iterator begin () const {return const_iterator (d->begin ());}
- const_iterator end () const {return const_iterator (d->end ());}
-
- const_iterator cbegin () const {return const_iterator (d->begin ());}
- const_iterator cend () const {return const_iterator (d->end ());}
-
- // Implementation details.
- //
- public:
- explicit vector_value (D& d): d (&d) {}
-
- vector_value (const vector_value&) = delete;
- vector_value& operator= (const vector_value&) = delete; // Rebind or deep?
-
- vector_value (vector_value&&) = default;
- vector_value& operator= (vector_value&&) = default; //@@ TMP
-
- explicit vector_value (std::nullptr_t): d (nullptr) {} //@@ TMP
-
- D* d; // names
- };
-
- template <typename T>
- struct value_traits<std::vector<T>>
- {
- using type = vector_value<T, names>;
- using const_type = vector_value<T, const names>;
-
- static type as (value&);
- static const_type as (const value&);
-
- template <typename V> static void assign (value&, V);
- template <typename V> static void append (value&, V);
-
- static const std::string type_name;
- static const build::value_type value_type;
- };
-
- template <typename T, typename D>
- struct value_traits<vector_value<T, D>>: value_traits<std::vector<T>> {};
-
- using strings_value = vector_value<std::string, names>;
- using const_strings_value = vector_value<std::string, const names>;
-
- extern const value_type* strings_type; // vector<string> aka strings
- extern const value_type* dir_paths_type; // vector<dir_path> aka dir_paths
- extern const value_type* names_type; // vector<name> aka names
-
- // map<K, V>
- //
- template <typename K, typename V, typename D>
- struct map_value
- {
- template <typename F, typename S>
- struct pair
- {
- using first_type = typename std::conditional<
- std::is_reference<F>::value,
- std::reference_wrapper<typename std::remove_reference<F>::type>,
- F>::type;
-
- using second_type = typename std::conditional<
- std::is_reference<S>::value,
- std::reference_wrapper<typename std::remove_reference<S>::type>,
- S>::type;
-
- first_type first;
- second_type second;
- };
-
- template <typename I, typename T>
- struct iterator_impl
- {
- using value_type = T;
- using pointer = value_type*;
- using reference = value_type; // Note: value.
- using difference_type = typename I::difference_type;
- using iterator_category = std::bidirectional_iterator_tag;
-
- iterator_impl () = default;
- iterator_impl (const I& i): i_ (i) {}
-
- pointer operator-> () const = delete;
- reference operator* () const
- {
- return value_type {as<K> (*i_), as<V> (*(i_ + 1))};
- }
-
- iterator_impl& operator++ () {i_ += 2; return *this;}
- iterator_impl operator++ (int) {auto r (*this); operator++ (); return r;}
-
- iterator_impl& operator-- () {i_ -= 2; return *this;}
- iterator_impl operator-- (int) {auto r (*this); operator-- (); return r;}
-
- bool operator== (const iterator_impl& y) const {return i_ == y.i_;}
- bool operator!= (const iterator_impl& y) const {return i_ != y.i_;}
-
- private:
- I i_;
- };
-
- using size_type = typename D::size_type;
-
- using value_type = pair<typename value_traits<K>::const_type,
- typename value_traits<V>::type>;
-
- using const_value_type = pair<typename value_traits<K>::const_type,
- typename value_traits<V>::const_type>;
-
- // Make iterator the same as const_iterator if our data type is const.
- //
- using const_iterator =
- iterator_impl<names::const_iterator, const_value_type>;
- using iterator = typename std::conditional<
- std::is_const<D>::value,
- const_iterator,
- iterator_impl<names::iterator, value_type>>::type;
-
-
- public:
- map_value&
- operator= (std::map<K, V> m) {assign (std::move (m)); return *this;}
-
- map_value&
- assign (std::map<K, V>);
-
- bool empty () const {return d->empty ();}
- size_type size () const {return d->size ();}
-
- iterator find (const K&);
- const_iterator find (const K&) const;
-
- iterator begin () {return iterator (d->begin ());}
- iterator end () {return iterator (d->end ());}
-
- const_iterator begin () const {return const_iterator (d->begin ());}
- const_iterator end () const {return const_iterator (d->end ());}
-
- // Implementation details.
- //
- public:
- explicit map_value (D& d): d (&d) {}
-
- map_value (const map_value&) = delete;
- map_value& operator= (const map_value&) = delete; // Rebind or deep?
-
- map_value (map_value&&) = default;
- map_value& operator= (map_value&&) = delete;
-
- D* d; // names
- };
-
- template <typename K, typename V>
- struct value_traits<std::map<K, V>>
- {
- using type = map_value<K, V, names>;
- using const_type = map_value<K, V, const names>;
-
- static type as (value&);
- static const_type as (const value&);
-
- template <typename M> static void assign (value&, M);
- template <typename M> static void append (value&, M);
-
- static const std::string type_name;
- static const build::value_type value_type;
- };
-
- template <typename K, typename V, typename D>
- struct value_traits<map_value<K, V, D>>: value_traits<std::map<K, V>> {};
-}
-
-namespace std
-{
- template <>
- struct hash<build::variable>: hash<string>
- {
- size_t
- operator() (const build::variable& v) const noexcept
- {
- return hash<string>::operator() (v.name);
- }
- };
-}
-
-namespace butl
-{
- template <>
- struct compare_prefix<build::variable_cref>: compare_prefix<std::string>
- {
- typedef compare_prefix<std::string> base;
-
- explicit
- compare_prefix (char d): base (d) {}
-
- bool
- operator() (const build::variable& x, const build::variable& y) const
- {
- return base::operator() (x.name, y.name);
- }
-
- bool
- prefix (const build::variable& p, const build::variable& k) const
- {
- return base::prefix (p.name, k.name);
- }
- };
-}
-
-namespace build
-{
- // variable_pool
- //
- using variable_pool_base = std::unordered_set<variable>;
- struct variable_pool: private variable_pool_base
- {
- const variable&
- find (string name, const build::value_type* t = nullptr, char p = '\0')
- {
- return find (name, nullptr, t, p);
- }
-
- const variable&
- find (string name,
- variable_visibility v,
- const build::value_type* t = nullptr,
- char p = '\0')
- {
- return find (name, &v, t, p);
- }
-
- using variable_pool_base::clear;
-
- private:
- const variable&
- find (string name,
- const variable_visibility* vv,
- const build::value_type* t,
- char p)
- {
- auto r (
- insert (
- variable {
- std::move (name),
- t,
- vv != nullptr ? *vv : variable_visibility::normal,
- p}));
- const variable& v (*r.first);
-
- // Update type?
- //
- if (!r.second && t != nullptr && v.type != t)
- {
- assert (v.type == nullptr);
- const_cast<variable&> (v).type = t; // Not changing the key.
- }
-
- // Change visibility? While this might at first seem like a bad idea,
- // it can happen that the variable lookup happens before any values
- // were set, in which case the variable will be entered with the
- // default visibility.
- //
- if (!r.second && vv != nullptr && v.visibility != *vv)
- {
- assert (v.visibility == variable_visibility::normal); // Default.
- const_cast<variable&> (v).visibility = *vv; // Not changing the key.
- }
-
- return v;
- }
- };
-
- extern variable_pool var_pool;
-
- // variable_map
- //
- struct variable_map
- {
- using map_type = butl::prefix_map<variable_cref, value, '.'>;
- using size_type = map_type::size_type;
-
- template <typename I>
- struct iterator_adapter: I
- {
- iterator_adapter () = default;
- iterator_adapter (const I& i): I (i) {}
- typename I::reference operator* () const;
- typename I::pointer operator-> () const;
- };
-
- using const_iterator = iterator_adapter<map_type::const_iterator>;
-
- const value*
- find (const variable& var) const
- {
- auto i (m_.find (var));
- const value* r (i != m_.end () ? &i->second : nullptr);
-
- // First access after being assigned a type?
- //
- if (r != nullptr && var.type != nullptr && r->type != var.type)
- build::assign (const_cast<value&> (*r), var.type, var);
-
- return r;
- }
-
- value*
- find (const variable& var)
- {
- auto i (m_.find (var));
- value* r (i != m_.end () ? &i->second : nullptr);
-
- // First access after being assigned a type?
- //
- if (r != nullptr && var.type != nullptr && r->type != var.type)
- build::assign (*r, var.type, var);
-
- return r;
- }
-
- lookup<const value>
- operator[] (const variable& var) const
- {
- return lookup<const value> (find (var), this);
- }
-
- lookup<const value>
- operator[] (const std::string& name) const
- {
- return operator[] (var_pool.find (name));
- }
-
- // Non-const lookup. Only exposed on the map directly.
- //
- lookup<value>
- operator[] (const variable& var)
- {
- return lookup<value> (find (var), this);
- }
-
- lookup<value>
- operator[] (const std::string& name)
- {
- return operator[] (var_pool.find (name));
- }
-
- // The second member in the pair indicates whether the new
- // value (which will be NULL) was assigned.
- //
- std::pair<std::reference_wrapper<value>, bool>
- assign (const variable& var)
- {
- auto r (m_.emplace (var, value (var.type)));
- value& v (r.first->second);
-
- // First access after being assigned a type?
- //
- if (!r.second && var.type != nullptr && v.type != var.type)
- build::assign (v, var.type, var);
-
- return std::make_pair (std::reference_wrapper<value> (v), r.second);
- }
-
- std::pair<std::reference_wrapper<value>, bool>
- assign (const std::string& name)
- {
- return assign (var_pool.find (name));
- }
-
- std::pair<const_iterator, const_iterator>
- find_namespace (const std::string& ns) const
- {
- auto r (m_.find_prefix (var_pool.find (ns)));
- return std::make_pair (const_iterator (r.first),
- const_iterator (r.second));
- }
-
- const_iterator
- begin () const {return m_.begin ();}
-
- const_iterator
- end () const {return m_.end ();}
-
- bool
- empty () const {return m_.empty ();}
-
- size_type
- size () const {return m_.size ();}
-
- private:
- map_type m_;
- };
-
- // Target type/pattern-specific variables.
- //
- // @@ In quite a few places we assume that we can store a reference
- // to the returned value (e.g., install::lookup_install()). If
- // we "instantiate" the value on the fly, then we will need to
- // consider its lifetime.
- //
- using variable_pattern_map = std::map<std::string, variable_map>;
-
- struct variable_type_map: std::map<std::reference_wrapper<const target_type>,
- variable_pattern_map>
- {
- build::lookup<const value>
- lookup (const target_type&, const string& name, const variable&) const;
- };
-}
-
-#include <build/variable.ixx>
-#include <build/variable.txx>
-
-#endif // BUILD_VARIABLE