diff options
Diffstat (limited to 'build/variable')
-rw-r--r-- | build/variable | 831 |
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 |