// 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 build::scope scope_type; virtual ~value () = default; value (scope_type& s): scope (s) {} scope_type& scope; // Scope to which this value belongs. }; typedef std::unique_ptr value_ptr; struct list_value: value { list_value (scope_type& s, names d): value (s), data (std::move (d)) {} list_value (scope_type& s, std::string d) : value (s) { data.emplace_back (std::move (d)); } // Note: stored in name as a directory. // list_value (scope_type& s, path d) : value (s) { data.emplace_back (std::move (d)); } names data; }; typedef std::unique_ptr list_value_ptr; // value_proxy // struct value_proxy { explicit operator bool () const {return p != nullptr && *p != nullptr;} explicit operator value_ptr& () const {return *p;} // Get interface. See available specializations below. // template T as () const = delete; // Set interface. // const value_proxy& operator= (value_ptr v) const { assert (v == nullptr || &v->scope == s); *p = std::move (v); return *this; } const value_proxy& operator= (std::string v) const { // 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 (*s, std::move (v))); return *this; } // Note: stored in name as a directory. // const value_proxy& operator= (path v) const { p->reset (new list_value (*s, std::move (v))); return *this; } // Implementation details. // explicit value_proxy (value_ptr* p, scope* s): p (p), s (s) {} protected: value_ptr* p; scope* s; }; template <> list_value& value_proxy:: as () const; template <> const std::string& value_proxy:: as () const; // Note: get the name's directory. // template <> const 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_); } explicit variable_map (scope& s): scope_ (s) {} private: scope& scope_; // Scope to which this map belongs (and all its value). }; } #endif // BUILD_VARIABLE