| 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) |
|---|
| 18 | static void skipped() |
|---|
| 19 | { |
|---|
| 20 | std::cout << "skipped\n"; |
|---|
| 21 | } |
|---|
| 22 | |
|---|
| 23 | int |
|---|
| 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/core/non_terminal/impl/object_with_id.ipp> |
|---|
| 47 | #include <boost/ref.hpp> |
|---|
| 48 | #include <boost/thread/xtime.hpp> |
|---|
| 49 | #include <vector> |
|---|
| 50 | #include <algorithm> |
|---|
| 51 | #include <boost/detail/lightweight_test.hpp> |
|---|
| 52 | |
|---|
| 53 | using boost::spirit::impl::object_with_id; |
|---|
| 54 | |
|---|
| 55 | struct tag1 {}; |
|---|
| 56 | typedef object_with_id<tag1> class1; |
|---|
| 57 | |
|---|
| 58 | unsigned long test_size = initial_test_size; |
|---|
| 59 | boost::xtime start_time; |
|---|
| 60 | |
|---|
| 61 | template <typename ClassT> |
|---|
| 62 | struct test_task |
|---|
| 63 | { |
|---|
| 64 | test_task() : v(), m(), progress(0) {} |
|---|
| 65 | |
|---|
| 66 | void operator ()() |
|---|
| 67 | { // create lots of objects |
|---|
| 68 | unsigned long i = 0; |
|---|
| 69 | |
|---|
| 70 | v.reserve(maximum_test_size); |
|---|
| 71 | do |
|---|
| 72 | { |
|---|
| 73 | for (; i<test_size; ++i) |
|---|
| 74 | v.push_back(new ClassT); |
|---|
| 75 | } |
|---|
| 76 | while ( i < increase_test_size(i) ); |
|---|
| 77 | } |
|---|
| 78 | |
|---|
| 79 | static unsigned long |
|---|
| 80 | increase_test_size(unsigned long size) |
|---|
| 81 | { |
|---|
| 82 | static boost::mutex m; |
|---|
| 83 | boost::mutex::scoped_lock l(m); |
|---|
| 84 | |
|---|
| 85 | if (size<test_size || test_size == maximum_test_size) |
|---|
| 86 | return test_size; |
|---|
| 87 | |
|---|
| 88 | boost::xtime now; |
|---|
| 89 | boost::xtime_get(&now, boost::TIME_UTC); |
|---|
| 90 | unsigned long seconds = now.sec - start_time.sec; |
|---|
| 91 | if (seconds < 4) |
|---|
| 92 | { |
|---|
| 93 | test_size *= 2; |
|---|
| 94 | if (test_size > maximum_test_size) |
|---|
| 95 | test_size = maximum_test_size; |
|---|
| 96 | } |
|---|
| 97 | |
|---|
| 98 | return test_size; |
|---|
| 99 | } |
|---|
| 100 | |
|---|
| 101 | std::vector<ClassT*> const &data() const |
|---|
| 102 | { |
|---|
| 103 | return v; |
|---|
| 104 | } |
|---|
| 105 | |
|---|
| 106 | private: |
|---|
| 107 | std::vector<ClassT*> v; |
|---|
| 108 | boost::mutex m; |
|---|
| 109 | unsigned int progress; |
|---|
| 110 | }; |
|---|
| 111 | |
|---|
| 112 | test_task<class1> test1; |
|---|
| 113 | test_task<class1> test2; |
|---|
| 114 | test_task<class1> test3; |
|---|
| 115 | |
|---|
| 116 | |
|---|
| 117 | template <typename ClassT> |
|---|
| 118 | void |
|---|
| 119 | check_ascending(test_task<ClassT> const &t) |
|---|
| 120 | { |
|---|
| 121 | typedef typename std::vector<ClassT*>::const_iterator iter; |
|---|
| 122 | iter p(t.data().begin()); |
|---|
| 123 | iter const e(t.data().end()); |
|---|
| 124 | iter n(p); |
|---|
| 125 | |
|---|
| 126 | while (++n!=e) |
|---|
| 127 | { |
|---|
| 128 | if ((**n).get_object_id()<=(**p).get_object_id()) |
|---|
| 129 | { |
|---|
| 130 | using namespace std; |
|---|
| 131 | throw std::runtime_error("object ids out of order"); |
|---|
| 132 | } |
|---|
| 133 | p = n; |
|---|
| 134 | } |
|---|
| 135 | }; |
|---|
| 136 | |
|---|
| 137 | struct less1 |
|---|
| 138 | { |
|---|
| 139 | bool operator()(class1 const *p, class1 const *q) const |
|---|
| 140 | { |
|---|
| 141 | return p->get_object_id() < q->get_object_id(); |
|---|
| 142 | } |
|---|
| 143 | }; |
|---|
| 144 | |
|---|
| 145 | template <typename ClassT> |
|---|
| 146 | void |
|---|
| 147 | check_not_contained_in( |
|---|
| 148 | test_task<ClassT> const &candidate, |
|---|
| 149 | test_task<ClassT> const &in |
|---|
| 150 | ) |
|---|
| 151 | { |
|---|
| 152 | typedef typename std::vector<ClassT*>::const_iterator iter; |
|---|
| 153 | iter p(candidate.data().begin()); |
|---|
| 154 | iter const e(candidate.data().end()); |
|---|
| 155 | |
|---|
| 156 | while (p!=e) |
|---|
| 157 | { |
|---|
| 158 | iter found = std::lower_bound(in.data().begin(),in.data().end(),*p,less1()); |
|---|
| 159 | if (found!=in.data().end() && |
|---|
| 160 | (**found).get_object_id() == (**p).get_object_id()) |
|---|
| 161 | { |
|---|
| 162 | using namespace std; |
|---|
| 163 | throw std::runtime_error("object ids not unqiue"); |
|---|
| 164 | } |
|---|
| 165 | ++p; |
|---|
| 166 | } |
|---|
| 167 | }; |
|---|
| 168 | |
|---|
| 169 | void concurrent_creation_of_objects() |
|---|
| 170 | { |
|---|
| 171 | { |
|---|
| 172 | boost::xtime_get(&start_time, boost::TIME_UTC); |
|---|
| 173 | boost::thread thread1(boost::ref(test1)); |
|---|
| 174 | boost::thread thread2(boost::ref(test2)); |
|---|
| 175 | boost::thread thread3(boost::ref(test3)); |
|---|
| 176 | |
|---|
| 177 | thread1.join(); |
|---|
| 178 | thread2.join(); |
|---|
| 179 | thread3.join(); |
|---|
| 180 | } |
|---|
| 181 | } |
|---|
| 182 | |
|---|
| 183 | void local_uniqueness() |
|---|
| 184 | { |
|---|
| 185 | |
|---|
| 186 | |
|---|
| 187 | BOOST_TEST(test1.data().size()==test_size); |
|---|
| 188 | BOOST_TEST(test2.data().size()==test_size); |
|---|
| 189 | BOOST_TEST(test3.data().size()==test_size); |
|---|
| 190 | } |
|---|
| 191 | |
|---|
| 192 | void local_ordering_and_uniqueness() |
|---|
| 193 | { |
|---|
| 194 | // now all objects should have unique ids, |
|---|
| 195 | // the ids must be ascending within each vector |
|---|
| 196 | // check for ascending ids |
|---|
| 197 | check_ascending(test1); |
|---|
| 198 | check_ascending(test2); |
|---|
| 199 | check_ascending(test3); |
|---|
| 200 | } |
|---|
| 201 | |
|---|
| 202 | void global_uniqueness() |
|---|
| 203 | { |
|---|
| 204 | check_not_contained_in(test1,test3); |
|---|
| 205 | check_not_contained_in(test1,test2); |
|---|
| 206 | check_not_contained_in(test2,test1); |
|---|
| 207 | check_not_contained_in(test2,test3); |
|---|
| 208 | check_not_contained_in(test3,test2); |
|---|
| 209 | check_not_contained_in(test3,test1); |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | int |
|---|
| 213 | main() |
|---|
| 214 | { |
|---|
| 215 | concurrent_creation_of_objects(); |
|---|
| 216 | local_ordering_and_uniqueness(); |
|---|
| 217 | global_uniqueness(); |
|---|
| 218 | return boost::report_errors(); |
|---|
| 219 | } |
|---|
| 220 | |
|---|
| 221 | #endif // BOOST_HAS_THREADS |
|---|
| 222 | |
|---|