~twpol/dcplusplus/trunk

« back to all changes in this revision

Viewing changes to boost/boost/units/io.hpp

  • Committer: James Ross
  • Date: 2010-07-05 00:03:18 UTC
  • mfrom: (1524.1.650 dcplusplus)
  • Revision ID: silver@warwickcompsoc.co.uk-20100705000318-awwqm8ocpp5m47yz
Merged to trunk.

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
// Boost.Units - A C++ library for zero-overhead dimensional analysis and 
2
 
// unit/quantity manipulation and conversion
3
 
//
4
 
// Copyright (C) 2003-2008 Matthias Christian Schabel
5
 
// Copyright (C) 2007-2008 Steven Watanabe
6
 
//
7
 
// Distributed under the Boost Software License, Version 1.0. (See
8
 
// accompanying file LICENSE_1_0.txt or copy at
9
 
// http://www.boost.org/LICENSE_1_0.txt)
10
 
 
11
 
#ifndef BOOST_UNITS_IO_HPP
12
 
#define BOOST_UNITS_IO_HPP
13
 
 
14
 
#include <cassert>
15
 
#include <string>
16
 
#include <iosfwd>
17
 
#include <ios>
18
 
#include <sstream>
19
 
 
20
 
#include <boost/mpl/size.hpp>
21
 
#include <boost/mpl/begin.hpp>
22
 
#include <boost/mpl/next.hpp>
23
 
#include <boost/mpl/deref.hpp>
24
 
#include <boost/serialization/nvp.hpp>
25
 
 
26
 
#include <boost/units/units_fwd.hpp>
27
 
#include <boost/units/heterogeneous_system.hpp>
28
 
#include <boost/units/quantity.hpp>
29
 
#include <boost/units/scale.hpp>
30
 
#include <boost/units/static_rational.hpp>
31
 
#include <boost/units/unit.hpp>
32
 
#include <boost/units/detail/utility.hpp>
33
 
 
34
 
