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