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         void*& pw = ios_.pword(index());
168         T* ptr = static_cast<T*> (pw);
169         pw = 0;
170         return ptr;
171       }
172 
173       /**
174        *
175        * @param new_ptr the new pointer.
176        * @Effects deletes the current state and replace it with the new one.
177        */
reset(T * new_ptr=0)178       void reset(T* new_ptr = 0)BOOST_NOEXCEPT
179       {
180         register_once(index(), ios_);
181         void*& pw = ios_.pword(index());
182         delete static_cast<T*> (pw);
183         pw = new_ptr;
184       }
185 
186 #if defined(BOOST_NO_CXX11_EXPLICIT_CONVERSION_OPERATORS)
187         typedef T* (ios_state_ptr::*bool_type)();
operator bool_type() const188         operator bool_type() const BOOST_NOEXCEPT
189         {
190             return (get()!=0)?&ios_state_ptr::release:0;
191         }
operator !() const192         bool operator!() const BOOST_NOEXCEPT
193         {
194           return (get()==0)?&ios_state_ptr::release:0;
195         }
196 #else
197         /**
198          * Explicit conversion to bool.
199          */
operator bool() const200         explicit operator bool() const BOOST_NOEXCEPT
201         {
202           return get()!=0;
203         }
204 #endif
205 
getios()206       std::ios_base& getios()BOOST_NOEXCEPT
207       {
208         return ios_;
209       }
getios() const210       std::ios_base& getios() const BOOST_NOEXCEPT
211       {
212         return ios_;
213       }
214       /**
215        * Implicit conversion to the ios_base
216        */
operator std::ios_base&()217       operator std::ios_base&() BOOST_NOEXCEPT
218       {
219         return ios_;
220       }
221       /**
222        * Implicit conversion to the ios_base const
223        */
operator std::ios_base&() const224       operator std::ios_base&() const BOOST_NOEXCEPT
225       {
226         return ios_;
227       }
228     private:
is_registerd(std::ios_base & ios)229       static inline bool is_registerd(std::ios_base& ios)
230       {
231         long iw = ios.iword(index());
232         return (iw == 1);
233       }
set_registered(std::ios_base & ios)234       static inline void set_registered(std::ios_base& ios)
235       {
236         long& iw = ios.iword(index());
237         iw = 1;
238       }
callback(std::ios_base::event evt,std::ios_base & ios,int index)239       static inline void callback(std::ios_base::event evt, std::ios_base& ios, int index)
240       {
241         switch (evt)
242         {
243         case std::ios_base::erase_event:
244         {
245           void*& pw = ios.pword(index);
246           if (pw != 0)
247           {
248             T* ptr = static_cast<T*> (pw);
249             delete ptr;
250             pw = 0;
251           }
252           break;
253         }
254         case std::ios_base::copyfmt_event:
255         {
256           void*& pw = ios.pword(index);
257           if (pw != 0)
258           {
259             pw = new T(*static_cast<T*> (pw));
260           }
261           break;
262         }
263         default:
264           break;
265         }
266       }
267 
index()268       static inline int index()
269       {
270         return detail::xalloc_key_holder<Final>::value;
271       }
272 
register_once(int indx,std::ios_base & ios)273       static inline void register_once(int indx, std::ios_base& ios)
274       {
275         // needs a mask registered
276         if (!is_registerd(ios))
277         {
278           set_registered(ios);
279           ios.register_callback(callback, indx);
280         }
281       }
282 
283 
284     protected:
285       std::ios_base& ios_;
286       //static detail::xalloc_key_initializer<Final> xalloc_key_initializer_;
287 
288     };
289     //template <typename Final, typename T>
290     //detail::xalloc_key_initializer<Final> ios_state_ptr<Final,T>::xalloc_key_initializer_;
291 
292 
293     /**
294      * @c ios_state_not_null_ptr is a non null variant of @c ios_state_ptr.
295      * @tparm T
296      * @Requires @c T must be @c DefaultConstructible and @c HeapAllocatable
297      */
298     template <typename Final, typename T>
299     class ios_state_not_null_ptr: public ios_state_ptr<Final, T>
300     {
301       typedef ios_state_ptr<Final, T> base_type;
302     public:
ios_state_not_null_ptr(std::ios_base & ios)303       explicit ios_state_not_null_ptr(std::ios_base& ios) :
304       base_type(ios)
305       {
306         if (this->get() == 0)
307         {
308           this->base_type::reset(new T());
309         }
310       }
~ios_state_not_null_ptr()311       ~ios_state_not_null_ptr()
312       {
313       }
314 
reset(T * new_value)315       void reset(T* new_value) BOOST_NOEXCEPT
316       {
317         BOOST_ASSERT(new_value!=0);
318         this->base_type::reset(new_value);
319       }
320 
321     };
322 
323     /**
324      * This class is useful to associate some flags to an std::ios_base.
325      */
326     template <typename Final>
327     class ios_flags
328     {
329     public:
330       /**
331        *
332        * @param ios the associated std::ios_base.
333        * @Postcondition <c>flags()==0</c>
334        */
ios_flags(std::ios_base & ios)335       explicit ios_flags(std::ios_base& ios) :
336         ios_(ios)
337       {
338       }
~ios_flags()339       ~ios_flags()
340       {
341       }
342       /**
343        * @Returns The format control information.
344        */
flags() const345       long flags() const BOOST_NOEXCEPT
346       {
347         return value();
348       }
349 
350       /**
351        * @param v the new bit mask.
352        * @Postcondition <c>v == flags()</c>.
353        * @Returns The previous value of @c flags().
354        */
flags(long v)355       long flags(long v)BOOST_NOEXCEPT
356       {
357         long tmp = flags();
358         ref() = v;
359         return tmp;
360       }
361 
362       /**
363        * @param v the new value
364        * @Effects: Sets @c v in @c flags().
365        * @Returns: The previous value of @c flags().
366        */
setf(long v)367       long setf(long v)
368       {
369         long tmp = value();
370         ref() |= v;
371         return tmp;
372       }
373 
374       /**
375        * @param mask the bit mask to clear.
376        * @Effects: Clears @c mask in @c flags().
377        */
unsetf(long mask)378       void unsetf(long mask)
379       {
380         ref() &= ~mask;
381       }
382 
383       /**
384        *
385        * @param v
386        * @param mask
387        * @Effects: Clears @c mask in @c flags(), sets <c>v & mask</c> in @c flags().
388        * @Returns: The previous value of flags().
389        */
setf(long v,long mask)390       long setf(long v, long mask)
391       {
392         long tmp = value();
393         unsetf(mask);
394         ref() |= v & mask;
395         return tmp;
396       }
397 
398       /**
399        * implicit conversion to the @c ios_base
400        */
operator std::ios_base&()401       operator std::ios_base&()BOOST_NOEXCEPT
402       {
403         return ios_;
404       }
405       /**
406        * implicit conversion to the @c ios_base const
407        */
operator std::ios_base const&() const408       operator std::ios_base const&() const BOOST_NOEXCEPT
409       {
410         return ios_;
411       }
412     private:
value() const413       long value() const BOOST_NOEXCEPT
414       {
415         return ios_.iword(index());
416       }
ref()417       long& ref()BOOST_NOEXCEPT
418       {
419         return ios_.iword(index());
420       }
index()421       static inline int index()
422       {
423         return detail::xalloc_key_holder<Final>::value;
424       }
425       ios_flags& operator=(ios_flags const& rhs) ;
426 
427       std::ios_base& ios_;
428       //static detail::xalloc_key_initializer<Final> xalloc_key_initializer_;
429 
430     };
431     //template <typename Final>
432     //detail::xalloc_key_initializer<Final> ios_flags<Final>::xalloc_key_initializer_;
433 
434   } // namespace chrono
435 } // namespace boost
436 
437 #endif // header
438