// 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 #include // unique_ptr #include // move() #include #include // hash #include #include #include #include #include namespace build { class scope; 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 variable_cref; // value // struct value; typedef std::unique_ptr 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 (&v)); return lv != nullptr && static_cast (*this) == *lv; } }; typedef std::unique_ptr list_value_ptr; // value_proxy // // A variable can be undefined, null, or contain some actual value. // struct value_proxy { typedef build::scope scope_type; 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;} scope_type* scope; // If NULL, then this is a target variable. // Get interface. See available specializations below. // template 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; // Implementation details. // value_proxy (value_ptr* p, scope_type* s): p (p), scope (s) {} private: value_ptr* p; }; template <> inline value& value_proxy:: as () const {return **p;} template <> inline const value& value_proxy:: as () const {return **p;} template <> list_value& value_proxy:: as () const; template <> inline const list_value& value_proxy:: as () const {return as ();} template <> const std::string& value_proxy:: as () const; template <> const dir_path& value_proxy:: as () const; } namespace std { template <> struct hash: hash { size_t operator() (const build::variable& v) const noexcept { return hash::operator() (v.name); } }; } namespace build { // variable_pool // struct variable_set: std::unordered_set { // @@ 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: compare_prefix { typedef compare_prefix 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 { typedef prefix_map base; value_proxy operator[] (const std::string& v) { return operator[] (variable_pool.find (v)); } value_proxy operator[] (const variable& v) { return value_proxy (&base::operator[] (v), scope_); } value_proxy operator[] (const std::string& v) const { return operator[] (variable_pool.find (v)); } value_proxy operator[] (const variable& v) const { auto i (find (v)); return i != end () // @@ To do this properly we seem to need ro_value_proxy. // ? value_proxy (&const_cast (i->second), scope_) : value_proxy (nullptr, nullptr); } std::pair find_namespace (const std::string& ns) { return find_prefix (variable_pool.find (ns)); } std::pair find_namespace (const std::string& ns) const { return find_prefix (variable_pool.find (ns)); } explicit variable_map (scope* s): scope_ (s) {} private: scope* scope_; // Scope to which this map belongs or NULL if this // is a target variable map. }; } #include #endif // BUILD_VARIABLE