| alpar@906 |      1 | /* -*- C++ -*-
 | 
| alpar@906 |      2 |  *
 | 
| alpar@1956 |      3 |  * This file is a part of LEMON, a generic C++ optimization library
 | 
| alpar@1956 |      4 |  *
 | 
| alpar@1956 |      5 |  * Copyright (C) 2003-2006
 | 
| alpar@1956 |      6 |  * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
 | 
| alpar@1956 |      7 |  * (Egervary Research Group on Combinatorial Optimization, EGRES).
 | 
| alpar@906 |      8 |  *
 | 
| alpar@906 |      9 |  * Permission to use, modify and distribute this software is granted
 | 
| alpar@906 |     10 |  * provided that this copyright notice appears in all copies. For
 | 
| alpar@906 |     11 |  * precise terms see the accompanying LICENSE file.
 | 
| alpar@906 |     12 |  *
 | 
| alpar@906 |     13 |  * This software is provided "AS IS" with no warranty of any kind,
 | 
| alpar@906 |     14 |  * express or implied, and with no claim as to its suitability for any
 | 
| alpar@906 |     15 |  * purpose.
 | 
| alpar@906 |     16 |  *
 | 
| alpar@906 |     17 |  */
 | 
| alpar@906 |     18 | 
 | 
| alpar@921 |     19 | #ifndef LEMON_ARRAY_MAP_H
 | 
| alpar@921 |     20 | #define LEMON_ARRAY_MAP_H
 | 
| deba@822 |     21 | 
 | 
| deba@822 |     22 | #include <memory>
 | 
| deba@1810 |     23 | #include <lemon/bits/map_extender.h>
 | 
| deba@1813 |     24 | #include <lemon/bits/alteration_notifier.h>
 | 
| deba@1669 |     25 | #include <lemon/concept_check.h>
 | 
| deba@1669 |     26 | #include <lemon/concept/maps.h>
 | 
| deba@822 |     27 | 
 | 
| alpar@1946 |     28 | /// \ingroup graphmapfactory
 | 
| deba@1669 |     29 | /// \file
 | 
| deba@1669 |     30 | /// \brief Graph maps that construct and destruct
 | 
| deba@1669 |     31 | /// their elements dynamically.
 | 
| deba@822 |     32 | 
 | 
