1 /// @file
2 // Boost.Convert
3 // Copyright (c) 2009-2014 Vladimir Batov.
4 //
5 // Many thanks to Julian Gonggrijp, Rob Stewart, Andrzej Krzemienski, Matus Chochlik, Jeroen Habraken,
6 // Hartmut Kaiser, Joel De Guzman, Thijs (M.A.) van den Berg, Roland Bock, Gavin Lambert, Paul Bristow,
7 // Alex Hagen-Zanker, Christopher Kormanyos for taking part in the Boost.Convert review.
8 //
9 // Special thanks to:
10 //
11 // 1. Alex Hagen-Zanker, Roland Bock, Rob Stewart for their considerable contributions to the design
12 //    and implementation of the library;
13 // 2. Andrzej Krzemienski for helping to partition responsibilities and to ultimately pave
14 //    the way for the boost::optional and future std::tr2::optional deployment;
15 // 3. Edward Diener the Boost Review Manager for helping with the converters' design, his continuous
16 //    involvement, technical and administrative help, guidance and advice;
17 // 4. Joel De Guzman, Rob Stewart and Alex Hagen-Zanker for making sure the performance tests work
18 //    as they should;
19 // 5. Paul Bristow for helping great deal with the documentation;
20 // 6. Kevlin Henney and Dave Abrahams for their lexical_cast-related insights and explanations.
21 //
22 // Use, modification and distribution are subject to the Boost Software License,
23 // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
24 
25 #ifndef BOOST_CONVERT_HPP
26 #define BOOST_CONVERT_HPP
27 
28 #include <boost/convert/detail/is_fun.hpp>
29 #include <boost/ref.hpp>
30 
31 namespace boost
32 {
33     namespace detail { enum throw_on_failure {}; }
34 
35     /// @details The boost::throw_on_failure is the name of an object of the
36     /// boost::detail::throw_on_failure type that is used to indicate
37     /// desired exception-throwing behavior.
38     detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0);
39 
40     namespace cnv
41     {
42         template<typename, typename, typename> struct reference;
43         struct by_default;
44     }
45 
46     /// @brief Boost.Convert main deployment interface
47     /// @param[in] value_in   Value of the TypeIn type to be converted to the TyeOut type
48     /// @param[in] converter  Converter to be used for conversion
49     /// @return boost::optional<TypeOut> result of conversion together with the indication of
50     ///         success or failure of the conversion request.
51     /// @details For example,
52     /// @code
53     ///    boost::cnv::cstream cnv;
54     ///
55     ///    boost::optional<int>    i = boost::convert<int>("12", cnv);
56     ///    boost::optional<string> s = boost::convert<string>(123.456, cnv);
57     /// @endcode
58 
59     template<typename TypeOut, typename TypeIn, typename Converter>
60     boost::optional<TypeOut>
convert(TypeIn const & value_in,Converter const & converter)61     convert(TypeIn const& value_in, Converter const& converter)
62     {
63         optional<TypeOut> result;
64         boost::unwrap_ref(converter)(value_in, result);
65         return result;
66     }
67 
68     namespace cnv { namespace detail
69     {
70         template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default>
71         struct delayed_resolution
72         {
convertboost::cnv::detail::delayed_resolution73             static optional<TypeOut> convert(TypeIn const& value_in)
74             {
75                 return boost::convert<TypeOut>(value_in, Converter());
76             }
77         };
78     }}
79     /// @brief Boost.Convert deployment interface with the default converter
80     /// @details For example,
81     /// @code
82     ///    struct boost::cnv::by_default : public boost::cnv::cstream {};
83     ///
84     ///    // boost::cnv::cstream (through boost::cnv::by_default) is deployed
85     ///    // as the default converter when no converter is provided explicitly.
86     ///    boost::optional<int>    i = boost::convert<int>("12");
87     ///    boost::optional<string> s = boost::convert<string>(123.456);
88     /// @endcode
89 
90     template<typename TypeOut, typename TypeIn>
91     boost::optional<TypeOut>
convert(TypeIn const & value_in)92     convert(TypeIn const& value_in)
93     {
94         return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in);
95     }
96 }
97 
98 namespace boost
99 {
100     /// @brief Boost.Convert non-optional deployment interface
101 
102     template<typename TypeOut, typename TypeIn, typename Converter>
103     TypeOut
104     convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure)
105     {
106         return convert<TypeOut>(value_in, converter).value();
107     }
108 
109     template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
110     typename enable_if<is_convertible<Fallback, TypeOut>, TypeOut>::type
convert(TypeIn const & value_in,Converter const & converter,Fallback const & fallback)111     convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback)
112     {
113         return convert<TypeOut>(value_in, converter).value_or(fallback);
114     }
115 
116     template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
117     typename enable_if<cnv::is_fun<Fallback, TypeOut>, TypeOut>::type
convert(TypeIn const & value_in,Converter const & converter,Fallback fallback)118     convert(TypeIn const& value_in, Converter const& converter, Fallback fallback)
119     {
120         return convert<TypeOut>(value_in, converter).value_or_eval(fallback);
121     }
122 }
123 
124 namespace boost { namespace cnv
125 {
126     template<typename Converter, typename TypeOut, typename TypeIn>
127     struct reference
128     {
129         typedef reference this_type;
130 
referenceboost::cnv::reference131         reference(Converter const& cnv) : converter_(cnv) {}
132 
133 #ifdef BOOST_CONVERT_CXX11
referenceboost::cnv::reference134         reference(Converter&& cnv) : converter_(std::move(cnv)) {}
135 #endif
136 
137         this_type&
value_orboost::cnv::reference138         value_or(TypeOut const& fallback)
139         {
140             return (fallback_ = fallback, *this);
141         }
142 
143         TypeOut
operator ()boost::cnv::reference144         operator()(TypeIn const& value_in)
145         {
146             optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
147             return result ? result.get() : fallback_.value();
148         }
149 
150         private:
151 
152         Converter        converter_;
153         optional<TypeOut> fallback_;
154     };
155     template<typename Converter, typename TypeOut>
156     struct reference<Converter, TypeOut, void>
157     {
158         typedef reference this_type;
159 
referenceboost::cnv::reference160         reference(Converter const& cnv) : converter_(cnv) {}
161 
162 #ifdef BOOST_CONVERT_CXX11
referenceboost::cnv::reference163         reference(Converter&& cnv) : converter_(std::move(cnv)) {}
164 #endif
165 
166         this_type&
value_orboost::cnv::reference167         value_or(TypeOut const& fallback)
168         {
169             return (fallback_ = fallback, *this);
170         }
171 
172         template<typename TypeIn>
173         TypeOut
operator ()boost::cnv::reference174         operator()(TypeIn const& value_in)
175         {
176             optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
177             return result ? result.get() : fallback_.value();
178         }
179 
180         private:
181 
182         Converter        converter_;
183         optional<TypeOut> fallback_;
184     };
185 
186     /// @brief Boost.Convert deployment interface with algorithms
187     /// @details For example,
188     /// @code
189     ///    boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
190     ///    std::vector<int>             ints;
191     ///    boost::cnv::cstream           cnv;
192     ///
193     ///    cnv(std::hex)(std::skipws);
194     ///
195     ///    std::transform(
196     ///        strs.begin(),
197     ///        strs.end(),
198     ///        std::back_inserter(ints),
199     ///        boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1));
200     /// @endcode
201 
202     template<typename TypeOut, typename TypeIn, typename Converter>
203     reference<Converter, TypeOut, TypeIn>
apply(Converter const & cnv)204     apply(Converter const& cnv)
205     {
206         return cnv::reference<Converter, TypeOut, TypeIn>(cnv);
207     }
208     template<typename TypeOut, typename Converter>
209     reference<Converter, TypeOut, void>
apply(Converter const & cnv)210     apply(Converter const& cnv)
211     {
212         return cnv::reference<Converter, TypeOut, void>(cnv);
213     }
214 }}
215 
216 #endif // BOOST_CONVERT_HPP
217