Index: kernel/include/IMP/base_types.h =================================================================== --- kernel/include/IMP/base_types.h (revision 537) +++ kernel/include/IMP/base_types.h (working copy) @@ -10,11 +10,11 @@ #include "IMP_config.h" #include "Index.h" -#include "internal/Vector.h" +#include "Key.h" #include -#include #include +#include namespace IMP { @@ -74,48 +74,6 @@ typedef std::vector ParticleIndexes; -template class Key; - - -/* - - NOTE: for stupid and obscure C++-related reasons, the key - declarations must go here. - - In detail, the index function declarations must appear before the data() - function which uses them. - - */ - -/** - Define a new key type. There must be an accompanying IMP_DEFINE_KEY_TYPE. - \note This macro should only be used down in this file after the - - \param[in] Name The name for the new type. - \param[in] Tag A class which is unique for this type. For attributes - use the type of the attributes. For other Keys, declare an empty - class with a unique name and use it. - */ -#define IMP_DECLARE_KEY_TYPE(Name, Tag) \ - typedef Key Name; \ - namespace internal { \ - IMPDLLEXPORT extern unsigned int next_attribute_table_index_; \ - IMPDLLEXPORT extern const unsigned int Name##_attribute_table_index_; \ - inline unsigned int attribute_table_index(Tag) { \ - return Name##_attribute_table_index_; \ - } \ - } \ - typedef std::vector Name##s; - -/** - Declare static data necessary for a new key type. - */ -#define IMP_DEFINE_KEY_TYPE(Name, Tag) \ - namespace internal { \ - const unsigned int \ - Name##_attribute_table_index_=next_attribute_table_index_++; \ - } - class Particle; //! The type used to identify float attributes in the Particles @@ -125,21 +83,9 @@ //! The type used to identify string attributes in the Particles IMP_DECLARE_KEY_TYPE(StringKey, String); //! The type used to identify a particle attribute in the Particles -IMP_DECLARE_KEY_TYPE(ParticleKey, Particle*) +IMP_DECLARE_KEY_TYPE(ParticleKey, Particle*); - -struct AtomTypeTag{}; -struct ResidueTypeTag{}; - -//! The type used to identify atom types -IMP_DECLARE_KEY_TYPE(AtomType, AtomTypeTag); -//! The type used to identify residue types -IMP_DECLARE_KEY_TYPE(ResidueType, ResidueTypeTag); - - - } // namespace IMP -#include "Key.h" #endif /* __IMP_BASE_TYPES_H */ Index: kernel/include/IMP/decorators/AtomDecorator.h =================================================================== --- kernel/include/IMP/decorators/AtomDecorator.h (revision 537) +++ kernel/include/IMP/decorators/AtomDecorator.h (working copy) @@ -8,18 +8,22 @@ #ifndef __IMP_ATOM_DECORATOR_H #define __IMP_ATOM_DECORATOR_H -#include -#include - +#include "../base_types.h" #include "../Particle.h" #include "../Model.h" #include "utility.h" #include "XYZDecorator.h" +#include +#include + namespace IMP { +struct AtomTypeTag{}; +IMP_DECLARE_KEY_TYPE(AtomType, AtomTypeTag); + //! A decorator for a particle representing an atom. /** At some point the Types and elements need to be expanded to be more complete. Index: kernel/include/IMP/decorators/ResidueDecorator.h =================================================================== --- kernel/include/IMP/decorators/ResidueDecorator.h (revision 537) +++ kernel/include/IMP/decorators/ResidueDecorator.h (working copy) @@ -8,6 +8,7 @@ #ifndef __IMP_RESIDUE_DECORATOR_H #define __IMP_RESIDUE_DECORATOR_H +#include "../base_types.h" #include "../Particle.h" #include "../Model.h" #include "../DecoratorBase.h" @@ -16,7 +17,10 @@ namespace IMP { +struct ResidueTypeTag{}; +IMP_DECLARE_KEY_TYPE(ResidueType, ResidueTypeTag); + //! A decorator for a residue. /** As with the AtomDecorator, the types of residues may been to be expanded Index: kernel/include/IMP/internal/AttributeTable.h =================================================================== --- kernel/include/IMP/internal/AttributeTable.h (revision 537) +++ kernel/include/IMP/internal/AttributeTable.h (working copy) @@ -14,6 +14,7 @@ #include #include +#include #include @@ -32,19 +33,59 @@ template class AttributeTable { + typedef AttributeTable This; struct Bin { bool first; VT second; Bin(): first(false){} }; - typedef AttributeTable This; - typedef std::vector Map; + typedef boost::scoped_array Map; Map map_; + unsigned int size_; + + void copy_from(unsigned int len, const Map &o) { + IMP_assert(map_, "Internal error in attribute table"); + IMP_assert(size_ >= len, "Table too small"); + //std::cout << "Copy from " << o << " to " << map_ << std::endl; + for (unsigned int i=0; i< len; ++i) { + map_[i]= o[i]; + } + } + + void realloc(unsigned int olen, const Map &o, unsigned int nlen) { + //std::cout << "Realloc from " << size_ << " " << map_ << " "; + if (nlen==0) { + size_=0; + map_.reset(); + } else { + size_=std::max(nlen, 6U); + map_.reset(new Bin[size_]); + copy_from(olen, o); + } + //std::cout << " to " << size_ << " " << map_ << std::endl; + } + public: typedef VT Value; typedef Key Key; - AttributeTable() {} + AttributeTable(): size_(0){} + AttributeTable(const This &o): size_(0) { + //std::cout << "Copy constructor called from " << o.map_ << std::endl; + realloc(o.size_, o.map_, o.size_); + } + ~AttributeTable(){ + //std::cout << "Deleting " << map_ << std::endl; + } + This &operator=(const This &o) { + //std::cout << "Operator= called from " << o.map_ << std::endl; + if (&o == this) { + //std::cout << "Self assignment" << std::endl; + return *this; + } + realloc(o.size_, o.map_, o.size_); + return *this; + } const Value get_value(Key k) const { IMP_assert(contains(k), "Attribute \"" << k.get_string() @@ -52,19 +93,28 @@ return map_[k.get_index()].second; } + Value& get_value(Key k) { IMP_assert(contains(k), "Attribute \"" << k.get_string() << "\" not found in table."); return map_[k.get_index()].second; } + + void insert(Key k, Value v); + + bool contains(Key k) const { IMP_assert(k != Key(), "Can't search for default key"); - return k.get_index() < map_.size() + return k.get_index() < size_ && map_[k.get_index()].first; } + + void show(std::ostream &out, const char *prefix="") const; + + std::vector get_keys() const; class IsAttribute @@ -85,15 +135,19 @@ AttributeKeyIterator attribute_keys_begin() const { return AttributeKeyIterator(IsAttribute(this), KeyIterator(Key(0U)), - KeyIterator(Key(map_.size()))); + KeyIterator(Key(size_))); } AttributeKeyIterator attribute_keys_end() const { return AttributeKeyIterator(IsAttribute(this), - KeyIterator(Key(map_.size())), - KeyIterator(Key(map_.size()))); + KeyIterator(Key(size_)), + KeyIterator(Key(size_))); } + unsigned int get_heap_memory_usage() const { + return size_*sizeof(Bin); + } + }; IMP_OUTPUT_OPERATOR_2(AttributeTable) @@ -104,10 +158,14 @@ template inline void AttributeTable::insert(Key k, Value v) { + /*std::cout << "Insert " << k << " in v of size " + << size_ << " " << map_ << " " << k.get_index() << std::endl;*/ IMP_assert(k != Key(), "Can't insert default key"); - if (map_.size() <= k.get_index()) { - map_.resize(k.get_index()+1); + if (size_ <= k.get_index()) { + boost::scoped_array old; + swap(old, map_); + realloc(size_, old, k.get_index()+1); } IMP_assert(!map_[k.get_index()].first, "Trying to add attribute \"" << k.get_string() @@ -122,7 +180,7 @@ inline void AttributeTable::show(std::ostream &out, const char *prefix) const { - for (unsigned int i=0; i< map_.size(); ++i) { + for (unsigned int i=0; i< size_; ++i) { if (map_[i].first) { out << prefix; out << Key(i).get_string() << ": "; @@ -139,43 +197,6 @@ { std::vector ret(attribute_keys_begin(), attribute_keys_end()); return ret; -} - -inline void show_attributes(std::ostream &out) -{ - if (attribute_key_data.size() < attribute_table_index(Float())) { - out << "Float attributes are "; - for (unsigned int i=0; - i< attribute_key_data[attribute_table_index(Float())].rmap.size(); - ++i) { - out << "\"" - << attribute_key_data[attribute_table_index(Float())].rmap[i] - << "\" "; - } - out << std::endl; - } - if (attribute_key_data.size() < attribute_table_index(Int())) { - out << "Int attributes are "; - for (unsigned int i=0; - i< attribute_key_data[attribute_table_index(Int())].rmap.size(); - ++i) { - out << "\"" - << attribute_key_data[attribute_table_index(Int())].rmap[i] - << "\" "; - } - } - if (attribute_key_data.size() < attribute_table_index(String())) { - out << "String attributes are "; - for (unsigned int i=0; - i< attribute_key_data[attribute_table_index(String())].rmap.size(); - ++i) { - out << "\"" - << attribute_key_data[attribute_table_index(String())].rmap[i] - << "\" "; - } - out << std::endl; - } - } Index: kernel/include/IMP/Key.h =================================================================== --- kernel/include/IMP/Key.h (revision 537) +++ kernel/include/IMP/Key.h (working copy) @@ -8,47 +8,116 @@ #ifndef __IMP_KEY_H #define __IMP_KEY_H +#include "macros.h" +#include "exception.h" + #include #include -#include "base_types.h" -#include "utility.h" -#include "log.h" +/** + \internal + \page keys How Keys work in IMP + The keys in IMP maintain a cached mapping between strings and indexes. + This mapping is global--that is all IMP Models and Particles in the + same program use the same mapping. + + The mapping uses a static table which is defined with the + IMP_DEFINE_KEY_TYPE macro. As a result, the macro must be used in exactly + one .o. If it appears more than once or that .o is linked in multiple times, + then bad things can happen. + + Since the order of initialization of static data is undefined + between .os, it is important that no other static data not in the + same .o uses the key data. Specifically, typedes defined by + IMP_DECLARE_KEY_TYPE should never be statically initialized. While + this is annoying, statically initializing them would be bad + practice anyway, as unused attribute keys would still be mapped to + indices and would make the set of indices less dense. + */ + +// Swig chokes on the specialization +#ifndef SWIG +//! \internal +#define IMP_KEY_DATA_HOLDER(Name, Tag) \ + namespace internal { \ + template <> \ + struct IMPDLLEXPORT KeyDataHolder { \ + static KeyData data; \ + }; \ + } +#else +#define IMP_KEY_DATA_HOLDER(Name, Tag) +#endif + + +/** + Define a new key type. There must be an accompanying IMP_DEFINE_KEY_TYPE + located in some .o file. This macro should be used in the IMP namespace. + + It defines two public types Name, which is an instantiation of Key and + Names which is a vector of Name. + + \param[in] Name The name for the new type. + \param[in] Tag A class which is unique for this type. For attributes + use the type of the attributes. For other Keys, declare an empty + class with a unique name and use it. + */ +#define IMP_DECLARE_KEY_TYPE(Name, Tag) \ + IMP_KEY_DATA_HOLDER(Name, Tag); \ + typedef Key Name; \ + typedef std::vector Name##s + + +/** This must occur in exactly one .o in the internal namespace. Should + be used in the IMP namespace.*/ +#define IMP_DEFINE_KEY_TYPE(Name, Tag) \ + namespace internal { \ + KeyData KeyDataHolder::data; \ + } + + namespace IMP { - namespace internal { -#define IMP_KEY_INITIALIZATION_HEURISTIC 1234678 +/** The data concerning a particular type of key. + \internal + */ +struct IMPDLLEXPORT KeyData { + typedef std::map Map; + typedef std::vector RMap; -/** This is a hack to try to catch people to initialize keys - before the cache table is initialized. Keys should be - initialized in code that is called after main starts. + void show(std::ostream &out= std::cout) const; + KeyData(); + void assert_is_initialized() const; + unsigned int add_key(std::string str) { + unsigned int i= map_.size(); + map_[str]=i; + rmap_.push_back(str); + return i; + } - This symbol is initialized in the same translation unit as - the tables and so is unlikely to have the above value unless - the tables have been initialized. -*/ -IMPDLLEXPORT extern double key_initialization_heuristic; + const Map &get_map() const {return map_;} + const RMap &get_rmap() const {return rmap_;} -struct KeyData -{ - std::map map; - std::vector rmap; +private: + double heuristic_; + Map map_; + RMap rmap_; + }; -IMPDLLEXPORT extern unsigned int next_attribute_table_index_; +/** A dummy class. Actual keys types create specializations + \internal +*/ +template +struct KeyDataHolder {}; -// print a list of attributes used so far by the program -void IMPDLLEXPORT show_attributes(std::ostream &out); - -extern IMPDLLEXPORT std::vector attribute_key_data; - } // namespace internal @@ -69,42 +138,32 @@ typedef T Type; - static internal::KeyData& data(); - bool is_default() const; + static const internal::KeyData::Map& get_map(); + static const internal::KeyData::RMap& get_rmap(); + public: static const std::string &get_string(int i); typedef Key This; //! make a default (uninitalized) key - Key():str_(-1) {} + Key(): str_(-1) {} //! Generate a key from the given string Key(const char *c) { - IMP_assert(internal::key_initialization_heuristic - == IMP_KEY_INITIALIZATION_HEURISTIC, - "Do not initialize keys statically. This can cause" - << " serious problems due to the initialization order" - << " among translation units being undefined."); std::string sc(c); - if (data().map.find(sc) == data().map.end()) { - - int sz= data().map.size(); - data().map[sc]=sz; - data().rmap.push_back(sc); - str_= sz; - IMP_assert(data().rmap.size() == data().map.size(), "Unequal map sizes"); + if (get_map().find(sc) == get_map().end()) { + str_= internal::KeyDataHolder::data.add_key(sc); } else { - str_= data().map.find(sc)->second; - } - //str_=c; - }; + str_= get_map().find(sc)->second; + } + } explicit Key(unsigned int i): str_(i) { - //IMP_assert(data().rmap.size() > i, "There is no such attribute " << i); + //IMP_assert(get_rmap().size() > i, "There is no such attribute " << i); } //! Turn a key into a pretty string @@ -133,7 +192,7 @@ /** This can be used to check for typos and similar keys. */ - static std::vector get_all_strings(); + static std::vector get_all_strings(); //! Get the total number of keys of this type /** @@ -141,7 +200,7 @@ keys created. */ static unsigned int get_number_unique() { - return data().map.size(); + return get_map().size(); } #ifndef SWIG @@ -167,16 +226,18 @@ template -inline internal::KeyData& Key::data() +inline const internal::KeyData::Map& Key::get_map() { - unsigned int i= internal::attribute_table_index(T()); - if ( internal::attribute_key_data.size() <= i) { - internal::attribute_key_data.resize(i+1); - } - return internal::attribute_key_data[i]; + return internal::KeyDataHolder::data.get_map(); } template +inline const internal::KeyData::RMap& Key::get_rmap() +{ + return internal::KeyDataHolder::data.get_rmap(); +} + +template inline bool Key::is_default() const { return str_==-1; @@ -186,30 +247,25 @@ inline const std::string &Key::get_string(int i) { IMP_assert(static_cast(i) - < data().rmap.size(), + < get_rmap().size(), "Corrupted " << " Key " << i - << " vs " << data().rmap.size()); - return data().rmap[i]; + << " vs " << get_rmap().size()); + return get_rmap()[i]; } template inline void Key::show_all(std::ostream &out) { - const internal::KeyData &d= data(); - for (std::map::const_iterator it= d.map.begin(); - it != d.map.end(); ++it) { - out << "\"" << it->first << "\" "; - } + internal::KeyDataHolder::data.show(out); } template -std::vector Key::get_all_strings() +std::vector Key::get_all_strings() { - std::vector str; - const internal::KeyData &d= data(); - for (std::map::const_iterator it= d.map.begin(); - it != d.map.end(); ++it) { + std::vector str; + for (internal::KeyData::Map::const_iterator it= get_map().begin(); + it != get_map().end(); ++it) { str.push_back(it->first); } return str; Index: kernel/include/IMP/Index.h =================================================================== --- kernel/include/IMP/Index.h (revision 537) +++ kernel/include/IMP/Index.h (working copy) @@ -8,8 +8,8 @@ #ifndef __IMP_INDEX_H #define __IMP_INDEX_H -#include "log.h" -#include "utility.h" +#include "macros.h" +#include "exception.h" namespace IMP { Index: kernel/include/IMP/macros.h =================================================================== --- kernel/include/IMP/macros.h (revision 537) +++ kernel/include/IMP/macros.h (working copy) @@ -291,8 +291,6 @@ \param[in] Ucname The name of the type in uppercase \param[in] lcname The name of the type in lower case \param[in] Data The type of the data to store. - \param[in] Onchanged Code to get executed every time the container - changes \note the type Ucnames must be declared and be a vector of Data. @@ -378,6 +376,7 @@ IMP_CONTAINER. \param[in] init Code to modify the passed in object. The object is obj its index index. + \param[in] onchanged Code to execute when the container is changed. \param[in] onremove Code to execute when an object is removed. The object being removed is obj. */ Index: kernel/src/base_types.cpp =================================================================== --- kernel/src/base_types.cpp (revision 537) +++ kernel/src/base_types.cpp (working copy) @@ -10,30 +10,9 @@ namespace IMP { -namespace internal -{ - -struct InitCheck -{ - InitCheck() { - std::cout << "Initializing attribute table." << std::endl; - key_initialization_heuristic = IMP_KEY_INITIALIZATION_HEURISTIC; - } -}; - -unsigned int next_attribute_table_index_ = 0; -std::vector attribute_key_data; -double key_initialization_heuristic=0; -InitCheck init_check_; - -} // namespace internal - -IMP_DEFINE_KEY_TYPE(IntKey, Int); IMP_DEFINE_KEY_TYPE(FloatKey, Float); +IMP_DEFINE_KEY_TYPE(IntKey, Int); IMP_DEFINE_KEY_TYPE(StringKey, String); -IMP_DEFINE_KEY_TYPE(ParticleKey, Particle); +IMP_DEFINE_KEY_TYPE(ParticleKey, Particle*) -IMP_DEFINE_KEY_TYPE(AtomType, AtomTypeTag); -IMP_DEFINE_KEY_TYPE(ResidueType, ResidueTypeTag); - } // namespace IMP Index: kernel/src/SConscript =================================================================== --- kernel/src/SConscript (revision 537) +++ kernel/src/SConscript (working copy) @@ -20,7 +20,7 @@ files = ['base_types.cpp', 'Model.cpp', 'Particle.cpp', 'ScoreState.cpp', 'OptimizerState.cpp', 'Log.cpp', 'Restraint.cpp', 'Optimizer.cpp', - 'random.cpp' + 'random.cpp', 'Key.cpp' ] + decorators_files + restraints_files + optimizers_files \ + unary_functions_files + pair_scores_files + singleton_scores_files \ + triplet_scores_files + score_states_files + internal_files Index: kernel/src/decorators/AtomDecorator.cpp =================================================================== --- kernel/src/decorators/AtomDecorator.cpp (revision 537) +++ kernel/src/decorators/AtomDecorator.cpp (working copy) @@ -15,8 +15,8 @@ namespace IMP { +IMP_DEFINE_KEY_TYPE(AtomType, AtomTypeTag); - #define TYPE_INIT(STR) AT_##STR= AtomType(#STR); #define TYPE_INIT2(NAME, STR) AT_##NAME = AtomType(#STR); Index: kernel/src/decorators/ResidueDecorator.cpp =================================================================== --- kernel/src/decorators/ResidueDecorator.cpp (revision 537) +++ kernel/src/decorators/ResidueDecorator.cpp (working copy) @@ -5,18 +5,19 @@ * */ -#include -#include - +#include "IMP/base_types.h" #include "IMP/decorators/ResidueDecorator.h" #include "IMP/decorators/AtomDecorator.h" #include "IMP/log.h" +#include +#include + namespace IMP { +IMP_DEFINE_KEY_TYPE(ResidueType, ResidueTypeTag); - IntKey ResidueDecorator::type_key_; IntKey ResidueDecorator::index_key_; Index: kernel/src/Key.cpp =================================================================== --- kernel/src/Key.cpp (revision 0) +++ kernel/src/Key.cpp (revision 0) @@ -0,0 +1,35 @@ +// namespace IMP +/** + * \file Key.cpp \brief Internal workings of keys. + * + * Copyright 2007-8 Sali Lab. All rights reserved. + * + */ + +#include "IMP/Key.h" +#include "IMP/exception.h" + +namespace IMP +{ + +namespace internal +{ + +static double heuristic_value=238471628; + +KeyData::KeyData(): heuristic_(heuristic_value){} + +void KeyData::assert_is_initialized() const { + IMP_assert(heuristic_== heuristic_value, + "Uninitialized KeyData. Do not initialize Keys statically."); +} + +void KeyData::show(std::ostream &out) const { + for (unsigned int i=0; i< rmap_.size(); ++i) { + out << "\"" << rmap_[i] << "\" "; + } +} + +} + +} // namespace IMP Index: kernel/pyext/IMP.i =================================================================== --- kernel/pyext/IMP.i (revision 537) +++ kernel/pyext/IMP.i (working copy) @@ -135,12 +135,12 @@ %feature("director"); +%include "IMP/Key.h" %include "IMP/internal/Object.h" %include "IMP/internal/RefCountedObject.h" %include "IMP/Index.h" %include "IMP/base_types.h" %include "IMP/VersionInfo.h" -%include "IMP/Key.h" %include "IMP/UnaryFunction.h" %include "IMP/unary_functions/Harmonic.h" %include "IMP/unary_functions/HarmonicLowerBound.h" @@ -217,6 +217,7 @@ %template(FloatKey) Key; %template(IntKey) Key; %template(StringKey) Key; + %template(ParticleKey) Key; %template(AtomType) Key; %template(ResidueType) Key; %template(show_named_hierarchy) show; @@ -231,6 +232,7 @@ %template(FloatKeys) ::std::vector; %template(StringKeys) ::std::vector; %template(IntKeys) ::std::vector; + %template(ParticleKeys) ::std::vector; %template(Floats) ::std::vector; %template(Strings) ::std::vector; %template(Ints) ::std::vector;