namespace boost {
35
 
 
36
 
namespace serialization {
37
 
 
38
 
/// Boost Serialization library support for units.
39
 
template<class Archive,class System,class Dim>
40
 
inline void serialize(Archive& ar,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
41
 
{ }
42
 
 
43
 
/// Boost Serialization library support for quantities.
44
 
template<class Archive,class Unit,class Y>
45
 
inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
46
 
{
47
 
    ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
48
 
}
49
 
        
50
 
} // namespace serialization
51
 
 
52
 
namespace units {
53
 
 
54
 
// get string representation of arbitrary type
55
 
template<class T> std::string to_string(const T& t)
56
 
{
57
 
    std::stringstream sstr;
58
 
    
59
 
    sstr << t;
60
 
    
61
 
    return sstr.str();
62
 
}
63
 
 
64
 
// get string representation of integral-valued @c static_rational
65
 
template<integer_type N> std::string to_string(const static_rational<N>&)
66
 
{
67
 
    return to_string(N);
68
 
}
69
 
 
70
 
// get string representation of @c static_rational
71
 
template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
72
 
{
73
 
    return '(' + to_string(N) + '/' + to_string(D) + ')';
74
 
}
75
 
 
76
 
/// Write @c static_rational to @c std::basic_ostream.
77
 
template<class Char, class Traits, integer_type N, integer_type D>
78
 
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
79
 
{
80
 
    os << to_string(r);
81
 
    return os;
82
 
}
83
 
 
84
 
/// traits template for unit names
85
 
template<class BaseUnit>
86
 
struct base_unit_info
87
 
{
88
 
    /// The full name of the unit (returns BaseUnit::name() by default)
89
 
    static std::string name()
90
 
    {
91
 
        return(BaseUnit::name());
92
 
    }
93
 
    
94
 
    /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
95
 
    static std::string symbol()
96
 
    {
97
 
        return(BaseUnit::symbol());
98
 
    }
99
 
};
100
 
 
101
 
enum format_mode 
102
 
{
103
 
    symbol_fmt = 0,     // default - reduces unit names to known symbols for both base and derived units
104
 
    name_fmt,           // output full unit names for base and derived units
105
 
    raw_fmt,            // output only symbols for base units 
106
 
    typename_fmt        // output demangled typenames
107
 
};
108
 
 
109
 
namespace detail {
110
 
 
111
 
template<bool>
112
 
struct xalloc_key_holder 
113
 
{
114
 
    static int value;
115
 
    static bool initialized;
116
 
};
117
 
 
118
 
template<bool b>
119
 
int xalloc_key_holder<b>::value = 0;
120
 
 
121
 
template<bool b>
122
 
bool xalloc_key_holder<b>::initialized = 0;
123
 
 
124
 
struct xalloc_key_initializer_t 
125
 
{
126
 
    xalloc_key_initializer_t() 
127
 
    {
128
 
        if (!xalloc_key_holder<true>::initialized) 
129
 
        {
130
 
            xalloc_key_holder<true>::value = std::ios_base::xalloc();
131
 
            xalloc_key_holder<true>::initialized = true;
132
 
        }
133
 
    }
134
 
};
135
 
 
136
 
namespace /**/ {
137
 
    
138
 
xalloc_key_initializer_t xalloc_key_initializer;
139
 
 
140
 
} // namespace
141
 
 
142
 
} // namespace detail
143
 
 
144
 
inline format_mode get_format(std::ios_base& ios) 
145
 
{
146
 
    return(static_cast<format_mode>(ios.iword(detail::xalloc_key_holder<true>::value)));
147
 
}
148
 
 
149
 
inline void set_format(std::ios_base& ios, format_mode new_mode) 
150
 
{
151
 
    ios.iword(detail::xalloc_key_holder<true>::value) = static_cast<long>(new_mode);
152
 
}
153
 
 
154
 
inline std::ios_base& typename_format(std::ios_base& ios) 
155
 
{
156
 
    (set_format)(ios, typename_fmt);
157
 
    return(ios);
158
 
}
159
 
 
160
 
inline std::ios_base& raw_format(std::ios_base& ios) 
161
 
{
162
 
    (set_format)(ios, raw_fmt);
163
 
    return(ios);
164
 
}
165
 
 
166
 
inline std::ios_base& symbol_format(std::ios_base& ios) 
167
 
{
168
 
    (set_format)(ios, symbol_fmt);
169
 
    return(ios);
170
 
}
171
 
 
172
 
inline std::ios_base& name_format(std::ios_base& ios) 
173
 
{
174
 
    (set_format)(ios, name_fmt);
175
 
    return(ios);
176
 
}
177
 
 
178
 
namespace detail {
179
 
 
180
 
template<integer_type N, integer_type D>
181
 
inline std::string exponent_string(const static_rational<N,D>& r)
182
 
{
183
 
    return '^' + to_string(r);
184
 
}
185
 
 
186
 
template<>
187
 
inline std::string exponent_string(const static_rational<1>&)
188
 
{
189
 
    return "";
190
 
}
191
 
 
192
 
template<class T>
193
 
inline std::string base_unit_symbol_string(const T&)
194
 
{
195
 
    return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
196
 
}
197
 
 
198
 
template<class T>    
199
 
inline std::string base_unit_name_string(const T&)
200
 
{
201
 
    return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
202
 
}
203
 
 
204
 
// stringify with symbols
205
 
template<int N>
206
 
struct symbol_string_impl
207
 
{
208
 
    template<class Begin>
209
 
    struct apply
210
 
    {
211
 
        typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
212
 
        static void value(std::string& str)
213
 
        {
214
 
            str += base_unit_symbol_string(typename Begin::item()) + ' ';
215
 
            next::value(str);
216
 
        }
217
 
    };
218
 
};
219
 
 
220
 
template<>
221
 
struct symbol_string_impl<1>
222
 
{
223
 
    template<class Begin>
224
 
    struct apply
225
 
    {
226
 
        static void value(std::string& str)
227
 
        {
228
 
            str += base_unit_symbol_string(typename Begin::item());
229
 
        };
230
 
    };
231
 
};
232
 
 
233
 
template<>
234
 
struct symbol_string_impl<0>
235
 
{
236
 
    template<class Begin>
237
 
    struct apply
238
 
    {
239
 
        static void value(std::string& str)
240
 
        {
241
 
            // better shorthand for dimensionless?
242
 
            str += "dimensionless";
243
 
        }
244
 
    };
245
 
};
246
 
 
247
 
template<int N>
248
 
struct scale_symbol_string_impl 
249
 
{
250
 
    template<class Begin>
251
 
    struct apply 
252
 
    {
253
 
        static void value(std::string& str) 
254
 
        {
255
 
            str += Begin::item::symbol();
256
 
            scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
257
 
        }
258
 
    };
259
 
};
260
 
 
261
 
template<>
262
 
struct scale_symbol_string_impl<0>
263
 
{
264
 
    template<class Begin>
265
 
    struct apply 
266
 
    {
267
 
        static void value(std::string&) { }
268
 
    };
269
 
};
270
 
 
271
 
// stringify with names
272
 
template<int N>
273
 
struct name_string_impl
274
 
{
275
 
    template<class Begin>
276
 
    struct apply
277
 
    {
278
 
        typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
279
 
        static void value(std::string& str)
280
 
        {
281
 
            str += base_unit_name_string(typename Begin::item()) + ' ';
282
 
            next::value(str);
283
 
        }
284
 
    };
285
 
};
286
 
 
287
 
template<>
288
 
struct name_string_impl<1>
289
 
{
290
 
    template<class Begin>
291
 
    struct apply
292
 
    {
293
 
        static void value(std::string& str)
294
 
        {
295
 
            str += base_unit_name_string(typename Begin::item());
296
 
        };
297
 
    };
298
 
};
299
 
 
300
 
template<>
301
 
struct name_string_impl<0>
302
 
{
303
 
    template<class Begin>
304
 
    struct apply
305
 
    {
306
 
        static void value(std::string& str)
307
 
        {
308
 
            str += "dimensionless";
309
 
        }
310
 
    };
311
 
};
312
 
 
313
 
template<int N>
314
 
struct scale_name_string_impl 
315
 
{
316
 
    template<class Begin>
317
 
    struct apply 
318
 
    {
319
 
        static void value(std::string& str) 
320
 
        {
321
 
            str += Begin::item::name();
322
 
            scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
323
 
        }
324
 
    };
325
 
};
326
 
 
327
 
template<>
328
 
struct scale_name_string_impl<0>
329
 
{
330
 
    template<class Begin>
331
 
    struct apply 
332
 
    {
333
 
        static void value(std::string&) { }
334
 
    };
335
 
};
336
 
 
337
 
} // namespace detail
338
 
 
339
 
namespace detail {
340
 
 
341
 
// These two overloads of symbol_string and name_string will
342
 
// will pick up homogeneous_systems.  They simply call the
343
 
// appropriate function with a heterogeneous_system.
344
 
template<class Dimension,class System, class SubFormatter>
345
 
inline std::string
346
 
to_string_impl(const unit<Dimension,System>&, SubFormatter f)
347
 
{
348
 
    return f(typename reduce_unit<unit<Dimension, System> >::type());
349
 
}
350
 
 
351
 
/// INTERNAL ONLY
352
 
// this overload picks up heterogeneous units that are not scaled.
353
 
template<class Dimension,class Units, class Subformatter>
354
 
inline std::string
355
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
356
 
{
357
 
    std::string str;
358
 
    f.template append_units_to<Units>(str);
359
 
    return(str);
360
 
}
361
 
 
362
 
// This overload is a special case for heterogeneous_system which
363
 
// is really unitless
364
 
/// INTERNAL ONLY
365
 
template<class Subformatter>
366
 
inline std::string
367
 
to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
368
 
{
369
 
    return("dimensionless");
370
 
}
371
 
 
372
 
// this overload deals with heterogeneous_systems which are unitless
373
 
// but scaled.
374
 
/// INTERNAL ONLY
375
 
template<class Scale, class Subformatter>
376
 
inline std::string
377
 
to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
378
 
{
379
 
    std::string str;
380
 
    f.template append_scale_to<Scale>(str);
381
 
    return(str);
382
 
}
383
 
 
384
 
// this overload deals with scaled units.
385
 
/// INTERNAL ONLY
386
 
template<class Dimension,class Units,class Scale, class Subformatter>
387
 
inline std::string
388
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
389
 
{
390
 
    std::string str;
391
 
 
392
 
    f.template append_scale_to<Scale>(str);
393
 
 
394
 
    std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
395
 
    
396
 
    if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
397
 
    {
398
 
        str += "(";
399
 
        str += without_scale;
400
 
        str += ")";
401
 
    } 
402
 
    else 
403
 
    {
404
 
        str += without_scale;
405
 
    }
406
 
 
407
 
    return(str);
408
 
}
409
 
 
410
 
// this overload catches scaled units that have a single base unit
411
 
// raised to the first power.  It causes si::nano * si::meters to not
412
 
// put parentheses around the meters.  i.e. nm rather than n(m)
413
 
/// INTERNAL ONLY
414
 
template<class Dimension,class Unit,class Scale, class Subformatter>
415
 
inline std::string
416
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
417
 
{
418
 
    std::string str;
419
 
 
420
 
    f.template append_scale_to<Scale>(str);
421
 
    str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
422
 
 
423
 
    return(str);
424
 
}
425
 
 
426
 
// this overload is necessary to disambiguate.
427
 
// it catches units that are unscaled and have a single
428
 
// base unit raised to the first power.  It is treated the
429
 
// same as any other unscaled unit.
430
 
/// INTERNAL ONLY
431
 
template<class Dimension,class Unit,class Subformatter>
432
 
inline std::string
433
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f)
434
 
{
435
 
    std::string str;
436
 
    f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
437
 
    return(str);
438
 
}
439
 
 
440
 
 
441
 
// this overload catches scaled units that have a single scaled base unit
442
 
// raised to the first power.  It moves that scaling on the base unit
443
 
// to the unit level scaling and recurses.  By doing this we make sure that
444
 
// si::milli * si::kilograms will print g rather than mkg
445
 
//
446
 
/// INTERNAL ONLY
447
 
template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
448
 
inline std::string
449
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
450
 
{
451
 
    return(f(
452
 
        unit<
453
 
            Dimension,
454
 
            heterogeneous_system<
455
 
                heterogeneous_system_impl<
456
 
                    list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
457
 
                    Dimension,
458
 
                    typename mpl::times<Scale, list<UnitScale, dimensionless_type> >::type
459
 
                >
460
 
            >
461
 
        >()));
462
 
}
463
 
 
464
 
// this overload disambuguates between the overload for an unscaled unit
465
 
// and the overload for a scaled base unit raised to the first power.
466
 
/// INTERNAL ONLY
467
 
template<class Dimension,class Unit,class UnitScale,class Subformatter>
468
 
inline std::string
469
 
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f)
470
 
{
471
 
    std::string str;
472
 
    f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
473
 
    return(str);
474
 
}
475
 
 
476
 
struct format_raw_symbol_impl {
477
 
