// file : build/variable -*- C++ -*- // copyright : Copyright (c) 2014-2015 Code Synthesis Tools CC // license : MIT; see accompanying LICENSE file #ifndef BUILD_VARIABLE #define BUILD_VARIABLE #include <string> #include <memory> // unique_ptr #include <cstddef> // nullptr_t #include <utility> // move() #include <cassert> #include <functional> // hash #include <typeindex> #include <unordered_set> #include <build/path> #include <build/name> #include <build/prefix-map> namespace build { struct value; struct value_type { std::type_index id; value* (*const factory) (); }; // variable // // The two variables are considered the same if they have the same name. // struct variable { explicit variable (std::string n): name (std::move (n)), type (nullptr) {} std::string name; const value_type* type; // If NULL, then this variable has no fixed type. }; inline bool operator== (const variable& x, const variable& y) {return x.name == y.name;} typedef std::reference_wrapper<const variable> variable_cref; // value // struct value; typedef std::unique_ptr<value> value_ptr; struct value { public: virtual value_ptr clone () const = 0; virtual bool compare (const value&) const = 0; virtual ~value () = default; }; struct list_value: value, names { public: list_value (names d): names (std::move (d)) {} list_value (std::string d) {emplace_back (std::move (d));} list_value (dir_path d) {emplace_back (std::move (d));} virtual value_ptr clone () const {return value_ptr (new list_value (*this));} virtual bool compare (const value& v) const { const list_value* lv (dynamic_cast<const list_value*> (&v)); return lv != nullptr && static_cast<const names&> (*this) == *lv; } }; typedef std::unique_ptr<list_value> list_value_ptr; // value_proxy // // A variable can be undefined, null, or contain some actual value. // struct variable_map; struct value_proxy { bool defined () const {return p != nullptr;} bool null () const {return *p == nullptr;} explicit operator bool () const {return defined () && !null ();} explicit operator value_ptr& () const {return *p;} // Get interface. See available specializations below. // template <typename T> T as () const = delete; // Set interface. // const value_proxy& operator= (value_ptr) const; const value_proxy& operator= (const value_proxy&) const; const value_proxy& operator= (std::string) const; // Append enother simple name to list_value. // const value_proxy& operator+= (std::string) const; const value_proxy& operator= (dir_path) const; const value_proxy& operator= (nullptr_t) const; // Return true if this value belongs to the specified scope or target. // template <typename T> bool belongs (const T& x) const {return map == &x.vars;} // Implementation details. // const variable_map* map; // Variable map to which this value belongs. value_proxy (value_ptr* p, const variable_map* m): map (m), p (p) {} private: value_ptr* p; }; template <> inline value& value_proxy:: as<value&> () const {return **p;} template <> inline const value& value_proxy:: as<const value&> () const {return **p;} template <> list_value& value_proxy:: as<list_value&> () const; template <> inline const list_value& value_proxy:: as<const list_value&> () const {return as<list_value&> ();} template <> const std::string& value_proxy:: as<const std::string&> () const; template <> const dir_path& value_proxy:: as<const dir_path&> () const; } 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 build { // variable_pool // struct variable_set: std::unordered_set<variable> { // @@ Need to check/set type? // const variable& find (std::string name) {return *emplace (std::move (name)).first;} }; extern variable_set variable_pool; // variable_map // template <> struct compare_prefix<variable_cref>: compare_prefix<std::string> { typedef compare_prefix<std::string> base; explicit compare_prefix (char d): base (d) {} bool operator() (const variable& x, const variable& y) const { return base::operator() (x.name, y.name); } bool prefix (const variable& p, const variable& k) const { return base::prefix (p.name, k.name); } }; struct variable_map: prefix_map<variable_cref, value_ptr, '.'> { typedef prefix_map<variable_cref, value_ptr, '.'> base; value_proxy operator[] (const variable& var) const { auto i (find (var)); return i != end () // @@ To do this properly we seem to need ro_value_proxy. // ? value_proxy (&const_cast<value_ptr&> (i->second), this) : value_proxy (nullptr, nullptr); } value_proxy operator[] (const std::string& name) const { return operator[] (variable_pool.find (name)); } value_proxy assign (const variable& var) { return value_proxy (&base::operator[] (var), this); } value_proxy assign (const std::string& name) { return assign (variable_pool.find (name)); } std::pair<iterator, iterator> find_namespace (const std::string& ns) { return find_prefix (variable_pool.find (ns)); } std::pair<const_iterator, const_iterator> find_namespace (const std::string& ns) const { return find_prefix (variable_pool.find (ns)); } }; } #include <build/variable.ixx> #endif // BUILD_VARIABLE