| alpar@921 |     33 | namespace lemon {
 | 
| deba@822 |     34 | 
 | 
| alpar@1946 |     35 |   /// \ingroup graphmapfactory
 | 
| deba@1669 |     36 |   ///
 | 
| deba@1669 |     37 |   /// \brief Graph map based on the array storage.
 | 
| deba@1669 |     38 |   ///
 | 
| deba@1414 |     39 |   /// The ArrayMap template class is graph map structure what
 | 
| deba@1910 |     40 |   /// automatically indates the map when a key is added to or erased from
 | 
| deba@1669 |     41 |   /// the map. This map uses the allocators to implement 
 | 
| deba@1414 |     42 |   /// the container functionality.
 | 
| deba@1414 |     43 |   ///
 | 
| deba@1414 |     44 |   /// The template parameter is the AlterationNotifier that the maps
 | 
| deba@1414 |     45 |   /// will belong to and the Value.
 | 
| deba@822 |     46 | 
 | 
| klao@946 |     47 |   template <typename _Graph, 
 | 
| klao@946 |     48 | 	    typename _Item,
 | 
| klao@946 |     49 | 	    typename _Value>
 | 
| deba@1039 |     50 |   class ArrayMap : public AlterationNotifier<_Item>::ObserverBase {
 | 
| deba@897 |     51 | 
 | 
| deba@1267 |     52 |     typedef _Item Item;
 | 
| deba@822 |     53 |   public:
 | 
| deba@822 |     54 |     /// The graph type of the maps. 
 | 
| klao@946 |     55 |     typedef _Graph Graph;
 | 
| deba@1719 |     56 |     /// The reference map tag.
 | 
| deba@1719 |     57 |     typedef True ReferenceMapTag;
 | 
| deba@1719 |     58 | 
 | 
| deba@822 |     59 |     /// The key type of the maps.
 | 
| alpar@987 |     60 |     typedef _Item Key;
 | 
| deba@1719 |     61 |     /// The value type of the map.
 | 
| deba@1719 |     62 |     typedef _Value Value;
 | 
| deba@1719 |     63 |     /// The const reference type of the map.
 | 
| deba@1719 |     64 |     typedef const _Value& ConstReference;
 | 
| deba@1719 |     65 |     /// The reference type of the map.
 | 
| deba@1719 |     66 |     typedef _Value& Reference;
 | 
| deba@1719 |     67 | 
 | 
| deba@1719 |     68 |     typedef const Value ConstValue;
 | 
| deba@1719 |     69 |     typedef Value* Pointer;
 | 
| deba@1719 |     70 |     typedef const Value* ConstPointer;
 | 
| klao@946 |     71 | 
 | 
| deba@1039 |     72 |     typedef AlterationNotifier<_Item> Registry;
 | 
| klao@946 |     73 | 
 | 
| deba@822 |     74 |     /// The MapBase of the Map which imlements the core regisitry function.
 | 
| klao@946 |     75 |     typedef typename Registry::ObserverBase Parent;
 | 
| deba@822 |     76 | 		
 | 
| deba@822 |     77 | 
 | 
| deba@822 |     78 | 
 | 
| klao@946 |     79 |   private:
 | 
| deba@822 |     80 |     typedef std::allocator<Value> Allocator;
 | 
| deba@822 |     81 | 
 | 
| klao@946 |     82 | 
 | 
| klao@946 |     83 |   public:
 | 
| klao@946 |     84 | 
 | 
| deba@1719 |     85 |     /// \brief Graph initialized map constructor.
 | 
| deba@1703 |     86 |     ///
 | 
| deba@1719 |     87 |     /// Graph initialized map constructor.
 | 
| deba@980 |     88 |     ArrayMap(const Graph& _g) : graph(&_g) {
 | 
| deba@1267 |     89 |       Item it;
 | 
| deba@1267 |     90 |       attach(_g.getNotifier(Item()));
 | 
| deba@822 |     91 |       allocate_memory();
 | 
| deba@1267 |     92 |       for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@980 |     93 | 	int id = graph->id(it);;
 | 
| deba@822 |     94 | 	allocator.construct(&(values[id]), Value());
 | 
| deba@822 |     95 |       }								
 | 
| deba@822 |     96 |     }
 | 
| deba@822 |     97 | 
 | 
| deba@1703 |     98 |     /// \brief Constructor to use default value to initialize the map. 
 | 
| deba@1703 |     99 |     ///
 | 
| deba@1703 |    100 |     /// It constructs a map and initialize all of the the map. 
 | 
| deba@980 |    101 |     ArrayMap(const Graph& _g, const Value& _v) : graph(&_g) {
 | 
| deba@1267 |    102 |       Item it;
 | 
| deba@1039 |    103 |       attach(_g.getNotifier(_Item()));
 | 
| deba@822 |    104 |       allocate_memory();
 | 
| deba@1267 |    105 |       for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@980 |    106 | 	int id = graph->id(it);;
 | 
| klao@946 |    107 | 	allocator.construct(&(values[id]), _v);
 | 
| deba@822 |    108 |       }								
 | 
| deba@822 |    109 |     }
 | 
| deba@822 |    110 | 
 | 
| deba@1703 |    111 |     /// \brief Constructor to copy a map of the same map type.
 | 
| deba@1703 |    112 |     ///
 | 
| deba@1703 |    113 |     /// Constructor to copy a map of the same map type.     
 | 
| alpar@1613 |    114 |     ArrayMap(const ArrayMap& copy) : Parent(), graph(copy.graph) {
 | 
| klao@946 |    115 |       if (copy.attached()) {
 | 
| klao@946 |    116 | 	attach(*copy.getRegistry());
 | 
| klao@946 |    117 |       }
 | 
| deba@822 |    118 |       capacity = copy.capacity;
 | 
| deba@822 |    119 |       if (capacity == 0) return;
 | 
| deba@822 |    120 |       values = allocator.allocate(capacity);
 | 
| deba@1267 |    121 |       Item it;
 | 
| deba@1267 |    122 |       for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@980 |    123 | 	int id = graph->id(it);;
 | 
| deba@891 |    124 | 	allocator.construct(&(values[id]), copy.values[id]);
 | 
| deba@822 |    125 |       }
 | 