    template<class Units>
478
 
    void append_units_to(std::string& str) {
479
 
        detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
480
 
    }
481
 
    template<class Scale>
482
 
    void append_scale_to(std::string& str) {
483
 
        detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
484
 
    }
485
 
    template<class Unit>
486
 
    std::string operator()(const Unit& unit) {
487
 
        return(to_string_impl(unit, *this));
488
 
    }
489
 
    template<class Unit>
490
 
    bool is_default_string(const std::string&, const Unit&) {
491
 
        return(true);
492
 
    }
493
 
};
494
 
 
495
 
struct format_symbol_impl : format_raw_symbol_impl {
496
 
    template<class Unit>
497
 
    std::string operator()(const Unit& unit) {
498
 
        return(symbol_string(unit));
499
 
    }
500
 
    template<class Unit>
501
 
    bool is_default_string(const std::string& str, const Unit& unit) {
502
 
        return(str == to_string_impl(unit, format_raw_symbol_impl()));
503
 
    }
504
 
};
505
 
 
506
 
struct format_raw_name_impl {
507
 
    template<class Units>
508
 
    void append_units_to(std::string& str) {
509
 
        detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
510
 
    }
511
 
    template<class Scale>
512
 
    void append_scale_to(std::string& str) {
513
 
        detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
514
 
    }
515
 
