text: #ifndef THREE_PROPERTIES_H
  #define THREE_PROPERTIES_H
  
  #include <three/config.h>
  
  #include <unordered_map>
  //#include <map>
  
  namespace three {
  
  template < typename Key, typename Value >
  class Properties {
  public:
  
    typedef std::unordered_map<Key, Value> MapType;
    //typedef std::map<Key, Value> MapType;
  
    Properties() { }
    Properties(Properties&& other) {
      swap(other);
    }
    Properties(const Properties& other) : contents( other.contents ) { }
    Properties& operator=(Properties other) {
      return swap(other);
    }
  
    Properties& add(Key key, Value value) {
      contents.insert( std::make_pair(std::move(key), std::move(value)) );
      return *this;
    }
  
  #if THREE_HAS_VARIADIC_TEMPLATES
    template < typename... T >
    Properties& emplace( Key&& key, T&&... ts ) {
      return add( std::move(key), Value( std::move(ts)...) );
    }
  #else
    template < typename T, typename U >
    Properties& emplace( Key&& key, T&& t, U&& u ) {
      return add( std::move(key), Value( std::move(t), std::move(u) ) );
    }
    template < typename T, typename U, typename V >
    Properties& emplace( Key&& key, T&& t, U&& u, V&& v ) {
      return add( std::move(key), Value( std::move(t), std::move(u), std::move(v) ) );
    }
    template < typename T, typename U, typename V, typename W >
    Properties& emplace( Key&& key, T&& t, U&& u, V&& v, W&& w ) {
      return add( std::move(key), Value( std::move(t), std::move(u), std::move(v), std::move(w) ) );
    }
  #endif // THREE_HAS_VARIADIC_TEMPLATES
  
    THREE_EXPLICIT operator bool() const {
      return contents.size() > 0;
    }
    size_t size() const {
      return contents.size();
    }
    bool empty() const {
      return contents.empty();
    }
  
    inline bool contains( const Key& key ) const {
      return contents.find( key ) != contents.end();
    }
  
    template < typename T >
    inline bool contains( const T& key ) const {
      return contains( Key(key) );
    }
  
    Value& operator[]( const char* key ) {
      return contents[Key(key)];
    }
    Value& operator[]( const Key& key ) {
      return contents[key];
    }
  
    const Value* get( const Key& key ) const {
      auto it = contents.find( key );
      return it == contents.end() ? nullptr : &it->second;
    }
  
    Value* get( const Key& key ) {
      auto it = contents.find( key );
      return it == contents.end() ? nullptr : &it->second;
    }
  
    typename MapType::iterator       find( const Key& key ) {
      return contents.find( key );
    }
    typename MapType::const_iterator find( const Key& key ) const {
      return contents.find( key );
    }
    typename MapType::iterator       begin()       {
      return contents.begin();
    }
    typename MapType::const_iterator begin() const {
      return contents.cbegin();
    }
    typename MapType::iterator       end()         {
      return contents.end();
    }
    typename MapType::const_iterator end() const   {
      return contents.cend();
    }
  
    MapType contents;
  
  private:
  
    Properties& swap( Properties& other ) {
      std::swap( contents, other.contents );
      return *this;
    }
  
  };
  
  } // namespace three
  
  #endif // THREE_PROPERTIES_H