lemon/bits/array_map.h
author alpar
Fri, 07 Oct 2005 11:05:35 +0000
changeset 1716 d8c28868f074
parent 1669 66ae78d29f1e
child 1719 674182524bd9
permissions -rw-r--r--
Sym -> Undir
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@1703
    51
    typedef True AdaptibleTag;
deba@822
    52
		
deba@822
    53
    /// The graph type of the maps. 
klao@946
    54
    typedef _Graph Graph;
deba@822
    55
    /// The key type of the maps.
alpar@987
    56
    typedef _Item Key;
klao@946
    57
deba@1039
    58
    typedef AlterationNotifier<_Item> Registry;
klao@946
    59
deba@822
    60
    /// The MapBase of the Map which imlements the core regisitry function.
klao@946
    61
    typedef typename Registry::ObserverBase Parent;
deba@822
    62
		
deba@822
    63
    /// The value type of the map.
alpar@987
    64
    typedef _Value Value;
deba@822
    65
deba@822
    66
klao@946
    67
  private:
deba@822
    68
    typedef std::allocator<Value> Allocator;
deba@822
    69
klao@946
    70
klao@946
    71
  public:
klao@946
    72
deba@1703
    73
    /// \brief Graph and Registry initialized map constructor.
deba@1703
    74
    ///
deba@1414
    75
    /// Graph and Registry initialized map constructor.
deba@980
    76
    ArrayMap(const Graph& _g) : graph(&_g) {
deba@1267
    77
      Item it;
deba@1267
    78
      attach(_g.getNotifier(Item()));
deba@822
    79
      allocate_memory();
deba@1267
    80
      for (graph->first(it); it != INVALID; graph->next(it)) {
deba@980
    81
	int id = graph->id(it);;
deba@822
    82
	allocator.construct(&(values[id]), Value());
deba@822
    83
      }								
deba@822
    84
    }
deba@822
    85
deba@1703
    86
    /// \brief Constructor to use default value to initialize the map. 
deba@1703
    87
    ///
deba@1703
    88
    /// It constructs a map and initialize all of the the map. 
deba@980
    89
    ArrayMap(const Graph& _g, const Value& _v) : graph(&_g) {
deba@1267
    90
      Item it;
deba@1039
    91
      attach(_g.getNotifier(_Item()));
deba@822
    92
      allocate_memory();
deba@1267
    93
      for (graph->first(it); it != INVALID; graph->next(it)) {
deba@980
    94
	int id = graph->id(it);;
klao@946
    95
	allocator.construct(&(values[id]), _v);
deba@822
    96
      }								
deba@822
    97
    }
deba@822
    98
deba@1703
    99
    /// \brief Constructor to copy a map of the same map type.
deba@1703
   100
    ///
deba@1703
   101
    /// Constructor to copy a map of the same map type.     
alpar@1613
   102
    ArrayMap(const ArrayMap& copy) : Parent(), graph(copy.graph) {
klao@946
   103
      if (copy.attached()) {
klao@946
   104
	attach(*copy.getRegistry());
klao@946
   105
      }
deba@822
   106
      capacity = copy.capacity;
deba@822
   107
      if (capacity == 0) return;
deba@822
   108
      values = allocator.allocate(capacity);
deba@1267
   109
      Item it;
deba@1267
   110
      for (graph->first(it); it != INVALID; graph->next(it)) {
deba@980
   111
	int id = graph->id(it);;
deba@891
   112
	allocator.construct(&(values[id]), copy.values[id]);
deba@822
   113
      }
deba@822
   114
    }
deba@822
   115
deba@1669
   116
    /// \brief The destructor of the map.
deba@1669
   117
    ///     
deba@1414
   118
    /// The destructor of the map.
klao@946
   119
    virtual ~ArrayMap() {      
klao@946
   120
      if (attached()) {
klao@946
   121
	clear();
klao@946
   122
	detach();
deba@822
   123
      }
deba@822
   124
    }
deba@1669
   125
		
deba@1669
   126
  private:
deba@1669
   127