    template<class Unit>
516
 
    std::string operator()(const Unit& unit) {
517
 
        return(to_string_impl(unit, *this));
518
 
    }
519
 
    template<class Unit>
520
 
    bool is_default_string(const std::string&, const Unit&) {
521
 
        return(true);
522
 
    }
523
 
};
524
 
 
525
 
struct format_name_impl : format_raw_name_impl {
526
 
    template<class Unit>
527
 
    std::string operator()(const Unit& unit) {
528
 
        return(name_string(unit));
529
 
    }
530
 
    template<class Unit>
531
 
    bool is_default_string(const std::string& str, const Unit& unit) {
532
 
        return(str == to_string_impl(unit, format_raw_name_impl()));
533
 
    }
534
 
};
535
 
 
536
 
} // namespace detail
537
 
 
538
 
template<class Dimension,class System>
539
 
inline std::string
540
 
typename_string(const unit<Dimension, System>&)
541
 
{
542
 
    return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
543
 
}
544
 
 
545
 
template<class Dimension,class System>
546
 
inline std::string
547
 
symbol_string(const unit<Dimension, System>&)
548
 
{
549
 
    return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
550
 
}
551
 
 
552
 
template<class Dimension,class System>
553
 
inline std::string
554
 
name_string(const unit<Dimension, System>&)
555
 
{
556
 
    return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
557
 
}
558
 
 
559
 
/// Print an @c unit as a list of base units and exponents
560
 
///
561
 
///     for @c symbol_format this gives e.g. "m s^-1" or "J"
562
 
///     for @c name_format this gives e.g. "meter second^-1" or "joule"
563
 
///     for @c raw_format this gives e.g. "m s^-1" or "meter kilogram^2 second^-2"
564
 
///     for @c typename_format this gives the typename itself (currently demangled only on GCC)
565
 
template<class Char, class Traits, class Dimension, class System>
566
 
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
567
 
{
568
 
    if (units::get_format(os) == typename_fmt) 
569
 
    {
570
 
        os << typename_string(u);
571
 
    } 
572
 
    else if (units::get_format(os) == raw_fmt) 
573
 
    {
574
 
        os << detail::to_string_impl(u, detail::format_raw_symbol_impl());
575
 
    } 
576
 
    else if (units::get_format(os) == symbol_fmt) 
577
 
    {
578
 
        os << symbol_string(u);
579
 
    } 
580
 
    else if (units::get_format(os) == name_fmt) 
581
 
    {
582
 
        os << name_string(u);
583
 
    } 
584
 
    else 
585
 
    {
586
 
        assert(!"The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
587
 
    }
588
 
    
589
 
    return(os);
590
 
}
591
 
 
592
 
/// INTERNAL ONLY
593
 
/// Print a @c quantity. Prints the value followed by the unit
594
 
template<class Char, class Traits, class Unit, class T>
595
 
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
596
 
{
597
 
    os << q.value() << ' ' << Unit();
598
 
    return(os);
599
 
}
600
 
 
601
 
} // namespace units
602
 
 
603
 
} // namespace boost
604
 
 
605
 
#endif
 
1
// Boost.Units - A C++ library for zero-overhead dimensional analysis and 
 
2
// unit/quantity manipulation and conversion
 
3
//
 
4
// Copyright (C) 2003-2008 Matthias Christian Schabel
 
5
// Copyright (C) 2007-2008 Steven Watanabe
 
6
//
 
7
// Distributed under the Boost Software License, Version 1.0. (See
 
8
// accompanying file LICENSE_1_0.txt or copy at
 
9
// http://www.boost.org/LICENSE_1_0.txt)
 
10
 
 
11
#ifndef BOOST_UNITS_IO_HPP
 
12
#define BOOST_UNITS_IO_HPP
 
13
 
 
14
#include <cassert>
 
15
#include <string>
 
16
#include <iosfwd>
 
17
#include <ios>
 
18
#include <sstream>
 
19
 
 
20
#include <boost/mpl/size.hpp>
 
21
#include <boost/mpl/begin.hpp>
 
22
#include <boost/mpl/next.hpp>
 
23
#include <boost/mpl/deref.hpp>
 
24
#include <boost/serialization/nvp.hpp>
 
25
 
 
26
#include <boost/units/units_fwd.hpp>
 
27
#include <boost/units/heterogeneous_system.hpp>
 
28
#include <boost/units/quantity.hpp>
 
29
#include <boost/units/scale.hpp>
 
30
#include <boost/units/static_rational.hpp>
 
31
#include <boost/units/unit.hpp>
 
