source: trunk/yat/utility/stl_utility.h @ 2964

Last change on this file since 2964 was 2964, checked in by Peter, 9 years ago

prefer quoting like 'this' and not like `this'

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 21.2 KB
Line 
1#ifndef _theplu_yat_utility_stl_utility_
2#define _theplu_yat_utility_stl_utility_
3
4// $Id: stl_utility.h 2964 2013-01-22 04:49:14Z peter $
5
6/*
7  Copyright (C) 2004 Jari Häkkinen
8  Copyright (C) 2005 Jari Häkkinen, Peter Johansson, Markus Ringnér
9  Copyright (C) 2006 Jari Häkkinen
10  Copyright (C) 2007, 2008 Jari Häkkinen, Peter Johansson
11  Copyright (C) 2009, 2010, 2011, 2012 Peter Johansson
12
13  This file is part of the yat library, http://dev.thep.lu.se/yat
14
15  The yat library is free software; you can redistribute it and/or
16  modify it under the terms of the GNU General Public License as
17  published by the Free Software Foundation; either version 3 of the
18  License, or (at your option) any later version.
19
20  The yat library is distributed in the hope that it will be useful,
21  but WITHOUT ANY WARRANTY; without even the implied warranty of
22  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
23  General Public License for more details.
24
25  You should have received a copy of the GNU General Public License
26  along with yat. If not, see <http://www.gnu.org/licenses/>.
27*/
28
29///
30/// \file stl_utility.h
31///
32/// There are a number of useful functionality missing in the Standard
33/// Template Library, STL. This file is an effort to provide
34/// extensions to STL functionality.
35///
36
37#include "concept_check.h"
38#include "DataWeight.h"
39#include "Exception.h"
40
41#include <boost/concept_check.hpp>
42#include <boost/iterator/transform_iterator.hpp>
43#include <boost/mpl/if.hpp>
44#include <boost/type_traits/add_const.hpp>
45#include <boost/type_traits/is_const.hpp>
46#include <boost/type_traits/remove_reference.hpp>
47
48#include <algorithm>
49#include <cmath>
50#include <exception>
51#include <functional>
52#include <iterator>
53#include <map>
54#include <ostream>
55#include <sstream>
56#include <string>
57#include <utility>
58#include <vector>
59
60// We are intruding standard namespace, which might cause
61// conflicts. Let the user turn off these declarations by defining
62// YAT_STD_DISABE
63#ifndef YAT_STD_DISABLE
64namespace std {
65
66  ///
67  /// Print out a pair
68  ///
69  // This is in namespace std because we have not figured out how to have
70  // pair and its operator<< in different namespaces
71  template <class T1, class T2>
72  std::ostream& operator<<(std::ostream& out, const std::pair<T1,T2>& p)
73  { out << p.first << "\t" << p.second; return out; }
74
75}
76#endif
77
78namespace theplu {
79namespace yat {
80namespace utility {
81
82  /**
83     Functor class taking absolute value
84  */
85  template<typename T>
86  struct abs : std::unary_function<T, T>
87  {
88    /**
89       \return absolute value
90     */
91    inline T operator()(T x) const
92    { return std::abs(x); }
93  };
94
95
96  /**
97     \brief Adaptor between pointer and pointee interface
98
99     Functor takes a pointer and returns a reference to the instance
100     pointer is pointing to. Return type is decided by <a
101     href=http://www.sgi.com/tech/stl/iterator_traits.html>
102     std::iterator_traits<Pointer>::reference </a>. Pointer must have
103     an \c operator*, i.e., \c Pointer can be a traditional pointer or
104     an \input_iterator.
105
106     The class is designed to be used with boost::transform_iterator
107
108     \code
109     std::vector<MyClass*> vec;
110     ...
111     Dereferencer<MyClass*> dereferencer;
112     std::set<MyClass> s;
113     s.insert(boost::make_transform_iterator(vec.begin(), dereferencer),
114              boost::make_transform_iterator(vec.end(), dereferencer))
115     \endcode
116
117     where elements in vec<MyClass*> are copied in to set<MyClass>.
118
119     \since New in yat 0.7
120   */
121  template<typename Pointer>
122  struct Dereferencer :
123    public std::unary_function<Pointer,
124                               typename std::iterator_traits<Pointer>::reference>
125  {
126    /**
127       \brief constructor
128     */
129    Dereferencer(void)
130    { BOOST_CONCEPT_ASSERT((TrivialIterator<Pointer>)); }
131
132    /**
133       \return * \a ti
134     */
135    typename std::iterator_traits<Pointer>::reference
136    operator()(Pointer ti) const { return *ti; }
137  };
138
139
140  /**
141     See The C++ Standard Library - A Tutorial and Reference by
142     Nicolai M. Josuttis
143
144     If f is a binary functor, both g and h are unary functors, and
145     return type of g (and h) is convertible to F's argument type,
146     then compose_f_gx_hy can be used to create a functor equivalent
147     to \f$ f(g(x), h(y)) \f$
148
149     - F must be an <a
150     href="http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html">
151     AdaptableBinaryFunction</a>
152     - G must be an <a
153     href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">
154     AdaptableUnaryFunction</a>
155     - H must be an <a
156     href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">
157     AdaptableUnaryFunction</a>
158     - \c G::result_type is convertible to \c F::first_argument_type
159     - \c H::result_type is convertible to \c F::second_argument_type
160
161     \see compose_f_gxy and compose_f_gx
162   */
163  template<class F, class G, class H>
164  class compose_f_gx_hy :
165    public std::binary_function<typename G::argument_type,
166                                typename H::argument_type,
167                                typename F::result_type>
168  {
169  public:
170    /**
171       \brief default constructor
172
173       Requires that F, G, and H have default constructors
174    */
175    compose_f_gx_hy(void) {}
176
177    /**
178       \brief Constructor
179     */
180    compose_f_gx_hy(F f, G g, H h)
181      : f_(f), g_(g), h_(h)
182    {
183      BOOST_CONCEPT_ASSERT((boost::Convertible<typename G::result_type
184                            , typename F::first_argument_type>));
185      BOOST_CONCEPT_ASSERT((boost::Convertible<typename H::result_type
186                            , typename F::second_argument_type>));
187
188    }
189
190    /**
191       \brief Does the work
192     */
193    typename F::result_type
194    operator()(typename G::argument_type x,
195               typename H::argument_type y) const
196    {
197      return f_(g_(x), h_(y));
198    }
199
200  private:
201    F f_;
202    G g_;
203    H h_;
204  };
205
206  /**
207     Convenient function to create a compose_f_gx_hy.
208
209     \relates compose_f_gx_hy
210
211     \see std::make_pair
212  */
213  template<class F, class G, class H>
214  compose_f_gx_hy<F, G, H> make_compose_f_gx_hy(F f, G g, H h)
215  {
216    return compose_f_gx_hy<F,G,H>(f,g,h);
217  }
218
219
220  /**
221     See The C++ Standard Library - A Tutorial and Reference by
222     Nicolai M. Josuttis
223
224     If f is a unary functor, g is a binary functor, and return type
225     of g is convertible to F's argument type, then
226     compose_f_gxy can be used to create a functor equivalent to
227     \f$ f(g(x,y)) \f$
228
229     - F must be an <a
230     href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">
231     AdaptableUnaryFunction</a>
232     - G must be an <a
233     href="http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html">
234     AdaptableBinaryFunction</a>
235     - \c G::result_type is convertible to \c F::argument_type
236
237     \see compose_f_gx_hy and compose_f_gx
238
239     \since New in yat 0.7
240   */
241  template<class F, class G>
242  class compose_f_gxy :
243    public std::binary_function<typename G::first_argument_type,
244                                typename G::second_argument_type,
245                                typename F::result_type>
246  {
247  public:
248    /**
249       \brief default constructor
250
251       Requires that F, G, and H have default constructors
252    */
253    compose_f_gxy(void) {}
254
255    /**
256       \brief Constructor
257     */
258    compose_f_gxy(F f, G g)
259      : f_(f), g_(g)
260    {
261      BOOST_CONCEPT_ASSERT((boost::Convertible<typename G::result_type
262                            , typename F::argument_type>));
263    }
264
265    /**
266       \brief Does the work
267     */
268    typename F::result_type
269    operator()(typename G::first_argument_type x,
270               typename G::second_argument_type y) const
271    {
272      return f_(g_(x,y));
273    }
274
275  private:
276    F f_;
277    G g_;
278  };
279
280  /**
281     Convenient function to create a compose_f_gxy.
282
283     \relates compose_f_gxy
284
285     \see std::make_pair
286
287     \since New in yat 0.7
288  */
289  template<class F, class G>
290  compose_f_gxy<F, G> make_compose_f_gxy(F f, G g)
291  {
292    return compose_f_gxy<F,G>(f,g);
293  }
294
295
296  /**
297     See The C++ Standard Library - A Tutorial and Reference by
298     Nicolai M. Josuttis
299
300     If f is a unary functor, g is a unary functor, and return type of
301     g is convertible to F's argument type, then compose_f_gx can be
302     used to create a functor equivalent to \f$ f(g(x)) \f$
303
304     - F must be an <a
305     href="http://www.sgi.com/tech/stl/AdaptableBinaryFunction.html">
306     AdaptableBinaryFunction</a>
307     - G must be an <a
308     href="http://www.sgi.com/tech/stl/AdaptableUnaryFunction.html">
309     AdaptableUnaryFunction</a>
310     - \c G::result_type is convertible to \c F::argument_type
311
312     \see compose_f_gx_hy and compose_f_gxy
313
314     \since New in yat 0.7
315   */
316  template<class F, class G>
317  class compose_f_gx : public std::unary_function<typename G::argument_type,
318                                                  typename F::result_type>
319  {
320  public:
321    /**
322       \brief default constructor
323
324       Requires that F and H have default constructors
325    */
326    compose_f_gx(void) {}
327
328    /**
329       \brief Constructor
330     */
331    compose_f_gx(F f, G g)
332      : f_(f), g_(g)
333    {
334      BOOST_CONCEPT_ASSERT((boost::Convertible<typename G::result_type
335                            , typename F::argument_type>));
336    }
337
338    /**
339       \brief Does the work
340     */
341    typename F::result_type
342    operator()(typename G::argument_type x) const
343    {
344      return f_(g_(x));
345    }
346
347  private:
348    F f_;
349    G g_;
350  };
351
352  /**
353     Convenient function to create a compose_f_gx.
354
355     \relates compose_f_gx
356
357     \see std::make_pair
358
359     \since New in yat 0.7
360  */
361  template<class F, class G>
362  compose_f_gx<F, G> make_compose_f_gx(F f, G g)
363  {
364    return compose_f_gx<F,G>(f,g);
365  }
366
367
368  /**
369     Functor class to exponentiate values using std::exp
370
371     T should be either \c float, \c double, or \c long \c double
372
373     \since New in yat 0.5
374  */
375  template<typename T>
376  struct Exp : std::unary_function<T, T>
377  {
378    /**
379       \return exponentiated value
380     */
381    inline T operator()(T x) const
382    { return std::exp(x); }
383  };
384
385  /**
386     \brief Identity functor that returns its argument
387
388     \since New in yat 0.7
389   */
390  template<typename T>
391  struct Identity : public std::unary_function<T, T>
392  {
393    /// \return \a arg
394    T operator()(T arg) const { return arg; }
395  };
396
397
398  /**
399     Same functionality as map::operator[] but the function does not
400     modify the map and the function throws if key does not exist in
401     the map.
402
403     \return const reference to m[k]
404
405     \since New in yat 0.7
406   */
407  template <typename Key, typename Tp, typename Compare, typename Alloc>
408  const Tp& get(const std::map<Key, Tp, Compare, Alloc>& m, const Key& k);
409
410
411  /**
412     Creating a map from a range [first, last) such that m[key]
413     returns a vector with indices of which element in [first, last)
414     that is equal to \a key, or more technically: m[element].size()
415     returns number of elements equal to \a element, and
416     m[*element][i] = distance(first, element) for every \a element in
417     [first, last) and \a i smaller than m[element].size().
418
419     Requirement: InputIterator's value type is assignable to Key
420
421     \since New in yat 0.5
422   */
423  template<typename InputIterator, typename Key, typename Comp>
424  void inverse(InputIterator first, InputIterator last,
425               std::map<Key, std::vector<size_t>, Comp >& m)
426  {
427    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
428    BOOST_CONCEPT_ASSERT((boost::Convertible<typename std::iterator_traits<InputIterator>::value_type, Key>));
429    m.clear();
430    for (size_t i=0; first!=last; ++i, ++first)
431      m[*first].push_back(i);
432  }
433
434  /**
435     In the created multimap each element e will fulfill: \f$ *(first
436     + e->second) == e->first \f$
437
438     Requirement: InputIterator's value type is assignable to Key
439
440     \since New in yat 0.5
441   */
442  template<typename Key, typename InputIterator, typename Comp>
443  void inverse(InputIterator first, InputIterator last,
444               std::multimap<Key, size_t, Comp>& m)
445  {
446    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
447    BOOST_CONCEPT_ASSERT((boost::Convertible<typename std::iterator_traits<InputIterator>::value_type, Key>));
448    m.clear();
449    for (size_t i=0; first!=last; ++i, ++first)
450      m.insert(std::make_pair(*first, i));
451  }
452
453
454  /**
455     Create a map mapping from values in range [first, last) to the
456     distance from first.
457
458     Post-condition: m[first[i]] == i (for all i that correspond to a
459     unique element). For non-unique element behaviour is undefined.
460
461     Requirement: InputIterator's value type is assignable to Key
462
463     \since New in yat 0.10
464   */
465  template<typename InputIterator, typename Key, typename Comp>
466  void inverse(InputIterator first, InputIterator last,
467               std::map<Key, size_t, Comp >& m)
468  {
469    BOOST_CONCEPT_ASSERT((boost::InputIterator<InputIterator>));
470    BOOST_CONCEPT_ASSERT((boost::Convertible<typename std::iterator_traits<InputIterator>::value_type, Key>));
471    m.clear();
472    for (size_t i=0; first!=last; ++i, ++first)
473      m[*first] = i;
474  }
475
476  /**
477     \brief Functor that behaves like std::less with the exception
478     that it treates NaN as a number larger than infinity.
479
480     This functor is useful when sorting ranges with NaNs. The problem
481     with NaNs is that std::less always returns \c false when one of
482     the arguments is NaN. That together with the fact that std::sort
483     only guarantees that an element \c i is never less than previous
484     element \c --i. Therefore {10, NaN, 2} is sorted according to
485     this definition, but most often it is desired that the 2 is
486     located before the 10 in the range. Using this functor, less_nan,
487     this can easily be achieved as std::sort(first, last, less_nan)
488
489     The default implementation uses std::isnan(T), which consequently
490     must be supported.
491
492     There is a specialization less_nan<DataWeight>
493
494     \since New in yat 0.6
495  */
496  template<typename T>
497  struct less_nan : std::binary_function<T, T, bool>
498  {
499    /**
500       \return \c true if x is less than y. NaNs are treated as a number
501       larger than infinity, which implies \c true is returned if y is
502       NaN and x is not.
503     */
504    inline bool operator()(T x, T y) const
505    {
506      if (std::isnan(x))
507        return false;
508      if (std::isnan(y))
509        return true;
510      return x<y;
511    }
512  };
513
514
515  /**
516     \brief Specialization for DataWeight.
517   */
518  template<>
519  struct less_nan<DataWeight>
520    : std::binary_function<DataWeight, DataWeight, bool>
521  {
522    /**
523       \return less_nan<double>(x.data(), y.data())
524     */
525    inline bool operator()(const DataWeight& x, const DataWeight& y) const
526    {
527      less_nan<double> compare;
528      return compare(x.data(), y.data());
529    }
530  };
531
532
533  /**
534     Functor class to take logarithm
535
536     T should be either \c float, \c double, or \c long \c double
537
538     \since New in yat 0.5
539  */
540  template<typename T>
541  class Log : std::unary_function<T, T>
542  {
543  public:
544    /**
545       Default constructor using natural base \f$ e \f$
546     */
547    Log(void)
548      : log_base_(1.0) {}
549
550    /**
551       \param base Taking logarithm in which base, e.g. 2 or 10.
552    */
553    explicit Log(double base) : log_base_(std::log(base)) {}
554
555    /**
556       \return logarithm
557     */
558    inline T operator()(T x) const
559    { return std::log(x)/log_base_; }
560
561  private:
562    double log_base_;
563  };
564
565  /**
566     \return max of values
567   */
568  template <typename T>
569  T max(const T& a, const T& b, const T& c)
570  {
571    return std::max(std::max(a,b),c);
572  }
573
574
575  /**
576     \return max of values
577   */
578  template <typename T>
579  T max(const T& a, const T& b, const T& c, const T& d)
580  {
581    return std::max(std::max(a,b), std::max(c,d));
582  }
583
584
585  /**
586     \return max of values
587   */
588  template <typename T>
589  T max(const T& a, const T& b, const T& c, const T& d, const T& e)
590  {
591    return std::max(max(a,b,c,d), e);
592  }
593
594
595  /**
596     \return max of values
597   */
598  template <typename T>
599  T max(const T& a, const T& b, const T& c, const T& d, const T& e, const T& f)
600  {
601    return std::max(max(a,b,c,d), std::max(e,f));
602  }
603
604
605  ///
606  /// @brief Functor comparing pairs using second.
607  ///
608  /// STL provides operator< for the pair.first element, but none for
609  /// pair.second. This template provides this and can be used as the
610  /// comparison object in generic functions such as the STL sort.
611  ///
612  template <class T1,class T2>
613  struct pair_value_compare
614  {
615    ///
616    /// @return true if x.second<y.second or (!(y.second<y.second) and
617    /// x.first<y.first)
618    ///
619    inline bool operator()(const std::pair<T1,T2>& x,
620                           const std::pair<T1,T2>& y) {
621      return ((x.second<y.second) ||
622              (!(y.second<x.second) && (x.first<y.first)));
623    }
624  };
625
626  /**
627     \brief Functor that return std::pair.first
628
629     \see pair_first_iterator
630
631     \since New in yat 0.5
632   */
633  template <class Pair>
634  struct PairFirst
635  {
636    /**
637       The type returned is Pair::first_type& with the exception when
638       Pair is const and Pair::first_type is non-const, in which case
639       const Pair::first_type& is return type.
640     */
641    typedef typename boost::mpl::if_<
642                  typename boost::is_const<Pair>::type,
643                  typename boost::add_const<typename Pair::first_type>::type&,
644                  typename Pair::first_type&>::type result_type;
645
646    /**
647       The argument type is Pair&.
648     */
649    typedef Pair& argument_type;
650
651    /**
652       \return p.first
653     */
654    inline result_type operator()(argument_type p) const
655    { return p.first; }
656
657  };
658
659
660  /**
661     \brief Functor that return std::pair.second
662
663     \see pair_second_iterator
664
665     \since New in yat 0.5
666   */
667  template <class Pair>
668  struct PairSecond
669  {
670    /**
671       The type returned is Pair::second_type& with the exception when
672       Pair is const and Pair::second_type is non-const, in which case
673       const Pair::first_type& is return type.
674     */
675    typedef typename boost::mpl::if_<
676                  typename boost::is_const<Pair>::type,
677                  typename boost::add_const<typename Pair::second_type>::type&,
678                  typename Pair::second_type&>::type result_type;
679
680    /**
681       The argument type is Pair&.
682     */
683    typedef Pair& argument_type;
684
685    /**
686       \return p.first
687     */
688    inline result_type operator()(argument_type p) const
689    { return p.second; }
690
691  };
692
693
694  /**
695     Creates a transform_iterator that transforms an iterator with
696     value type std::pair to an iterator with value type
697     std::pair::first_type. This can be used, for example, to
698     communicate between a std::map and std::vector
699
700     \code
701     std::map<std::string, int> map;
702     ...
703     std::vector<std::string> vec;
704     vec.resize(map.size());
705     std::copy(pair_first_iterator(map.begin()), pair_first_iterator(map.end()),
706               vec.begin());
707     \endcode
708
709     \since New in yat 0.5
710   */
711  template<class Iter>
712  boost::transform_iterator<
713    PairFirst<typename boost::remove_reference<
714                 typename std::iterator_traits<Iter>::reference
715                 >::type>,
716    Iter> pair_first_iterator(Iter i)
717  {
718    // We are going via ::reference in order to remain const info;
719    // ::value_type does not contain const information.
720    typedef typename std::iterator_traits<Iter>::reference ref_type;
721    typedef typename boost::remove_reference<ref_type>::type val_type;
722    typedef PairFirst<val_type> PF;
723    return boost::transform_iterator<PF, Iter>(i, PF());
724  }
725
726
727  /**
728     Creates a transform_iterator that transforms an iterator with
729     value type std::pair to an iterator with value type
730     std::pair::second_type. This can be used, for example, to
731     communicate between a std::map and std::vector
732
733     \code
734     std::map<std::string, int> map;
735     ...
736     std::vector<int> vec(map.size(),0);
737     std::copy(vec.begin(), vec.end(), pair_second_iterator(map.begin()));
738     \endcode
739
740     \since New in yat 0.5
741   */
742  template<class Iter>
743  boost::transform_iterator<
744    PairSecond<typename boost::remove_reference<
745                 typename std::iterator_traits<Iter>::reference
746                 >::type>,
747    Iter> pair_second_iterator(Iter i)
748  {
749    // We are going via ::reference in order to remain const info;
750    // ::value_type does not contain const information.
751    typedef typename std::iterator_traits<Iter>::reference ref_type;
752    typedef typename boost::remove_reference<ref_type>::type val_type;
753    typedef PairSecond<val_type> PS;
754    return boost::transform_iterator<PS, Iter>(i, PS());
755  }
756
757
758  /**
759     Convenient function that creates a binary predicate that can be
760     used to compare pointers when you want to compare them with
761     respect to the objects they point to.
762
763     Example:
764     \code
765     std::vector<MyClass*> vec(18);
766     ...
767     std::sort(vec.begin(), vec.end(),
768               make_ptr_compare(vec[0], std::greater<MyClass>());
769     \endcode
770
771
772     Type Requirement:
773     - \a compare must be a <a
774     href="http://www.sgi.com/tech/stl/AdaptableBinaryPredicate.html">Adaptable
775     Binary Predicate</a>.
776     - value_type of Pointer must be convertible to argument_type of
777       compare
778
779     \return a compose_f_gx_hy in which \c F is defined by \a compare
780     and both \c G and \c H are \c Dereferencer functors.
781
782     \see compose_f_gx_hy
783
784     \since New in yat 0.7
785   */
786  template<typename Pointer, class Compare>
787  compose_f_gx_hy<Compare, Dereferencer<Pointer>, Dereferencer<Pointer> >
788  make_ptr_compare(Pointer p, Compare compare)
789  {
790    return make_compose_f_gx_hy(compare, Dereferencer<Pointer>(),
791                                Dereferencer<Pointer>());
792  }
793
794  /**
795     Same as make_ptr_compare(2) except that std::less is used to
796     compare pointers.
797
798     \since New in yat 0.7
799   */
800  template<typename Pointer>
801  compose_f_gx_hy<std::less<typename std::iterator_traits<Pointer>::value_type>,
802                  Dereferencer<Pointer>, Dereferencer<Pointer> >
803  make_ptr_compare(Pointer p)
804  {
805    typedef typename std::iterator_traits<Pointer>::value_type value_type;
806    BOOST_CONCEPT_ASSERT((boost::LessThanComparable<value_type>));
807    std::less<value_type> compare;
808    return make_ptr_compare(p, compare);
809  }
810
811
812  ///
813  /// @brief Function converting a string to lower case
814  ///
815  std::string& to_lower(std::string& s);
816
817  ///
818  /// @brief Function converting a string to upper case
819  ///
820  std::string& to_upper(std::string& s);
821
822
823  // template implementations
824
825  template <typename Key, typename Tp, typename Compare, typename Alloc>
826  const Tp& get(const std::map<Key, Tp, Compare, Alloc>& m, const Key& key)
827  {
828    typename std::map<Key, Tp, Compare,Alloc>::const_iterator iter(m.find(key));
829    if (iter==m.end()) {
830      std::stringstream ss;
831      ss << "utility::get(const Map&, const Key&): '"
832         << key << "' not found in map\n";
833      throw runtime_error(ss.str());
834    }
835    return iter->second;
836  }
837
838}}} // of namespace utility, yat, and theplu
839#endif
Note: See TracBrowser for help on using the repository browser.