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