32
#include <boost/units/detail/utility.hpp>
 
33
 
 
34
namespace boost {
 
35
 
 
36
namespace serialization {
 
37
 
 
38
/// Boost Serialization library support for units.
 
39
template<class Archive,class System,class Dim>
 
40
inline void serialize(Archive& ar,boost::units::unit<Dim,System>&,const unsigned int /*version*/)
 
41
{ }
 
42
 
 
43
/// Boost Serialization library support for quantities.
 
44
template<class Archive,class Unit,class Y>
 
45
inline void serialize(Archive& ar,boost::units::quantity<Unit,Y>& q,const unsigned int /*version*/)
 
46
{
 
47
    ar & boost::serialization::make_nvp("value", units::quantity_cast<Y&>(q));
 
48
}
 
49
        
 
50
} // namespace serialization
 
51
 
 
52
namespace units {
 
53
 
 
54
// get string representation of arbitrary type
 
55
template<class T> std::string to_string(const T& t)
 
56
{
 
57
    std::stringstream sstr;
 
58
    
 
59
    sstr << t;
 
60
    
 
61
    return sstr.str();
 
62
}
 
63
 
 
64
// get string representation of integral-valued @c static_rational
 
65
template<integer_type N> std::string to_string(const static_rational<N>&)
 
66
{
 
67
    return to_string(N);
 
68
}
 
69
 
 
70
// get string representation of @c static_rational
 
71
template<integer_type N, integer_type D> std::string to_string(const static_rational<N,D>&)
 
72
{
 
73
    return '(' + to_string(N) + '/' + to_string(D) + ')';
 
74
}
 
75
 
 
76
/// Write @c static_rational to @c std::basic_ostream.
 
77
template<class Char, class Traits, integer_type N, integer_type D>
 
78
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os,const static_rational<N,D>& r)
 
79
{
 
80
    os << to_string(r);
 
81
    return os;
 
82
}
 
83
 
 
84
/// traits template for unit names
 
85
template<class BaseUnit>
 
86
struct base_unit_info
 
87
{
 
88
    /// The full name of the unit (returns BaseUnit::name() by default)
 
89
    static std::string name()
 
90
    {
 
91
        return(BaseUnit::name());
 
92
    }
 
93
    
 
94
    /// The symbol for the base unit (Returns BaseUnit::symbol() by default)
 
95
    static std::string symbol()
 
96
    {
 
97
        return(BaseUnit::symbol());
 
98
    }
 
99
};
 
100
 
 
101
enum format_mode 
 
102
{
 
103
    symbol_fmt = 0,     // default - reduces unit names to known symbols for both base and derived units
 
104
    name_fmt,           // output full unit names for base and derived units
 
105
    raw_fmt,            // output only symbols for base units 
 
106
    typename_fmt        // output demangled typenames
 
107
};
 
108
 
 
109
namespace detail {
 
110
 
 
111
template<bool>
 
112
struct xalloc_key_holder 
 
113
{
 
114
    static int value;
 
115
    static bool initialized;
 
116
};
 
117
 
 
118
template<bool b>
 
119
int xalloc_key_holder<b>::value = 0;
 
120
 
 
121
template<bool b>
 
122
bool xalloc_key_holder<b>::initialized = 0;
 
123
 
 
124
struct xalloc_key_initializer_t 
 
125
{
 
126
    xalloc_key_initializer_t() 
 
127
    {
 
128
        if (!xalloc_key_holder<true>::initialized) 
 
129
        {
 
130
            xalloc_key_holder<true>::value = std::ios_base::xalloc();
 
131
            xalloc_key_holder<true>::initialized = true;
 
132
        }
 
133
    }
 
134
};
 
135
 
 
136
namespace /**/ {
 
137
    
 
138
xalloc_key_initializer_t xalloc_key_initializer;
 
139
 
 
140
} // namespace
 
141
 
 
142
} // namespace detail
 
143
 
 
144
inline format_mode get_format(std::ios_base& ios) 
 
145
{
 
146
    return(static_cast<format_mode>(ios.iword(detail::xalloc_key_holder<true>::value)));
 
147
}
 
148
 
 
149
inline void set_format(std::ios_base& ios, format_mode new_mode) 
 
150
{
 
151
    ios.iword(detail::xalloc_key_holder<true>::value) = static_cast<long>(new_mode);
 
152
}
 
153
 
 
154
inline std::ios_base& typename_format(std::ios_base& ios) 
 
155
{
 
156
    (set_format)(ios, typename_fmt);
 
157
    return(ios);
 
158
}
 
159
 
 
160
inline std::ios_base& raw_format(std::ios_base& ios) 
 
161
{
 
162
    (set_format)(ios, raw_fmt);
 
163
    return(ios);
 
164
}
 
165
 
 
166
inline std::ios_base& symbol_format(std::ios_base& ios) 
 
167
{
 
168
    (set_format)(ios, symbol_fmt);
 
169
    return(ios);
 
170
}
 
171
 
 
172
inline std::ios_base& name_format(std::ios_base& ios) 
 
173
{
 
174
    (set_format)(ios, name_fmt);
 
175
    return(ios);
 
176
}
 
177
 
 
178
namespace detail {
 
179
 
 
180
template<integer_type N, integer_type D>
 
181
inline std::string exponent_string(const static_rational<N,D>& r)
 
182
{
 
183
    return '^' + to_string(r);
 
184
}
 
185
 
 
186
template<>
 
187
inline std::string exponent_string(const static_rational<1>&)
 
188
{
 
189
    return "";
 
190
}
 
191
 
 
192
template<class T>
 
193
inline std::string base_unit_symbol_string(const T&)
 
194
{
 
195
    return base_unit_info<typename T::tag_type>::symbol() + exponent_string(typename T::value_type());
 
196
}
 
197
 
 
198
template<class T>    
 
199
inline std::string base_unit_name_string(const T&)
 
200
{
 
201
    return base_unit_info<typename T::tag_type>::name() + exponent_string(typename T::value_type());
 
202
}
 
203
 
 
204
// stringify with symbols
 
205
template<int N>
 
206
struct symbol_string_impl
 
207
{
 
208
    template<class Begin>
 
209
    struct apply
 
210
    {
 
211
        typedef typename symbol_string_impl<N-1>::template apply<typename Begin::next> next;
 
212
        static void value(std::string& str)
 
213
        {
 
214
            str += base_unit_symbol_string(typename Begin::item()) + ' ';
 
215
            next::value(str);
 
216
        }
 
217
    };
 
218
};
 
219
 
 
220
template<>
 
221
struct symbol_string_impl<1>
 
222
{
 
223
    template<class Begin>
 
224
    struct apply
 
225
    {
 
226
        static void value(std::string& str)
 
227
        {
 
228
            str += base_unit_symbol_string(typename Begin::item());
 
229
        };
 
230
    };
 
231
};
 
232
 
 
233
template<>
 
234
struct symbol_string_impl<0>
 
235
{
 
236
    template<class Begin>
 
237
    struct apply
 
238
    {
 
239
        static void value(std::string& str)
 
240
        {
 
241
            // better shorthand for dimensionless?
 
242
            str += "dimensionless";
 
243
        }
 
244
    };
 
245
};
 
246
 
 
247
template<int N>
 
248
struct scale_symbol_string_impl 
 
249
{
 
250
    template<class Begin>
 
251
    struct apply 
 
252
    {
 
253
        static void value(std::string& str) 
 
254
        {
 
255
            str += Begin::item::symbol();
 
256
            scale_symbol_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
 
257
        }
 
258
    };
 
259
};
 
260
 
 
261
template<>
 
262
struct scale_symbol_string_impl<0>
 
263
{
 
264
    template<class Begin>
 
265
    struct apply 
 
266
    {
 
267
        static void value(std::string&) { }
 
268
    };
 
269
};
 
270
 
 
271
// stringify with names
 
272
template<int N>
 
273
struct name_string_impl
 
274
{
 
275
    template<class Begin>
 
276
    struct apply
 
277
    {
 
278
        typedef typename name_string_impl<N-1>::template apply<typename Begin::next> next;
 
279
        static void value(std::string& str)
 
280
        {
 
281
            str += base_unit_name_string(typename Begin::item()) + ' ';
 
282
            next::value(str);
 
283
        }
 
284
    };
 
285
};
 
286
 
 
287
template<>
 
288
struct name_string_impl<1>
 
289
{
 
290
    template<class Begin>
 
291
    struct apply
 
292
    {
 
293
        static void value(std::string& str)
 
294
        {
 
295
            str += base_unit_name_string(typename Begin::item());
 
296
        };
 
297
    };
 
298
};
 
299
 
 
300
template<>
 
301
struct name_string_impl<0>
 
302
{
 
303
    template<class Begin>
 
304
    struct apply
 
305
    {
 
306
        static void value(std::string& str)
 
307
        {
 
308
            str += "dimensionless";
 
309
        }
 
310
    };
 
311
};
 
312
 
 
313
template<int N>
 
314
struct scale_name_string_impl 
 
315
{
 
316
    template<class Begin>
 
317
    struct apply 
 
318
    {
 
319
        static void value(std::string& str) 
 
320
        {
 
321
            str += Begin::item::name();
 
322
            scale_name_string_impl<N - 1>::template apply<typename Begin::next>::value(str);
 
323
        }
 
324
    };
 
325
};
 
326
 
 
327
template<>
 
328
struct scale_name_string_impl<0>
 
329
{
 
330
    template<class Begin>
 
331
    struct apply 
 
332
    {
 
333
        static void value(std::string&) { }
 
334
    };
 
335
};
 
336
 
 
337
} // namespace detail
 
338
 
 
339
namespace detail {
 
340
 
 
341
// These two overloads of symbol_string and name_string will
 
342
// will pick up homogeneous_systems.  They simply call the
 
343
// appropriate function with a heterogeneous_system.
 
344
template<class Dimension,class System, class SubFormatter>
 
345
inline std::string
 
346
to_string_impl(const unit<Dimension,System>&, SubFormatter f)
 
347
{
 
348
    return f(typename reduce_unit<unit<Dimension, System> >::type());
 
349
}
 
350
 
 
351
/// INTERNAL ONLY
 
352
// this overload picks up heterogeneous units that are not scaled.
 
353
template<class Dimension,class Units, class Subformatter>
 
354
inline std::string
 
355
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >&, Subformatter f)
 
356
{
 
357
    std::string str;
 
358
    f.template append_units_to<Units>(str);
 
359
    return(str);
 
360
}
 
361
 
 
362
// This overload is a special case for heterogeneous_system which
 
363
// is really unitless
 
364
/// INTERNAL ONLY
 
365
template<class Subformatter>
 
366
inline std::string
 
367
to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, dimensionless_type> > >&, Subformatter)
 
