/indra/test/lldoubledispatch_tut.cpp

https://bitbucket.org/lindenlab/viewer-beta/ · C++ · 239 lines · 143 code · 27 blank · 69 comment · 0 complexity · 6c869bd1c0d0ce72089590d657239eb2 MD5 · raw file

  1. /**
  2. * @file lldoubledispatch_tut.cpp
  3. * @author Nat Goodspeed
  4. * @date 2008-11-13
  5. * @brief Test for lldoubledispatch.h
  6. *
  7. * This program tests the DoubleDispatch class, using a variation on the example
  8. * from Scott Meyers' "More Effective C++", Item 31.
  9. *
  10. * $LicenseInfo:firstyear=2008&license=viewerlgpl$
  11. * Second Life Viewer Source Code
  12. * Copyright (C) 2010, Linden Research, Inc.
  13. *
  14. * This library is free software; you can redistribute it and/or
  15. * modify it under the terms of the GNU Lesser General Public
  16. * License as published by the Free Software Foundation;
  17. * version 2.1 of the License only.
  18. *
  19. * This library is distributed in the hope that it will be useful,
  20. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  21. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
  22. * Lesser General Public License for more details.
  23. *
  24. * You should have received a copy of the GNU Lesser General Public
  25. * License along with this library; if not, write to the Free Software
  26. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  27. *
  28. * Linden Research, Inc., 945 Battery Street, San Francisco, CA 94111 USA
  29. * $/LicenseInfo$
  30. */
  31. // Precompiled header
  32. #include "linden_common.h"
  33. // associated header
  34. #include "lldoubledispatch.h"
  35. // STL headers
  36. // std headers
  37. #include <string>
  38. #include <iostream>
  39. #include <typeinfo>
  40. // external library headers
  41. // other Linden headers
  42. #include "lltut.h"
  43. /*---------------------------- Class hierarchy -----------------------------*/
  44. // All objects are GameObjects.
  45. class GameObject
  46. {
  47. public:
  48. GameObject(const std::string& name): mName(name) {}
  49. virtual ~GameObject() {}
  50. virtual std::string stringize() { return std::string(typeid(*this).name()) + " " + mName; }
  51. protected:
  52. std::string mName;
  53. };
  54. // SpaceStation, Asteroid and SpaceShip are peer GameObjects.
  55. struct SpaceStation: public GameObject
  56. {
  57. SpaceStation(const std::string& name): GameObject(name) {}
  58. // Only a dummy SpaceStation is constructed without a name
  59. SpaceStation(): GameObject("dummy") {}
  60. };
  61. struct Asteroid: public GameObject
  62. {
  63. Asteroid(const std::string& name): GameObject(name) {}
  64. Asteroid(): GameObject("dummy") {}
  65. };
  66. struct SpaceShip: public GameObject
  67. {
  68. SpaceShip(const std::string& name): GameObject(name) {}
  69. SpaceShip(): GameObject("dummy") {}
  70. };
  71. // SpaceShip is specialized further into CommercialShip and MilitaryShip.
  72. struct CommercialShip: public SpaceShip
  73. {
  74. CommercialShip(const std::string& name): SpaceShip(name) {}
  75. CommercialShip(): SpaceShip("dummy") {}
  76. };
  77. struct MilitaryShip: public SpaceShip
  78. {
  79. MilitaryShip(const std::string& name): SpaceShip(name) {}
  80. MilitaryShip(): SpaceShip("dummy") {}
  81. };
  82. /*-------------------------- Collision functions ---------------------------*/
  83. // This mechanism permits us to overcome a limitation of Meyers' approach: we
  84. // can declare the parameter types exactly as we want, rather than having to
  85. // make them all GameObject& parameters.
  86. std::string shipAsteroid(SpaceShip& ship, Asteroid& rock)
  87. {
  88. // std::cout << rock.stringize() << " has pulverized " << ship.stringize() << std::endl;
  89. return "shipAsteroid";
  90. }
  91. std::string militaryShipAsteroid(MilitaryShip& ship, Asteroid& rock)
  92. {
  93. // std::cout << rock.stringize() << " has severely damaged " << ship.stringize() << std::endl;
  94. return "militaryShipAsteroid";
  95. }
  96. std::string shipStation(SpaceShip& ship, SpaceStation& dock)
  97. {
  98. // std::cout << ship.stringize() << " has docked at " << dock.stringize() << std::endl;
  99. return "shipStation";
  100. }
  101. std::string asteroidStation(Asteroid& rock, SpaceStation& dock)
  102. {
  103. // std::cout << rock.stringize() << " has damaged " << dock.stringize() << std::endl;
  104. return "asteroidStation";
  105. }
  106. /*------------------------------- Test code --------------------------------*/
  107. namespace tut
  108. {
  109. struct dispatch_data
  110. {
  111. dispatch_data():
  112. home(new SpaceStation("Terra Station")),
  113. obstacle(new Asteroid("Ganymede")),
  114. tug(new CommercialShip("Pilotfish")),
  115. patrol(new MilitaryShip("Enterprise"))
  116. {}
  117. // Instantiate and populate the DoubleDispatch object.
  118. typedef LLDoubleDispatch<std::string, GameObject> DD;
  119. DD dispatcher;
  120. // Instantiate a few GameObjects. Make sure we refer to them
  121. // polymorphically, and don't let them leak.
  122. std::auto_ptr<GameObject> home;
  123. std::auto_ptr<GameObject> obstacle;
  124. std::auto_ptr<GameObject> tug;
  125. std::auto_ptr<GameObject> patrol;
  126. // prototype objects
  127. Asteroid dummyAsteroid;
  128. SpaceShip dummyShip;
  129. MilitaryShip dummyMilitary;
  130. CommercialShip dummyCommercial;
  131. SpaceStation dummyStation;
  132. };
  133. typedef test_group<dispatch_data> dispatch_group;
  134. typedef dispatch_group::object dispatch_object;
  135. tut::dispatch_group ddgr("double dispatch");
  136. template<> template<>
  137. void dispatch_object::test<1>()
  138. {
  139. // Describe param types using explicit DD::Type objects
  140. // (order-sensitive add() variant)
  141. dispatcher.add(DD::Type<SpaceShip>(), DD::Type<Asteroid>(), shipAsteroid, true);
  142. // naive adding, won't work
  143. dispatcher.add(DD::Type<MilitaryShip>(), DD::Type<Asteroid>(), militaryShipAsteroid, true);
  144. dispatcher.add(DD::Type<SpaceShip>(), DD::Type<SpaceStation>(), shipStation, true);
  145. dispatcher.add(DD::Type<Asteroid>(), DD::Type<SpaceStation>(), asteroidStation, true);
  146. // Try colliding them.
  147. ensure_equals(dispatcher(*home, *tug), // reverse params, SpaceShip subclass
  148. "shipStation");
  149. ensure_equals(dispatcher(*patrol, *home), // forward params, SpaceShip subclass
  150. "shipStation");
  151. ensure_equals(dispatcher(*obstacle, *home), // forward params
  152. "asteroidStation");
  153. ensure_equals(dispatcher(*home, *obstacle), // reverse params
  154. "asteroidStation");
  155. ensure_equals(dispatcher(*tug, *obstacle), // forward params, SpaceShip subclass
  156. "shipAsteroid");
  157. ensure_equals(dispatcher(*obstacle, *patrol), // reverse params, SpaceShip subclass
  158. // won't use militaryShipAsteroid() because it was added
  159. // in wrong order
  160. "shipAsteroid");
  161. }
  162. template<> template<>
  163. void dispatch_object::test<2>()
  164. {
  165. // Describe param types using explicit DD::Type objects
  166. // (order-sensitive add() variant)
  167. // adding in correct order
  168. dispatcher.add(DD::Type<MilitaryShip>(), DD::Type<Asteroid>(), militaryShipAsteroid, true);
  169. dispatcher.add(DD::Type<SpaceShip>(), DD::Type<Asteroid>(), shipAsteroid, true);
  170. dispatcher.add(DD::Type<SpaceShip>(), DD::Type<SpaceStation>(), shipStation, true);
  171. dispatcher.add(DD::Type<Asteroid>(), DD::Type<SpaceStation>(), asteroidStation, true);
  172. ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid");
  173. ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid");
  174. }
  175. template<> template<>
  176. void dispatch_object::test<3>()
  177. {
  178. // Describe param types with actual prototype instances
  179. // (order-insensitive add() variant)
  180. dispatcher.add(dummyMilitary, dummyAsteroid, militaryShipAsteroid);
  181. dispatcher.add(dummyShip, dummyAsteroid, shipAsteroid);
  182. dispatcher.add(dummyShip, dummyStation, shipStation);
  183. dispatcher.add(dummyAsteroid, dummyStation, asteroidStation);
  184. ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid");
  185. ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid");
  186. ensure_equals(dispatcher(*obstacle, *patrol), "");
  187. }
  188. template<> template<>
  189. void dispatch_object::test<4>()
  190. {
  191. // Describe param types with actual prototype instances
  192. // (order-insensitive add() variant)
  193. dispatcher.add(dummyShip, dummyAsteroid, shipAsteroid);
  194. // Even if we add the militaryShipAsteroid in the wrong order, it
  195. // should still work.
  196. dispatcher.add(dummyMilitary, dummyAsteroid, militaryShipAsteroid);
  197. dispatcher.add(dummyShip, dummyStation, shipStation);
  198. dispatcher.add(dummyAsteroid, dummyStation, asteroidStation);
  199. ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid");
  200. ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid");
  201. }
  202. template<> template<>
  203. void dispatch_object::test<5>()
  204. {
  205. dispatcher.add<SpaceShip, Asteroid>(shipAsteroid);
  206. dispatcher.add<MilitaryShip, Asteroid>(militaryShipAsteroid);
  207. dispatcher.add<SpaceShip, SpaceStation>(shipStation);
  208. dispatcher.add<Asteroid, SpaceStation>(asteroidStation);
  209. ensure_equals(dispatcher(*patrol, *obstacle), "militaryShipAsteroid");
  210. ensure_equals(dispatcher(*tug, *obstacle), "shipAsteroid");
  211. }
  212. } // namespace tut