]>
Commit | Line | Data |
---|---|---|
7c673cae FG |
1 | /*============================================================================= |
2 | Copyright (c) 2006 Joao Abecasis | |
3 | http://spirit.sourceforge.net/ | |
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 | #if !defined(BOOST_SPIRIT_STATIC_HPP) | |
9 | #define BOOST_SPIRIT_STATIC_HPP | |
10 | ||
11 | #include <boost/noncopyable.hpp> | |
12 | #include <boost/call_traits.hpp> | |
13 | #include <boost/aligned_storage.hpp> | |
14 | ||
15 | #include <boost/type_traits/add_pointer.hpp> | |
16 | #include <boost/type_traits/alignment_of.hpp> | |
17 | ||
18 | #include <boost/thread/once.hpp> | |
19 | ||
20 | #include <memory> // for placement new | |
21 | ||
22 | #include <boost/spirit/home/classic/namespace.hpp> | |
23 | ||
24 | namespace boost { namespace spirit { | |
25 | ||
26 | BOOST_SPIRIT_CLASSIC_NAMESPACE_BEGIN | |
27 | ||
28 | // | |
29 | // Provides thread-safe initialization of a single static instance of T. | |
30 | // | |
31 | // This instance is guaranteed to be constructed on static storage in a | |
32 | // thread-safe manner, on the first call to the constructor of static_. | |
33 | // | |
34 | // Requirements: | |
35 | // T is default constructible | |
36 | // (There's an alternate implementation that relaxes this | |
37 | // requirement -- Joao Abecasis) | |
38 | // T::T() MUST not throw! | |
39 | // this is a requirement of boost::call_once. | |
40 | // | |
41 | template <class T, class Tag> | |
42 | struct static_ | |
43 | : boost::noncopyable | |
44 | { | |
45 | private: | |
46 | ||
47 | struct destructor | |
48 | { | |
49 | ~destructor() | |
50 | { | |
51 | static_::get_address()->~value_type(); | |
52 | } | |
53 | }; | |
54 | ||
55 | struct default_ctor | |
56 | { | |
57 | static void construct() | |
58 | { | |
59 | ::new (static_::get_address()) value_type(); | |
60 | static destructor d; | |
61 | } | |
62 | }; | |
63 | ||
64 | public: | |
65 | ||
66 | typedef T value_type; | |
67 | typedef typename boost::call_traits<T>::reference reference; | |
68 | typedef typename boost::call_traits<T>::const_reference const_reference; | |
69 | ||
70 | static_(Tag = Tag()) | |
71 | { | |
72 | boost::call_once(&default_ctor::construct, constructed_); | |
73 | } | |
74 | ||
75 | operator reference() | |
76 | { | |
77 | return this->get(); | |
78 | } | |
79 | ||
80 | operator const_reference() const | |
81 | { | |
82 | return this->get(); | |
83 | } | |
84 | ||
85 | reference get() | |
86 | { | |
87 | return *this->get_address(); | |
88 | } | |
89 | ||
90 | const_reference get() const | |
91 | { | |
92 | return *this->get_address(); | |
93 | } | |
94 | ||
95 | private: | |
96 | typedef typename boost::add_pointer<value_type>::type pointer; | |
97 | ||
98 | static pointer get_address() | |
99 | { | |
100 | return static_cast<pointer>(data_.address()); | |
101 | } | |
102 | ||
103 | typedef boost::aligned_storage<sizeof(value_type), | |
104 | boost::alignment_of<value_type>::value> storage_type; | |
105 | ||
106 | static storage_type data_; | |
107 | static once_flag constructed_; | |
108 | }; | |
109 | ||
110 | template <class T, class Tag> | |
111 | typename static_<T, Tag>::storage_type static_<T, Tag>::data_; | |
112 | ||
113 | template <class T, class Tag> | |
114 | #ifndef BOOST_THREAD_PROVIDES_ONCE_CXX11 | |
115 | once_flag static_<T, Tag>::constructed_ = BOOST_ONCE_INIT; | |
116 | #else | |
117 | once_flag static_<T, Tag>::constructed_; | |
118 | #endif | |
119 | ||
120 | BOOST_SPIRIT_CLASSIC_NAMESPACE_END | |
121 | ||
122 | }} // namespace BOOST_SPIRIT_CLASSIC_NS | |
123 | ||
124 | #endif // include guard |