1 /* 2 * Copyright (C) 2004-2021 Edward F. Valeev 3 * 4 * This file is part of Libint. 5 * 6 * Libint is free software: you can redistribute it and/or modify 7 * it under the terms of the GNU General Public License as published by 8 * the Free Software Foundation, either version 3 of the License, or 9 * (at your option) any later version. 10 * 11 * Libint is distributed in the hope that it will be useful, 12 * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 * GNU General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with Libint. If not, see <http://www.gnu.org/licenses/>. 18 * 19 */ 20 21 #ifndef _libint2_src_bin_libint_singlstack_h_ 22 #define _libint2_src_bin_libint_singlstack_h_ 23 24 #include <map> 25 #include <iostream> 26 #include <smart_ptr.h> 27 #include <key.h> 28 #include <hashable.h> 29 #include <purgeable.h> 30 31 namespace libint2 { 32 33 class RecurrenceRelation; 34 35 /** 36 SingletonStack<T,KeyType> helps to implement Singleton-like objects of type T. 37 SingletonStack maintains a map of keys of type KeyType to 38 smart pointers to objects of type T. Keys are computed from T by 39 calling a callback of type HashingFunction passed to the constructor to SingletonStack -- hence 40 HashingFunction is a member function T which takes no arguments and returns a const KeyType&. 41 */ 42 template <class T, class KeyType> 43 class SingletonStack : public PurgeableStack<T> 44 { 45 public: 46 typedef KeyType key_type; 47 typedef SafePtr<T> data_type; 48 /// Specifies type for the instance index variables 49 typedef KeyTypes::InstanceID InstanceID; 50 typedef std::pair<InstanceID,SafePtr<T> > value_type; 51 typedef std::map<key_type,value_type> map_type; 52 /// use iter_type objects to iterate over the stack 53 typedef typename map_type::iterator iter_type; 54 /// const version of iter_type 55 typedef typename map_type::const_iterator citer_type; 56 /// hashing function returns keys as key_return_type 57 typedef typename KeyTraits<key_type>::ReturnType key_return_type; 58 /// Specifies the type of callback which computes hashes 59 typedef key_return_type (T::* HashingFunction)() const; 60 /// PurgingPolicy determines whether and which objects on this stack are obsolete and can be removed 61 typedef typename PurgeableStack<T>::PurgingPolicy PurgingPolicy; 62 63 64 /// callback to compute hash values is the only parameter SingletonStack(HashingFunction callback)65 SingletonStack(HashingFunction callback) : 66 map_(), callback_(callback), next_instance_(0) 67 { 68 if (PurgingPolicy::purgeable()) { // if this stack contains objects that can be purged, add to the registry 69 PurgeableStacks::Instance()->register_stack(this); 70 } 71 } 72 ~SingletonStack()73 virtual ~SingletonStack() {} 74 75 /** Returns the pointer to the unique instance of object obj. 76 find() computes obj->*callback_(), searches it in hstack_, 77 if found -- returns the pointer to the corresponding object on ostack_, 78 otherwise pushes obj to the end of ostack_ and returns obj. 79 */ find(const SafePtr<T> & obj)80 const value_type& find(const SafePtr<T>& obj) { 81 key_type key = ((obj.get())->*callback_)(); 82 83 typedef typename map_type::iterator miter; 84 miter pos = map_.find(key); 85 if (pos != map_.end()) { 86 #if DEBUG || LOCAL_DEBUG 87 std::cout << "SingletonStack::find -- " << obj->label() << " already found" << std::endl; 88 #endif 89 return (*pos).second; 90 } 91 else { 92 value_type result(next_instance_++,obj); 93 map_[key] = result; 94 #if DEBUG || LOCAL_DEBUG 95 std::cout << "SingletonStack::find -- " << obj->label() << " is new (instid_ = " << next_instance_-1 << ")" << std::endl; 96 #endif 97 return map_[key]; 98 } 99 } 100 101 /** Returns the pointer to the unique instance of object corresponding to key. 102 if found returns the pointer to the corresponding object on ostack_, 103 else returns a null value_type. 104 */ find(const key_type & key)105 const value_type& find(const key_type& key) { 106 static value_type null_value(make_pair(InstanceID(0),SafePtr<T>())); 107 typedef typename map_type::iterator miter; 108 miter pos = map_.find(key); 109 if (pos != map_.end()) { 110 return (*pos).second; 111 } 112 else { 113 return null_value; 114 } 115 } 116 117 /** Returns the pointer to the unique instance of object corresponding to the hashed_key. 118 if found returns the pointer to the corresponding object on ostack_, 119 else returns a null value_type. 120 */ find_hashed(const InstanceID & hashed_key)121 const value_type& find_hashed(const InstanceID& hashed_key) const { 122 static value_type null_value(make_pair(InstanceID(0),SafePtr<T>())); 123 for(auto& i: map_) { 124 if (i.second.first == hashed_key) 125 return i.second; 126 } 127 return null_value; 128 } 129 130 /** Searches for obj on the stack and, if found, removes the unique instance 131 */ remove(const SafePtr<T> & obj)132 void remove(const SafePtr<T>& obj) { 133 key_type key = ((obj.get())->*callback_)(); 134 135 typedef typename map_type::iterator miter; 136 miter pos = map_.find(key); 137 if (pos != map_.end()) { 138 map_.erase(pos); 139 #if DEBUG || LOCAL_DEBUG 140 std::cout << "Removed from stack " << obj->label() << std::endl; 141 #endif 142 } 143 } 144 145 /** Returns iterator to the beginning of the stack */ begin()146 citer_type begin() const { return map_.begin(); } 147 /** Returns iterator to the end of the stack */ end()148 citer_type end() const { return map_.end(); } 149 150 // Implementation of PurgeableStack::purge() purge()151 void purge() override { 152 for(iter_type i = map_.begin(); i!=map_.end();) { 153 const T* v = i->second.second.get(); 154 if (PurgingPolicy::purge(v)) 155 // map::erase invalidates the iterator, increment it beforehand 156 map_.erase(i++); 157 else 158 ++i; 159 } 160 } 161 162 private: 163 map_type map_; 164 HashingFunction callback_; 165 InstanceID next_instance_; 166 }; 167 168 }; 169 170 #endif 171