368
{
 
369
    return("dimensionless");
 
370
}
 
371
 
 
372
// this overload deals with heterogeneous_systems which are unitless
 
373
// but scaled.
 
374
/// INTERNAL ONLY
 
375
template<class Scale, class Subformatter>
 
376
inline std::string
 
377
to_string_impl(const unit<dimensionless_type, heterogeneous_system<heterogeneous_system_impl<dimensionless_type, dimensionless_type, Scale> > >&, Subformatter f)
 
378
{
 
379
    std::string str;
 
380
    f.template append_scale_to<Scale>(str);
 
381
    return(str);
 
382
}
 
383
 
 
384
// this overload deals with scaled units.
 
385
/// INTERNAL ONLY
 
386
template<class Dimension,class Units,class Scale, class Subformatter>
 
387
inline std::string
 
388
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, Scale> > >&, Subformatter f)
 
389
{
 
390
    std::string str;
 
391
 
 
392
    f.template append_scale_to<Scale>(str);
 
393
 
 
394
    std::string without_scale = f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >());
 
395
    
 
396
    if (f.is_default_string(without_scale, unit<Dimension, heterogeneous_system<heterogeneous_system_impl<Units, Dimension, dimensionless_type> > >()))
 
397
    {
 
398
        str += "(";
 
399
        str += without_scale;
 
400
        str += ")";
 
401
    } 
 
