1 /// @file
2 // Boost.Convert
3 // Copyright (c) 2009-2016 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 boost::throw_on_failure is the 'tag' object
36     /// to request the exception-throwing behavior.
37     detail::throw_on_failure const throw_on_failure = detail::throw_on_failure(0);
38 
39     namespace cnv
40     {
41         template<typename, typename, typename> struct reference;
42         struct by_default;
43     }
44 
45     /// @brief Boost.Convert main deployment interface
46     /// @param[in] value_in   Value of the TypeIn type to be converted to the TypeOut type
47     /// @param[in] converter  Converter to be used for conversion
48     /// @return boost::optional<TypeOut> result of conversion together with the indication of
49     ///         success or failure of the conversion request.
50     /// @details For example,
51     /// @code
52     ///    boost::cnv::cstream cnv;
53     ///
54     ///    boost::optional<int>    i = boost::convert<int>("12", cnv);
55     ///    boost::optional<string> s = boost::convert<string>(123.456, cnv);
56     /// @endcode
57 
58     template<typename TypeOut, typename TypeIn, typename Converter>
59     boost::optional<TypeOut>
convert(TypeIn const & value_in,Converter const & converter)60     convert(TypeIn const& value_in, Converter const& converter)
61     {
62         optional<TypeOut> result;
63         boost::unwrap_ref(converter)(value_in, result);
64         return result;
65     }
66 
67     namespace cnv { namespace detail
68     {
69         template<typename TypeOut, typename TypeIn, typename Converter =boost::cnv::by_default>
70         struct delayed_resolution
71         {
convertboost::cnv::detail::delayed_resolution72             static optional<TypeOut> convert(TypeIn const& value_in)
73             {
74                 return boost::convert<TypeOut>(value_in, Converter());
75             }
76         };
77     }}
78     /// @brief Boost.Convert deployment interface with the default converter
79     /// @details For example,
80     /// @code
81     ///    struct boost::cnv::by_default : boost::cnv::cstream {};
82     ///
83     ///    // boost::cnv::cstream (through boost::cnv::by_default) is deployed
84     ///    // as the default converter when no converter is provided explicitly.
85     ///    boost::optional<int>    i = boost::convert<int>("12");
86     ///    boost::optional<string> s = boost::convert<string>(123.456);
87     /// @endcode
88 
89     template<typename TypeOut, typename TypeIn>
90     boost::optional<TypeOut>
convert(TypeIn const & value_in)91     convert(TypeIn const& value_in)
92     {
93         return cnv::detail::delayed_resolution<TypeOut, TypeIn>::convert(value_in);
94     }
95 }
96 
97 namespace boost
98 {
99     /// @brief Boost.Convert non-optional deployment interface
100 
101     template<typename TypeOut, typename TypeIn, typename Converter>
102     TypeOut
103     convert(TypeIn const& value_in, Converter const& converter, boost::detail::throw_on_failure)
104     {
105         return convert<TypeOut>(value_in, converter).value();
106     }
107 
108     template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
109     typename enable_if<is_convertible<Fallback, TypeOut>, TypeOut>::type
convert(TypeIn const & value_in,Converter const & converter,Fallback const & fallback)110     convert(TypeIn const& value_in, Converter const& converter, Fallback const& fallback)
111     {
112         return convert<TypeOut>(value_in, converter).value_or(fallback);
113     }
114 
115     template<typename TypeOut, typename TypeIn, typename Converter, typename Fallback>
116     typename enable_if<cnv::is_fun<Fallback, TypeOut>, TypeOut>::type
convert(TypeIn const & value_in,Converter const & converter,Fallback fallback)117     convert(TypeIn const& value_in, Converter const& converter, Fallback fallback)
118     {
119         return convert<TypeOut>(value_in, converter).value_or_eval(fallback);
120     }
121 }
122 
123 namespace boost { namespace cnv
124 {
125     template<typename Converter, typename TypeOut, typename TypeIn>
126     struct reference
127     {
128         typedef reference this_type;
129 
referenceboost::cnv::reference130         reference(Converter const& cnv) : converter_(cnv) {}
131 
132 #ifdef BOOST_CONVERT_CXX11
referenceboost::cnv::reference133         reference(Converter&& cnv) : converter_(std::move(cnv)) {}
134 #endif
135 
136         this_type&
value_orboost::cnv::reference137         value_or(TypeOut const& fallback)
138         {
139             return (fallback_ = fallback, *this);
140         }
141 
142         TypeOut
operator ()boost::cnv::reference143         operator()(TypeIn const& value_in)
144         {
145             optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
146             return result ? result.get() : fallback_.value();
147         }
148 
149         private:
150 
151         Converter        converter_;
152         optional<TypeOut> fallback_;
153     };
154     template<typename Converter, typename TypeOut>
155     struct reference<Converter, TypeOut, void>
156     {
157         typedef reference this_type;
158 
referenceboost::cnv::reference159         reference(Converter const& cnv) : converter_(cnv) {}
160 
161 #ifdef BOOST_CONVERT_CXX11
referenceboost::cnv::reference162         reference(Converter&& cnv) : converter_(std::move(cnv)) {}
163 #endif
164 
165         this_type&
value_orboost::cnv::reference166         value_or(TypeOut const& fallback)
167         {
168             return (fallback_ = fallback, *this);
169         }
170 
171         template<typename TypeIn>
172         TypeOut
operator ()boost::cnv::reference173         operator()(TypeIn const& value_in)
174         {
175             optional<TypeOut> result = convert<TypeOut>(value_in, converter_);
176             return result ? result.get() : fallback_.value();
177         }
178 
179         private:
180 
181         Converter        converter_;
182         optional<TypeOut> fallback_;
183     };
184 
185     /// @brief Boost.Convert deployment interface with algorithms
186     /// @details For example,
187     /// @code
188     ///    boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
189     ///    std::vector<int>             ints;
190     ///    boost::cnv::cstream           cnv;
191     ///
192     ///    cnv(std::hex)(std::skipws);
193     ///
194     ///    std::transform(
195     ///        strs.begin(),
196     ///        strs.end(),
197     ///        std::back_inserter(ints),
198     ///        boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1));
199     /// @endcode
200 
201     template<typename TypeOut, typename TypeIn, typename Converter>
202     reference<Converter, TypeOut, TypeIn>
apply(Converter const & cnv)203     apply(Converter const& cnv)
204     {
205         return cnv::reference<Converter, TypeOut, TypeIn>(cnv);
206     }
207     template<typename TypeOut, typename Converter>
208     reference<Converter, TypeOut, void>
apply(Converter const & cnv)209     apply(Converter const& cnv)
210     {
211         return cnv::reference<Converter, TypeOut, void>(cnv);
212     }
213 }}
214 
215 #endif // BOOST_CONVERT_HPP
216