1 // ---------------------------------------------------------------------------
2 // Utilities for use with Scott Meyers' "Effective STL" Course.
3 // Copyright 2000 by Scott Meyers.
4 //
5 // Last modified 3/27/01.
6 //
7 // This file offers four basic utilities:
8 //   - A preprocessor symbol, MSVC, that's defined only when compiling with
9 //     MSVC.
10 //   - Functions to help fill containers with seqences of values.  Search
11 //     for "makeSequence".
12 //   - Functions to print the contents of STL containers.  Search for
13 //     "printContainer"
14 //   - A class to time how long it takes to do something.  Search for
15 //     "Timer".
16 // Note that everything in this file except MSVC is in the namespace
17 // ESTLUtils.  (Macros and preprocessor symbols never respect namespace
18 // boundaries.)
19 //
20 // Platforms on which this header has so far been tested:
21 //   Borland C++ 5.5, native library, WinNT 4.0
22 //   MetroWerks CodeWarrior Pro 5.3, native library, WinNT 4.0 or
23 //     MetroWerks CodeWarrior Pro 6.0, native library, Windows 2000
24 //   Microsoft Visual C++ 6.0 (SP3), native library, WinNT 4.0
25 //   Gnu gcc 2.95.2 (mingw32 distribution), native library, WinNT 4.0
26 //   Comeau C++ 4.2.45.2, native library, Windows 2000
27 //
28 // All functions are inline, because otherwise MSVC complains about
29 // multiply defined symbols when linking projects made up of multiple
30 // source files, at least two of which #include this file.
31 // ---------------------------------------------------------------------------
32 #ifndef ESTLUTILS_H
33 #define ESTLUTILS_H
34 
35 #include <algorithm>
36 #include <functional>
37 #include <iostream>
38 #include <string>
39 #include <ctime>
40 #include "InitUtil.h"
41 
42 // ---------------------------------------------------------------------------
43 // MSVC6, when used in conjunction with the library that ships with the
44 // compiler, has some limitations not present in most other compilers
45 // (e.g., it lacks member templates), so it's convenient to know when we're
46 // compiling with MSVC6.  The following figures that out.  (In theory, all
47 // we need to do is look for the preprocessor symbol "_MSC_VER"), but other
48 // compilers for Windows define that, too, so we need to rule the other
49 // compilers out before concluding that we've got MSVC.)
50 //
51 // If you're using MSVC6, but you're not using the library that ships with
52 // the compiler, much of the conditional compilation for MSVC may become
53 // unnecessary.  MSVC6 does have limitations, but it is a much more capable
54 // compiler than the library shipping with it suggests.
55 // ---------------------------------------------------------------------------
56 #if defined(_MSC_VER) && !defined(__MWERKS__) && !defined(__ICL) && !defined(__COMO__) && !defined(__BORLANDC__)
57   #define MSVC
58 # endif
59 
60 
61 namespace ESTLUtils {
62 
63   // -------------------------------------------------------------------------
64   // SequenceGenerator is a functor class template whose function objects
65   // generate arithmetic sequences of values.  Rather than creating
66   // SequenceGenerator objects directly, clients are expected to use the
67   // convenience function makeSequence (see below).  (This is analogous to
68   // how STL clients use make_pair() instead of creating pair<T1, T2>
69   // objects directly.)
70   //
71   // On the off chance you care, SequenceGenerator/makeSequence is a
72   // generalization of the "iota" algorithm that was in the original STL
73   // but that failed to make it into standard C++.
74   // -------------------------------------------------------------------------
75   template<typename T>
76   class SequenceGenerator {
77   public:
78     SequenceGenerator(const T& initValue = T(), const T& increment = 1)
nextVal(initValue)79     : nextVal(initValue), incr(increment) {}
80 
operator()81     T operator()()
82     {
83       T valToReturn(nextVal);
84       nextVal += incr;
85       return valToReturn;
86     }
87 
88   private:
89     T nextVal;
90     T incr;
91   };
92 
93   // -------------------------------------------------------------------------
94   // The makeSequence functions generate objects that themselves generate
95   // sequences of values.  By default, the values are of type int, the
96   // initial value is 0, and the increment between values is 1.  All these
97   // defaults may be overridden.  makeSequence is designed to be used with
98   // the generate_n algorithm to fill containers with values.  Here are
99   // three examples of how it is expected to be used:
100   //
101   //   list<int> L;
102   //   generate_n(back_inserter(L), 5,     // insert 0, 1, 2, 3, 4, and 5
103   //              makeSequence());         // into L
104   //
105   //   vector<int> v;
106   //   generate_n(back_inserter(v), 3,     // insert 50, 51, and 52 into v
107   //              makeSequence(50));
108   //
109   //   deque<double> d;
110   //   generate_n(back_inserter(d), 10,    // insert 0.5, 1.5, ..., 9.5
111   //              makeSequence(0.5, 1.0)); // into d
112   //
113   // Note that makeSequence() can't be used to generate values for maps or
114   // multimaps, because it generates sequences of individual values, not
115   // sequences of pairs.
116   // -------------------------------------------------------------------------
117   inline
makeSequence()118   SequenceGenerator<int> makeSequence()
119   {
120     return SequenceGenerator<int>(0, 1);
121   }
122 
123   template<typename T>
124   inline
125   SequenceGenerator<T> makeSequence(const T& initValue = T(),
126                                     const T& increment = 1)
127   {
128     return SequenceGenerator<T>(initValue, increment);
129   }
130 
131 
132   // -------------------------------------------------------------------------
133   // The following templates generate functions to print the contents of
134   // one or two containers:
135   //
136   //   printContainer(container);
137   //   printContainer(container, stream);
138   //   printContainer(name, container);
139   //   printContainer(name, container, stream);
140   //
141   //   printContainers(container1, container2);
142   //   printContainers(container1, container2, stream);
143   //   printContainers(name1, container1, name2, container2);
144   //   printContainers(name1, container1, name2, container2, stream);
145   //
146   // The next two are just macros (by LZ). They use the container's name
147   // as the name, and don't have "overloads" to specify a stream. They're
148   // for quick-and-dirty console debugging only:
149   //
150   //   show(container1)
151   //   show2(container1, container2)
152   //
153   // For containers of pointers other than char* and const char*, each of
154   // the above dereferences each pointer before printing.  Containers of
155   // pairs (including maps and multimaps) print each pair like this:
156   // "(key,value)".
157   //
158   // For most platforms, the implementation is relatively straightforward:
159   // printContainers creates and invokes printValue objects, and printValue
160   // is partially specialized for pairs and pointer types and fully
161   // specialized for char* and const char* types.  Alas, MSVC lacks support
162   // for partial specialization, so we have to play games from the world of
163   // template metaprogramming, and even those we have to modify to work
164   // around the lack of partial specialization.  The MSVC implementation is
165   // based on a posting to comp.lang.c++.moderated by Aleksey Gurtovoy.
166   // -------------------------------------------------------------------------
167 #ifndef MSVC
168   // Print a non-pointer value.  (A specialization for when T=std::pair is
169   // below.)
170   template<typename T>
171   struct printValue {
operatorprintValue172     void operator()(std::ostream& s, const T& val) const
173     { s << val; }
174   };
175 
176   // Print a pointed-to value.  (Specializations for char* and const char*
177   // are below.)
178   template<typename T>
179   struct printValue<T*> {
180     void operator()(std::ostream& s, const T* pVal) const
181     { if (pVal)		// Modified by LZ to handle null pointers
182 		s << *pVal;
183 	  else
184 		s << "(null)";
185 	}
186   };
187 
188   // print a const char*
189   template<>
190   struct printValue<const char*> {
191     void operator()(std::ostream& s, const char* pVal) const
192     { s << pVal; }
193   };
194 
195   // print a char*
196   template<>
197   struct printValue<char*> {
198     void operator()(std::ostream& s, char* pVal) const
199     { s << pVal; }
200   };
201 
202   // print a std::pair
203   template<typename K, typename V>
204   struct printValue<std::pair<K, V> > {
205     void operator()(std::ostream& s, const std::pair<K, V>& p) const
206     {
207       s << '(';
208       printValue<K>()(s, p.first);
209       s << ',';
210       printValue<V>()(s, p.second);
211       s << ')';
212     }
213   };
214 #else
215   // MSVC lacks partial template specialization, so the approach above
216   // won't work.  Instead, we call TypeQuery::examine on an object of type
217   // T, and the result type of the function call is used as an additional
218   // argument to drive overloading resolution among several functions named
219   // printValue.
220   struct IsAPtr {};             // TypeQuery::examine returns this if T is
221                                 // a pointer.
222   struct IsAPair {};            // It returns this if T is a std::pair.
223   struct IsNothingSpecial {};   // Otherwise it returns this type.
224 
225   struct TypeQuery {
226     static IsAPtr examine(const void*) { return IsAPtr(); }
227 
228     template<typename K, typename V>
229     static IsAPair examine(const std::pair<K, V>&) { return IsAPair(); }
230 
231     static IsNothingSpecial examine(...) { return IsNothingSpecial(); }
232   };
233 
234   // Print a non-pointer value.  (A specialization for when T=std::pair is
235   // below.)
236   template<typename T>
237   inline
238   void printValue(std::ostream& s, const T& val, IsNothingSpecial)
239   { s << val; }
240 
241   // Print a pointed-to value.  (Specializations for char* and const char*
242   // are below.)
243   template<typename T>
244   inline
245   void printValue(std::ostream& s, const T& val, IsAPtr)
246   {
247 	  if (val)		// Modified by LZ to handle null pointers
248 		  s << *val;
249   	  else
250 		  s << "(null)";
251   }
252 
253   // print a const char*
254   template<>
255   inline
256   void printValue<const char*>(std::ostream& s, const char * const & val,
257                                IsAPtr)
258   { s << val; }
259 
260   // print a char*
261   template<>
262   inline
263   void printValue<char*>(std::ostream& s, char * const & val, IsAPtr)
264   { s << val; }
265 
266   // print a std::pair
267   template<typename K, typename V>
268   inline
269   void printValue(std::ostream& s, const std::pair<K, V>& p,
270                   IsAPair)
271     {
272       s << '(';
273       printValue(s, p.first, TypeQuery::examine(p.first));
274       s << ',';
275       printValue(s, p.second, TypeQuery::examine(p.second));
276       s << ')';
277     }
278 #endif
279 
280   ////////////////////////////////////////////////////////////////////////////
281   // In case you're looking for it, here's the main printContainer function.
282   ////////////////////////////////////////////////////////////////////////////
283   template<typename Container>
284   inline
285   void printContainer(const Container& c, std::ostream& s = std::cout)
286   {
287     using namespace std;
288 
289     // for non-MSVC, we could probably use for_each and bind1st to
290     // eliminate the explicit loop, but this works fine, and it's easier to
291     // understand for new STL users.
292     for (typename Container::const_iterator b = c.begin();
293          b != c.end();
294          ++b) {
295 #ifndef MSVC
296       printValue<typename Container::value_type>()(s, *b);
297 #else
298       printValue(s, *b, TypeQuery::examine(*b));
299 #endif
300       s << ' ';
301     }
302     s << endl;
303   }
304 
305 #ifndef MSVC
306   // This version of printContainer is for when the container is a string.
307   // It prints the contents of the string as you'd expect.
308   inline
309   void printContainer(const std::string& s, std::ostream& stream)
310   {
311     using namespace std;
312 
313     stream << s << endl;
314   }
315 #else
316   // MSVC thinks the above function is a specialization of
317   // printContainer<Container> instead of a standalone function.  To
318   // suppress that interpretation, we give this version of printContainer
319   // an extra, unused, parameter with a default value (so callers can
320   // ignore it).  Thanks to Eric Merrill for the workaround.
321   inline
322   void printContainer(const std::string& s, std::ostream& stream = std::cout,
323                       int /* dummyParameter */ = 0)
324   {
325     using namespace std;
326 
327     stream << s << endl;
328   }
329 #endif
330 
331   template<typename Container>
332   inline
333   void printContainer(const char *name, const Container& c,
334                       std::ostream& s = std::cout)
335   {
336     using namespace std;
337 
338     cout << name << ": ";
339     printContainer(c, s);
340   }
341 
342   template<typename Container>
343   inline
344   void printContainer(const std::string& name, const Container& c,
345                       std::ostream& s = std::cout)
346   {
347     printContainer(name.c_str(), c, s);
348   }
349 
350   template<typename Container1, typename Container2>
351   inline
352   void printContainers(const Container1& c1, const Container2& c2,
353                        std::ostream& s = std::cout)
354   {
355     printContainer(c1, s);
356     printContainer(c2, s);
357   }
358 
359   template<typename Container1, typename Container2>
360   inline
361   void printContainers(const char *name1, const Container1& c1,
362                        const char *name2, const Container2& c2,
363                        std::ostream& s = std::cout)
364   {
365     printContainer(name1, c1, s);
366     printContainer(name2, c2, s);
367   }
368 
369   template<typename Container1, typename Container2>
370   inline
371   void printContainers(const std::string& name1, const Container1& c1,
372                        const std::string& name2, const Container2& c2,
373                        std::ostream& s = std::cout)
374   {
375     printContainers(name1.c_str(), c1, name2.c_str(), c2, s);
376   }
377 
378 
379 
380 //
381 // by LZ: Convenience macros to display containers using their names
382 //		  as the labels:
383 //
384 
385 //
386 //	show(Container)
387 //						Display container's name and contents
388 
389 #define show(container) ESTLUtils::printContainer(#container, container)
390 
391 //
392 //	show2(Container, Container)
393 //
394 
395 #define show2(c1, c2) ESTLUtils::printContainers(#c1, c2, #c2, c2)
396 
397 
398 
399 
400   // -------------------------------------------------------------------------
401   // A Timer object keeps track of CPU time used since the object was
402   // created or last reset.  It implicitly converts to a double, so it can
403   // be used like this:
404   //
405   //   Timer t;             // begin timing some operation
406   //   ...
407   //   cout << t;           // print out how much CPU time has elapsed
408   //                        // in seconds
409   //
410   // MSVC doesn't understand that the contents of <ctime> are supposed to
411   // be in std, so for MSVC, we make them global.  Note that the macro
412   // CLOCKS_PER_SEC is global regardless.  After all, it's a macro.
413   //
414   // This is a portable, but fairly crude way to time things.  For a full
415   // discussion of its limitations, including an approach to overcoming
416   // them, consult Chapter 19 of "STL Tutorial and Reference Guide,"
417   // (second edition), by David R. Musser, Gillmer J. Derge, and Atul
418   // Saini, Addison-Wesley, 2001.
419   // ---------------------------------------------------------------------------
420 #ifdef MSVC
421   #define STD_CLOCK_T  clock_t
422   #define STD_CLOCK    clock
423   #define STD_DIFFTIME difftime
424 #else
425   #define STD_CLOCK_T  std::clock_t
426   #define STD_CLOCK    std::clock
427   #define STD_DIFFTIME std::difftime
428 #endif
429 
430   class Timer {
431   public:
432     Timer(): start(STD_CLOCK()) {}
433 
434     operator double() const
435     { return (STD_CLOCK() - start) / static_cast<double>(CLOCKS_PER_SEC); }
436 
437     void reset() { start = STD_CLOCK(); }
438 
439   private:
440     STD_CLOCK_T start;
441   };
442 
443 }  // namespace ESTLUtils
444 
445 #endif
446