402
    else 
 
403
    {
 
404
        str += without_scale;
 
405
    }
 
406
 
 
407
    return(str);
 
408
}
 
409
 
 
410
// this overload catches scaled units that have a single base unit
 
411
// raised to the first power.  It causes si::nano * si::meters to not
 
412
// put parentheses around the meters.  i.e. nm rather than n(m)
 
413
/// INTERNAL ONLY
 
414
template<class Dimension,class Unit,class Scale, class Subformatter>
 
415
inline std::string
 
416
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
 
417
{
 
418
    std::string str;
 
419
 
 
420
    f.template append_scale_to<Scale>(str);
 
421
    str += f(unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >());
 
422
 
 
423
    return(str);
 
424
}
 
425
 
 
426
// this overload is necessary to disambiguate.
 
427
// it catches units that are unscaled and have a single
 
428
// base unit raised to the first power.  It is treated the
 
429
// same as any other unscaled unit.
 
430
/// INTERNAL ONLY
 
431
template<class Dimension,class Unit,class Subformatter>
 
432
inline std::string
 
433
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f)
 
434
{
 
435
    std::string str;
 
436
    f.template append_units_to<list<heterogeneous_system_dim<Unit, static_rational<1> >,dimensionless_type> >(str);
 
437
    return(str);
 
438
}
 
439
 
 
440
 
 
441
// this overload catches scaled units that have a single scaled base unit
 
442
// raised to the first power.  It moves that scaling on the base unit
 
443
// to the unit level scaling and recurses.  By doing this we make sure that
 
444
// si::milli * si::kilograms will print g rather than mkg
 
445
//
 
446
/// INTERNAL ONLY
 
447
template<class Dimension,class Unit,class UnitScale, class Scale, class Subformatter>
 
448
inline std::string
 
449
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, Dimension, Scale> > >&, Subformatter f)
 
450
{
 
451
    return(f(
 
452
        unit<
 
453
            Dimension,
 
454
            heterogeneous_system<
 
455
                heterogeneous_system_impl<
 
456
                    list<heterogeneous_system_dim<Unit, static_rational<1> >, dimensionless_type>,
 
457
                    Dimension,
 
458
                    typename mpl::times<Scale, list<UnitScale, dimensionless_type> >::type
 
459
                >
 
460
            >
 
461
        >()));
 
462
}
 
463
 
 
464
// this overload disambuguates between the overload for an unscaled unit
 
465
// and the overload for a scaled base unit raised to the first power.
 
466
/// INTERNAL ONLY
 
467
template<class Dimension,class Unit,class UnitScale,class Subformatter>
 
468
inline std::string
 
469
to_string_impl(const unit<Dimension, heterogeneous_system<heterogeneous_system_impl<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type>, Dimension, dimensionless_type> > >&, Subformatter f)
 
470
{
 
471
    std::string str;
 
472
    f.template append_units_to<list<heterogeneous_system_dim<scaled_base_unit<Unit, UnitScale>, static_rational<1> >, dimensionless_type> >(str);
 
473
    return(str);
 
474
}
 
475
 
 
476
struct format_raw_symbol_impl {
 
477
    template<class Units>
 
478
    void append_units_to(std::string& str) {
 
479
        detail::symbol_string_impl<Units::size::value>::template apply<Units>::value(str);
 
480
    }
 
481
    template<class Scale>
 
482
    void append_scale_to(std::string& str) {
 
483
        detail::scale_symbol_string_impl<Scale::size::value>::template apply<Scale>::value(str);
 
484
    }
 
485
    template<class Unit>
 
486
    std::string operator()(const Unit& unit) {
 
487
        return(to_string_impl(unit, *this));
 
488
    }
 
489
    template<class Unit>
 
490
    bool is_default_string(const std::string&, const Unit&) {
 
491
        return(true);
 
492
    }
 
493
};
 
