• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*=============================================================================
2     Copyright (c) 2002-2004 Martin Wille
3     http://spirit.sourceforge.net/
4 
5     Use, modification and distribution is subject to the Boost Software
6     License, Version 1.0. (See accompanying file LICENSE_1_0.txt or copy at
7     http://www.boost.org/LICENSE_1_0.txt)
8 =============================================================================*/
9 
10 // std::lower_bound seems to perform awfully slow with _GLIBCXX_DEBUG enabled
11 #undef _GLIBCXX_DEBUG
12 
13 #include <iostream>
14 #include <boost/config.hpp>
15 #include <boost/detail/lightweight_test.hpp>
16 
17 #if !defined(BOOST_HAS_THREADS) || defined(DONT_HAVE_BOOST) || defined(BOOST_DISABLE_THREADS)
skipped()18 static void skipped()
19 {
20     std::cout << "skipped\n";
21 }
22 
23 int
main()24 main()
25 {
26     skipped();
27     return 0;
28 }
29 #else
30 
31 ////////////////////////////////////////////////////////////////////////////////
32 
33 static const unsigned long initial_test_size = 5000UL;
34 #if defined(_DEBUG) && (BOOST_MSVC >= 1400)
35 static const unsigned long maximum_test_size = 10000UL;
36 #else
37 static const unsigned long maximum_test_size = 1000000UL;
38 #endif
39 
40 ////////////////////////////////////////////////////////////////////////////////
41 
42 #undef BOOST_SPIRIT_THREADSAFE
43 #define BOOST_SPIRIT_THREADSAFE
44 
45 #include <boost/thread/thread.hpp>
46 #include <boost/spirit/home/classic/core/non_terminal/impl/object_with_id.ipp>
47 #include <boost/ref.hpp>
48 #include <boost/thread/xtime.hpp>
49 #include <boost/thread/mutex.hpp>
50 #include <boost/thread/lock_types.hpp>
51 #include <vector>
52 #include <algorithm>
53 #include <boost/detail/lightweight_test.hpp>
54 
55 using BOOST_SPIRIT_CLASSIC_NS::impl::object_with_id;
56 
57 struct tag1 {};
58 typedef object_with_id<tag1> class1;
59 
60 unsigned long test_size = initial_test_size;
61 boost::xtime start_time;
62 
63 template <typename ClassT>
64 struct test_task
65 {
test_tasktest_task66     test_task() : v(), m(), progress(0) {}
67 
operator ()test_task68     void operator ()()
69     {   // create lots of objects
70         unsigned long i = 0;
71 
72         v.reserve(maximum_test_size);
73         do
74         {
75             for (; i<test_size; ++i)
76                 v.push_back(new ClassT);
77         }
78         while ( i < increase_test_size(i) );
79     }
80 
81     static unsigned long
increase_test_sizetest_task82     increase_test_size(unsigned long size)
83     {
84         static boost::mutex  m;
85         boost::unique_lock<boost::mutex> l(m);
86 
87         if (size<test_size || test_size == maximum_test_size)
88             return test_size;
89 
90         boost::xtime now;
91         boost::xtime_get(&now, boost::TIME_UTC_);
92         boost::xtime::xtime_sec_t seconds = now.sec - start_time.sec;
93         if (seconds < 4)
94         {
95             test_size *= 2;
96             if (test_size > maximum_test_size)
97                 test_size = maximum_test_size;
98         }
99 
100         return test_size;
101     }
102 
datatest_task103     std::vector<ClassT*> const &data() const
104     {
105         return v;
106     }
107 
108 private:
109     std::vector<ClassT*> v;
110     boost::mutex         m;
111     unsigned int         progress;
112 };
113 
114 template <typename T>
115 class callable_reference_wrapper
116     : public boost::reference_wrapper<T>
117 {
118 public:
callable_reference_wrapper(T & t)119     explicit callable_reference_wrapper(T& t)
120         : boost::reference_wrapper<T>(t)
121     {}
operator ()()122     inline void operator()() { this->get().operator()(); }
123 };
124 
125 template <typename T>
126 callable_reference_wrapper<T>
callable_ref(T & t)127 callable_ref(T &t)
128 {
129     return callable_reference_wrapper<T>(t);
130 }
131 
132 test_task<class1> test1;
133 test_task<class1> test2;
134 test_task<class1> test3;
135 
136 
137 template <typename ClassT>
138 void
check_ascending(test_task<ClassT> const & t)139 check_ascending(test_task<ClassT> const &t)
140 {
141     typedef typename std::vector<ClassT*>::const_iterator iter;
142     iter p(t.data().begin());
143     iter const e(t.data().end());
144     iter n(p);
145 
146     while (++n!=e)
147     {
148         if ((**n).get_object_id()<=(**p).get_object_id())
149         {
150             using namespace std;
151             throw std::runtime_error("object ids out of order");
152         }
153         p = n;
154     }
155 }
156 
157 struct less1
158 {
operator ()less1159     bool operator()(class1 const *p, class1 const *q) const
160     {
161         return p->get_object_id() < q->get_object_id();
162     }
163 };
164 
165 template <typename ClassT>
166 void
check_not_contained_in(test_task<ClassT> const & candidate,test_task<ClassT> const & in)167 check_not_contained_in(
168     test_task<ClassT> const &candidate,
169     test_task<ClassT> const &in
170 )
171 {
172     typedef typename std::vector<ClassT*>::const_iterator iter;
173     iter p(candidate.data().begin());
174     iter const e(candidate.data().end());
175 
176     while (p!=e)
177     {
178         iter found = std::lower_bound(in.data().begin(),in.data().end(),*p,less1());
179         if  (found!=in.data().end() &&
180             (**found).get_object_id() == (**p).get_object_id())
181         {
182             using namespace std;
183             throw std::runtime_error("object ids not unqiue");
184         }
185         ++p;
186     }
187 }
188 
concurrent_creation_of_objects()189 void concurrent_creation_of_objects()
190 {
191     {
192         boost::xtime_get(&start_time, boost::TIME_UTC_);
193         boost::thread thread1(callable_ref(test1));
194         boost::thread thread2(callable_ref(test2));
195         boost::thread thread3(callable_ref(test3));
196 
197         thread1.join();
198         thread2.join();
199         thread3.join();
200     }
201 }
202 
local_uniqueness()203 void local_uniqueness()
204 {
205 
206 
207     BOOST_TEST(test1.data().size()==test_size);
208     BOOST_TEST(test2.data().size()==test_size);
209     BOOST_TEST(test3.data().size()==test_size);
210 }
211 
local_ordering_and_uniqueness()212 void local_ordering_and_uniqueness()
213 {
214     // now all objects should have unique ids,
215     // the ids must be ascending within each vector
216     // check for ascending ids
217     check_ascending(test1);
218     check_ascending(test2);
219     check_ascending(test3);
220 }
221 
global_uniqueness()222 void global_uniqueness()
223 {
224     check_not_contained_in(test1,test3);
225     check_not_contained_in(test1,test2);
226     check_not_contained_in(test2,test1);
227     check_not_contained_in(test2,test3);
228     check_not_contained_in(test3,test2);
229     check_not_contained_in(test3,test1);
230 }
231 
232 int
main()233 main()
234 {
235     concurrent_creation_of_objects();
236     local_ordering_and_uniqueness();
237     global_uniqueness();
238     return boost::report_errors();
239 }
240 
241 #endif // BOOST_HAS_THREADS
242 
243