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