| deba@822 |    126 |     }
 | 
| deba@822 |    127 | 
 | 
| deba@1669 |    128 |     /// \brief The destructor of the map.
 | 
| deba@1669 |    129 |     ///     
 | 
| deba@1414 |    130 |     /// The destructor of the map.
 | 
| klao@946 |    131 |     virtual ~ArrayMap() {      
 | 
| klao@946 |    132 |       if (attached()) {
 | 
| klao@946 |    133 | 	clear();
 | 
| klao@946 |    134 | 	detach();
 | 
| deba@822 |    135 |       }
 | 
| deba@822 |    136 |     }
 | 
| deba@1669 |    137 | 		
 | 
| deba@1669 |    138 |   private:
 | 
| deba@1669 |    139 | 
 | 
| deba@1669 |    140 |     ArrayMap& operator=(const ArrayMap&);
 | 
| deba@1669 |    141 | 
 | 
| deba@1669 |    142 |   protected:
 | 
| deba@1669 |    143 | 
 | 
| deba@1669 |    144 |     using Parent::attach;
 | 
| deba@1669 |    145 |     using Parent::detach;
 | 
| deba@1669 |    146 |     using Parent::attached;
 | 
| deba@1669 |    147 | 
 | 
| deba@1669 |    148 |     const Graph* getGraph() {
 | 
| deba@1669 |    149 |       return graph;
 | 
| deba@1669 |    150 |     }
 | 
| deba@1669 |    151 | 
 | 
| deba@1669 |    152 | 
 | 
| deba@1669 |    153 |   public:
 | 
| deba@1669 |    154 | 
 | 
| deba@1703 |    155 |     /// \brief The subscript operator. 
 | 
| deba@1703 |    156 |     ///
 | 
| deba@1703 |    157 |     /// The subscript operator. The map can be subscripted by the
 | 
| deba@1703 |    158 |     /// actual keys of the graph. 
 | 
| deba@1267 |    159 |     Value& operator[](const Key& key) {
 | 
| deba@980 |    160 |       int id = graph->id(key);
 | 
| deba@822 |    161 |       return values[id];
 | 
| deba@822 |    162 |     } 
 | 
| deba@822 |    163 | 		
 | 
| deba@1703 |    164 |     /// \brief The const subscript operator.
 | 
| deba@1703 |    165 |     ///
 | 
| deba@1703 |    166 |     /// The const subscript operator. The map can be subscripted by the
 | 
| deba@1703 |    167 |     /// actual keys of the graph. 
 | 
| deba@1267 |    168 |     const Value& operator[](const Key& key) const {
 | 
| deba@980 |    169 |       int id = graph->id(key);
 | 
| deba@822 |    170 |       return values[id];
 | 
| deba@822 |    171 |     }
 | 
| deba@1703 |    172 | 
 | 
| deba@1703 |    173 |     /// \brief Setter function of the map.
 | 
| deba@1703 |    174 |     ///	
 | 
| deba@1414 |    175 |     /// Setter function of the map. Equivalent with map[key] = val.
 | 
| deba@1414 |    176 |     /// This is a compatibility feature with the not dereferable maps.
 | 
| alpar@987 |    177 |     void set(const Key& key, const Value& val) {
 | 
| klao@946 |    178 |       (*this)[key] = val;
 | 
| deba@822 |    179 |     }
 | 
| deba@1669 |    180 | 
 | 
| deba@1669 |    181 |   protected:
 | 
| deba@1703 |    182 | 
 | 
| deba@1414 |    183 |     /// Add a new key to the map. It called by the map registry.
 | 
| deba@1703 |    184 |          
 | 
