1 //  boost/chrono/utility/ios_base_pword_ptr.hpp  ------------------------------------------------------------//
2 
3 //  Copyright 2011 Vicente J. Botet Escriba
4 
5 //  Distributed under the Boost Software License, Version 1.0. (See accompanying
6 //  file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
7 
8 //  See http://www.boost.org/libs/chrono for documentation.
9 
10 #ifndef BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP
11 #define BOOST_CHRONO_UTILITY_IOS_BASE_STATE_PTR_HPP
12 
13 #include <ios>
14 #include <boost/assert.hpp>
15 
16 /**
17  *
18 
19 
20  */
21 namespace boost
22 {
23   namespace chrono
24   {
25     namespace detail
26     {
27 
28       /**
29        * xalloc key holder.
30        */
31       template <typename T>
32       struct xalloc_key_holder
33       {
34         static int value; //< the xalloc value associated to T.
35         static bool initialized; //< whether the value has been initialized or not.
36       };
37 
38       template <typename T>
39       int xalloc_key_holder<T>::value = 0;
40 
41       template <typename T>
42       bool xalloc_key_holder<T>::initialized = false;
43 
44     }
45 
46     /**
47      * xalloc key initialiazer.
48      *
49      * Declare a static variable of this type to ensure that the xalloc_key_holder<T> is initialized correctly.
50      */
51     template <typename T>
52     struct xalloc_key_initializer
53     {
xalloc_key_initializerboost::chrono::xalloc_key_initializer54       xalloc_key_initializer()
55       {
56         if (!detail::xalloc_key_holder<T>::initialized)
57         {
58           detail::xalloc_key_holder<T>::value = std::ios_base::xalloc();
59           detail::xalloc_key_holder<T>::initialized = true;
60         }
61       }
62     };
63     /**
64      * @c ios_state_ptr is a smart pointer to a ios_base specific state.
65      */
66     template <typename Final, typename T>
67     class ios_state_ptr
68     {
69       ios_state_ptr& operator=(ios_state_ptr const& rhs) ;
70 
71     public:
72       /**
73        * The pointee type
74        */
75       typedef T element_type;
76       /**
77        * Explicit constructor.
78        * @param ios the ios
79        * @Effects Constructs a @c ios_state_ptr by storing the associated @c ios.
80        */
ios_state_ptr(std::ios_base & ios)81       explicit ios_state_ptr(std::ios_base& ios) :
82         ios_(ios)
83       {
84 
85       }
86       /**
87        * Nothing to do as xalloc index can not be removed.
88        */
~ios_state_ptr()89       ~ios_state_ptr()
90       {
91       }
92 
93       /**
94        * @Effects Allocates the index if not already done.
95        * Registers the callback responsible of maintaining the state pointer coherency, if not already done.
96        * Retrieves the associated ios pointer
97        * @return the retrieved pointer statically casted to const.
98        */
get() const99       T const* get() const BOOST_NOEXCEPT
100       {
101         register_once(index(), ios_);
102         void* &pw = ios_.pword(index());
103         if (pw == 0)
104         {
105           return 0;
106         }
107         return static_cast<const T*> (pw);
108       }
109       /**
110        * @Effects Allocates the index if not already done.
111        * Registers the callback responsible of maintaining the state pointer coherency, if not already done.
112        * Retrieves the associated ios pointer
113        * @return the retrieved pointer.
114        */
get()115       T * get() BOOST_NOEXCEPT
116       {
117         register_once(index(), ios_);
118         void* &pw = ios_.pword(index());
119         if (pw == 0)
120         {
121           return 0;
122         }
123         return static_cast<T*> (pw);
124       }
125       /**
126        * @Effects as if @c return get();
127        * @return the retrieved pointer.
128        */
operator ->()129       T * operator->()BOOST_NOEXCEPT
130       {
131         return get();
132       }
133       /**
134        * @Effects as if @c return get();
135        * @return the retrieved pointer.
136        */
operator ->() const137       T const * operator->() const BOOST_NOEXCEPT
138       {
139         return get();
140       }
141 
142       /**
143        * @Effects as if @c return *get();
144        * @return a reference to the retrieved state.
145        * @Remark The behavior is undefined if @c get()==0.
146        */
operator *()147       T & operator*() BOOST_NOEXCEPT
148       {
149         return *get();
150       }
151       /**
152        * @Effects as if @c return *get();
153        * @return a reference to the retrieved state.
154        * @Remark The behavior is undefined if @c get()==0.
155        */
operator *() const156       T const & operator *() const BOOST_NOEXCEPT
157       {
158         return *get();
159       }
160 
161       /**
162        * @Effects reset the current pointer after storing in a temporary variable the pointer to the current state.
163        * @return the stored state pointer.
164        */
release()165       T * release() BOOST_NOEXCEPT
166       {
167         T const* f = get();
168         reset();
169         return f;
170       }
171 
172       /**
173        *
174        * @param new_ptr the new pointer.
175        * @Effects deletes the current state and replace it with the new one.
176        */
reset(T * new_ptr=0)177       void reset(T* new_ptr = 0)BOOST_NOEXCEPT
178       {
179         register_once(index(), ios_);
180         void*& pw = ios_.pword(index());
181         delete static_cast<T*> (pw);
182         pw = new_ptr;
183       }
184 
185 #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
186         typedef T* (ios_state_ptr::*bool_type)();
operator bool_type() const187         operator bool_type() const BOOST_NOEXCEPT
188         {
189             return (get()!=0)?&ios_state_ptr::release:0;
190         }
operator !() const191         bool operator!() const BOOST_NOEXCEPT
192         {
193           return (get()==0)?&ios_state_ptr::release:0;
194         }
195 #else
196         /**
197          * Explicit conversion to bool.
198          */
operator bool() const199         explicit operator bool() const BOOST_NOEXCEPT
200         {
201           return get()!=0;
202         }
203 #endif
204 
getios()205       std::ios_base& getios()BOOST_NOEXCEPT
206       {
207         return ios_;
208       }
getios() const209       std::ios_base& getios() const BOOST_NOEXCEPT
210       {
211         return ios_;
212       }
213       /**
214        * Implicit conversion to the ios_base
215        */
operator std::ios_base&()216       operator std::ios_base&() BOOST_NOEXCEPT
217       {
218         return ios_;
219       }
220       /**
221        * Implicit conversion to the ios_base const
222        */
operator std::ios_base&() const223       operator std::ios_base&() const BOOST_NOEXCEPT
224       {
225         return ios_;
226       }
227     private:
is_registerd(std::ios_base & ios)228       static inline bool is_registerd(std::ios_base& ios)
229       {
230         long iw = ios.iword(index());
231         return (iw == 1);
232       }
set_registered(std::ios_base & ios)233       static inline void set_registered(std::ios_base& ios)
234       {
235         long& iw = ios.iword(index());
236         iw = 1;
237       }
callback(std::ios_base::event evt,std::ios_base & ios,int index)238       static inline void callback(std::ios_base::event evt, std::ios_base& ios, int index)
239       {
240         switch (evt)
241         {
242         case std::ios_base::erase_event:
243         {
244           void*& pw = ios.pword(index);
245           if (pw != 0)
246           {
247             T* ptr = static_cast<T*> (pw);
248             delete ptr;
249             pw = 0;
250           }
251           break;
252         }
253         case std::ios_base::copyfmt_event:
254         {
255           void*& pw = ios.pword(index);
256           if (pw != 0)
257           {
258             pw = new T(*static_cast<T*> (pw));
259           }
260           break;
261         }
262         default:
263           break;
264         }
265       }
266 
index()267       static inline int index()
268       {
269         return detail::xalloc_key_holder<Final>::value;
270       }
271 
register_once(int indx,std::ios_base & ios)272       static inline void register_once(int indx, std::ios_base& ios)
273       {
274         // needs a mask registered
275         if (!is_registerd(ios))
276         {
277           set_registered(ios);
278           ios.register_callback(callback, indx);
279         }
280       }
281 
282 
283     protected:
284       std::ios_base& ios_;
285       //static detail::xalloc_key_initializer<Final> xalloc_key_initializer_;
286 
287     };
288     //template <typename Final, typename T>
289     //detail::xalloc_key_initializer<Final> ios_state_ptr<Final,T>::xalloc_key_initializer_;
290 
291 
292     /**
293      * @c ios_state_not_null_ptr is a non null variant of @c ios_state_ptr.
294      * @tparm T
295      * @Requires @c T must be @c DefaultConstructible and @c HeapAllocatable
296      */
297     template <typename Final, typename T>
298     class ios_state_not_null_ptr: public ios_state_ptr<Final, T>
299     {
300       typedef ios_state_ptr<Final, T> base_type;
301     public:
ios_state_not_null_ptr(std::ios_base & ios)302       explicit ios_state_not_null_ptr(std::ios_base& ios) :
303       base_type(ios)
304       {
305         if (this->get() == 0)
306         {
307           this->base_type::reset(new T());
308         }
309       }
~ios_state_not_null_ptr()310       ~ios_state_not_null_ptr()
311       {
312       }
313 
reset(T * new_value)314       void reset(T* new_value) BOOST_NOEXCEPT
315       {
316         BOOST_ASSERT(new_value!=0);
317         this->base_type::reset(new_value);
318       }
319 
320     };
321 
322     /**
323      * This class is useful to associate some flags to an std::ios_base.
324      */
325     template <typename Final>
326     class ios_flags
327     {
328     public:
329       /**
330        *
331        * @param ios the associated std::ios_base.
332        * @Postcondition <c>flags()==0</c>
333        */
ios_flags(std::ios_base & ios)334       explicit ios_flags(std::ios_base& ios) :
335         ios_(ios)
336       {
337       }
~ios_flags()338       ~ios_flags()
339       {
340       }
341       /**
342        * @Returns The format control information.
343        */
flags() const344       long flags() const BOOST_NOEXCEPT
345       {
346         return value();
347       }
348 
349       /**
350        * @param v the new bit mask.
351        * @Postcondition <c>v == flags()</c>.
352        * @Returns The previous value of @c flags().
353        */
flags(long v)354       long flags(long v)BOOST_NOEXCEPT
355       {
356         long tmp = flags();
357         ref() = v;
358         return tmp;
359       }
360 
361       /**
362        * @param v the new value
363        * @Effects: Sets @c v in @c flags().
364        * @Returns: The previous value of @c flags().
365        */
setf(long v)366       long setf(long v)
367       {
368         long tmp = value();
369         ref() |= v;
370         return tmp;
371       }
372 
373       /**
374        * @param mask the bit mask to clear.
375        * @Effects: Clears @c mask in @c flags().
376        */
unsetf(long mask)377       void unsetf(long mask)
378       {
379         ref() &= ~mask;
380       }
381 
382       /**
383        *
384        * @param v
385        * @param mask
386        * @Effects: Clears @c mask in @c flags(), sets <c>v & mask</c> in @c flags().
387        * @Returns: The previous value of flags().
388        */
setf(long v,long mask)389       long setf(long v, long mask)
390       {
391         long tmp = value();
392         unsetf(mask);
393         ref() |= v & mask;
394         return tmp;
395       }
396 
397       /**
398        * implicit conversion to the @c ios_base
399        */
operator std::ios_base&()400       operator std::ios_base&()BOOST_NOEXCEPT
401       {
402         return ios_;
403       }
404       /**
405        * implicit conversion to the @c ios_base const
406        */
operator std::ios_base const&() const407       operator std::ios_base const&() const BOOST_NOEXCEPT
408       {
409         return ios_;
410       }
411     private:
value() const412       long value() const BOOST_NOEXCEPT
413       {
414         return ios_.iword(index());
415       }
ref()416       long& ref()BOOST_NOEXCEPT
417       {
418         return ios_.iword(index());
419       }
index()420       static inline int index()
421       {
422         return detail::xalloc_key_holder<Final>::value;
423       }
424       ios_flags& operator=(ios_flags const& rhs) ;
425 
426       std::ios_base& ios_;
427       //static detail::xalloc_key_initializer<Final> xalloc_key_initializer_;
428 
429     };
430     //template <typename Final>
431     //detail::xalloc_key_initializer<Final> ios_flags<Final>::xalloc_key_initializer_;
432 
433   } // namespace chrono
434 } // namespace boost
435 
436 #endif // header
437