New map type based on array map for debugging purpose
authordeba
Wed, 06 Sep 2006 10:19:57 +0000
changeset 220209cbc87cb4ab
parent 2201 597714206430
child 2203 5f1a83b565fb
New map type based on array map for debugging purpose

It checks multiple allocation and deallocation of map values and
some consistency.

todo:
clarification of debugging concepts
assertions - exceptions - debug
revision of attic/debug.h

motto:
testing is at least so important as coding
lemon/Makefile.am
lemon/bits/array_map.h
lemon/bits/debug_map.h
lemon/bits/default_map.h
lemon/bits/vector_map.h
     1.1 --- a/lemon/Makefile.am	Wed Sep 06 10:10:48 2006 +0000
     1.2 +++ b/lemon/Makefile.am	Wed Sep 06 10:19:57 2006 +0000
     1.3 @@ -100,6 +100,7 @@
     1.4  	lemon/bits/array_map.h \
     1.5  	lemon/bits/base_extender.h \
     1.6  	lemon/bits/bezier.h \
     1.7 +	lemon/bits/debug_map.h \
     1.8  	lemon/bits/default_map.h \
     1.9  	lemon/bits/edge_set_extender.h \
    1.10  	lemon/bits/graph_adaptor_extender.h \
     2.1 --- a/lemon/bits/array_map.h	Wed Sep 06 10:10:48 2006 +0000
     2.2 +++ b/lemon/bits/array_map.h	Wed Sep 06 10:19:57 2006 +0000
     2.3 @@ -41,7 +41,7 @@
     2.4    /// the map. This map uses the allocators to implement 
     2.5    /// the container functionality.
     2.6    ///
     2.7 -  /// The template parameter is the Graph the current Item type and
     2.8 +  /// The template parameters are the Graph the current Item type and
     2.9    /// the Value type of the map.
    2.10    template <typename _Graph, typename _Item, typename _Value>
    2.11    class ArrayMap 
     3.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     3.2 +++ b/lemon/bits/debug_map.h	Wed Sep 06 10:19:57 2006 +0000
     3.3 @@ -0,0 +1,378 @@
     3.4 +/* -*- C++ -*-
     3.5 + *
     3.6 + * This file is a part of LEMON, a generic C++ optimization library
     3.7 + *
     3.8 + * Copyright (C) 2003-2006
     3.9 + * Egervary Jeno Kombinatorikus Optimalizalasi Kutatocsoport
    3.10 + * (Egervary Research Group on Combinatorial Optimization, EGRES).
    3.11 + *
    3.12 + * Permission to use, modify and distribute this software is granted
    3.13 + * provided that this copyright notice appears in all copies. For
    3.14 + * precise terms see the accompanying LICENSE file.
    3.15 + *
    3.16 + * This software is provided "AS IS" with no warranty of any kind,
    3.17 + * express or implied, and with no claim as to its suitability for any
    3.18 + * purpose.
    3.19 + *
    3.20 + */
    3.21 +
    3.22 +#ifndef LEMON_BITS_DEBUG_MAP_H
    3.23 +#define LEMON_BITS_DEBUG_MAP_H
    3.24 +
    3.25 +#include <vector>
    3.26 +#include <algorithm>
    3.27 +
    3.28 +#include <lemon/bits/traits.h>
    3.29 +#include <lemon/bits/utility.h>
    3.30 +#include <lemon/error.h>
    3.31 +
    3.32 +#include <lemon/bits/alteration_notifier.h>
    3.33 +
    3.34 +#include <lemon/concept_check.h>
    3.35 +#include <lemon/concept/maps.h>
    3.36 +
    3.37 +///\ingroup graphbits
    3.38 +///
    3.39 +///\file
    3.40 +///\brief Vector based graph maps for debugging.
    3.41 +namespace lemon {
    3.42 +
    3.43 +  /// \ingroup graphbits
    3.44 +  ///
    3.45 +  /// \brief Graph map based on the std::vector storage.
    3.46 +  ///
    3.47 +  /// The DebugMap template class is graph map structure what
    3.48 +  /// automatically updates the map when a key is added to or erased from
    3.49 +  /// the map. This map also checks some programming failures by example
    3.50 +  /// multiple addition of items, erasing of not existing item or
    3.51 +  /// not erased items at the destruction of the map. It helps the
    3.52 +  /// programmer to avoid segmentation faults and memory leaks.
    3.53 +  ///
    3.54 +  /// \param Notifier The AlterationNotifier that will notify this map.
    3.55 +  /// \param Item The item type of the graph items.
    3.56 +  /// \param Value The value type of the map.
    3.57 +  /// 
    3.58 +  /// \author Balazs Dezso  	
    3.59 +  template <typename _Graph, typename _Item, typename _Value>
    3.60 +  class DebugMap 
    3.61 +    : public ItemSetTraits<_Graph, _Item>::ItemNotifier::ObserverBase {
    3.62 +  private:
    3.63 +		
    3.64 +    /// The container type of the map.
    3.65 +    typedef std::vector<_Value> Container;	
    3.66 +
    3.67 +    /// The container type of the debug flags.
    3.68 +    typedef std::vector<bool> Flag;	
    3.69 +
    3.70 +  public:
    3.71 +
    3.72 +    static const bool strictCheck = true;
    3.73 +
    3.74 +    struct MapError {
    3.75 +    public:
    3.76 +      virtual ~MapError() {}
    3.77 +      virtual const char* what() const throw() {
    3.78 +        return "lemon::DebugMap::MapError";
    3.79 +      }
    3.80 +    };
    3.81 +
    3.82 +    /// The graph type of the map. 
    3.83 +    typedef _Graph Graph;
    3.84 +    /// The item type of the map.
    3.85 +    typedef _Item Item;
    3.86 +    /// The reference map tag.
    3.87 +    typedef True ReferenceMapTag;
    3.88 +
    3.89 +    /// The key type of the map.
    3.90 +    typedef _Item Key;
    3.91 +    /// The value type of the map.
    3.92 +    typedef _Value Value;
    3.93 +
    3.94 +    /// The notifier type.
    3.95 +    typedef typename ItemSetTraits<_Graph, _Item>::ItemNotifier Notifier;
    3.96 +
    3.97 +    /// The map type.
    3.98 +    typedef DebugMap Map;
    3.99 +    /// The base class of the map.
   3.100 +    typedef typename Notifier::ObserverBase Parent;
   3.101 +
   3.102 +    /// The reference type of the map;
   3.103 +    typedef typename Container::reference Reference;
   3.104 +    /// The const reference type of the map;
   3.105 +    typedef typename Container::const_reference ConstReference;
   3.106 +
   3.107 +
   3.108 +    /// \brief Constructor to attach the new map into the notifier.
   3.109 +    ///
   3.110 +    /// It constructs a map and attachs it into the notifier.
   3.111 +    /// It adds all the items of the graph to the map.
   3.112 +    DebugMap(const Graph& graph) {
   3.113 +      Parent::attach(graph.getNotifier(Item()));
   3.114 +      container.resize(Parent::getNotifier()->maxId() + 1);
   3.115 +      flag.resize(Parent::getNotifier()->maxId() + 1, false);
   3.116 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.117 +      Item it;
   3.118 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.119 +        flag[Parent::getNotifier()->id(it)] = true;
   3.120 +      }
   3.121 +    }
   3.122 +
   3.123 +    /// \brief Constructor uses given value to initialize the map. 
   3.124 +    ///
   3.125 +    /// It constructs a map uses a given value to initialize the map. 
   3.126 +    /// It adds all the items of the graph to the map.
   3.127 +    DebugMap(const Graph& graph, const Value& value) {
   3.128 +      Parent::attach(graph.getNotifier(Item()));
   3.129 +      container.resize(Parent::getNotifier()->maxId() + 1, value);
   3.130 +      flag.resize(Parent::getNotifier()->maxId() + 1, false);
   3.131 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.132 +      Item it;
   3.133 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.134 +        flag[Parent::getNotifier()->id(it)] = true;
   3.135 +      }
   3.136 +    }
   3.137 +
   3.138 +    /// \brief Copy constructor
   3.139 +    ///
   3.140 +    /// Copy constructor.
   3.141 +    DebugMap(const DebugMap& _copy) : Parent() {
   3.142 +      if (_copy.attached()) {
   3.143 +	Parent::attach(*_copy.getNotifier());
   3.144 +	container = _copy.container;
   3.145 +      }
   3.146 +      flag.resize(Parent::getNotifier()->maxId() + 1, false);
   3.147 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.148 +      Item it;
   3.149 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.150 +        flag[Parent::getNotifier()->id(it)] = true;
   3.151 +        LEMON_ASSERT(_copy.flag[Parent::getNotifier()->id(it)], MapError());
   3.152 +      }
   3.153 +    }
   3.154 +
   3.155 +    /// \brief Destructor
   3.156 +    ///
   3.157 +    /// Destructor.
   3.158 +    ~DebugMap() {
   3.159 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.160 +      if (notifier != 0) {
   3.161 +        Item it;
   3.162 +        for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.163 +          LEMON_ASSERT(flag[Parent::getNotifier()->id(it)], MapError());
   3.164 +          flag[Parent::getNotifier()->id(it)] = false;
   3.165 +        }
   3.166 +      }
   3.167 +      for (int i = 0; i < (int)flag.size(); ++i) {
   3.168 +        LEMON_ASSERT(!flag[i], MapError());
   3.169 +      }
   3.170 +    }
   3.171 +
   3.172 +    /// \brief Assign operator.
   3.173 +    ///
   3.174 +    /// This operator assigns for each item in the map the
   3.175 +    /// value mapped to the same item in the copied map.  
   3.176 +    /// The parameter map should be indiced with the same
   3.177 +    /// itemset because this assign operator does not change
   3.178 +    /// the container of the map. 
   3.179 +    DebugMap& operator=(const DebugMap& cmap) {
   3.180 +      return operator=<DebugMap>(cmap);
   3.181 +    }
   3.182 +
   3.183 +
   3.184 +    /// \brief Template assign operator.
   3.185 +    ///
   3.186 +    /// The given parameter should be conform to the ReadMap
   3.187 +    /// concecpt and could be indiced by the current item set of
   3.188 +    /// the NodeMap. In this case the value for each item
   3.189 +    /// is assigned by the value of the given ReadMap. 
   3.190 +    template <typename CMap>
   3.191 +    DebugMap& operator=(const CMap& cmap) {
   3.192 +      checkConcept<concept::ReadMap<Key, _Value>, CMap>();
   3.193 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.194 +      Item it;
   3.195 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.196 +        set(it, cmap[it]);
   3.197 +      }
   3.198 +      return *this;
   3.199 +    }
   3.200 +    
   3.201 +  public:
   3.202 +
   3.203 +    /// \brief The subcript operator.
   3.204 +    ///
   3.205 +    /// The subscript operator. The map can be subscripted by the
   3.206 +    /// actual items of the graph.      
   3.207 +    Reference operator[](const Key& key) {
   3.208 +      LEMON_ASSERT(flag[Parent::getNotifier()->id(key)], MapError());
   3.209 +      return container[Parent::getNotifier()->id(key)];
   3.210 +    } 
   3.211 +		
   3.212 +    /// \brief The const subcript operator.
   3.213 +    ///
   3.214 +    /// The const subscript operator. The map can be subscripted by the
   3.215 +    /// actual items of the graph. 
   3.216 +    ConstReference operator[](const Key& key) const {
   3.217 +      LEMON_ASSERT(flag[Parent::getNotifier()->id(key)], MapError());
   3.218 +      return container[Parent::getNotifier()->id(key)];
   3.219 +    }
   3.220 +
   3.221 +
   3.222 +    /// \brief The setter function of the map.
   3.223 +    ///
   3.224 +    /// It the same as operator[](key) = value expression.
   3.225 +    void set(const Key& key, const Value& value) {
   3.226 +      (*this)[key] = value;
   3.227 +    }
   3.228 +
   3.229 +  protected:
   3.230 +
   3.231 +    /// \brief Adds a new key to the map.
   3.232 +    ///		
   3.233 +    /// It adds a new key to the map. It called by the observer notifier
   3.234 +    /// and it overrides the add() member function of the observer base.     
   3.235 +    virtual void add(const Key& key) {
   3.236 +      int id = Parent::getNotifier()->id(key);
   3.237 +      if (id >= (int)container.size()) {
   3.238 +	container.resize(id + 1);
   3.239 +        flag.resize(id + 1, false);
   3.240 +      }
   3.241 +      LEMON_ASSERT(!flag[Parent::getNotifier()->id(key)], MapError());
   3.242 +      flag[Parent::getNotifier()->id(key)] = true;
   3.243 +      if (strictCheck) {
   3.244 +        std::vector<bool> fl(flag.size(), false);
   3.245 +        const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.246 +        Item it;
   3.247 +        for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.248 +          int id = Parent::getNotifier()->id(it);
   3.249 +          fl[id] = true;
   3.250 +        }
   3.251 +        LEMON_ASSERT(fl == flag, MapError());
   3.252 +      }
   3.253 +    }
   3.254 +
   3.255 +    /// \brief Adds more new keys to the map.
   3.256 +    ///		
   3.257 +    /// It adds more new keys to the map. It called by the observer notifier
   3.258 +    /// and it overrides the add() member function of the observer base.     
   3.259 +    virtual void add(const std::vector<Key>& keys) {
   3.260 +      int max = container.size() - 1;
   3.261 +      for (int i = 0; i < (int)keys.size(); ++i) {
   3.262 +        int id = Parent::getNotifier()->id(keys[i]);
   3.263 +        if (id >= max) {
   3.264 +          max = id;
   3.265 +        }
   3.266 +      }
   3.267 +      container.resize(max + 1);
   3.268 +      flag.resize(max + 1, false);
   3.269 +      for (int i = 0; i < (int)keys.size(); ++i) {
   3.270 +        LEMON_ASSERT(!flag[Parent::getNotifier()->id(keys[i])], MapError());
   3.271 +        flag[Parent::getNotifier()->id(keys[i])] = true;
   3.272 +      }
   3.273 +      if (strictCheck) {
   3.274 +        std::vector<bool> fl(flag.size(), false);
   3.275 +        const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.276 +        Item it;
   3.277 +        for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.278 +          int id = Parent::getNotifier()->id(it);
   3.279 +          fl[id] = true;
   3.280 +        }
   3.281 +        LEMON_ASSERT(fl == flag, MapError());
   3.282 +      }
   3.283 +    }
   3.284 +
   3.285 +    /// \brief Erase a key from the map.
   3.286 +    ///
   3.287 +    /// Erase a key from the map. It called by the observer notifier
   3.288 +    /// and it overrides the erase() member function of the observer base.     
   3.289 +    virtual void erase(const Key& key) {
   3.290 +      if (strictCheck) {
   3.291 +        std::vector<bool> fl(flag.size(), false);
   3.292 +        const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.293 +        Item it;
   3.294 +        for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.295 +          int id = Parent::getNotifier()->id(it);
   3.296 +          fl[id] = true;
   3.297 +        }
   3.298 +        LEMON_ASSERT(fl == flag, MapError());
   3.299 +      }
   3.300 +      container[Parent::getNotifier()->id(key)] = Value();
   3.301 +      LEMON_ASSERT(flag[Parent::getNotifier()->id(key)], MapError());
   3.302 +      flag[Parent::getNotifier()->id(key)] = false;
   3.303 +    }
   3.304 +
   3.305 +    /// \brief Erase more keys from the map.
   3.306 +    ///
   3.307 +    /// Erase more keys from the map. It called by the observer notifier
   3.308 +    /// and it overrides the erase() member function of the observer base.     
   3.309 +    virtual void erase(const std::vector<Key>& keys) {
   3.310 +      if (strictCheck) {
   3.311 +        std::vector<bool> fl(flag.size(), false);
   3.312 +        const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.313 +        Item it;
   3.314 +        for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.315 +          int id = Parent::getNotifier()->id(it);
   3.316 +          fl[id] = true;
   3.317 +        }
   3.318 +        LEMON_ASSERT(fl == flag, MapError());
   3.319 +      }
   3.320 +      for (int i = 0; i < (int)keys.size(); ++i) {
   3.321 +	container[Parent::getNotifier()->id(keys[i])] = Value();
   3.322 +        LEMON_ASSERT(flag[Parent::getNotifier()->id(keys[i])], MapError());
   3.323 +        flag[Parent::getNotifier()->id(keys[i])] = false;
   3.324 +      }
   3.325 +    }
   3.326 +    
   3.327 +    /// \brief Buildes the map.
   3.328 +    ///	
   3.329 +    /// It buildes the map. It called by the observer notifier
   3.330 +    /// and it overrides the build() member function of the observer base.
   3.331 +    virtual void build() { 
   3.332 +      if (strictCheck) {
   3.333 +        for (int i = 0; i < (int)flag.size(); ++i) {
   3.334 +          LEMON_ASSERT(flag[i], MapError());
   3.335 +        }
   3.336 +      }
   3.337 +      int size = Parent::getNotifier()->maxId() + 1;
   3.338 +      container.reserve(size);
   3.339 +      container.resize(size);
   3.340 +      flag.reserve(size);
   3.341 +      flag.resize(size, false);
   3.342 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.343 +      Item it;
   3.344 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.345 +        int id = Parent::getNotifier()->id(it);
   3.346 +        LEMON_ASSERT(!flag[id], MapError());
   3.347 +        flag[id] = true;
   3.348 +      }
   3.349 +    }
   3.350 +
   3.351 +    /// \brief Clear the map.
   3.352 +    ///
   3.353 +    /// It erase all items from the map. It called by the observer notifier
   3.354 +    /// and it overrides the clear() member function of the observer base.     
   3.355 +    virtual void clear() { 
   3.356 +      const typename Parent::Notifier* notifier = Parent::getNotifier();
   3.357 +      Item it;
   3.358 +      for (notifier->first(it); it != INVALID; notifier->next(it)) {
   3.359 +        int id = Parent::getNotifier()->id(it);
   3.360 +        LEMON_ASSERT(flag[id], MapError());
   3.361 +        flag[id] = false;
   3.362 +      }
   3.363 +      if (strictCheck) {
   3.364 +        for (int i = 0; i < (int)flag.size(); ++i) {
   3.365 +          LEMON_ASSERT(!flag[i], MapError());
   3.366 +        }
   3.367 +      }
   3.368 +      container.clear();
   3.369 +      flag.clear();
   3.370 +    }
   3.371 +    
   3.372 +  private:
   3.373 +		
   3.374 +    Container container;
   3.375 +    Flag flag;
   3.376 +
   3.377 +  };
   3.378 +
   3.379 +}
   3.380 +
   3.381 +#endif
     4.1 --- a/lemon/bits/default_map.h	Wed Sep 06 10:10:48 2006 +0000
     4.2 +++ b/lemon/bits/default_map.h	Wed Sep 06 10:19:57 2006 +0000
     4.3 @@ -22,6 +22,7 @@
     4.4  
     4.5  #include <lemon/bits/array_map.h>
     4.6  #include <lemon/bits/vector_map.h>
     4.7 +#include <lemon/bits/debug_map.h>
     4.8  
     4.9  ///\ingroup graphbits
    4.10  ///\file
    4.11 @@ -37,15 +38,6 @@
    4.12      typedef ArrayMap<_Graph, _Item, _Value> Map;
    4.13    };
    4.14  
    4.15 -#else
    4.16 -
    4.17 -  template <typename _Graph, typename _Item, typename _Value>
    4.18 -  struct DefaultMapSelector {
    4.19 -    typedef VectorMap<_Graph, _Item, _Value> Map;
    4.20 -  };
    4.21 -
    4.22 -#endif
    4.23 -
    4.24    // bool
    4.25    template <typename _Graph, typename _Item>
    4.26    struct DefaultMapSelector<_Graph, _Item, bool> {
    4.27 @@ -148,6 +140,15 @@
    4.28      typedef VectorMap<_Graph, _Item, _Ptr*> Map;
    4.29    };
    4.30  
    4.31 +#else 
    4.32 +
    4.33 +  template <typename _Graph, typename _Item, typename _Value>
    4.34 +  struct DefaultMapSelector {
    4.35 +    typedef DebugMap<_Graph, _Item, _Value> Map;
    4.36 +  };
    4.37 +
    4.38 +#endif  
    4.39 +
    4.40    /// \e
    4.41    template <typename _Graph, typename _Item, typename _Value>
    4.42    class DefaultMap 
     5.1 --- a/lemon/bits/vector_map.h	Wed Sep 06 10:10:48 2006 +0000
     5.2 +++ b/lemon/bits/vector_map.h	Wed Sep 06 10:19:57 2006 +0000
     5.3 @@ -42,9 +42,7 @@
     5.4    ///
     5.5    /// The VectorMap template class is graph map structure what
     5.6    /// automatically updates the map when a key is added to or erased from
     5.7 -  /// the map. This map factory uses the allocators to implement 
     5.8 -  /// the container functionality. This map factory
     5.9 -  /// uses the std::vector to implement the container function.
    5.10 +  /// the map. This map type uses the std::vector to store the values.
    5.11    ///
    5.12    /// \param Notifier The AlterationNotifier that will notify this map.
    5.13    /// \param Item The item type of the graph items.