| deba@1703 |    185 |     virtual void add(const Key& key) {
 | 
| deba@980 |    186 |       int id = graph->id(key);
 | 
| deba@822 |    187 |       if (id >= capacity) {
 | 
| deba@822 |    188 | 	int new_capacity = (capacity == 0 ? 1 : capacity);
 | 
| deba@822 |    189 | 	while (new_capacity <= id) {
 | 
| deba@822 |    190 | 	  new_capacity <<= 1;
 | 
| deba@822 |    191 | 	}
 | 
| klao@946 |    192 | 	Value* new_values = allocator.allocate(new_capacity);
 | 
| deba@1267 |    193 | 	Item it;
 | 
| deba@1267 |    194 | 	for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@980 |    195 | 	  int jd = graph->id(it);;
 | 
| deba@822 |    196 | 	  if (id != jd) {
 | 
| deba@822 |    197 | 	    allocator.construct(&(new_values[jd]), values[jd]);
 | 
| deba@822 |    198 | 	    allocator.destroy(&(values[jd]));
 | 
| deba@822 |    199 | 	  }
 | 
| deba@822 |    200 | 	}
 | 
| deba@822 |    201 | 	if (capacity != 0) allocator.deallocate(values, capacity);
 | 
| deba@822 |    202 | 	values = new_values;
 | 
| deba@822 |    203 | 	capacity = new_capacity;
 | 
| deba@822 |    204 |       }
 | 
| deba@822 |    205 |       allocator.construct(&(values[id]), Value());
 | 
| deba@822 |    206 |     }
 | 
| deba@1414 |    207 | 
 | 
| deba@1703 |    208 |     virtual void add(const std::vector<Key>& keys) {
 | 
| deba@1414 |    209 |       int max_id = -1;
 | 
| deba@1414 |    210 |       for (int i = 0; i < (int)keys.size(); ++i) {
 | 
| deba@1414 |    211 | 	int id = graph->id(keys[i]);
 | 
| deba@1414 |    212 | 	if (id > max_id) {
 | 
| deba@1414 |    213 | 	  max_id = id;
 | 
| deba@1414 |    214 | 	}
 | 
| deba@1414 |    215 |       }
 | 
| deba@1414 |    216 |       if (max_id >= capacity) {
 | 
| deba@1414 |    217 | 	int new_capacity = (capacity == 0 ? 1 : capacity);
 | 
| deba@1414 |    218 | 	while (new_capacity <= max_id) {
 | 
| deba@1414 |    219 | 	  new_capacity <<= 1;
 | 
| deba@1414 |    220 | 	}
 | 
| deba@1414 |    221 | 	Value* new_values = allocator.allocate(new_capacity);
 | 
| deba@1414 |    222 | 	Item it;
 | 
| deba@1414 |    223 | 	for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@1414 |    224 | 	  int id = graph->id(it);
 | 
| deba@1414 |    225 | 	  bool found = false;
 | 
| deba@1414 |    226 | 	  for (int i = 0; i < (int)keys.size(); ++i) {
 | 
| deba@1414 |    227 | 	    int jd = graph->id(keys[i]);
 | 
| deba@1414 |    228 | 	    if (id == jd) {
 | 
| deba@1414 |    229 | 	      found = true;
 | 
| deba@1414 |    230 | 	      break;
 | 
| deba@1414 |    231 | 	    }
 | 
| deba@1414 |    232 | 	  }
 | 
| deba@1414 |    233 | 	  if (found) continue;
 | 
| deba@1414 |    234 | 	  allocator.construct(&(new_values[id]), values[id]);
 | 
| deba@1414 |    235 | 	  allocator.destroy(&(values[id]));
 | 
| deba@1414 |    236 | 	}
 | 
| deba@1414 |    237 | 	if (capacity != 0) allocator.deallocate(values, capacity);
 | 
| deba@1414 |    238 | 	values = new_values;
 | 
| deba@1414 |    239 | 	capacity = new_capacity;
 | 
| deba@1414 |    240 |       }
 | 