deba@1669
   128
    ArrayMap& operator=(const ArrayMap&);
deba@1669
   129
deba@1669
   130
  protected:
deba@1669
   131
deba@1669
   132
    using Parent::attach;
deba@1669
   133
    using Parent::detach;
deba@1669
   134
    using Parent::attached;
deba@1669
   135
deba@1669
   136
    const Graph* getGraph() {
deba@1669
   137
      return graph;
deba@1669
   138
    }
deba@1669
   139
deba@1669
   140
deba@1669
   141
  public:
deba@1669
   142
deba@1703
   143
    /// \brief The subscript operator. 
deba@1703
   144
    ///
deba@1703
   145
    /// The subscript operator. The map can be subscripted by the
deba@1703
   146
    /// actual keys of the graph. 
deba@1267
   147
    Value& operator[](const Key& key) {
deba@980
   148
      int id = graph->id(key);
deba@822
   149
      return values[id];
deba@822
   150
    } 
deba@822
   151
		
deba@1703
   152
    /// \brief The const subscript operator.
deba@1703
   153
    ///
deba@1703
   154
    /// The const subscript operator. The map can be subscripted by the
deba@1703
   155
    /// actual keys of the graph. 
deba@1267
   156
    const Value& operator[](const Key& key) const {
deba@980
   157
      int id = graph->id(key);
deba@822
   158
      return values[id];
deba@822
   159
    }
deba@1703
   160
deba@1703
   161
    /// \brief Setter function of the map.
deba@1703
   162
    ///	
deba@1414
   163
    /// Setter function of the map. Equivalent with map[key] = val.
deba@1414
   164
    /// This is a compatibility feature with the not dereferable maps.
alpar@987
   165
    void set(const Key& key, const Value& val) {
klao@946
   166
      (*this)[key] = val;
deba@822
   167
    }
deba@1669
   168
deba@1669
   169
  protected:
deba@1703
   170
deba@1414
   171
    /// Add a new key to the map. It called by the map registry.
deba@1703
   172
         
deba@1703
   173
    virtual void add(const Key& key) {
deba@980
   174
      int id = graph->id(key);
deba@822
   175
      if (id >= capacity) {
deba@822
   176
	int new_capacity = (capacity == 0 ? 1 : capacity);
deba@822
   177
	while (new_capacity <= id) {
deba@822
   178
	  new_capacity <<= 1;
deba@822
   179
	}
klao@946
   180
	Value* new_values = allocator.allocate(new_capacity);
deba@1267
   181
	Item it;
deba@1267
   182
	for (graph->first(it); it != INVALID; graph->next(it)) {
deba@980
   183
	  int jd = graph->id(it);;
deba@822
   184
	  if (id != jd) {
deba@822
   185
	    allocator.construct(&(new_values[jd]), values[jd]);
deba@822
   186
	    allocator.destroy(&(values[jd]));
deba@822
   187
	  }
deba@822
   188
	}
deba@822
   189
	if (capacity != 0) allocator.deallocate(values, capacity);
deba@822
   190
	values = new_values;
deba@822
   191
	capacity = new_capacity;
deba@822
   192
      }
deba@822
   193
      allocator.construct(&(values[id]), Value());
deba@822
   194
    }
deba@1414
   195
