1 //                                               -*- C++ -*-
2 /**
3  *  @brief The class OSS streams out objects
4  *
5  *  Copyright 2005-2021 Airbus-EDF-IMACS-ONERA-Phimeca
6  *
7  *  This library is free software: you can redistribute it and/or modify
8  *  it under the terms of the GNU Lesser General Public License as published by
9  *  the Free Software Foundation, either version 3 of the License, or
10  *  (at your option) any later version.
11  *
12  *  This library is distributed in the hope that it will be useful,
13  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15  *  GNU Lesser General Public License for more details.
16  *
17  *  You should have received a copy of the GNU Lesser General Public License
18  *  along with this library.  If not, see <http://www.gnu.org/licenses/>.
19  *
20  */
21 #ifndef OPENTURNS_OSS_HXX
22 #define OPENTURNS_OSS_HXX
23 
24 #include <sstream>
25 #include <iterator>
26 #include <functional>
27 #include <utility>        // for std::pair
28 #include "openturns/OStream.hxx"
29 
30 BEGIN_NAMESPACE_OPENTURNS
31 
32 template <typename U, typename V>
operator <<(std::ostream & os,const std::pair<U,V> & p)33 std::ostream & operator << (std::ostream & os, const std::pair<U, V> & p)
34 {
35   return os << "(" << p.first << "," << p.second << ")";
36 }
37 
38 template <typename U, typename V>
operator <<(OStream & OS,const std::pair<U,V> & p)39 OStream & operator << (OStream & OS, const std::pair<U, V> & p)
40 {
41   return OS << "(" << p.first << "," << p.second << ")";
42 }
43 
44 
45 
46 /**
47  * Struct Bulk protects the underlying object output from being
48  * modified by OSSFormater
49  */
50 template <class T>
51 struct Bulk
52 {
53   T data_;
BulkBulk54   Bulk(T data) : data_(data) {}
operator TBulk55   operator T() const
56   {
57     return data_;
58   }
59 };
60 
61 /**
62  * Struct OSSFormater is a helper class for OSS that adapt the
63  * format of output according to type T
64  */
65 
66 /* Any type */
67 template <class T>
68 struct OSSFormater
69 {
70   inline
71   static
applyOSSFormater72   void apply(std::ostringstream & oss, T obj, int /*precision*/)
73   {
74     oss << obj;
75   }
76 
77   inline
78   static
applyOSSFormater79   void apply(OStream & OS, T obj, int /*precision*/)
80   {
81     OS << obj;
82   }
83 }; /* struct OSSFormater */
84 
85 /* double */
86 template <>
87 struct OSSFormater<double>
88 {
89   inline
90   static
applyOSSFormater91   void apply(std::ostringstream & oss, double d, int precision)
92   {
93     int oldPrecision = static_cast<int>(oss.precision(precision));
94     oss << d;
95     oss.precision(oldPrecision);
96   }
97 
98   inline
99   static
applyOSSFormater100   void apply(OStream & OS, double d, int precision)
101   {
102     int oldPrecision = static_cast<int>(OS.getStream().precision(precision));
103     OS.getStream() << d;
104     OS.getStream().precision(oldPrecision);
105   }
106 };
107 
108 /* float */
109 template <>
110 struct OSSFormater<float>
111 {
112   inline
113   static
applyOSSFormater114   void apply(std::ostringstream & oss, float f, int precision)
115   {
116     int oldPrecision = static_cast<int>(oss.precision(precision));
117     oss << f;
118     oss.precision(oldPrecision);
119   }
120 
121   inline
122   static
applyOSSFormater123   void apply(OStream & OS, float f, int precision)
124   {
125     int oldPrecision = static_cast<int>(OS.getStream().precision(precision));
126     OS.getStream() << f;
127     OS.getStream().precision(oldPrecision);
128   }
129 };
130 
131 /* bool */
132 template <>
133 struct OSSFormater<bool>
134 {
135   inline
136   static
applyOSSFormater137   void apply(std::ostringstream & oss, bool b, int /*precision*/)
138   {
139     oss << (b ? "true" : "false");
140   }
141 
142   inline
143   static
applyOSSFormater144   void apply(OStream & OS, bool b, int /*precision*/)
145   {
146     OS.getStream() << (b ? "true" : "false");
147   }
148 };
149 
150 
151 
152 
153 
154 
155 /**
156  * Class OSS is useful when streaming data through a function
157  * that expect a string as parameter
158  */
159 class OT_API OSS
160 {
161 private:
162   std::ostringstream oss_;
163   mutable int precision_;
164   mutable bool full_;
165 
166 public:
167   explicit OSS(bool full = true);
168 
169   template <class T>
170   inline
operator <<(T obj)171   OSS & operator << (T obj)
172   {
173     if (full_)
174     {
175       OStream OS(oss_);
176       OSSFormater<T>::apply(OS, obj, precision_);
177     }
178     else OSSFormater<T>::apply(oss_, obj, precision_);
179     return *this;
180   }
181 
182   inline
setPrecision(int precision)183   OSS & setPrecision(int precision)
184   {
185     precision_ = precision;
186     oss_.precision(precision_);
187     return *this;
188   }
189 
190   inline
getPrecision() const191   int getPrecision() const
192   {
193     precision_ = static_cast<int>(oss_.precision());
194     return precision_;
195   }
196 
197   operator std::string() const;
198   std::string str() const;
199 
200   void clear();
201 
202 }; /* class OSS */
203 
204 template <typename _Tp>
205 struct AllElementsPredicate : public std::unary_function<_Tp, Bool>
206 {
207   Bool
operator ()AllElementsPredicate208   operator()(const _Tp&) const
209   {
210     return true;
211   }
212 };
213 
214 template < typename _Tp, typename _UnaryPredicate = AllElementsPredicate<_Tp>, typename _CharT = char,
215            typename _Traits = std::char_traits<_CharT> >
216 class OSS_iterator
217   : public std::iterator<std::output_iterator_tag, void, void, void, void>
218 {
219 public:
220   //@{
221   /// Public typedef
222   typedef _CharT                         char_type;
223   typedef _Traits                        traits_type;
224   typedef OSS                            ostream_type;
225   //@}
226 
227 private:
228   ostream_type*     _M_stream;
229   String            _M_string;
230   String            _M_prefix;
231   mutable bool      _M_first;
232 
233 public:
234   /**
235    *  Construct from an ostream
236    *
237    *  The delimiter string @a c is written to the stream after every Tp
238    *  written to the stream.  The delimiter is not copied, and thus must
239    *  not be destroyed while this iterator is in use.
240    *
241    *  @param  s  Underlying ostream to write to.
242    *  @param  c  CharT delimiter string to insert.
243    */
OSS_iterator(ostream_type & __s,const String & __c="",const String & __p="")244   OSS_iterator(ostream_type & __s, const String & __c = "", const String & __p = "")
245     : _M_stream(&__s)
246     , _M_string(__c)
247     , _M_prefix(__p)
248     , _M_first(true)
249   {}
250 
251   /// Copy constructor.
OSS_iterator(const OSS_iterator & __obj)252   OSS_iterator(const OSS_iterator& __obj)
253     : _M_stream(__obj._M_stream)
254     , _M_string(__obj._M_string)
255     , _M_prefix(__obj._M_prefix)
256     , _M_first(__obj._M_first)
257   {}
258 
259   /// Copy assignment
260   OSS_iterator&
operator =(const OSS_iterator & obj)261   operator=(const OSS_iterator& obj)
262   {
263     _M_stream = obj._M_stream;
264     _M_string = obj._M_string;
265     _M_prefix = obj._M_prefix;
266     _M_first  = obj._M_first;
267     return *this;
268   }
269 
270   /// Writes @a value to underlying ostream using operator<<.  If
271   /// constructed with delimiter string, writes delimiter to ostream.
272   OSS_iterator&
operator =(const _Tp & value)273   operator=(const _Tp& value)
274   {
275     if (_UnaryPredicate()(value))
276     {
277       if (!_M_first) *_M_stream << _M_string;
278       *_M_stream << _M_prefix << value;
279       _M_first = false;
280     }
281     return *this;
282   }
283 
284   OSS_iterator&
operator *()285   operator*()
286   {
287     return *this;
288   }
289 
290   OSS_iterator&
operator ++()291   operator++()
292   {
293     return *this;
294   }
295 
296   OSS_iterator
operator ++(int)297   operator++(int)
298   {
299     return *this;
300   }
301 
302 };
303 
304 
305 END_NAMESPACE_OPENTURNS
306 
307 #endif /* OPENTURNS_OSS_HXX */
308