preamble.hpp 33 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. #ifndef BOOST_OPENMETHOD_REGISTRY_HPP
  2. #define BOOST_OPENMETHOD_REGISTRY_HPP
  3. #include <boost/openmethod/detail/static_list.hpp>
  4. #include <boost/mp11/algorithm.hpp>
  5. #include <boost/mp11/bind.hpp>
  6. #include <stdlib.h>
  7. #include <vector>
  8. #include <cstdint>
  9. #ifdef _MSC_VER
  10. #pragma warning(push)
  11. #pragma warning(disable : 4702)
  12. #endif
  13. namespace boost::openmethod {
  14. namespace detail {
  15. union word {
  16. word() {
  17. } // undefined
  18. word(void (*pf)()) : pf(pf) {
  19. }
  20. word(word* pw) : pw(pw) {
  21. }
  22. word(std::size_t i) : i(i) {
  23. }
  24. void (*pf)();
  25. std::size_t i;
  26. word* pw;
  27. };
  28. } // namespace detail
  29. //! Alias to v-table pointer type.
  30. //!
  31. //! `vptr_type` is an alias to the type of a v-table pointer.
  32. using vptr_type = const detail::word*;
  33. //! Type used to identify a class.
  34. //!
  35. //! `type_id` is the return type of the @ref static_type and @ref dynamic_type
  36. //! functions. It can be used as an actual data pointer (e.g. to a
  37. //! `std::type_info` object), or as an opaque integer type.
  38. using type_id = const void*;
  39. //! Decorator for virtual parameters.
  40. //!
  41. //! `virtual_` marks a formal parameter of a method as virtual. It is a @em
  42. //! decorator, not an actual type that can be instantiated (it does not have a
  43. //! definition). It is removed from the method's signature.
  44. //!
  45. //! @note `virtual_` can be used @em only in method declarations, @em not in
  46. //! overriders. A parameter in overriders is implicitly virtual if it is in
  47. //! the same position as a virtual parameter in the method's declaration.
  48. //!
  49. //! @par Requirements
  50. //!
  51. //! - @ref virtual_traits must be specialized for `T`.
  52. //!
  53. //! @tparam T A class.
  54. template<typename T>
  55. struct virtual_;
  56. template<typename T, class Registry>
  57. struct virtual_traits;
  58. // -----------------------------------------------------------------------------
  59. // Error handling
  60. //! Base class for all OpenMethod errors.
  61. struct openmethod_error {};
  62. //! One Definition Rule violation.
  63. //!
  64. //! This error is raised if the definition of @ref default_registry is
  65. //! inconsistent across translation units, due to misuse of
  66. //! {{BOOST_OPENMETHOD_ENABLE_RUNTIME_CHECKS}}.
  67. struct odr_violation : openmethod_error {
  68. //! Write a description of the error to a stream.
  69. //! @tparam Registry The registry containing this policy.
  70. //! @param stream The stream to write to.
  71. template<class Registry, class Stream>
  72. auto write(Stream& stream) const {
  73. stream << "conflicting definitions of ";
  74. Registry::rtti::type_name(
  75. Registry::rtti::template static_type<Registry>(), stream);
  76. }
  77. };
  78. namespace detail {
  79. template<class Registry>
  80. struct odr_check {
  81. static std::size_t count;
  82. template<class R>
  83. static std::size_t inc;
  84. odr_check() {
  85. [[maybe_unused]] auto _ = &inc<typename Registry::registry_type>;
  86. }
  87. };
  88. template<class Registry>
  89. std::size_t odr_check<Registry>::count;
  90. template<class Registry>
  91. template<class R>
  92. std::size_t odr_check<Registry>::inc = count++;
  93. } // namespace detail
  94. //! Registry not initialized
  95. struct not_initialized : openmethod_error {
  96. //! Write a short description to an output stream
  97. //! @param os The output stream
  98. //! @tparam Registry The registry
  99. //! @tparam Stream A @ref LightweightOutputStream
  100. template<class Registry, class Stream>
  101. auto write(Stream& os) const {
  102. os << "not initialized";
  103. }
  104. };
  105. //! Missing class.
  106. //!
  107. //! A class used as a virtual parameter in a method, an overrider or a method
  108. //! call was not registered.
  109. //!
  110. //! @par Examples
  111. //!
  112. //! Missing registration of a class used as a virtual parameter in a method:
  113. //! @code
  114. //! struct Animal { virtual ~Animal() {} };
  115. //! struct Dog : Animal {};
  116. //!
  117. //! BOOST_OPENMETHOD_CLASSES(Animal);
  118. //!
  119. //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
  120. //!
  121. //! initialize(); // throws missing_class;
  122. //! @endcode
  123. //!
  124. //! Missing registration of a class used as a virtual parameter in an overrider:
  125. //! @code
  126. //! BOOST_OPENMETHOD_CLASSES(Animal);
  127. //!
  128. //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
  129. //!
  130. //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
  131. //!
  132. //! initialize(); // throws missing_class;
  133. //! @endcode
  134. //!
  135. //! Missing registration of a class used as a virtual parameter in a call:
  136. //! @code
  137. //! struct Bulldog : Dog {};
  138. //!
  139. //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
  140. //!
  141. //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
  142. //!
  143. //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
  144. //!
  145. //! Bulldog hector;
  146. //! poke(hector); // throws missing_class;
  147. //! @endcode
  148. struct missing_class : openmethod_error {
  149. //! The type_id of the unknown class.
  150. type_id type;
  151. //! Write a short description to an output stream
  152. //! @param os The output stream
  153. //! @tparam Registry The registry
  154. //! @tparam Stream A @ref LightweightOutputStream
  155. template<class Registry, class Stream>
  156. auto write(Stream& os) const;
  157. };
  158. //! Missing base.
  159. //!
  160. //! A class used in an overrider virtual parameter was not registered as a
  161. //! derived class of the class in the same position in the method's virtual
  162. //! parameter list.
  163. //!
  164. //! @par Example
  165. //! In the following code, OpenMethod cannot infer that `Dog` is derived from
  166. //! `Animal`, because they are not registered in a same call to @ref
  167. //! BOOST_OPENMETHOD_CLASSES.
  168. //!
  169. //! @code
  170. //! BOOST_OPENMETHOD_CLASSES(Animal);
  171. //! BOOST_OPENMETHOD_CLASSES(Dog);
  172. //!
  173. //! BOOST_OPENMETHOD(poke, (virtual_ptr<Animal>), void);
  174. //!
  175. //! BOOST_OPENMETHOD_OVERRIDE(poke, (virtual_ptr<Dog>), void) { /* ... */ }
  176. //!
  177. //! initialize(); // throws missing_base;
  178. //! @endcode
  179. //!
  180. //! Fix:
  181. //!
  182. //! @code
  183. //! BOOST_OPENMETHOD_CLASSES(Animal, Dog);
  184. //! @endcode
  185. struct missing_base : openmethod_error {
  186. //! The type_id of the base class.
  187. type_id base;
  188. //! The type_id of the derived class.
  189. type_id derived;
  190. //! Write a short description to an output stream
  191. //! @param os The output stream
  192. //! @tparam Registry The registry
  193. //! @tparam Stream A @ref LightweightOutputStream
  194. template<class Registry, class Stream>
  195. auto write(Stream& os) const;
  196. };
  197. //! No valid overrider
  198. struct bad_call : openmethod_error {
  199. //! The type_id of method that was called
  200. type_id method;
  201. //! The number of @em virtual arguments in the call
  202. std::size_t arity;
  203. //! The maximum size of `types`
  204. static constexpr std::size_t max_types = 16;
  205. //! The type_ids of the arguments.
  206. type_id types[max_types];
  207. };
  208. //! No overrider for virtual tuple
  209. //!
  210. //! @see @ref bad_call for data members.
  211. struct no_overrider : bad_call {
  212. //! Write a short description to an output stream
  213. //! @param os The output stream
  214. //! @tparam Registry The registry
  215. //! @tparam Stream A @ref LightweightOutputStream
  216. template<class Registry, class Stream>
  217. auto write(Stream& os) const {
  218. os << "not implemented";
  219. }
  220. };
  221. //! Ambiguous call
  222. //!
  223. //! @see @ref bad_call for data members.
  224. struct ambiguous_call : bad_call {
  225. //! Write a short description to an output stream
  226. //! @param os The output stream
  227. //! @tparam Registry The registry
  228. //! @tparam Stream A @ref LightweightOutputStream
  229. template<class Registry, class Stream>
  230. auto write(Stream& os) const {
  231. os << "ambiguous";
  232. }
  233. };
  234. //! Static and dynamic type mismatch in "final" construct
  235. //!
  236. //! If runtime checks are enabled, the "final" construct checks that the static
  237. //! and dynamic types of the object, as reported by the `rtti` policy, are the
  238. //! same. If they are not, and if the registry contains an @ref error_handler
  239. //! policy, its @ref error function is called with a `final_error` object, then
  240. //! the program is terminated with
  241. //! @ref abort.
  242. struct final_error : openmethod_error {
  243. type_id static_type, dynamic_type;
  244. //! Write a short description to an output stream
  245. //! @param os The output stream
  246. //! @tparam Registry The registry
  247. //! @tparam Stream A @ref LightweightOutputStream
  248. template<class Registry, class Stream>
  249. auto write(Stream& os) const;
  250. };
  251. namespace detail {
  252. struct empty {};
  253. template<typename Iterator>
  254. struct range {
  255. range(Iterator first, Iterator last) : first(first), last(last) {
  256. }
  257. Iterator first, last;
  258. auto begin() const -> Iterator {
  259. return first;
  260. }
  261. auto end() const -> Iterator {
  262. return last;
  263. }
  264. };
  265. // -----------------------------------------------------------------------------
  266. // class info
  267. struct class_info : static_list<class_info>::static_link {
  268. type_id type;
  269. vptr_type* static_vptr;
  270. type_id *first_base, *last_base;
  271. bool is_abstract{false};
  272. auto vptr() const {
  273. return static_vptr;
  274. }
  275. auto type_id_begin() const {
  276. return &type;
  277. }
  278. auto type_id_end() const {
  279. return &type + 1;
  280. }
  281. };
  282. struct deferred_class_info : class_info {
  283. virtual void resolve_type_ids() = 0;
  284. };
  285. // -----------
  286. // method info
  287. struct overrider_info;
  288. struct method_info : static_list<method_info>::static_link {
  289. type_id* vp_begin;
  290. type_id* vp_end;
  291. static_list<overrider_info> overriders;
  292. void (*not_implemented)();
  293. void (*ambiguous)();
  294. type_id method_type_id;
  295. type_id return_type_id;
  296. std::size_t* slots_strides_ptr;
  297. auto arity() const {
  298. return std::distance(vp_begin, vp_end);
  299. }
  300. };
  301. struct deferred_method_info : method_info {
  302. virtual void resolve_type_ids() = 0;
  303. };
  304. struct overrider_info : static_list<overrider_info>::static_link {
  305. ~overrider_info() {
  306. method->overriders.remove(*this);
  307. }
  308. method_info* method; // for the destructor, to remove definition
  309. type_id return_type; // for N2216 disambiguation
  310. type_id type; // of the function, for trace
  311. void (**next)();
  312. type_id *vp_begin, *vp_end;
  313. void (*pf)();
  314. };
  315. struct deferred_overrider_info : overrider_info {
  316. virtual void resolve_type_ids() = 0;
  317. };
  318. struct unspecified {};
  319. } // namespace detail
  320. #ifdef __MRDOCS__
  321. //! Blueprint for a lightweight output stream (exposition only).
  322. //!
  323. //! Classes used as output streams in policies must provide the operations
  324. //! described on this page, either as members or as free functions.
  325. struct LightweightOutputStream {
  326. //! Writes a null-terminated string to the stream.
  327. LightweightOutputStream& operator<<(const char* str);
  328. //! Writes a string view to the stream.
  329. LightweightOutputStream& operator<<(const std::string_view& view);
  330. //! Writes a pointer value to the stream.
  331. LightweightOutputStream& operator<<(const void* value);
  332. //! Writes a size_t value to the stream.
  333. LightweightOutputStream& operator<<(std::size_t value);
  334. };
  335. #endif
  336. //! N2216 ambiguity resolution.
  337. //!
  338. //! If `n2216` is present in @ref initialize\'s `Options`, additional steps are
  339. //! taken to select a single overrider in presence of ambiguous overriders sets,
  340. //! according to the rules defined in the N2216 paper. If the normal resolution
  341. //! procedure fails to select a single overrider, the following steps are
  342. //! applied, in order:
  343. //!
  344. //! - If the return types of the remaining overriders are all polymorphic and
  345. //! covariant, and one of the return types is more specialized thjat all the
  346. //! others, use it.
  347. //!
  348. //! - Otherwise, pick one of the overriders. Which one is used is unspecified,
  349. //! but remains the same throughtout the program, and across different runs of
  350. //! the same program.
  351. struct n2216 {};
  352. //! Enable `initialize` tracing.
  353. //!
  354. //! If `trace` is passed to @ref initialize, tracing code is added to various
  355. //! parts of the initialization process (dispatch table construction, hash
  356. //! factors search, etc). The tracing code is executed only if
  357. //! @ref trace::on is set to `true`.
  358. //!
  359. //! `trace` requires the registry being initialized to have an @ref output
  360. //! policy.
  361. //!
  362. //! The content of the trace is neither specified, nor stable across versions.
  363. //! It is comprehensive, and useful for troubleshooting missing class
  364. //! registrations, missing or ambiguous overriders, etc.
  365. struct trace {
  366. //! Enable trace if `true`.
  367. bool on = true;
  368. trace(bool on = true) : on(on) {
  369. }
  370. //! Returns a `trace` object with `on` set to `true` if the environment
  371. //! variable `BOOST_OPENMETHOD_TRACE` is set to the string "1", and false
  372. //! otherwise.
  373. static trace from_env();
  374. };
  375. inline trace trace::from_env() {
  376. #ifdef _MSC_VER
  377. char* env;
  378. std::size_t len;
  379. auto result = _dupenv_s(&env, &len, "BOOST_OPENMETHOD_TRACE") == 0 && env &&
  380. len == 2 && *env == '1';
  381. free(env);
  382. return trace(result);
  383. #else
  384. auto env = getenv("BOOST_OPENMETHOD_TRACE");
  385. return trace(env && *env++ == '1' && *env++ == 0);
  386. #endif
  387. }
  388. //! Namespace for policies.
  389. //!
  390. //! Classes with snake case names are "blueprints", i.e. exposition-only classes
  391. //! that describe the requirements for policies of a given category. Classes
  392. //! implementing these blueprints must provide a `fn<Registry>` metafunction
  393. //! that conforms to the blueprint's requirements.
  394. //!
  395. //! @see @ref registry for a complete explanation of registries and policies.
  396. namespace policies {
  397. #ifdef __MRDOCS__
  398. //! Class information for initializing a policy (exposition only).
  399. //!
  400. //! Provides the v-table pointer for a class, identified by one or more type
  401. //! ids, via the members described on this page.
  402. struct InitializeClass {
  403. //! Beginning of a range of type ids for a class.
  404. //!
  405. //! @return A forward iterator to the beginning of a range of type ids for
  406. //! a class.
  407. auto type_id_begin() const -> detail::unspecified;
  408. //! End of a range of type ids for a class.
  409. //!
  410. //! @return A forward iterator to the end of a range of type ids for a
  411. //! class.
  412. auto type_id_end() const -> detail::unspecified;
  413. //! Reference to the v-table pointer for the class.
  414. //!
  415. //! @return A reference to the v-table pointer for the class.
  416. auto vptr() const -> const vptr_type&;
  417. };
  418. //! Context for initializing a policy (exposition only).
  419. //!
  420. //! @ref initialize passes a "context" object, of unspecified type, to the
  421. //! `initialize` functions of the policies that have one. It provides the
  422. //! v-table pointer for the registered classes, via the members described on
  423. //! this page.
  424. struct InitializeContext {
  425. //! Beginning of a range of `InitializeClass` objects.
  426. //!
  427. //! @return A forward iterator to the beginning of a range of @ref
  428. //! InitializeClass objects.
  429. detail::unspecified classes_begin() const;
  430. //! End of a range of `InitializeClass` objects.
  431. //!
  432. //! @return A forward iterator to the end of a range of @ref
  433. //! InitializeClass objects.
  434. detail::unspecified classes_end() const;
  435. };
  436. //! Blueprint for @ref rtti metafunctions (exposition only).
  437. template<class Registry>
  438. struct RttiFn {
  439. //! Tests if a class is polymorphic.
  440. //!
  441. //! @tparam Class A class.
  442. template<class Class>
  443. static constexpr bool is_polymorphic = std::is_polymorphic_v<Class>;
  444. //! Returns the static @ref type_id of a type.
  445. //!
  446. //! @note `Class` is not necessarily a @e registered class. This
  447. //! function is also called to acquire the type_id of non-virtual
  448. //! parameters, library types, etc, for diagnostic and trace purposes.
  449. //!
  450. //! @tparam Class A class.
  451. //! @return The static type_id of Class.
  452. template<class Class>
  453. static auto static_type() -> type_id;
  454. //! Returns the dynamic @ref type_id of an object.
  455. //!
  456. //! @tparam Class A registered class.
  457. //! @param obj A reference to an instance of `Class`.
  458. //! @return The type_id of `obj`'s class.
  459. template<class Class>
  460. static auto dynamic_type(const Class& obj) -> type_id;
  461. //! Writes a representation of a @ref type_id to a stream.
  462. //!
  463. //! @tparam Stream A LightweightOutputStream.
  464. //! @param type The `type_id` to write.
  465. //! @param stream The stream to write to.
  466. template<typename Stream>
  467. static auto type_name(type_id type, Stream& stream);
  468. //! Returns a key that uniquely identifies a class.
  469. //!
  470. //! @param type A `type_id`.
  471. //! @return A unique value that identifies a class with the given
  472. //! `type_id`.
  473. static auto type_index(type_id type);
  474. //! Casts an object to a type.
  475. //!
  476. //! @tparam D A reference to a subclass of `B`.
  477. //! @tparam B A registered class.
  478. //! @param obj A reference to an instance of `B`.
  479. template<typename D, typename B>
  480. static auto dynamic_cast_ref(B&& obj) -> D;
  481. };
  482. #endif
  483. //! Policy for manipulating type information.
  484. //!
  485. //! `rtti` policies are responsible for type information acquisition and dynamic
  486. //! casting.
  487. //!
  488. //! @par Requirements
  489. //!
  490. //! Classes implementing this policy must:
  491. //! @li derive from `rtti`.
  492. //! @li provide a `fn<Registry>` metafunction that conforms to the @ref RttiFn
  493. //! blueprint.
  494. struct rtti {
  495. // Policy category.
  496. using category = rtti;
  497. //! Default implementations of some `rtti` requirements.
  498. struct defaults {
  499. //! Default implementation for `type_index`.
  500. //!
  501. //! @param type A `type_id`.
  502. //!
  503. //! @return `type` itself.
  504. static auto type_index(type_id type) -> type_id {
  505. return type;
  506. }
  507. //! Default implementation of `type_name`.
  508. //!
  509. //! Executes `stream << "type_id(" << type << ")"`.
  510. //!
  511. //! @param type A `type_id`.
  512. //! @param stream A stream to write to.
  513. template<typename Stream>
  514. static void type_name(type_id type, Stream& stream) {
  515. stream << "type_id(" << type << ")";
  516. }
  517. };
  518. };
  519. //! Policy for deferred type id collection.
  520. //!
  521. //! Some custom RTTI systems rely on static constructors to assign type ids.
  522. //! OpenMethod itself relies on static constructors to register classes, methods
  523. //! and overriders. This creates order-of-initialization issues. Deriving a @e
  524. //! rtti policy from this class - instead of just `rtti` - causes the collection
  525. //! of type ids to be deferred until the first call to @ref update.
  526. struct deferred_static_rtti : rtti {};
  527. #ifdef __MRDOCS__
  528. //! Blueprint for @ref error_handler metafunctions (exposition only).
  529. template<class Registry>
  530. struct ErrorHandlerFn {
  531. //! Called when an error is detected.
  532. //!
  533. //! `error` is a function, or a set of functions, that can be called
  534. //! with an instance of any subclass of `openmethod_error`.
  535. static auto error(const auto& error) -> void;
  536. };
  537. #endif
  538. //! Policy for error handling.
  539. //!
  540. //! A @e error_handler policy runs code before the library terminates the
  541. //! program due to an error. This can be useful for throwing, logging, cleanup,
  542. //! or other actions.
  543. //!
  544. //! @par Requirements
  545. //!
  546. //! Classes implementing this policy must:
  547. //! @li derive from `error_handler`.
  548. //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
  549. //! ErrorHandlerFn blueprint.
  550. struct error_handler {
  551. // Policy category.
  552. using category = error_handler;
  553. };
  554. #ifdef __MRDOCS__
  555. //! Blueprint for `vptr` metafunctions (exposition only).
  556. //!
  557. //! @tparam Registry The registry containing the policy.
  558. template<class Registry>
  559. struct VptrFn {
  560. //! Register the v-table pointers.
  561. //!
  562. //! Called by @ref registry::initialize to let the policy store the v-table
  563. //! pointer associated to each `type_id`.
  564. //!
  565. //! @tparam Context A class that conforms to the @ref InitializeContext
  566. //! blueprint.
  567. template<class Context>
  568. static auto initialize(const Context& ctx) -> void;
  569. //! Return a *reference* to a v-table pointer for an object.
  570. //!
  571. //! @tparam Class A registered class.
  572. //! @param arg A reference to a const object of type `Class`.
  573. //! @return A reference to a the v-table pointer for `Class`.
  574. template<class Class>
  575. static auto dynamic_vptr(const Class& arg) -> const vptr_type&;
  576. //! Release the resources allocated by `initialize`.
  577. //!
  578. //! This function is optional.
  579. //!
  580. //! @tparam Options... Zero or more option types, deduced from the
  581. //! function arguments.
  582. //! @param options A tuple of option objects.
  583. template<class... Options>
  584. static auto finalize(const std::tuple<Options...>& options) -> void;
  585. };
  586. #endif
  587. //! Policy for v-table pointer acquisition.
  588. //!
  589. //! @par Requirements
  590. //!
  591. //! Classes implementing this policy must:
  592. //! @li derive from `vptr`.
  593. //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
  594. //! VptrFn blueprint.
  595. struct vptr {
  596. // Policy category.
  597. using category = vptr;
  598. };
  599. //! Policy to add an indirection to pointers to v-tables.
  600. //!
  601. //! If this policy is present, constructs like @ref virtual_ptr, @ref
  602. //! inplace_vptr, @ref vptr_vector, etc use pointers to pointers to v-tables.
  603. //! These indirect pointers remain valid after a call to @ref initialize, after
  604. //! dynamically loading a library that adds classes, methods and overriders to
  605. //! the registry.
  606. struct indirect_vptr final {
  607. // Policy category.
  608. using category = indirect_vptr;
  609. template<class Registry>
  610. struct fn {};
  611. };
  612. #ifdef __MRDOCS__
  613. //! Blueprint for @ref type_hash metafunctions (exposition only).
  614. //!
  615. //! @tparam Registry The registry containing the policy.
  616. template<class Registry>
  617. struct TypeHashFn {
  618. //! Initialize the hash table.
  619. //!
  620. //! @tparam Context A class that conforms to the @ref InitializeContext
  621. //! blueprint.
  622. //! @return A pair containing the minimum and maximum hash values.
  623. template<class Context>
  624. static auto
  625. initialize(const Context& ctx) -> std::pair<std::size_t, std::size_t>;
  626. //! Hash a `type_id`.
  627. //!
  628. //! @param type A @ref type_id.
  629. //! @return A hash value for the given `type_id`.
  630. static auto hash(type_id type) -> std::size_t;
  631. //! Release the resources allocated by `initialize`.
  632. //!
  633. //! This function is optional.
  634. //!
  635. //! @tparam Options... Zero or more option types, deduced from the
  636. //! function arguments.
  637. //! @param options A tuple of option objects.
  638. template<class... Options>
  639. static auto finalize(const std::tuple<Options...>& options) -> void;
  640. };
  641. #endif
  642. //! Policy for hashing type ids.
  643. //!
  644. //! @par Requirements
  645. //!
  646. //! Classes implementing this policy must:
  647. //! @li derive from `rtti`.
  648. //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
  649. //! TypeHashFn blueprint.
  650. struct type_hash {
  651. // Policy category.
  652. using category = type_hash;
  653. };
  654. #ifdef __MRDOCS__
  655. //! Blueprint for @ref output metafunctions (exposition only).
  656. //!
  657. //! @tparam Registry The registry containing the policy.
  658. template<class Registry>
  659. struct OutputFn {
  660. //! A @ref LightweightOutputStream.
  661. inline static LightweightOutputStream os;
  662. };
  663. #endif
  664. //! Policy for writing diagnostics and trace.
  665. //!
  666. //! If an `output` policy is present, the default error handler uses it to write
  667. //! error messages to its output stream. @ref registry::initialize can also use
  668. //! it to write trace messages.
  669. //!
  670. //! @par Requirements
  671. //!
  672. //! Classes implementing this policy must:
  673. //! @li derive from `output`.
  674. //! @li provide a `fn<Registry>` metafunction that conforms to the @ref
  675. //! OutputFn blueprint.
  676. struct output {
  677. // Policy category.
  678. using category = output;
  679. };
  680. //! Policy for post-initialize runtime checks.
  681. //!
  682. //! If this policy is present, performs the following checks:
  683. //! @li Classes of virtual arguments have been registered.
  684. //! @li Dynamic and static types match in "final" constructs (@ref
  685. //! final_virtual_ptr and related functions).
  686. struct runtime_checks final {
  687. // Policy category.
  688. using category = runtime_checks;
  689. template<class Registry>
  690. struct fn {};
  691. };
  692. } // namespace policies
  693. namespace detail {
  694. struct registry_base {};
  695. template<typename T>
  696. constexpr bool is_registry = std::is_base_of_v<registry_base, T>;
  697. template<typename T>
  698. constexpr bool is_not_void = !std::is_same_v<T, void>;
  699. template<
  700. class Registry, class Index,
  701. class Size = mp11::mp_size<typename Registry::policy_list>>
  702. struct get_policy_aux {
  703. using type = typename mp11::mp_at<
  704. typename Registry::policy_list, Index>::template fn<Registry>;
  705. };
  706. template<class Registry, class Size>
  707. struct get_policy_aux<Registry, Size, Size> {
  708. using type = void;
  709. };
  710. using class_catalog = detail::static_list<detail::class_info>;
  711. using method_catalog = detail::static_list<detail::method_info>;
  712. template<class Policies, class...>
  713. struct with_aux;
  714. template<class Policies>
  715. struct with_aux<Policies> {
  716. using type = Policies;
  717. };
  718. template<class Policies, class Policy, class... MorePolicies>
  719. struct with_aux<Policies, Policy, MorePolicies...> {
  720. using replace = mp11::mp_replace_if_q<
  721. Policies,
  722. mp11::mp_bind_front_q<
  723. mp11::mp_quote_trait<std::is_base_of>, typename Policy::category>,
  724. Policy>;
  725. using replace_or_add = std::conditional_t<
  726. std::is_same_v<replace, Policies>, mp11::mp_push_back<Policies, Policy>,
  727. replace>;
  728. using type = typename with_aux<replace_or_add, MorePolicies...>::type;
  729. };
  730. template<class Policies, class...>
  731. struct without_aux;
  732. template<class Policies>
  733. struct without_aux<Policies> {
  734. using type = Policies;
  735. };
  736. template<class Policies, class Policy, class... MorePolicies>
  737. struct without_aux<Policies, Policy, MorePolicies...> {
  738. using type = typename without_aux<
  739. mp11::mp_remove_if_q<
  740. Policies,
  741. mp11::mp_bind_front_q<
  742. mp11::mp_quote_trait<std::is_base_of>,
  743. typename Policy::category>>,
  744. MorePolicies...>::type;
  745. };
  746. template<class...>
  747. struct use_class_aux;
  748. template<typename, class...>
  749. struct initialize_aux;
  750. } // namespace detail
  751. //! Methods, classes and policies.
  752. //!
  753. //! Methods exist in the context of a registry. Any class used as a method or
  754. //! overrider parameter, or in as a method call argument, must be registered
  755. //! with the same registry.
  756. //!
  757. //! Before calling a method, its registry must be initialized with the @ref
  758. //! initialize function. This is typically done at the beginning of `main`.
  759. //!
  760. //! Multiple registries can co-exist in the same program. They must be
  761. //! initialized individually. Classes referenced by methods in different
  762. //! registries must be registered with each registry.
  763. //!
  764. //! A registry also contains a set of @ref policies that control how certain
  765. //! operations are performed. For example, the `rtti` policy provides type
  766. //! information, implements dynamic casting, etc. It can be replaced to
  767. //! interface with custom RTII systems (like LLVM's).
  768. //!
  769. //! Policies are implemented as Boost.MP11 quoted metafunctions. A policy class
  770. //! must contain a `fn<Registry>` template that provides a set of static
  771. //! members, specific to the responsibility of the policy. Registries
  772. //! instantiate policies by passing themselves to the nested `fn` class
  773. //! templates.
  774. //!
  775. //! There are two reason for this design.
  776. //!
  777. //! Some policies are "stateful": they contain static _data_ members. Since
  778. //! several registries can co-exist in the same program, each stateful policy
  779. //! needs its own, separate set of static data members. For example, @ref
  780. //! vptr_vector, a "vptr" policy, contains a static vector of vptrs, which
  781. //! cannot be shared with other registries.
  782. //!
  783. //! Also, some policies need access to other policies in the same registry. They
  784. //! can be accessed via the `Registry` template parameter. For example, @ref
  785. //! vptr_vector hashes type_ids before using them as an indexes, if `Registry`
  786. //! cotains a `type_hash` policy. It performs out-of-bounds checks if `Registry`
  787. //! contains the `runtime_checks` policy. If an error is detected, it invokes
  788. //! the @ref error_handler policy if there is one.
  789. //!
  790. //! @tparam Policy The policies used in the registry.
  791. //!
  792. //! @par Requirements
  793. //!
  794. //! @li `Policy` must contain a `category` alias to its root base class. The
  795. //! registry may contain at most one policy per category.
  796. //!
  797. //! @li `Policy` must contain a `fn<Registry>` metafunction.
  798. //!
  799. //! @see @ref policies
  800. template<class... Policy>
  801. class registry : detail::registry_base {
  802. static detail::class_catalog classes;
  803. static detail::method_catalog methods;
  804. template<class...>
  805. friend struct detail::use_class_aux;
  806. template<typename Name, typename ReturnType, class Registry>
  807. friend class method;
  808. static std::vector<detail::word> dispatch_data;
  809. static bool initialized;
  810. public:
  811. //! The type of this registry.
  812. using registry_type = registry;
  813. template<class... Options>
  814. struct compiler;
  815. //! Check that the registry is initialized.
  816. //!
  817. //! Check if `initialize` has been called for this registry, and report an
  818. //! error if not.
  819. //!
  820. //! @par Errors
  821. //!
  822. //! @li @ref not_initialized: The registry is not initialized.
  823. static void require_initialized();
  824. template<class... Options>
  825. static void finalize(Options... opts);
  826. //! A pointer to the virtual table for a registered class.
  827. //!
  828. //! `static_vptr` is set by @ref registry::initialize to the address of the
  829. //! class' virtual table. It remains valid until the next call to
  830. //! `initialize` or `finalize`.
  831. //!
  832. //! @tparam Class A registered class.
  833. template<class Class>
  834. static vptr_type static_vptr;
  835. //! List of policies selected in a registry.
  836. //!
  837. //! `policy_list` is a Boost.Mp11 list containing the policies passed to the
  838. //! @ref registry clas template.
  839. //!
  840. //! @tparam Class A registered class.
  841. using policy_list = mp11::mp_list<Policy...>;
  842. //! Find a policy by category.
  843. //!
  844. //! `policy` searches for a policy that derives from the specified @ref
  845. //! Category. If none is found, it aliases to `void`. Otherwise, it aliases
  846. //! to the policy's `fn` metafunction, applied to the registry.
  847. //!
  848. //! @tparam A policy.
  849. template<class Category>
  850. using policy = typename detail::get_policy_aux<
  851. registry,
  852. mp11::mp_find_if_q<
  853. policy_list,
  854. mp11::mp_bind_front_q<
  855. mp11::mp_quote_trait<std::is_base_of>, Category>>>::type;
  856. //! Add or replace policies.
  857. //!
  858. //! `with` aliases to a registry with additional policies, overwriting any
  859. //! existing policies in the same category as the new ones.
  860. //!
  861. //! @tparam NewPolicies Models of @ref policies::Policy.
  862. template<class... NewPolicies>
  863. using with = boost::mp11::mp_apply<
  864. registry, typename detail::with_aux<policy_list, NewPolicies...>::type>;
  865. //! Remove policies.
  866. //!
  867. //! `without` aliases to a registry containing the same policies, except those
  868. //! that derive from `Categories`.
  869. //!
  870. //! @tparam Categories Models of @ref policies::PolicyCategory.
  871. template<class... Categories>
  872. using without = boost::mp11::mp_apply<
  873. registry,
  874. typename detail::without_aux<policy_list, Categories...>::type>;
  875. //! The registry's rtti policy.
  876. using rtti = policy<policies::rtti>;
  877. //! The registry's vptr policy if it contains one, or `void`.
  878. using vptr = policy<policies::vptr>;
  879. //! `true` if the registry has a vptr policy.
  880. static constexpr auto has_vptr = !std::is_same_v<vptr, void>;
  881. //! The registry's error_handler policy if it contains one, or `void`.
  882. using error_handler = policy<policies::error_handler>;
  883. //! `true` if the registry has an error_handler policy.
  884. static constexpr auto has_error_handler =
  885. !std::is_same_v<error_handler, void>;
  886. //! The registry's output policy if it contains one, or `void`.
  887. using output = policy<policies::output>;
  888. //! `true` if the registry has an output policy.
  889. static constexpr auto has_output = !std::is_same_v<output, void>;
  890. //! `true` if the registry has a deferred_static_rtti policy.
  891. static constexpr auto has_deferred_static_rtti =
  892. !std::is_same_v<policy<policies::deferred_static_rtti>, void>;
  893. //! `true` if the registry has a runtime_checks policy.
  894. static constexpr auto has_runtime_checks =
  895. !std::is_same_v<policy<policies::runtime_checks>, void>;
  896. //! `true` if the registry has an indirect_vptr policy.
  897. static constexpr auto has_indirect_vptr =
  898. !std::is_same_v<policy<policies::indirect_vptr>, void>;
  899. };
  900. template<class... Policies>
  901. detail::class_catalog registry<Policies...>::classes;
  902. template<class... Policies>
  903. detail::method_catalog registry<Policies...>::methods;
  904. template<class... Policies>
  905. std::vector<detail::word> registry<Policies...>::dispatch_data;
  906. template<class... Policies>
  907. bool registry<Policies...>::initialized;
  908. template<class... Policies>
  909. template<class Class>
  910. vptr_type registry<Policies...>::static_vptr;
  911. template<class... Policies>
  912. void registry<Policies...>::require_initialized() {
  913. if constexpr (registry::has_runtime_checks) {
  914. if (!initialized) {
  915. if constexpr (registry::has_error_handler) {
  916. error_handler::error(not_initialized());
  917. }
  918. abort();
  919. }
  920. }
  921. }
  922. template<class Registry, class Stream>
  923. auto missing_class::write(Stream& os) const {
  924. os << "unknown class ";
  925. Registry::rtti::type_name(type, os);
  926. }
  927. template<class Registry, class Stream>
  928. auto missing_base::write(Stream& os) const {
  929. os << "missing base ";
  930. Registry::rtti::type_name(base, os);
  931. os << " -<| ";
  932. Registry::rtti::type_name(derived, os);
  933. }
  934. template<class Registry, class Stream>
  935. auto final_error::write(Stream& os) const {
  936. os << "invalid call to final construct: static type = ";
  937. Registry::rtti::type_name(static_type, os);
  938. os << ", dynamic type = ";
  939. Registry::rtti::type_name(dynamic_type, os);
  940. }
  941. } // namespace boost::openmethod
  942. #ifdef _MSC_VER
  943. #pragma warning(pop)
  944. #endif
  945. #endif // BOOST_OPENMETHOD_REGISTRY_HPP