lemon/linear_heap.h
author deba
Mon, 03 Apr 2006 09:45:23 +0000
changeset 2031 080d51024ac5
parent 1906 7fa90b66ca9e
permissions -rw-r--r--
Correcting the structure of the graph's and adaptor's map.
The template assign operators and map iterators can be used for adaptors also.

Some bugfix in the adaptors

New class SwapBpUGraphAdaptor which swaps the two nodeset of the graph.
deba@1724
     1
/* -*- C++ -*-
deba@1724
     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
deba@1724
     7
 * (Egervary Research Group on Combinatorial Optimization, EGRES).
deba@1724
     8
 *
deba@1724
     9
 * Permission to use, modify and distribute this software is granted
deba@1724
    10
 * provided that this copyright notice appears in all copies. For
deba@1724
    11
 * precise terms see the accompanying LICENSE file.
deba@1724
    12
 *
deba@1724
    13
 * This software is provided "AS IS" with no warranty of any kind,
deba@1724
    14
 * express or implied, and with no claim as to its suitability for any
deba@1724
    15
 * purpose.
deba@1724
    16
 *
deba@1724
    17
 */
deba@1724
    18
deba@1724
    19
#ifndef LEMON_LINEAR_HEAP_H
deba@1724
    20
#define LEMON_LINEAR_HEAP_H
deba@1724
    21
deba@1724
    22
///\ingroup auxdat
deba@1724
    23
///\file
deba@1724
    24
///\brief Binary Heap implementation.
deba@1724
    25
deba@1724
    26
#include <vector>
deba@1724
    27
#include <utility>
deba@1724
    28
#include <functional>
deba@1724
    29
deba@1724
    30
