// Copyright (c) 2005-2007 Andre Merzky (andre@merzky.net) // Copyright (c) 2005-2007 Hartmut Kaiser (hartmut.kaiser@gmail.com) // // Use, modification and distribution is subject to the Boost Software // License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at // http://www.boost.org/LICENSE_1_0.txt) #include #include #include #include #include #include #include ///////////////////////////////////////////////////////////////// namespace { inline std::string escape (const std::string & in) { std::string out = in; // FIXME: escape !! return (out); } inline std::string unescape (const std::string & in) { std::string out = in; // FIXME: unescape !! return (out); } inline std::vector attrib_split (const std::string & in) { std::vector out; out.push_back (in); // FIXME: unescape !! return (out); } inline std::string concat (const std::vector & in) { std::vector ::const_iterator i = in.begin (); // get first entry std::string out (*i); ++i; for ( ; i != in.end(); ++i ) { out += ", " + escape (*i); } return (out); } } ///////////////////////////////////////////////////////////////// namespace saga { namespace impl { ///////////////////////////////////////////////////////////////// attrib::attrib (type type, bool ro, bool ext) : key_ ("") , type_ (type) , ro_ (ro) , ext_ (ext) { val_ = attrib_split (std::string ("")); } attrib::attrib (const std::string & key, const std::string & val, type type, bool ro, bool ext) : key_ (key) , type_ (type) , ro_ (ro) , ext_ (ext) { val_ = attrib_split (val); } attrib::attrib (const std::string & key, const std::vector & val, type type, bool ro, bool ext) : key_ (key) , val_ (val) , type_ (type) , ro_ (ro) , ext_ (ext) { } bool attrib::is_ro (void) const { return (ro_); } bool attrib::is_ext (void) const { return (ext_); } bool attrib::is_vec (void) const { return ( Vector == type_); } std::string attrib::key (void) const { return (key_); } std::string attrib::val_s (void) const { return (concat (val_)); } std::vector attrib::val_v (void) const { return (val_); } void attrib::val (const std::string & val) { std::vector new_val; new_val.push_back (val); val_ = new_val; } void attrib::val (const std::vector & val) { val_ = val; } bool operator==(attrib const& lhs, attrib const& rhs) { return true; } ///////////////////////////////////////////////////////////////// attribute_cache::attribute_cache (void) : inited_ (false), extensible_ (false) { } // copy constructor attribute_cache::attribute_cache (attribute_cache const& rhs) : a_map_(rhs.a_map_), keynames_(rhs.keynames_), inited_(rhs.inited_), extensible_(rhs.extensible_) { } bool attribute_cache::is_valid_key(std::string const& key) const { if (extensible_) return true; // all key's are allowed for extensible attribute strvec_type::const_iterator end = keynames_.end(); for (strvec_type::const_iterator it = keynames_.begin(); it != end; ++it) { if (*it == key) return true; // allowed key } return false; // key is not allowed for this object } void attribute_cache::init (bool extensible) { extensible_ = extensible; } void attribute_cache::init (strmap_type const& ro_scalar, strmap_type const& rw_scalar, strmap_type const& ro_vector, strmap_type const& rw_vector) { strmap_type::const_iterator i; for ( i = ro_scalar.begin () ; i != ro_scalar.end (); ++i ) { if (!is_valid_key(i->first)) { SAGA_THROW("attribute '" + i->first + "' is not valid for " "this object", saga::DoesNotExist); } a_map_[i->first] = attrib (i->first, i->second, saga::impl::attrib::Scalar, true); } for ( i = rw_scalar.begin () ; i != rw_scalar.end (); ++i ) { if (!is_valid_key(i->first)) { SAGA_THROW("attribute '" + i->first + "' is not valid for " "this object", saga::DoesNotExist); } a_map_[i->first] = attrib (i->first, i->second, saga::impl::attrib::Scalar, false); } for ( i = ro_vector.begin () ; i != ro_vector.end (); ++i ) { if (!is_valid_key(i->first)) { SAGA_THROW("attribute '" + i->first + "' is not valid for " "this object", saga::DoesNotExist); } a_map_[i->first] = attrib (i->first, i->second, saga::impl::attrib::Vector, true); } for ( i = rw_vector.begin () ; i != rw_vector.end (); ++i ) { if (!is_valid_key(i->first)) { SAGA_THROW("attribute '" + i->first + "' is not valid for " "this object", saga::DoesNotExist); } a_map_[i->first] = attrib (i->first, i->second, saga::impl::attrib::Vector, false); } inited_ = true; } void attribute_cache::init_keynames(strvec_type const& keynames) { keynames_ = keynames; if (inited_ && !extensible_) { // go over existing attrib's and check for their validity a_map_type::const_iterator end = a_map_.end(); for (a_map_type::const_iterator it = a_map_.begin(); it != end; ++it) { if (!is_valid_key(it->first)) { SAGA_THROW("attribute '" + it->first + "' is not valid " "for this object", saga::DoesNotExist); } } } } ///////////////////////////////////////////////////////////////// void attribute_cache::set_attribute (const std::string & key, const std::string & val) { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key) && !extensible_) { SAGA_THROW("attribute '" + key + "' does not exist, and cannot be " "created (is not valid for this object)", saga::DoesNotExist); } a_map_type :: iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // does not exist, and need to be created a_map_[key] = attrib (key, val, saga::impl::attrib::Scalar, false, true); } else { // exists and can be changed ai->second.val (val); } } ///////////////////////////////////////////////////////////////// std::string attribute_cache::get_attribute (const std::string & key) const { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } // return val as scalar return (ai->second.val_s ()); } ///////////////////////////////////////////////////////////////// void attribute_cache::set_vector_attribute (std::string const& key, strvec_type const& val) { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key) && !extensible_) { SAGA_THROW("attribute '" + key + "' does not exist, and cannot be " "created (is not valid for this object)", saga::DoesNotExist); } a_map_type :: iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // does not exist, and need to be created a_map_[key] = attrib (key, val, saga::impl::attrib::Vector, false, true); } else { // exists and can be changed ai->second.val (val); } } ///////////////////////////////////////////////////////////////// // set/get vector attribute attribute_cache::strvec_type attribute_cache::get_vector_attribute (const std::string & key) const { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } // return val as vector return (ai->second.val_v ()); } ///////////////////////////////////////////////////////////////// void attribute_cache::remove_attribute (const std::string & key) { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } // exists and can be removed: a_map_.erase (key); } ///////////////////////////////////////////////////////////////// // list attribute struct string_appender { typedef attribute_cache::a_map_type::value_type value_type; typedef attribute_cache::strvec_type strvec_type; string_appender(strvec_type& v) : v_(v) {} void operator()(value_type v) { v_.push_back(v.first); } strvec_type& v_; }; attribute_cache::strvec_type attribute_cache::list_attributes (void) const { mutex_type::scoped_lock lock(mtx_); strvec_type keys; std::copy(a_map_.begin(), a_map_.end(), boost::make_function_output_iterator(string_appender(keys))); return keys; } ///////////////////////////////////////////////////////////////// attribute_cache::strvec_type attribute_cache::find_attributes (const std::string &pattern) const { // FIXME: implement return (list_attributes ()); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attribute_exists (const std::string & key ) const { mutex_type::scoped_lock lock(mtx_); // FIXME: should we report an error for invalid keys here? // if (!is_valid_key(key)) // { // SAGA_THROW("attribute '" + key + "' is not valid for " // "this object", saga::DoesNotExist); // } return a_map_.end() != a_map_.find (key); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attribute_is_readonly (const std::string & key ) const { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } return ai->second.is_ro(); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attribute_is_writable (const std::string & key ) const { return ( ! attribute_is_readonly (key) ); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attribute_is_vector (const std::string & key ) const { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } return ai->second.is_vec (); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attribute_is_extended (const std::string & key ) const { mutex_type::scoped_lock lock(mtx_); if (!is_valid_key(key)) { SAGA_THROW("attribute '" + key + "' is not valid for " "this object", saga::DoesNotExist); } a_map_type :: const_iterator ai = a_map_.find (key); if ( a_map_.end () == ai ) { // DoesNotExist SAGA_THROW("attribute '" + key + "' does not exist", saga::DoesNotExist); } return ai->second.is_ext (); } ///////////////////////////////////////////////////////////////// bool attribute_cache::attributes_extensible (void) const { return (extensible_); } /////////////////////////////////////////////////////////////////////////// attribute_cache attribute_cache::clone() const { mutex_type::scoped_lock lock(mtx_); return *this; } bool attribute_cache::is_equal(attribute_cache const& rhs) const { mutex_type::scoped_lock lock(mtx_); return a_map_ == rhs.a_map_ && keynames_ == rhs.keynames_ && extensible_ == rhs.extensible_; } } // namespace impl } // namespace saga