1 // Copyright (c) 2009-2014 Vladimir Batov.
2 // Use, modification and distribution are subject to the Boost Software License,
3 // Version 1.0. See http://www.boost.org/LICENSE_1_0.txt.
4 
5 #include <boost/convert.hpp>
6 #include <boost/convert/stream.hpp>
7 #include <boost/convert/lexical_cast.hpp>
8 #include <boost/detail/lightweight_test.hpp>
9 #include <boost/array.hpp>
10 #include <boost/bind.hpp>
11 #include <vector>
12 
13 using std::string;
14 
15 static
16 void
introduction()17 introduction()
18 {
19 //[algorithm_introduction
20 
21    /*`The following code demonstrates conversion of an array of integers from their textual ['hexadecimal]
22       representation and assigns -1 to those which fail to convert:
23    */
24 
25     boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
26     std::vector<int>             ints;
27     boost::cnv::cstream           cnv;
28 
29     // Configure converter to read as a string of hexadecimal characters, skip (leading) white spaces.
30     cnv(std::hex)(std::skipws);
31 
32     std::transform(strs.begin(), strs.end(), std::back_inserter(ints),
33         boost::cnv::apply<int>(boost::cref(cnv)).value_or(-1));
34 
35     BOOST_TEST(ints.size() == 3); // Number of values processed.
36     BOOST_TEST(ints[0] ==  5);    // " 5"
37     BOOST_TEST(ints[1] == 15);    // "0XF"
38     BOOST_TEST(ints[2] == -1);    // "not an int"
39 //]
40 }
41 
42 static
43 void
example1()44 example1()
45 {
46 //[algorithm_example1
47     /*`The following code demonstrates a failed attempt (and one of the reasons ['Boost.Convert]
48        has been developed) to convert a few `string`s to `int`s with `boost::lexical_cast`:
49     */
50 
51     boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
52     std::vector<int>             ints;
53 
54     try
55     {
56         std::transform(strs.begin(), strs.end(), std::back_inserter(ints),
57             boost::bind(boost::lexical_cast<int, string>, _1));
58 
59         BOOST_TEST(0 && "Never reached!");
60     }
61     catch (std::exception&)
62     {
63         BOOST_TEST(ints.size() == 0); // No strings converted.
64     }
65 //]
66 }
67 
68 static
69 void
example2()70 example2()
71 {
72 //[algorithm_example2
73     /*`If the exception-throwing behavior is the desired behavior, then ['Boost.Convert] supports that.
74       In addition, it also provides a non-throwing process-flow:
75     */
76     boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
77     std::vector<int>             ints;
78 
79     std::transform(strs.begin(), strs.end(), std::back_inserter(ints),
80         boost::cnv::apply<int>(boost::cnv::lexical_cast()).value_or(-1));
81 
82     BOOST_TEST(ints.size() == 3);
83     BOOST_TEST(ints[0] == -1); // Failed conversion does not throw.
84     BOOST_TEST(ints[1] == -1); // Failed conversion does not throw.
85     BOOST_TEST(ints[2] == -1); // Failed conversion does not throw.
86 //]
87 }
88 
89 static
90 void
example3()91 example3()
92 {
93 //[algorithm_example3
94     /*`Deploying `boost::cnv::cstream` with better formatting capabilities yields
95        better results with exception-throwing and non-throwing process-flows still supported:
96     */
97 
98     boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
99     std::vector<int>             ints;
100     boost::cnv::cstream           cnv;
101 
102     try
103     {
104         std::transform(strs.begin(), strs.end(), std::back_inserter(ints),
105             boost::cnv::apply<int>(boost::cref(cnv(std::hex)(std::skipws))));
106 
107         BOOST_TEST(0 && "Never reached!");
108     }
109     catch (boost::bad_optional_access const&)
110     {
111         BOOST_TEST(ints.size() == 2); // Only the first two strings converted.
112         BOOST_TEST(ints[0] ==  5);    // " 5"
113         BOOST_TEST(ints[1] == 15);    // "0XF"
114 
115         // "not an int" causes the exception thrown.
116     }
117 //]
118 }
119 
120 static
121 void
example4()122 example4()
123 {
124     boost::array<char const*, 3> strs = {{ " 5", "0XF", "not an int" }};
125     std::vector<int>             ints;
126     boost::cnv::cstream           cnv;
127 
128 //[algorithm_example4
129 
130     std::transform(strs.begin(), strs.end(), std::back_inserter(ints),
131         boost::cnv::apply<int>(boost::cref(cnv(std::hex)(std::skipws))).value_or(-1));
132 
133     BOOST_TEST(ints.size() == 3);
134     BOOST_TEST(ints[0] ==  5);
135     BOOST_TEST(ints[1] == 15);
136     BOOST_TEST(ints[2] == -1); // Failed conversion
137 
138     /*`[important One notable difference in the deployment of `boost::cnv::cstream` with algorithms is
139        the use of `boost::cref` (or `std::cref` in C++11).
140 
141        It needs to be remembered that with standard algorithms the deployed converter needs to be
142        [@http://en.cppreference.com/w/cpp/concept/TriviallyCopyable copyable] or
143        [@http://en.cppreference.com/w/cpp/concept/MoveAssignable movable (C++11)]
144        and is, in fact, copied or moved by the respective algorithm before being used.
145        Given that `std::cstringstream` is not copyable, `boost::cnv::cstream` is not copyable either.
146        That limitation is routinely worked-around using `boost::ref` or `boost::cref`.]
147     */
148 //]
149 }
150 
151 static
152 void
example5()153 example5()
154 {
155 //[algorithm_example5
156     /*`And now an example of algorithm-based integer-to-string formatted conversion with
157        `std::hex`, `std::uppercase` and `std::showbase` formatting applied:
158     */
159     boost::array<int, 3>     ints = {{ 15, 16, 17 }};
160     std::vector<std::string> strs;
161     boost::cnv::cstream       cnv;
162 
163     cnv(std::hex)(std::uppercase)(std::showbase);
164 
165     std::transform(ints.begin(), ints.end(), std::back_inserter(strs),
166         boost::cnv::apply<string>(boost::cref(cnv)));
167 
168     BOOST_TEST(strs.size() == 3);
169     BOOST_TEST(strs[0] ==  "0XF"); // 15
170     BOOST_TEST(strs[1] == "0X10"); // 16
171     BOOST_TEST(strs[2] == "0X11"); // 17
172 //]
173 }
174 
175 int
main(int argc,char const * argv[])176 main(int argc, char const* argv[])
177 {
178     introduction();
179     example1();
180     example2();
181     example3();
182     example4();
183     example5();
184 
185     return boost::report_errors();
186 }
187