| deba@1414 |    241 |       for (int i = 0; i < (int)keys.size(); ++i) {
 | 
| deba@1414 |    242 | 	int id = graph->id(keys[i]);
 | 
| deba@1414 |    243 | 	allocator.construct(&(values[id]), Value());
 | 
| deba@1414 |    244 |       }
 | 
| deba@1414 |    245 |     }
 | 
| deba@822 |    246 | 		
 | 
| deba@1414 |    247 |     /// Erase a key from the map. It called by the map registry.
 | 
| deba@1414 |    248 |      
 | 
| deba@1703 |    249 |     virtual void erase(const Key& key) {
 | 
| deba@980 |    250 |       int id = graph->id(key);
 | 
| deba@822 |    251 |       allocator.destroy(&(values[id]));
 | 
| deba@822 |    252 |     }
 | 
| deba@822 |    253 | 
 | 
| deba@1703 |    254 |     virtual void erase(const std::vector<Key>& keys) {
 | 
| deba@1414 |    255 |       for (int i = 0; i < (int)keys.size(); ++i) {
 | 
| deba@1414 |    256 | 	int id = graph->id(keys[i]);
 | 
| deba@1414 |    257 | 	allocator.destroy(&(values[id]));
 | 
| deba@1414 |    258 |       }
 | 
| deba@1414 |    259 |     }
 | 
| deba@1414 |    260 | 
 | 
| deba@1703 |    261 |     virtual void build() {
 | 
| klao@946 |    262 |       allocate_memory();
 | 
| deba@1267 |    263 |       Item it;
 | 
| deba@1267 |    264 |       for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@980 |    265 | 	int id = graph->id(it);;
 | 
| klao@946 |    266 | 	allocator.construct(&(values[id]), Value());
 | 
| klao@946 |    267 |       }								
 | 
| klao@946 |    268 |     }
 | 
| klao@946 |    269 | 
 | 
| deba@1703 |    270 |     virtual void clear() {	
 | 
| deba@822 |    271 |       if (capacity != 0) {
 | 
| deba@1267 |    272 | 	Item it;
 | 
| deba@1267 |    273 | 	for (graph->first(it); it != INVALID; graph->next(it)) {
 | 
| deba@1414 |    274 | 	  int id = graph->id(it);
 | 
| klao@946 |    275 | 	  allocator.destroy(&(values[id]));
 | 
| klao@946 |    276 | 	}								
 | 
| deba@822 |    277 | 	allocator.deallocate(values, capacity);
 | 
| deba@822 |    278 | 	capacity = 0;
 | 
| deba@822 |    279 |       }
 | 
| deba@822 |    280 |     }
 | 
| deba@822 |    281 | 
 | 
| deba@822 |    282 |   private:
 | 
| deba@822 |    283 |       
 | 
| deba@822 |    284 |     void allocate_memory() {
 | 
| deba@980 |    285 |       int max_id = graph->maxId(_Item());
 | 
| deba@822 |    286 |       if (max_id == -1) {
 | 
| deba@822 |    287 | 	capacity = 0;
 | 
| deba@822 |    288 | 	values = 0;
 | 
| deba@822 |    289 | 	return;
 | 
| deba@822 |    290 |       }
 | 
| deba@822 |    291 |       capacity = 1;
 | 
| deba@822 |    292 |       while (capacity <= max_id) {
 | 
| deba@822 |    293 | 	capacity <<= 1;
 | 
| deba@822 |    294 |       }
 | 
| deba@822 |    295 |       values = allocator.allocate(capacity);	
 | 
| deba@822 |    296 |     }      
 | 
| deba@822 |    297 | 
 | 
| klao@946 |    298 |     const Graph* graph;
 | 
| deba@822 |    299 |     int capacity;
 | 
| deba@822 |    300 |     Value* values;
 | 
| deba@822 |    301 |     Allocator allocator;
 | 
| deba@844 |    302 | 
 | 
| deba@822 |    303 |   };		
 | 
| deba@822 |    304 | 
 | 
| deba@822 |    305 | }
 | 
| deba@822 |    306 | 
 | 
| alpar@921 |    307 | #endif //LEMON_ARRAY_MAP_H
 |