namespace lemon {
deba@1724
    31
deba@1834
    32
  /// \ingroup auxdat
deba@1724
    33
deba@1724
    34
  /// \brief A Linear Heap implementation.
deba@1724
    35
  ///
deba@1724
    36
  /// This class implements the \e linear \e heap data structure. A \e heap
deba@1724
    37
  /// is a data structure for storing items with specified values called \e
deba@1724
    38
  /// priorities in such a way that finding the item with minimum priority is
deba@1724
    39
  /// efficient. The linear heap is very simple implementation, it can store
deba@1724
    40
  /// only integer priorities and it stores for each priority in the [0..C]
deba@1724
    41
  /// range a list of items. So it should be used only when the priorities
deba@1724
    42
  /// are small. It is not intended to use as dijkstra heap.
deba@1724
    43
  ///
deba@1724
    44
  /// \param _Item Type of the items to be stored.  
deba@1724
    45
  /// \param _ItemIntMap A read and writable Item int map, used internally
deba@1724
    46
  /// to handle the cross references.
deba@1724
    47
  /// \param minimize If the given parameter is true then the heap gives back
deba@1724
    48
  /// the lowest priority. 
deba@1724
    49
  template <typename _Item, typename _ItemIntMap, bool minimize = true >
deba@1724
    50
  class LinearHeap {
deba@1724
    51
deba@1724
    52
  public:
deba@1724
    53
    typedef _Item Item;
deba@1724
    54
    typedef int Prio;
deba@1724
    55
    typedef std::pair<Item, Prio> Pair;
deba@1724
    56
    typedef _ItemIntMap ItemIntMap;
deba@1724
    57
deba@1724
    58
    /// \brief Type to represent the items states.
deba@1724
    59
    ///
deba@1724
    60
    /// Each Item element have a state associated to it. It may be "in heap",
deba@1724
    61
    /// "pre heap" or "post heap". The latter two are indifferent from the
deba@1724
    62
    /// heap's point of view, but may be useful to the user.
deba@1724
    63
    ///
deba@1724
    64
    /// The ItemIntMap \e should be initialized in such way that it maps
deba@1724
    65
    /// PRE_HEAP (-1) to any element to be put in the heap...
deba@1724
    66
    enum state_enum {
deba@1724
    67
      IN_HEAP = 0,
deba@1724
    68
      PRE_HEAP = -1,
deba@1724
    69
      POST_HEAP = -2
deba@1724
    70
    };
deba@1724
    71
deba@1724
    72
  public:
deba@1724
    73
    /// \brief The constructor.
deba@1724
    74
    ///
deba@1724
    75
    /// The constructor.
deba@1724
    76
    /// \param _index should be given to the constructor, since it is used
deba@1724
    77
    /// internally to handle the cross references. The value of the map
deba@1724
    78
    /// should be PRE_HEAP (-1) for each element.
deba@1724
    79
    explicit LinearHeap(ItemIntMap &_index) : index(_index), minimal(0) {}
deba@1724
    80
    
deba@1724
    81
    /// The number of items stored in the heap.
deba@1724
    82
    ///
deba@1724
    83
    /// \brief Returns the number of items stored in the heap.
deba@1724
    84
    int size() const { return data.size(); }
deba@1724
    85
    
deba@1724
    86
    /// \brief Checks if the heap stores no items.
deba@1724
    87
    ///
deba@1724
    88
    /// Returns \c true if and only if the heap stores no items.
deba@1724
    89
    bool empty() const { return data.empty(); }
deba@1724
    90
deba@1724
    91
    /// \brief Make empty this heap.
deba@1724
    92
    /// 
deba@1724
    93
    /// Make empty this heap.
deba@1724
    94
    void clear() { 
deba@1724
    95
      for (int i = 0; i < (int)data.size(); ++i) {
deba@1724
    96
	index[data[i].item] = -2;
deba@1724
    97
      }
deba@1724
    98
      data.clear(); first.clear(); minimal = 0;
deba@1724
    99
    }
deba@1724
   100
deba@1724
   101
  private:
deba@1724
   102
deba@1724
   103
    void relocate_last(int idx) {
deba@1724
   104
      if (idx + 1 < (int)data.size()) {
deba@1724
   105
	data[idx] = data.back();
deba@1724
   106
	if (data[idx].prev != -1) {
deba@1724
   107
	  data[data[idx].prev].next = idx;
deba@1724
   108
	} else {
deba@1724
   109
	  first[data[idx].value] = idx;
deba@1724
   110
	}
deba@1724
   111
	if (data[idx].next != -1) {
deba@1724
   112
	  data[data[idx].next].prev = idx;
deba@1724
   113
	}
deba@1724
   114
	index[data[idx].item] = idx;
deba@1724
   115
      }
deba@1724
   116
      data.pop_back();
deba@1724
   117
    }
deba@1724
   118
deba@1724
   119
    void unlace(int idx) {
deba@1724
   120
      if (data[idx].prev != -1) {
deba@1724
   121
	data[data[idx].prev].next = data[idx].next;
deba@1724
   122
      } else {
deba@1724
   123
	first[data[idx].value] = data[idx].next;
deba@1724
   124
      }
deba@1724
   125
      if (data[idx].next != -1) {
deba@1724
   126
	data[data[idx].next].prev = data[idx].prev;
deba@1724
   127
      }
deba@1724
   128
    }
deba@1724
   129
deba@1724
   130
    void lace(int idx) {
deba@1724
   131
      if ((int)first.size() <= data[idx].value) {
deba@1724
   132
	first.resize(data[idx].value + 1, -1);
deba@1724
   133
      }
deba@1724
   134
      data[idx].next = first[data[idx].value];
deba@1724
   135
      if (data[idx].next != -1) {
deba@1724
   136
	data[data[idx].next].prev = idx;
deba@1724
   137
      }
deba@1724
   138
      first[data[idx].value] = idx;
deba@1724
   139
      data[idx].prev = -1;
deba@1724
   140
    }
deba@1724
   141
deba@1724
   142
  public:
deba@1724
   143
    /// \brief Insert a pair of item and priority into the heap.
deba@1724
   144
    ///
deba@1724
   145
    /// Adds \c p.first to the heap with priority \c p.second.
deba@1724
   146
    /// \param p The pair to insert.
deba@1724
   147
    void push(const Pair& p) {
deba@1724
   148
      push(p.first, p.second);
deba@1724
   149
    }
deba@1724
   150
deba@1724
   151
    /// \brief Insert an item into the heap with the given priority.
deba@1724
   152
    ///    
deba@1724
   153
    /// Adds \c i to the heap with priority \c p. 
deba@1724
   154
    /// \param i The item to insert.
deba@1724
   155
    /// \param p The priority of the item.
deba@1724
   156
    void push(const Item &i, const Prio &p) { 
deba@1724
   157
      int idx = data.size();
deba@1724
   158
      index[i] = idx;
deba@1724
   159
      data.push_back(LinearItem(i, p));
deba@1724
   160
      lace(idx);
deba@1724
   161
      if (p < minimal) {
deba@1724
   162
	minimal = p;
deba@1724
   163
      }
deba@1724
   164
    }
deba@1724
   165
deba@1758
   166
    /// \brief Returns the item with minimum priority.
deba@1724
   167
    ///
deba@1758
   168
    /// This method returns the item with minimum priority.
deba@1724
   169
    /// \pre The heap must be nonempty.  
deba@1724
   170
    Item top() const {
deba@1724
   171
      while (first[minimal] == -1) {
deba@1724
   172
	++minimal;
deba@1724
   173
      }
deba@1724
   174
      return data[first[minimal]].item;
deba@1724
   175
    }
deba@1724
   176
deba@1758
   177
    /// \brief Returns the minimum priority.
deba@1724
   178
    ///
deba@1758
   179
    /// It returns the minimum priority.
deba@1724
   180
    /// \pre The heap must be nonempty.
deba@1724
   181
    Prio prio() const {
deba@1724
   182
      while (first[minimal] == -1) {
deba@1724
   183
	++minimal;
deba@1724
   184
      }
deba@1724
   185
      return minimal;
deba@1724
   186
    }
deba@1724
   187
deba@1758
   188
    /// \brief Deletes the item with minimum priority.
deba@1724
   189
    ///
deba@1758
   190
    /// This method deletes the item with minimum priority from the heap.  
deba@1724
   191
    /// \pre The heap must be non-empty.  
deba@1724
   192
    void pop() {
deba@1724
   193
      while (first[minimal] == -1) {
deba@1724
   194
	++minimal;
deba@1724
   195
      }
deba@1724
   196
      int idx = first[minimal];
deba@1724
   197
      index[data[idx].item] = -2;
deba@1724
   198
      unlace(idx);
deba@1724
   199
      relocate_last(idx);
deba@1724
   200
    }
deba@1724
   201
deba@1724
   202
    /// \brief Deletes \c i from the heap.
deba@1724
   203
    ///
deba@1724
   204
    /// This method deletes item \c i from the heap, if \c i was
deba@1724
   205
    /// already stored in the heap.
deba@1724
   206
    /// \param i The item to erase. 
deba@1724
   207
    void erase(const Item &i) {
deba@1724
   208
      int idx = index[i];
deba@1724
   209
      index[data[idx].item] = -2;
deba@1724
   210
      unlace(idx);
deba@1724
   211
      relocate_last(idx);
deba@1724
   212
    }
deba@1724
   213
deba@1724
   214
    
deba@1724
   215
    /// \brief Returns the priority of \c i.
deba@1724
   216
    ///
deba@1724
   217
    /// This function returns the priority of item \c i.  
deba@1724
   218
    /// \pre \c i must be in the heap.
deba@1724
   219
    /// \param i The item.
deba@1724
   220
    Prio operator[](const Item &i) const {
deba@1724
   221
      int idx = index[i];
deba@1724
   222
      return data[idx].value;
deba@1724
   223
    }
deba@1724
   224
deba@1724
   225
    /// \brief \c i gets to the heap with priority \c p independently 
deba@1724
   226
    /// if \c i was already there.
deba@1724
   227
    ///
deba@1724
   228
    /// This method calls \ref push(\c i, \c p) if \c i is not stored
deba@1724
   229
    /// in the heap and sets the priority of \c i to \c p otherwise.
deba@1724
   230
    /// \param i The item.
deba@1724
   231
    /// \param p The priority.
deba@1724
   232
    void set(const Item &i, const Prio &p) {
deba@1724
   233
      int idx = index[i];
deba@1724
   234
      if (idx < 0) {
deba@1724
   235
	push(i,p);
deba@1724
   236
      } else if (p > data[idx].value) {
deba@1724
   237
	increase(i, p);
deba@1724
   238
      } else {
deba@1724
   239
	decrease(i, p);
deba@1724
   240
      }
deba@1724
   241
    }
deba@1724
   242
deba@1724
   243
    /// \brief Decreases the priority of \c i to \c p.
deba@1724
   244
deba@1724
   245
    /// This method decreases the priority of item \c i to \c p.
deba@1724
   246
    /// \pre \c i must be stored in the heap with priority at least \c
deba@1724
   247
    /// p relative to \c Compare.
deba@1724
   248
    /// \param i The item.
deba@1724
   249
    /// \param p The priority.
deba@1724
   250
    void decrease(const Item &i, const Prio &p) {
deba@1724
   251
      int idx = index[i];
deba@1724
   252
      unlace(idx);
deba@1724
   253
      data[idx].value = p;
deba@1724
   254
      if (p < minimal) {
deba@1724
   255
	minimal = p;
deba@1724
   256
      }
deba@1724
   257
      lace(idx);
deba@1724
   258
    }
deba@1724
   259
    
deba@1724
   260
    /// \brief Increases the priority of \c i to \c p.
deba@1724
   261
    ///
deba@1724
   262
    /// This method sets the priority of item \c i to \c p. 
deba@1724
   263
    /// \pre \c i must be stored in the heap with priority at most \c
deba@1724
   264
    /// p relative to \c Compare.
deba@1724
   265
    /// \param i The item.
deba@1724
   266
    /// \param p The priority.
deba@1724
   267
    void increase(const Item &i, const Prio &p) {
deba@1724
   268
      int idx = index[i];
deba@1724
   269
      unlace(idx);
deba@1724
   270
      data[idx].value = p;
deba@1724
   271
      lace(idx);
deba@1724
   272
    }
deba@1724
   273
deba@1724
   274
    /// \brief Returns if \c item is in, has already been in, or has 
deba@1724
   275
    /// never been in the heap.
deba@1724
   276
    ///
deba@1724
   277
    /// This method returns PRE_HEAP if \c item has never been in the
deba@1724
   278
    /// heap, IN_HEAP if it is in the heap at the moment, and POST_HEAP
deba@1724
   279
    /// otherwise. In the latter case it is possible that \c item will
deba@1724
   280
    /// get back to the heap again.
deba@1724
   281
    /// \param i The item.
deba@1724
   282
    state_enum state(const Item &i) const {
deba@1724
   283
      int idx = index[i];
deba@1724
   284
      if (idx >= 0) idx = 0;
deba@1724
   285
      return state_enum(idx);
deba@1724
   286
    }
deba@1724
   287
deba@1902
   288
    /// \brief Sets the state of the \c item in the heap.
deba@1902
   289
    ///
deba@1902
   290
    /// Sets the state of the \c item in the heap. It can be used to
deba@1902
   291
    /// manually clear the heap when it is important to achive the
deba@1902
   292
    /// better time complexity.
deba@1902
   293
    /// \param i The item.
deba@1902
   294
    /// \param st The state. It should not be \c IN_HEAP. 
deba@1902
   295
    void state(const Item& i, state_enum st) {
deba@1902
   296
      switch (st) {
deba@1902
   297
      case POST_HEAP:
deba@1902
   298
      case PRE_HEAP:
deba@1902
   299
        if (state(i) == IN_HEAP) {
deba@1902
   300
          erase(i);
deba@1902
   301
        }
deba@1902
   302
        index[i] = st;
deba@1902
   303
        break;
deba@1906
   304
      case IN_HEAP:
deba@1906
   305
        break;
deba@1902
   306
      }
deba@1902
   307
    }
deba@1902
   308
deba@1724
   309
  private:
deba@1724
   310
deba@1724
   311
    struct LinearItem {
deba@1724
   312
      LinearItem(const Item& _item, int _value) 
deba@1724
   313
	: item(_item), value(_value) {}
deba@1724
   314
deba@1724
   315
      Item item;
deba@1724
   316
      int value;
deba@1724
   317
deba@1724
   318
      int prev, next;
deba@1724
   319
    };
deba@1724
   320
deba@1724
   321
    ItemIntMap& index;
deba@1724
   322
    std::vector<int> first;
deba@1724
   323
    std::vector<LinearItem> data;
deba@1724
   324
    mutable int minimal;
deba@1724
   325
deba@1724
   326
  }; // class LinearHeap
deba@1724
   327
deba@1724
   328
deba@1724
   329
  template <typename _Item, typename _ItemIntMap>
deba@1724
   330
  class LinearHeap<_Item, _ItemIntMap, false> {
deba@1724
   331
deba@1724
   332
  public:
deba@1724
   333
    typedef _Item Item;
deba@1724
   334
    typedef int Prio;
deba@1724
   335
    typedef std::pair<Item, Prio> Pair;
deba@1724
   336
    typedef _ItemIntMap ItemIntMap;
deba@1724
   337
deba@1724
   338
    enum state_enum {
deba@1724
   339
      IN_HEAP = 0,
deba@1724
   340
      PRE_HEAP = -1,
deba@1724
   341
      POST_HEAP = -2
deba@1724
   342
    };
deba@1724
   343
deba@1724
   344
  public:
deba@1724
   345
deba@1724
   346
    explicit LinearHeap(ItemIntMap &_index) : index(_index), maximal(-1) {}
deba@1724
   347
deba@1724
   348
    int size() const { return data.size(); }
deba@1724
   349
    bool empty() const { return data.empty(); }
deba@1724
   350
deba@1724
   351
    void clear() { 
deba@1724
   352
      for (int i = 0; i < (int)data.size(); ++i) {
deba@1724
   353
	index[data[i].item] = -2;
deba@1724
   354
      }
deba@1724
   355
      data.clear(); first.clear(); maximal = -1; 
deba@1724
   356
    }
deba@1724
   357
deba@1724
   358
  private:
deba@1724
   359
deba@1724
   360
    void relocate_last(int idx) {
deba@1724
   361
      if (idx + 1 != (int)data.size()) {
deba@1724
   362
	data[idx] = data.back();
deba@1724
   363
	if (data[idx].prev != -1) {
deba@1724
   364
	  data[data[idx].prev].next = idx;
deba@1724
   365
	} else {
deba@1724
   366
	  first[data[idx].value] = idx;
deba@1724
   367
	}
deba@1724
   368
	if (data[idx].next != -1) {
deba@1724
   369
	  data[data[idx].next].prev = idx;
deba@1724
   370
	}
deba@1724
   371
	index[data[idx].item] = idx;
deba@1724
   372
      }
deba@1724
   373
      data.pop_back();
deba@1724
   374
    }
deba@1724
   375
deba@1724
   376
    void unlace(int idx) {
deba@1724
   377
      if (data[idx].prev != -1) {
deba@1724
   378
	data[data[idx].prev].next = data[idx].next;
deba@1724
   379
      } else {
deba@1724
   380
	first[data[idx].value] = data[idx].next;
deba@1724
   381
      }
deba@1724
   382
      if (data[idx].next != -1) {
deba@1724
   383
	data[data[idx].next].prev = data[idx].prev;
deba@1724
   384
      }
deba@1724
   385
    }
deba@1724
   386
deba@1724
   387
    void lace(int idx) {
deba@1724
   388
      if ((int)first.size() <= data[idx].value) {
deba@1724
   389
	first.resize(data[idx].value + 1, -1);
deba@1724
   390
      }
deba@1724
   391
      data[idx].next = first[data[idx].value];
deba@1724
   392
      if (data[idx].next != -1) {
deba@1724
   393
	data[data[idx].next].prev = idx;
deba@1724
   394
      }
deba@1724
   395
      first[data[idx].value] = idx;
deba@1724
   396
      data[idx].prev = -1;
deba@1724
   397
    }
deba@1724
   398
deba@1724
   399
  public:
deba@1724
   400
deba@1724
   401
    void push(const Pair& p) {
deba@1724
   402
      push(p.first, p.second);
deba@1724
   403
    }
deba@1724
   404
deba@1724
   405
    void push(const Item &i, const Prio &p) { 
deba@1724
   406
      int idx = data.size();
deba@1724
   407
      index[i] = idx;
deba@1724
   408
      data.push_back(LinearItem(i, p));
deba@1724
   409
      lace(idx);
deba@1724
   410
      if (data[idx].value > maximal) {
deba@1724
   411
	maximal = data[idx].value;
deba@1724
   412
      }
deba@1724
   413
    }
deba@1724
   414
deba@1724
   415
    Item top() const {
deba@1724
   416
      while (first[maximal] == -1) {
deba@1724
   417
	--maximal;
deba@1724
   418
      }
deba@1724
   419
      return data[first[maximal]].item;
deba@1724
   420
    }
deba@1724
   421
deba@1724
   422
    Prio prio() const {
deba@1724
   423
      while (first[maximal] == -1) {
deba@1724
   424
	--maximal;
deba@1724
   425
      }
deba@1724
   426
      return maximal;
deba@1724
   427
    }
deba@1724
   428
deba@1724
   429
    void pop() {
deba@1724
   430
      while (first[maximal] == -1) {
deba@1724
   431
	--maximal;
deba@1724
   432
      }
deba@1724
   433
      int idx = first[maximal];
deba@1724
   434
      index[data[idx].item] = -2;
deba@1724
   435
      unlace(idx);
deba@1724
   436
      relocate_last(idx);
deba@1724
   437
    }
deba@1724
   438
deba@1724
   439
    void erase(const Item &i) {
deba@1724
   440
      int idx = index[i];
deba@1724
   441
      index[data[idx].item] = -2;
deba@1724
   442
      unlace(idx);
deba@1724
   443
      relocate_last(idx);
deba@1724
   444
    }
deba@1724
   445
deba@1724
   446
    Prio operator[](const Item &i) const {
deba@1724
   447
      int idx = index[i];
deba@1724
   448
      return data[idx].value;
deba@1724
   449
    }
deba@1724
   450
deba@1724
   451
    void set(const Item &i, const Prio &p) {
deba@1724
   452
      int idx = index[i];
deba@1724
   453
      if (idx < 0) {
deba@1724
   454
	push(i,p);
deba@1724
   455
      } else if (p > data[idx].value) {
deba@1724
   456
	decrease(i, p);
deba@1724
   457
      } else {
deba@1724
   458
	increase(i, p);
deba@1724
   459
      }
deba@1724
   460
    }
deba@1724
   461
deba@1724
   462
    void decrease(const Item &i, const Prio &p) {
deba@1724
   463
      int idx = index[i];
deba@1724
   464
      unlace(idx);
deba@1724
   465
      data[idx].value = p;
deba@1724
   466
      if (p > maximal) {
deba@1724
   467
	maximal = p;
deba@1724
   468
      }
deba@1724
   469
      lace(idx);
deba@1724
   470
    }
deba@1724
   471
    
deba@1724
   472
    void increase(const Item &i, const Prio &p) {
deba@1724
   473
      int idx = index[i];
deba@1724
   474
      unlace(idx);
deba@1724
   475
      data[idx].value = p;
deba@1724
   476
      lace(idx);
deba@1724
   477
    }
deba@1724
   478
deba@1724
   479
    state_enum state(const Item &i) const {
deba@1724
   480
      int idx = index[i];
deba@1724
   481
      if (idx >= 0) idx = 0;
deba@1724
   482
      return state_enum(idx);
deba@1724
   483
    }
deba@1724
   484
deba@1902
   485
    void state(const Item& i, state_enum st) {
deba@1902
   486
      switch (st) {
deba@1902
   487
      case POST_HEAP:
deba@1902
   488
      case PRE_HEAP:
deba@1902
   489
        if (state(i) == IN_HEAP) {
deba@1902
   490
          erase(i);
deba@1902
   491
        }
deba@1902
   492
        index[i] = st;
deba@1902
   493
        break;
deba@1906
   494
      case IN_HEAP:
deba@1906
   495
        break;
deba@1902
   496
      }
deba@1902
   497
    }
deba@1902
   498
deba@1724
   499
  private:
deba@1724
   500
deba@1724
   501
    struct LinearItem {
deba@1724
   502
      LinearItem(const Item& _item, int _value) 
deba@1724
   503
	: item(_item), value(_value) {}
deba@1724
   504
deba@1724
   505
      Item item;
deba@1724
   506
      int value;
deba@1724
   507
deba@1724
   508
      int prev, next;
deba@1724
   509
    };
deba@1724
   510
deba@1724
   511
    ItemIntMap& index;
deba@1724
   512
    std::vector<int> first;
deba@1724
   513
    std::vector<LinearItem> data;
deba@1724
   514
    mutable int maximal;
deba@1724
   515
deba@1724
   516
  }; // class LinearHeap
deba@1724
   517
deba@1724
   518
}
deba@1724
   519
  
deba@1724
   520
#endif