deba@1703
   196
    virtual void add(const std::vector<Key>& keys) {
deba@1414
   197
      int max_id = -1;
deba@1414
   198
      for (int i = 0; i < (int)keys.size(); ++i) {
deba@1414
   199
	int id = graph->id(keys[i]);
deba@1414
   200
	if (id > max_id) {
deba@1414
   201
	  max_id = id;
deba@1414
   202
	}
deba@1414
   203
      }
deba@1414
   204
      if (max_id >= capacity) {
deba@1414
   205
	int new_capacity = (capacity == 0 ? 1 : capacity);
deba@1414
   206
	while (new_capacity <= max_id) {
deba@1414
   207
	  new_capacity <<= 1;
deba@1414
   208
	}
deba@1414
   209
	Value* new_values = allocator.allocate(new_capacity);
deba@1414
   210
	Item it;
deba@1414
   211
	for (graph->first(it); it != INVALID; graph->next(it)) {
deba@1414
   212
	  int id = graph->id(it);
deba@1414
   213
	  bool found = false;
deba@1414
   214
	  for (int i = 0; i < (int)keys.size(); ++i) {
deba@1414
   215
	    int jd = graph->id(keys[i]);
deba@1414
   216
	    if (id == jd) {
deba@1414
   217
	      found = true;
deba@1414
   218
	      break;
deba@1414
   219
	    }
deba@1414
   220
	  }
deba@1414
   221
	  if (found) continue;
deba@1414
   222
	  allocator.construct(&(new_values[id]), values[id]);
deba@1414
   223
	  allocator.destroy(&(values[id]));
deba@1414
   224
	}
deba@1414
   225
	if (capacity != 0) allocator.deallocate(values, capacity);
deba@1414
   226
	values = new_values;
deba@1414
   227
	capacity = new_capacity;
deba@1414
   228
      }
deba@1414
   229
      for (int i = 0; i < (int)keys.size(); ++i) {
deba@1414
   230
	int id = graph->id(keys[i]);
deba@1414
   231
	allocator.construct(&(values[id]), Value());
deba@1414
   232
      }
deba@1414
   233
    }
deba@822
   234
		
deba@1414
   235
    /// Erase a key from the map. It called by the map registry.
deba@1414
   236
     
deba@1703
   237
    virtual void erase(const Key& key) {
deba@980
   238
      int id = graph->id(key);
deba@822
   239
      allocator.destroy(&(values[id]));
deba@822
   240
    }
deba@822
   241
deba@1703
   242
    virtual void erase(const std::vector<Key>& keys) {
deba@1414
   243
      for (int i = 0; i < (int)keys.size(); ++i) {
deba@1414
   244
	int id = graph->id(keys[i]);
deba@1414
   245
	allocator.destroy(&(values[id]));
deba@1414
   246
      }
deba@1414
   247
    }
deba@1414
   248
deba@1703
   249
    virtual void build() {
klao@946
   250
      allocate_memory();
deba@1267
   251
      Item it;
deba@1267
   252
      for (graph->first(it); it != INVALID; graph->next(it)) {
deba@980
   253
	int id = graph->id(it);;
klao@946
   254
	allocator.construct(&(values[id]), Value());
klao@946
   255
      }								
klao@946
   256
    }
klao@946
   257
deba@1703
   258
    virtual void clear() {	
deba@822
   259
      if (capacity != 0) {
deba@1267
   260
	Item it;
deba@1267
   261
	for (graph->first(it); it != INVALID; graph->next(it)) {
deba@1414
   262
	  int id = graph->id(it);
klao@946
   263
	  allocator.destroy(&(values[id]));
klao@946
   264
	}								
deba@822
   265
	allocator.deallocate(values, capacity);
deba@822
   266
	capacity = 0;
deba@822
   267
      }
deba@822
   268
    }
deba@822
   269
deba@822
   270
  private:
deba@822
   271
      
deba@822
   272
    void allocate_memory() {
deba@980
   273
      int max_id = graph->maxId(_Item());
deba@822
   274
      if (max_id == -1) {
deba@822
   275
	capacity = 0;
deba@822
   276
	values = 0;
deba@822
   277
	return;
deba@822
   278
      }
deba@822
   279
      capacity = 1;
deba@822
   280
      while (capacity <= max_id) {
deba@822
   281
	capacity <<= 1;
deba@822
   282
      }
deba@822
   283
      values = allocator.allocate(capacity);	
deba@822
   284
    }      
deba@822
   285
klao@946
   286
    const Graph* graph;
deba@822
   287
    int capacity;
deba@822
   288
    Value* values;
deba@822
   289
    Allocator allocator;
deba@844
   290
deba@822
   291
  };		
deba@822
   292
deba@822
   293
}
deba@822
   294
alpar@921
   295
#endif //LEMON_ARRAY_MAP_H