494
 
 
495
struct format_symbol_impl : format_raw_symbol_impl {
 
496
    template<class Unit>
 
497
    std::string operator()(const Unit& unit) {
 
498
        return(symbol_string(unit));
 
499
    }
 
500
    template<class Unit>
 
501
    bool is_default_string(const std::string& str, const Unit& unit) {
 
502
        return(str == to_string_impl(unit, format_raw_symbol_impl()));
 
503
    }
 
504
};
 
505
 
 
506
struct format_raw_name_impl {
 
507
    template<class Units>
 
508
    void append_units_to(std::string& str) {
 
509
        detail::name_string_impl<(Units::size::value)>::template apply<Units>::value(str);
 
510
    }
 
511
    template<class Scale>
 
512
    void append_scale_to(std::string& str) {
 
513
        detail::scale_name_string_impl<Scale::size::value>::template apply<Scale>::value(str);
 
514
    }
 
515
    template<class Unit>
 
516
    std::string operator()(const Unit& unit) {
 
517
        return(to_string_impl(unit, *this));
 
518
    }
 
519
    template<class Unit>
 
520
    bool is_default_string(const std::string&, const Unit&) {
 
521
        return(true);
 
522
    }
 
523
};
 
524
 
 
525
struct format_name_impl : format_raw_name_impl {
 
526
    template<class Unit>
 
527
    std::string operator()(const Unit& unit) {
 
528
        return(name_string(unit));
 
529
    }
 
530
    template<class Unit>
 
531
    bool is_default_string(const std::string& str, const Unit& unit) {
 
532
        return(str == to_string_impl(unit, format_raw_name_impl()));
 
533
    }
 
534
};
 
535
 
 
536
template<class Char, class Traits>
 
537
inline void do_print(std::basic_ostream<Char, Traits>& os, const std::string& s) {
 
538
    os << s.c_str();
 
539
}
 
540
 
 
541
inline void do_print(std::ostream& os, const std::string& s) {
 
542
    os << s;
 
543
}
 
544
 
 
545
template<class Char, class Traits>
 
546
inline void do_print(std::basic_ostream<Char, Traits>& os, const char* s) {
 
547
    os << s;
 
548
}
 
549
 
 
550
} // namespace detail
 
551
 
 
552
template<class Dimension,class System>
 
553
inline std::string
 
554
typename_string(const unit<Dimension, System>&)
 
555
{
 
556
    return simplify_typename(typename reduce_unit< unit<Dimension,System> >::type());
 
557
}
 
558
 
 
559
template<class Dimension,class System>
 
560
inline std::string
 
561
symbol_string(const unit<Dimension, System>&)
 
562
{
 
563
    return detail::to_string_impl(unit<Dimension,System>(), detail::format_symbol_impl());
 
564
}
 
565
 
 
566
template<class Dimension,class System>
 
567
inline std::string
 
568
name_string(const unit<Dimension, System>&)
 
569
{
 
570
    return detail::to_string_impl(unit<Dimension,System>(), detail::format_name_impl());
 
571
}
 
572
 
 
573
/// Print an @c unit as a list of base units and exponents
 
574
///
 
575
///     for @c symbol_format this gives e.g. "m s^-1" or "J"
 
576
///     for @c name_format this gives e.g. "meter second^-1" or "joule"
 
577
///     for @c raw_format this gives e.g. "m s^-1" or "meter kilogram^2 second^-2"
 
578
///     for @c typename_format this gives the typename itself (currently demangled only on GCC)
 
579
template<class Char, class Traits, class Dimension, class System>
 
580
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const unit<Dimension, System>& u)
 
581
{
 
582
    if (units::get_format(os) == typename_fmt) 
 
583
    {
 
584
        detail::do_print(os , typename_string(u));
 
585
    }
 
586
    else if (units::get_format(os) == raw_fmt) 
 
587
    {
 
588
        detail::do_print(os, detail::to_string_impl(u, detail::format_raw_symbol_impl()));
 
589
    }
 
590
    else if (units::get_format(os) == symbol_fmt) 
 
591
    {
 
592
        detail::do_print(os, symbol_string(u));
 
593
    }
 
594
    else if (units::get_format(os) == name_fmt) 
 
595
    {
 
596
        detail::do_print(os, name_string(u));
 
597
    }
 
598
    else 
 
599
    {
 
600
        assert(!"The format mode must be one of: typename_format, raw_format, name_format, symbol_format");
 
601
    }
 
602
    
 
603
    return(os);
 
604
}
 
605
 
 
606
/// INTERNAL ONLY
 
607
/// Print a @c quantity. Prints the value followed by the unit
 
608
template<class Char, class Traits, class Unit, class T>
 
609
inline std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& os, const quantity<Unit, T>& q)
 
610
{
 
611
    os << q.value() << ' ' << Unit();
 
612
    return(os);
 
613
}
 
614
 
 
615
} // namespace units
 
616
 
 
617
} // namespace boost
 
618
 
 
619
#endif