00001
00002
00003
00004
00005
00006
00007
00008
00009
00010 #include <iostream>
00011 #include <iomanip>
00012 #include <functional>
00013 #include <boost/enum.hpp>
00014 #include <boost/concept_check.hpp>
00015 #include <boost/function.hpp>
00016 #include <boost/array.hpp>
00017 #include <boost/type_traits/is_virtual_base_of.hpp>
00018
00019 using namespace std;
00020
00021 struct Log
00022 {
00023 BOOST_ENUM_VALUES(Level, const char*,
00024 (Abort)("unrecoverable problem")
00025 (Error)("recoverable problem")
00026 (Alert)("unexpected behavior")
00027 (Info) ("expected behavior")
00028 (Trace)("normal flow of execution")
00029 (Debug)("detailed object state listings")
00030 )
00031 };
00032
00033 namespace expanded
00034 {
00035 class Level : public boost::detail::enum_base<Level, string>
00036 {
00037 public:
00038 enum domain
00039 {
00040 Abort,
00041 Error,
00042 Alert,
00043 Info,
00044 Trace,
00045 Debug,
00046 };
00047
00048 BOOST_STATIC_CONSTANT(index_type, size = 6);
00049
00050 Level() {}
00051 Level(domain index) : boost::detail::enum_base<Level, string>(index) {}
00052
00053 typedef boost::optional<Level> optional;
00054 static optional get_by_name(const char* str)
00055 {
00056 if(strcmp(str, "Abort") == 0) return optional(Abort);
00057 if(strcmp(str, "Error") == 0) return optional(Error);
00058 if(strcmp(str, "Alert") == 0) return optional(Alert);
00059 if(strcmp(str, "Info") == 0) return optional(Info);
00060 if(strcmp(str, "Trace") == 0) return optional(Trace);
00061 if(strcmp(str, "Debug") == 0) return optional(Debug);
00062 return optional();
00063 }
00064
00065 private:
00066 friend class boost::detail::enum_base<Level, string>;
00067 static const char* names(domain index)
00068 {
00069 switch(index)
00070 {
00071 case Abort: return "Abort";
00072 case Error: return "Error";
00073 case Alert: return "Alert";
00074 case Info: return "Info";
00075 case Trace: return "Trace";
00076 case Debug: return "Debug";
00077 default: return NULL;
00078 }
00079 }
00080
00081 typedef boost::optional<value_type> optional_value;
00082 static optional_value values(domain index)
00083 {
00084 switch(index)
00085 {
00086 case Abort: return optional_value("unrecoverable problem");
00087 case Error: return optional_value("recoverable problem");
00088 case Alert: return optional_value("unexpected behavior");
00089 case Info: return optional_value("expected behavior");
00090 case Trace: return optional_value("normal flow of execution");
00091 case Debug: return optional_value("detailed object state listings");
00092 default: return optional_value();
00093 }
00094 }
00095 };
00096 }
00097
00098
00099 BOOST_ENUM(boolean,
00100 (False)
00101 (True)
00102 )
00103
00104
00105 namespace expanded
00106 {
00107 class boolean : public boost::detail::enum_base<boolean>
00108 {
00109 public:
00110 enum domain
00111 {
00112 False,
00113 True,
00114 };
00115
00116 BOOST_STATIC_CONSTANT(index_type, size = 2);
00117
00118 public:
00119 boolean() {}
00120 boolean(domain index) : boost::detail::enum_base<boolean>(index) {}
00121
00122 typedef boost::optional<boolean> optional;
00123 static optional get_by_name(const char* str)
00124 {
00125 if(strcmp(str, "False") == 0) return optional(False);
00126 if(strcmp(str, "True") == 0) return optional(True);
00127 return optional();
00128 }
00129
00130 private:
00131 friend class boost::detail::enum_base<boolean>;
00132 static const char* names(domain index)
00133 {
00134 BOOST_ASSERT(static_cast<index_type>(index) < size);
00135 switch(index)
00136 {
00137 case False: return "False";
00138 case True: return "True";
00139 default: return "";
00140 }
00141 }
00142 };
00143 }
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153 BOOST_ENUM_VALUES(VirtualKey, int,
00154 (Zero) (0)
00155 (Space)(0x20)
00156 (Prior)(0x21)
00157 (Next) (0x22)
00158 (End) (0x23)
00159 (Home) (0x24)
00160 )
00161
00162
00163 namespace expanded
00164 {
00165 class VirtualKey : public boost::detail::enum_base<VirtualKey>
00166 {
00167 public:
00168 enum domain
00169 {
00170 Space,
00171 Prior,
00172 Next,
00173 End,
00174 Home,
00175 };
00176
00177 BOOST_STATIC_CONSTANT(index_type, size = 5);
00178
00179 VirtualKey() {}
00180 VirtualKey(domain index) : boost::detail::enum_base<VirtualKey>(index) {}
00181
00182 typedef boost::optional<VirtualKey> optional;
00183 static optional get_by_name(const char* str)
00184 {
00185 if(strcmp(str, "Space") == 0) return optional(Space);
00186 if(strcmp(str, "Prior") == 0) return optional(Prior);
00187 if(strcmp(str, "Next") == 0) return optional(Next);
00188 if(strcmp(str, "End") == 0) return optional(End);
00189 if(strcmp(str, "Home") == 0) return optional(Home);
00190 return optional();
00191 }
00192
00193 private:
00194 friend class boost::detail::enum_base<VirtualKey>;
00195 static const char* names(domain index)
00196 {
00197 switch(index)
00198 {
00199 case Space: return "Space";
00200 case Prior: return "Prior";
00201 case Next: return "Next";
00202 case End: return "End";
00203 case Home: return "Home";
00204 default: return NULL;
00205 }
00206 }
00207
00208 typedef boost::optional<value_type> optional_value;
00209 static optional_value values(domain index)
00210 {
00211 switch(index)
00212 {
00213 case Space: return optional_value(0x20);
00214 case Prior: return optional_value(0x21);
00215 case Next: return optional_value(0x22);
00216 case End: return optional_value(0x23);
00217 case Home: return optional_value(0x24);
00218 default: return optional_value();
00219 }
00220 }
00221 };
00222 }
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 BOOST_BITFIELD(MouseKey,
00233 (LeftButton) (0x0001)
00234 (RightButton) (0x0002)
00235 (Shift) (0x0004)
00236 (Control) (0x0008)
00237 (MiddleButton)(0x0010)
00238 )
00239
00240
00241 namespace expanded
00242 {
00243 class MouseKey : public boost::detail::bitfield_base<MouseKey>
00244 {
00245 public:
00246 enum domain
00247 {
00248 LeftButton,
00249 RightButton,
00250 Shift,
00251 Control,
00252 MiddleButton,
00253 };
00254
00255 BOOST_STATIC_CONSTANT(index_type, size = 5);
00256
00257 MouseKey() {}
00258 MouseKey(domain index) : boost::detail::bitfield_base<MouseKey>(index) {}
00259
00260 typedef boost::optional<MouseKey> optional;
00261 static optional get_by_name(const char* str)
00262 {
00263 if(strcmp(str, "LeftButton") == 0) return optional(LeftButton);
00264 if(strcmp(str, "RightButton") == 0) return optional(RightButton);
00265 if(strcmp(str, "Shift") == 0) return optional(Shift);
00266 if(strcmp(str, "Control") == 0) return optional(Control);
00267 if(strcmp(str, "MiddleButton") == 0) return optional(MiddleButton);
00268 return optional();
00269 }
00270
00271 private:
00272 friend class boost::detail::bitfield_access;
00273 static const char* names(domain index)
00274 {
00275 switch(index)
00276 {
00277 case LeftButton: return "LeftButton";
00278 case RightButton: return "RightButton";
00279 case Shift: return "Shift";
00280 case Control: return "Control";
00281 case MiddleButton: return "MiddleButton";
00282 default: return NULL;
00283 }
00284 }
00285
00286 typedef boost::optional<value_type> optional_value;
00287 static optional_value values(domain index)
00288 {
00289 switch(index)
00290 {
00291 case LeftButton: return optional_value(0x0001);
00292 case RightButton: return optional_value(0x0002);
00293 case Shift: return optional_value(0x0004);
00294 case Control: return optional_value(0x0008);
00295 case MiddleButton: return optional_value(0x0010);
00296 default: return optional_value();
00297 }
00298 }
00299 };
00300
00301
00302
00303
00304
00305
00306
00307
00308
00309
00310
00311
00312
00313
00314
00315
00316
00317
00318
00319
00320
00321
00322
00323
00324
00325
00326
00327
00328
00329
00330
00331
00332
00333
00334
00335
00336
00337
00338
00339
00340
00341 }
00342
00343 struct Point
00344 {
00345 Point(int x_, int y_) : x(x_), y(y_) {}
00346 int x;
00347 int y;
00348 };
00349
00350 ostream& operator << (ostream& os, const Point& rhs)
00351 {
00352 os << rhs.x << ", " << rhs.y;
00353 return os;
00354 }
00355
00356 bool operator == (const Point& lhs, const Point& rhs)
00357 {
00358 return lhs.x == rhs.x && lhs.y == rhs.y;
00359 }
00360
00361 BOOST_ENUM_VALUES(Points, Point,
00362 (Origin)(Point(0, 0))
00363 (LeftField)(Point(-100, -100))
00364 )
00365
00366 template <typename T>
00367 void test_iterator()
00368 {
00369 boost::function_requires<boost::RandomAccessIteratorConcept
00370 <BOOST_DEDUCED_TYPENAME T::const_iterator> >();
00371
00372 cout << "iteration begin" << endl;
00373 copy(T::begin(), T::end(), ostream_iterator<T>(cout, "\n"));
00374 cout << "iteration end" << endl;
00375 }
00376
00377 template <typename T, typename A>
00378 void test_optional_method(
00379 const A& arg,
00380 const BOOST_DEDUCED_TYPENAME T::optional& expected,
00381 const char* method_name,
00382 const boost::function1<BOOST_DEDUCED_TYPENAME T::optional, A>& method
00383 )
00384 {
00385 BOOST_DEDUCED_TYPENAME T::optional ret = method(arg);
00386 cout << method_name << "(" << arg << "): ";
00387 if(ret)
00388 {
00389 BOOST_ASSERT(*ret == *expected);
00390 cout << *ret << endl;
00391 }
00392 else
00393 {
00394 BOOST_ASSERT(!expected);
00395 cout << "failed" << endl;
00396 }
00397 }
00398
00399 template <typename T>
00400 void test_get_by_name(const std::string& str, const boost::optional<T>& expected)
00401 {
00402 test_optional_method<T, const char*>(str.c_str(), expected, "get_by_name", &T::get_by_name);
00403 if(expected)
00404 {
00405 stringstream ss;
00406 ss << str;
00407 T value;
00408 ss >> value;
00409
00410 BOOST_ASSERT(value == *expected);
00411 }
00412 }
00413
00414 template <typename T>
00415 void test_get_by_index(
00416 BOOST_DEDUCED_TYPENAME T::index_type index,
00417 const boost::optional<T>& expected)
00418 {
00419 test_optional_method<T, BOOST_DEDUCED_TYPENAME T::index_type>(
00420 index, expected, "get_by_index", &T::get_by_index);
00421 }
00422
00423 template <typename T>
00424 void test_get_by_value(
00425 BOOST_DEDUCED_TYPENAME T::value_type value,
00426 const boost::optional<T>& expected)
00427 {
00428 test_optional_method<T, BOOST_DEDUCED_TYPENAME T::value_type>(
00429 value, expected, "get_by_value", &T::get_by_value);
00430 }
00431
00432 template <typename T>
00433 void take_enum(const T& value)
00434 {
00435 cout << "take: " << value << endl;
00436 }
00437
00438 namespace detail
00439 {
00440 template <bool is_enum = false>
00441 struct switch_helper
00442 {
00443 template <typename T>
00444 static void apply(const T& value)
00445 {
00446
00447
00448
00449 }
00450 };
00451
00452 template <>
00453 struct switch_helper<true>
00454 {
00455 template <typename T>
00456 static void apply(const T& value)
00457 {
00458 cout << "switch(" << value << "): ";
00459 switch(value.index())
00460 {
00461 case 0:
00462 cout << "0" << endl;
00463 break;
00464 case 1:
00465 cout << "1" << endl;
00466 break;
00467 default:
00468 cout << "invalid" << endl;
00469 }
00470 }
00471 };
00472 }
00473
00474 template <typename T>
00475 struct switch_enum
00476 {
00477 static void apply(const T& value)
00478 {
00479 typedef BOOST_DEDUCED_TYPENAME T::value_type value_type;
00480 typedef boost::detail::enum_base<T, value_type> base_type;
00481 detail::switch_helper<boost::is_base_of<base_type, T>::value>::apply(value);
00482
00483 }
00484 };
00485
00486 template <>
00487 struct switch_enum<boolean>
00488 {
00489 static void apply(const boolean& value)
00490 {
00491 switch(value.index())
00492 {
00493 case boolean::True:
00494 cout << "switch(boolean::True)" << endl;
00495 break;
00496 case boolean::False:
00497 cout << "switch(boolean::False)" << endl;
00498 break;
00499 default:
00500 cout << "switch(boolean::invalid)" << endl;
00501 }
00502 }
00503 };
00504
00505 template <>
00506 struct switch_enum<Points>
00507 {
00508 static void apply(const Points& value)
00509 {
00510 switch(value.index())
00511 {
00512 case Points::Origin:
00513 cout << "switch(Points::Origin)" << endl;
00514 break;
00515 case Points::LeftField:
00516 cout << "switch(Points::LeftField)" << endl;
00517 break;
00518 default:
00519 cout << "switch(Points::invalid)" << endl;
00520 }
00521 }
00522 };
00523
00524 template <typename T>
00525 void test_enum(BOOST_DEDUCED_TYPENAME T::value_type invalid_value)
00526 {
00527 boost::function_requires<boost::AssignableConcept<T> >();
00528 boost::function_requires<boost::DefaultConstructibleConcept<T> >();
00529 boost::function_requires<boost::CopyConstructibleConcept<T> >();
00530 boost::function_requires<boost::EqualityComparableConcept<T> >();
00531
00532 cout << "Testing: " << typeid(T).name() << endl;
00533
00534 test_iterator<T>();
00535
00536 cout << "begin: " << *T::begin() << endl;
00537
00538
00539
00540 T invalid;
00541 T first = *T::begin();
00542 T second = T::begin()[1];
00543 T copy = first;
00544 T assign;
00545 assign = first;
00546
00547
00548
00549 cout << "first: " << first << endl;
00550 take_enum(first);
00551 cout << "second: " << second << endl;
00552 cout << "copy: " << copy << endl;
00553 BOOST_ASSERT(copy == first);
00554 cout << "assign: " << assign << endl;
00555 BOOST_ASSERT(assign == first);
00556
00557 cout << "value(first): " << dec << first.value() << endl;
00558
00559
00560
00561 test_get_by_name(first.str(), BOOST_DEDUCED_TYPENAME T::optional(first));
00562 test_get_by_name(second.str(), BOOST_DEDUCED_TYPENAME T::optional(second));
00563 test_get_by_name("foo", BOOST_DEDUCED_TYPENAME T::optional());
00564
00565 test_get_by_index(0, BOOST_DEDUCED_TYPENAME T::optional(first));
00566 test_get_by_index(T::size, BOOST_DEDUCED_TYPENAME T::optional());
00567 test_get_by_value(first.value(), BOOST_DEDUCED_TYPENAME T::optional(first));
00568 test_get_by_value(invalid_value, BOOST_DEDUCED_TYPENAME T::optional());
00569
00570 switch_enum<T>::apply(first);
00571 switch_enum<T>::apply(second);
00572 }
00573
00574 template <typename T>
00575 void test_bitfield(BOOST_DEDUCED_TYPENAME T::value_type invalid_value)
00576 {
00577 test_enum<T>(invalid_value);
00578
00579 T all_mask(T::all_mask);
00580 T not_mask(T::not_mask);
00581
00582 cout << hex;
00583 test_get_by_value(all_mask.value(), BOOST_DEDUCED_TYPENAME T::optional(all_mask));
00584 test_get_by_value(not_mask.value(), BOOST_DEDUCED_TYPENAME T::optional());
00585
00586 T first = *T::begin();
00587 T second = T::begin()[1];
00588 T test;
00589 test |= first;
00590 cout << "test |= first: " << test << endl;
00591
00592 test |= second;
00593 cout << "test |= second: " << test << endl;
00594
00595 cout << "all_mask: " << all_mask << endl;
00596 cout << all_mask << " = 0x" << hex << setw(8) << setfill('0') << all_mask.value() << endl;
00597 cout << not_mask << " = 0x" << hex << setw(8) << setfill('0') << not_mask.value() << endl;
00598 cout << "all_mask & first: " << (all_mask & first) << endl;
00599 cout << "first & second: " << (first & second) << endl;
00600 cout << "first | second: " << (first | second) << endl;
00601 cout << "all_mask[first]: " << all_mask[first] << endl;
00602 cout << "first[second]: " << first[second] << endl;
00603
00604 T first_set_second = first;
00605 bool ret = first_set_second.set(second);
00606 cout << "first.set(second): " << first_set_second << ", " << ret << endl;
00607 ret = first_set_second.set(second, false);
00608 cout << "first.set(second, false): " << first_set_second << ", " << ret << endl;
00609
00610 }
00611
00612 int main(int argc, char* argv[])
00613 {
00614 boolean bFalse = boolean::False;
00615 test_enum<boolean>(-1);
00616 cout << endl;
00617
00618 test_enum<Log::Level>("foo");
00619 cout << endl;
00620
00621 test_enum<VirtualKey>(123456789);
00622 cout << endl;
00623
00624 test_bitfield<MouseKey>(0xffffffff);
00625 MouseKey mkAll = MouseKey::all_mask;
00626 MouseKey mkLeftControl = MouseKey::LeftButton;
00627 mkLeftControl.set(MouseKey::Control);
00628 cout << "mkAll[MouseKey::Control]: " << mkAll[MouseKey::Control] << endl;
00629 cout << "mkLeft.set(MouseKey::Control): " << mkLeftControl << endl;
00630 mkLeftControl.reset(MouseKey::Control);
00631 cout << "mkLeft.reset(MouseKey::Control): " << mkLeftControl << endl;
00632 cout << endl;
00633
00634 test_enum<expanded::Level>("foo");
00635 cout << endl;
00636
00637 test_enum<Points>(Point(-1,-1));
00638
00639 return 0;
00640 }