initialize.hpp 50 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684
  1. // Copyright (c) 2018-2025 Jean-Louis Leroy
  2. // Distributed under the Boost Software License, Version 1.0.
  3. // See accompanying file LICENSE_1_0.txt
  4. // or copy at http://www.boost.org/LICENSE_1_0.txt)
  5. #ifndef BOOST_OPENMETHOD_COMPILER_HPP
  6. #define BOOST_OPENMETHOD_COMPILER_HPP
  7. #include <boost/openmethod/core.hpp>
  8. #include <boost/openmethod/detail/ostdstream.hpp>
  9. #include <algorithm>
  10. #include <cstdint>
  11. #include <deque>
  12. #include <map>
  13. #include <memory>
  14. #include <numeric>
  15. #include <string>
  16. #include <unordered_map>
  17. #include <unordered_set>
  18. #include <utility>
  19. #include <vector>
  20. #include <boost/assert.hpp>
  21. #include <boost/dynamic_bitset.hpp>
  22. #ifdef _MSC_VER
  23. #pragma warning(push)
  24. #pragma warning(disable : 4456)
  25. #pragma warning(disable : 4458)
  26. #pragma warning(disable : 4702) // unreachable code
  27. #endif
  28. namespace boost::openmethod {
  29. namespace detail {
  30. template<class Reports, class Facets, typename = void>
  31. struct aggregate_reports;
  32. template<class... Reports, class Facet, class... MoreFacets>
  33. struct aggregate_reports<
  34. mp11::mp_list<Reports...>, mp11::mp_list<Facet, MoreFacets...>,
  35. std::void_t<typename Facet::report>> {
  36. using type = typename aggregate_reports<
  37. mp11::mp_list<Reports..., typename Facet::report>,
  38. mp11::mp_list<MoreFacets...>>::type;
  39. };
  40. template<class... Reports, class Facet, class... MoreFacets, typename Void>
  41. struct aggregate_reports<
  42. mp11::mp_list<Reports...>, mp11::mp_list<Facet, MoreFacets...>, Void> {
  43. using type = typename aggregate_reports<
  44. mp11::mp_list<Reports...>, mp11::mp_list<MoreFacets...>>::type;
  45. };
  46. template<class... Reports, typename Void>
  47. struct aggregate_reports<mp11::mp_list<Reports...>, mp11::mp_list<>, Void> {
  48. struct type : Reports... {};
  49. };
  50. inline void merge_into(boost::dynamic_bitset<>& a, boost::dynamic_bitset<>& b) {
  51. if (b.size() < a.size()) {
  52. b.resize(a.size());
  53. }
  54. for (std::size_t i = 0; i < a.size(); ++i) {
  55. if (a[i]) {
  56. b[i] = true;
  57. }
  58. }
  59. }
  60. inline void set_bit(boost::dynamic_bitset<>& mask, std::size_t bit) {
  61. if (bit >= mask.size()) {
  62. mask.resize(bit + 1);
  63. }
  64. mask[bit] = true;
  65. }
  66. struct generic_compiler {
  67. struct method;
  68. struct parameter {
  69. struct method* method;
  70. std::size_t param;
  71. };
  72. struct vtbl_entry {
  73. std::size_t method_index, vp_index, group_index;
  74. };
  75. struct class_ {
  76. bool is_abstract = false;
  77. std::vector<type_id> type_ids;
  78. std::vector<class_*> transitive_bases;
  79. std::vector<class_*> direct_bases;
  80. std::vector<class_*> direct_derived;
  81. std::unordered_set<class_*> transitive_derived;
  82. std::vector<parameter> used_by_vp;
  83. boost::dynamic_bitset<> used_slots;
  84. boost::dynamic_bitset<> reserved_slots;
  85. std::size_t first_slot = 0;
  86. std::size_t mark = 0; // temporary mark to detect cycles
  87. std::vector<vtbl_entry> vtbl;
  88. vptr_type* static_vptr;
  89. auto is_base_of(class_* other) const -> bool {
  90. return transitive_derived.find(other) != transitive_derived.end();
  91. }
  92. auto vptr() const -> const vptr_type& {
  93. return *static_vptr;
  94. }
  95. auto type_id_begin() const {
  96. return type_ids.begin();
  97. }
  98. auto type_id_end() const {
  99. return type_ids.end();
  100. }
  101. };
  102. struct overrider {
  103. detail::overrider_info* info = nullptr;
  104. overrider* next = nullptr;
  105. std::vector<class_*> vp;
  106. class_* covariant_return_type = nullptr;
  107. void (*pf)();
  108. std::size_t method_index, spec_index;
  109. };
  110. using bitvec = boost::dynamic_bitset<>;
  111. struct group {
  112. std::vector<class_*> classes;
  113. bool has_concrete_classes{false};
  114. };
  115. using group_map = std::map<bitvec, group>;
  116. struct method_report {
  117. std::size_t cells = 0;
  118. std::size_t not_implemented = 0;
  119. std::size_t ambiguous = 0;
  120. };
  121. struct report : method_report {};
  122. static void accumulate(const method_report& partial, report& total);
  123. struct method {
  124. detail::method_info* info;
  125. std::vector<class_*> vp;
  126. class_* covariant_return_type = nullptr;
  127. std::vector<overrider> overriders;
  128. std::vector<std::size_t> slots;
  129. std::vector<std::size_t> strides;
  130. std::vector<const overrider*> dispatch_table;
  131. // following two are dummies, when converting to a function pointer, we will
  132. // get the corresponding pointer from method_info
  133. overrider not_implemented;
  134. overrider ambiguous;
  135. vptr_type gv_dispatch_table = nullptr;
  136. auto arity() const {
  137. return vp.size();
  138. }
  139. method_report report;
  140. };
  141. const method* operator[](const detail::method_info& info) const {
  142. auto iter = std::find_if(
  143. methods.begin(), methods.end(),
  144. [&info](const method& m) { return m.info == &info; });
  145. if (iter != methods.end()) {
  146. return &*iter;
  147. }
  148. return nullptr;
  149. }
  150. std::deque<class_> classes;
  151. auto classes_begin() const {
  152. return classes.begin();
  153. }
  154. auto classes_end() const {
  155. return classes.end();
  156. }
  157. std::vector<method> methods;
  158. std::size_t class_mark = 0;
  159. bool compilation_done = false;
  160. };
  161. template<class Compiler>
  162. struct trace_stream {
  163. bool on = false;
  164. std::size_t indentation_level{0};
  165. auto operator++() -> trace_stream& {
  166. if constexpr (Compiler::has_trace) {
  167. if (on) {
  168. for (std::size_t i = 0; i < indentation_level; ++i) {
  169. Compiler::Registry::output::os << " ";
  170. }
  171. }
  172. }
  173. return *this;
  174. }
  175. struct indent {
  176. trace_stream& trace;
  177. int by;
  178. explicit indent(trace_stream& trace, int by = 2)
  179. : trace(trace), by(by) {
  180. trace.indentation_level += by;
  181. }
  182. ~indent() {
  183. trace.indentation_level -= by;
  184. }
  185. };
  186. };
  187. struct rflush {
  188. std::size_t width;
  189. std::size_t value;
  190. explicit rflush(std::size_t width, std::size_t value)
  191. : width(width), value(value) {
  192. }
  193. };
  194. struct type_name {
  195. type_name(type_id type) : type(type) {
  196. }
  197. type_id type;
  198. };
  199. template<class Compiler>
  200. auto operator<<(trace_stream<Compiler>& tr, const generic_compiler::class_& cls)
  201. -> trace_stream<Compiler>& {
  202. if constexpr (Compiler::has_trace) {
  203. tr << type_name(cls.type_ids[0]);
  204. }
  205. return tr;
  206. }
  207. template<class Compiler, template<typename...> class Container, typename... T>
  208. auto operator<<(
  209. trace_stream<Compiler>& tr,
  210. Container<generic_compiler::class_*, T...>& classes)
  211. -> trace_stream<Compiler>& {
  212. if constexpr (Compiler::has_trace) {
  213. tr << "(";
  214. const char* sep = "";
  215. for (auto cls : classes) {
  216. tr << sep << *cls;
  217. sep = ", ";
  218. }
  219. tr << ")";
  220. }
  221. return tr;
  222. }
  223. struct spec_name {
  224. spec_name(
  225. const detail::generic_compiler::method& method,
  226. const detail::generic_compiler::overrider* def)
  227. : method(method), def(def) {
  228. }
  229. const detail::generic_compiler::method& method;
  230. const detail::generic_compiler::overrider* def;
  231. };
  232. template<class Compiler>
  233. auto operator<<(trace_stream<Compiler>& tr, const spec_name& sn)
  234. -> trace_stream<Compiler>& {
  235. if (sn.def == &sn.method.not_implemented) {
  236. tr << "not implemented";
  237. } else if (sn.def == &sn.method.ambiguous) {
  238. tr << "ambiguous";
  239. } else {
  240. tr << type_name(sn.def->info->type);
  241. }
  242. return tr;
  243. }
  244. template<typename Iterator>
  245. struct range;
  246. template<class Compiler, typename T, typename F>
  247. auto write_range(trace_stream<Compiler>& tr, range<T> range, F fn) -> auto& {
  248. if constexpr (Compiler::has_trace) {
  249. if (tr.on) {
  250. tr << "(";
  251. const char* sep = "";
  252. for (auto value : range) {
  253. tr << sep << fn(value);
  254. sep = ", ";
  255. }
  256. tr << ")";
  257. }
  258. }
  259. return tr;
  260. }
  261. template<class Compiler, typename T>
  262. auto operator<<(trace_stream<Compiler>& tr, const T& value) -> auto& {
  263. if constexpr (Compiler::has_trace) {
  264. if (tr.on) {
  265. Compiler::Registry::output::os << value;
  266. }
  267. }
  268. return tr;
  269. }
  270. template<class Compiler>
  271. auto operator<<(trace_stream<Compiler>& tr, const rflush& rf) -> auto& {
  272. if constexpr (Compiler::has_trace) {
  273. if (tr.on) {
  274. std::size_t digits = 1;
  275. auto tmp = rf.value / 10;
  276. while (tmp) {
  277. ++digits;
  278. tmp /= 10;
  279. }
  280. while (digits < rf.width) {
  281. tr << " ";
  282. ++digits;
  283. }
  284. tr << rf.value;
  285. }
  286. }
  287. return tr;
  288. }
  289. template<class Compiler>
  290. auto operator<<(trace_stream<Compiler>& tr, const boost::dynamic_bitset<>& bits)
  291. -> auto& {
  292. if constexpr (Compiler::has_trace) {
  293. if (tr.on) {
  294. auto i = bits.size();
  295. while (i != 0) {
  296. --i;
  297. Compiler::Registry::output::os << bits[i];
  298. }
  299. }
  300. }
  301. return tr;
  302. }
  303. template<class Compiler>
  304. auto operator<<(trace_stream<Compiler>& tr, const range<type_id*>& tips)
  305. -> auto& {
  306. return write_range(tr, tips, [](auto tip) { return type_name(tip); });
  307. }
  308. template<class Compiler, typename T>
  309. auto operator<<(trace_stream<Compiler>& tr, const range<T>& range) -> auto& {
  310. return write_range(tr, range, [](auto value) { return value; });
  311. }
  312. template<class Compiler>
  313. auto operator<<(trace_stream<Compiler>& tr, const type_name& manip) -> auto& {
  314. if constexpr (Compiler::has_trace) {
  315. Compiler::Registry::rtti::type_name(manip.type, tr);
  316. }
  317. return tr;
  318. }
  319. } // namespace detail
  320. // Definition of the nested template struct outside the registry class
  321. template<class... Policies>
  322. template<class... Options>
  323. struct registry<Policies...>::compiler : detail::generic_compiler {
  324. using type_index_type = decltype(rtti::type_index(0));
  325. typename detail::aggregate_reports<mp11::mp_list<report>, policy_list>::type
  326. report;
  327. std::unordered_map<type_index_type, class_*> class_map;
  328. using Registry = registry;
  329. compiler(Options... opts);
  330. auto compile();
  331. void initialize();
  332. void install_global_tables();
  333. void augment_classes();
  334. void collect_transitive_bases(class_* cls, class_* base);
  335. void calculate_transitive_derived(class_& cls);
  336. void augment_methods();
  337. void assign_slots();
  338. void assign_tree_slots(class_& cls, std::size_t base_slot);
  339. void assign_lattice_slots(class_& cls);
  340. void build_dispatch_tables();
  341. void build_dispatch_table(
  342. method& m, std::size_t dim,
  343. std::vector<group_map>::const_iterator group, const bitvec& candidates,
  344. bool concrete);
  345. void write_global_data();
  346. void print(const method_report& report) const;
  347. static void select_dominant_overriders(
  348. std::vector<overrider*>& dominants, std::size_t& pick,
  349. std::size_t& remaining);
  350. static auto
  351. is_more_specific(const overrider* a, const overrider* b) -> bool;
  352. static auto is_base(const overrider* a, const overrider* b) -> bool;
  353. std::tuple<Options...> options;
  354. template<class Option>
  355. static constexpr bool has_option =
  356. mp11::mp_contains<mp11::mp_list<Options...>, Option>::value;
  357. static constexpr bool has_trace = has_option<trace>;
  358. static constexpr bool has_n2216 = has_option<n2216>;
  359. mutable detail::trace_stream<compiler> tr;
  360. using indent = typename detail::trace_stream<compiler>::indent;
  361. };
  362. template<class... Policies>
  363. template<class... Options>
  364. void registry<Policies...>::compiler<Options...>::install_global_tables() {
  365. if (!compilation_done) {
  366. abort();
  367. }
  368. write_global_data();
  369. print(report);
  370. ++tr << "Finished\n";
  371. }
  372. template<class... Policies>
  373. template<class... Options>
  374. auto registry<Policies...>::compiler<Options...>::compile() {
  375. augment_classes();
  376. augment_methods();
  377. assign_slots();
  378. build_dispatch_tables();
  379. compilation_done = true;
  380. return report;
  381. }
  382. template<class... Policies>
  383. template<class... Options>
  384. void registry<Policies...>::compiler<Options...>::initialize() {
  385. compile();
  386. install_global_tables();
  387. registry<Policies...>::initialized = true;
  388. }
  389. #ifdef _MSC_VER
  390. namespace detail {
  391. template<bool HasTrace, typename T>
  392. struct msvc_tuple_get;
  393. template<typename T>
  394. struct msvc_tuple_get<true, T> {
  395. template<class Tuple>
  396. static decltype(auto) fn(const Tuple& t) {
  397. return std::get<T>(t);
  398. }
  399. };
  400. template<typename T>
  401. struct msvc_tuple_get<false, T> {
  402. template<class Tuple>
  403. static decltype(auto) fn(const Tuple&) {
  404. return T();
  405. }
  406. };
  407. } // namespace detail
  408. #endif
  409. template<class... Policies>
  410. template<class... Options>
  411. registry<Policies...>::compiler<Options...>::compiler(Options... opts)
  412. : options(opts...) {
  413. if constexpr (has_trace) {
  414. #ifdef _MSC_VER
  415. tr.on = detail::msvc_tuple_get<has_trace, trace>::fn(options).on;
  416. #else
  417. // Even with the constexpr has_trace guard, msvc errors on this.
  418. tr.on = std::get<trace>(options).on;
  419. #endif
  420. }
  421. }
  422. template<class... Policies>
  423. template<class... Options>
  424. void registry<Policies...>::compiler<Options...>::collect_transitive_bases(
  425. class_* cls, class_* base) {
  426. if (base->mark == class_mark) {
  427. return;
  428. }
  429. cls->transitive_bases.push_back(base);
  430. base->mark = class_mark;
  431. for (auto base_base : base->transitive_bases) {
  432. collect_transitive_bases(cls, base_base);
  433. }
  434. }
  435. template<class... Policies>
  436. template<class... Options>
  437. void registry<Policies...>::compiler<Options...>::augment_classes() {
  438. using namespace detail;
  439. // scope
  440. {
  441. ++tr << "Static class info:\n";
  442. // The standard does not guarantee that there is exactly one
  443. // type_info object per class. However, it guarantees that the
  444. // type_index for a class has a unique value.
  445. for (auto& cr : registry::classes) {
  446. if constexpr (has_deferred_static_rtti) {
  447. static_cast<deferred_class_info&>(cr).resolve_type_ids();
  448. }
  449. {
  450. indent _(tr);
  451. ++tr << type_name(cr.type) << ": "
  452. << range{cr.first_base, cr.last_base} << "\n";
  453. }
  454. auto& rtc = class_map[rtti::type_index(cr.type)];
  455. if (rtc == nullptr) {
  456. rtc = &classes.emplace_back();
  457. rtc->is_abstract = cr.is_abstract;
  458. rtc->static_vptr = cr.static_vptr;
  459. }
  460. if (std::find(
  461. rtc->type_ids.begin(), rtc->type_ids.end(), cr.type) ==
  462. rtc->type_ids.end()) {
  463. rtc->type_ids.push_back(cr.type);
  464. }
  465. }
  466. }
  467. // All known classes now have exactly one associated class_* in the
  468. // map. Collect the bases.
  469. for (auto& cr : registry::classes) {
  470. auto rtc = class_map[rtti::type_index(cr.type)];
  471. for (auto& base : range{cr.first_base, cr.last_base}) {
  472. auto rtb = class_map[rtti::type_index(base)];
  473. if (!rtb) {
  474. missing_class error;
  475. error.type = base;
  476. if constexpr (has_error_handler) {
  477. error_handler::error(error);
  478. }
  479. abort();
  480. }
  481. if (rtc != rtb) {
  482. // At compile time we collected the class as its own
  483. // improper base, as per std::is_base_of. Eliminate that.
  484. ++class_mark;
  485. collect_transitive_bases(rtc, rtb);
  486. }
  487. }
  488. }
  489. // At this point bases may contain duplicates, and also indirect
  490. // bases. Clean that up.
  491. std::size_t mark = ++class_mark;
  492. for (auto& rtc : classes) {
  493. decltype(rtc.transitive_bases) bases;
  494. mark = ++class_mark;
  495. for (auto rtb : rtc.transitive_bases) {
  496. if (rtb->mark != mark) {
  497. bases.push_back(rtb);
  498. rtb->mark = mark;
  499. }
  500. }
  501. rtc.transitive_bases.swap(bases);
  502. }
  503. for (auto& rtc : classes) {
  504. // Sort base classes by number of transitive bases. This ensures that a
  505. // base class is never preceded by one if its own base classes.
  506. std::sort(
  507. rtc.transitive_bases.begin(), rtc.transitive_bases.end(),
  508. [](auto a, auto b) {
  509. return a->transitive_bases.size() > b->transitive_bases.size();
  510. });
  511. mark = ++class_mark;
  512. // Collect the direct base classes. The first base is certainly a
  513. // direct one. Remove *its* bases from the candidates, by marking
  514. // them. Continue with the next base that is not marked. It is the
  515. // next direct base. And so on...
  516. for (auto rtb : rtc.transitive_bases) {
  517. if (rtb->mark == mark) {
  518. continue;
  519. }
  520. rtc.direct_bases.push_back(rtb);
  521. for (auto rtbb : rtb->transitive_bases) {
  522. rtbb->mark = mark;
  523. }
  524. }
  525. }
  526. for (auto& rtc : classes) {
  527. for (auto rtb : rtc.direct_bases) {
  528. rtb->direct_derived.push_back(&rtc);
  529. }
  530. }
  531. for (auto& rtc : classes) {
  532. calculate_transitive_derived(rtc);
  533. }
  534. if constexpr (has_trace) {
  535. ++tr << "Inheritance lattice:\n";
  536. for (auto& rtc : classes) {
  537. indent _2(tr);
  538. ++tr << rtc << "\n";
  539. {
  540. indent _3(tr);
  541. ++tr << "bases: " << rtc.direct_bases << "\n";
  542. ++tr << "derived: " << rtc.direct_derived << "\n";
  543. ++tr << "covariant: " << rtc.transitive_derived << "\n";
  544. }
  545. }
  546. }
  547. }
  548. template<class... Policies>
  549. template<class... Options>
  550. void registry<Policies...>::compiler<Options...>::calculate_transitive_derived(
  551. class_& cls) {
  552. if (!cls.transitive_derived.empty()) {
  553. return;
  554. }
  555. cls.transitive_derived.insert(&cls);
  556. for (auto derived : cls.direct_derived) {
  557. if (derived->transitive_derived.empty()) {
  558. calculate_transitive_derived(*derived);
  559. }
  560. std::copy(
  561. derived->transitive_derived.begin(),
  562. derived->transitive_derived.end(),
  563. std::inserter(
  564. cls.transitive_derived, cls.transitive_derived.end()));
  565. }
  566. }
  567. template<class... Policies>
  568. template<class... Options>
  569. void registry<Policies...>::compiler<Options...>::augment_methods() {
  570. using namespace policies;
  571. using namespace detail;
  572. methods.resize(registry::methods.size());
  573. ++tr << "Methods:\n";
  574. indent _(tr);
  575. auto meth_iter = methods.begin();
  576. for (auto& meth_info : registry::methods) {
  577. if constexpr (has_deferred_static_rtti) {
  578. static_cast<deferred_method_info&>(meth_info).resolve_type_ids();
  579. }
  580. ++tr << type_name(meth_info.method_type_id) << " "
  581. << range{meth_info.vp_begin, meth_info.vp_end} << "\n";
  582. indent _(tr);
  583. meth_iter->info = &meth_info;
  584. meth_iter->vp.reserve(meth_info.arity());
  585. meth_iter->slots.resize(meth_info.arity());
  586. {
  587. std::size_t param_index = 0;
  588. for (auto ti : range{meth_info.vp_begin, meth_info.vp_end}) {
  589. auto class_ = class_map[rtti::type_index(ti)];
  590. if (!class_) {
  591. ++tr << "unknown class " << ti << "(" << type_name(ti)
  592. << ") for parameter #" << (param_index + 1) << "\n";
  593. missing_class error;
  594. error.type = ti;
  595. if constexpr (has_error_handler) {
  596. error_handler::error(error);
  597. }
  598. abort();
  599. }
  600. meth_iter->vp.push_back(class_);
  601. }
  602. }
  603. if (rtti::type_index(meth_info.return_type_id) !=
  604. rtti::type_index(rtti::template static_type<void>())) {
  605. auto covariant_return_iter =
  606. class_map.find(rtti::type_index(meth_info.return_type_id));
  607. if (covariant_return_iter != class_map.end()) {
  608. meth_iter->covariant_return_type =
  609. covariant_return_iter->second;
  610. }
  611. }
  612. // initialize the function pointer in the synthetic not_implemented
  613. // overrider
  614. const auto method_index = meth_iter - methods.begin();
  615. auto spec_size = meth_info.overriders.size();
  616. meth_iter->not_implemented.pf = meth_iter->info->not_implemented;
  617. meth_iter->not_implemented.method_index = method_index;
  618. meth_iter->not_implemented.spec_index = spec_size;
  619. meth_iter->ambiguous.pf = meth_iter->info->ambiguous;
  620. meth_iter->ambiguous.method_index = method_index;
  621. meth_iter->ambiguous.spec_index = spec_size + 1;
  622. meth_iter->overriders.resize(spec_size);
  623. auto spec_iter = meth_iter->overriders.begin();
  624. for (auto& overrider_info : meth_info.overriders) {
  625. if constexpr (has_deferred_static_rtti) {
  626. static_cast<deferred_overrider_info&>(overrider_info)
  627. .resolve_type_ids();
  628. }
  629. spec_iter->method_index = method_index;
  630. spec_iter->spec_index = spec_iter - meth_iter->overriders.begin();
  631. ++tr << type_name(overrider_info.type) << " (" << overrider_info.pf
  632. << ")\n";
  633. spec_iter->info = &overrider_info;
  634. spec_iter->vp.reserve(meth_info.arity());
  635. std::size_t param_index = 0;
  636. for (auto type :
  637. range{overrider_info.vp_begin, overrider_info.vp_end}) {
  638. indent _(tr);
  639. auto class_ = class_map[rtti::type_index(type)];
  640. if (!class_) {
  641. ++tr << "unknown class error for *virtual* parameter #"
  642. << (param_index + 1) << "\n";
  643. missing_class error;
  644. error.type = type;
  645. if constexpr (has_error_handler) {
  646. error_handler::error(error);
  647. }
  648. abort();
  649. }
  650. spec_iter->pf = spec_iter->info->pf;
  651. spec_iter->vp.push_back(class_);
  652. }
  653. if (meth_iter->covariant_return_type) {
  654. auto covariant_return_iter = class_map.find(
  655. rtti::type_index(overrider_info.return_type));
  656. if (covariant_return_iter != class_map.end()) {
  657. spec_iter->covariant_return_type =
  658. covariant_return_iter->second;
  659. } else {
  660. missing_class error;
  661. error.type = overrider_info.return_type;
  662. if constexpr (has_error_handler) {
  663. error_handler::error(error);
  664. }
  665. abort();
  666. }
  667. }
  668. ++spec_iter;
  669. }
  670. ++meth_iter;
  671. }
  672. for (auto& method : methods) {
  673. std::size_t param_index = 0;
  674. for (auto vp : method.vp) {
  675. for (auto& overrider : method.overriders) {
  676. if (overrider.vp[param_index] == vp) {
  677. continue;
  678. }
  679. if (!vp->is_base_of(overrider.vp[param_index])) {
  680. missing_base error;
  681. error.base = overrider.vp[param_index]->type_ids[0];
  682. error.derived = vp->type_ids[0];
  683. if constexpr (has_error_handler) {
  684. error_handler::error(error);
  685. }
  686. abort();
  687. }
  688. }
  689. vp->used_by_vp.push_back({&method, param_index++});
  690. }
  691. }
  692. }
  693. template<class... Policies>
  694. template<class... Options>
  695. void registry<Policies...>::compiler<Options...>::assign_slots() {
  696. ++tr << "Allocating slots...\n";
  697. {
  698. indent _(tr);
  699. ++class_mark;
  700. for (auto& cls : classes) {
  701. if (cls.direct_bases.size() == 0) {
  702. if (std::find_if(
  703. cls.transitive_derived.begin(),
  704. cls.transitive_derived.end(), [](auto cls) {
  705. return cls->direct_bases.size() > 1;
  706. }) == cls.transitive_derived.end()) {
  707. indent _(tr);
  708. assign_tree_slots(cls, 0);
  709. } else {
  710. assign_lattice_slots(cls);
  711. }
  712. }
  713. }
  714. }
  715. ++tr << "Allocating MI v-tables...\n";
  716. {
  717. indent _(tr);
  718. for (auto& cls : classes) {
  719. if (cls.used_slots.empty()) {
  720. // not involved in multiple inheritance
  721. continue;
  722. }
  723. auto first_slot = cls.used_slots.find_first();
  724. cls.first_slot =
  725. first_slot == boost::dynamic_bitset<>::npos ? 0u : first_slot;
  726. cls.vtbl.resize(cls.used_slots.size() - cls.first_slot);
  727. ++tr << cls << " vtbl: " << cls.first_slot << "-"
  728. << cls.used_slots.size() << " slots " << cls.used_slots
  729. << "\n";
  730. }
  731. }
  732. }
  733. template<class... Policies>
  734. template<class... Options>
  735. void registry<Policies...>::compiler<Options...>::assign_tree_slots(
  736. class_& cls, std::size_t base_slot) {
  737. auto next_slot = base_slot;
  738. using namespace detail;
  739. for (const auto& mp : cls.used_by_vp) {
  740. ++tr << " in " << cls << " for "
  741. << type_name(mp.method->info->method_type_id) << " parameter "
  742. << mp.param << ": " << next_slot << "\n";
  743. mp.method->slots[mp.param] = next_slot++;
  744. }
  745. cls.first_slot = 0;
  746. cls.vtbl.resize(next_slot);
  747. for (auto pd : cls.direct_derived) {
  748. assign_tree_slots(*pd, next_slot);
  749. }
  750. }
  751. template<class... Policies>
  752. template<class... Options>
  753. void registry<Policies...>::compiler<Options...>::assign_lattice_slots(
  754. class_& cls) {
  755. using namespace detail;
  756. if (cls.mark == class_mark) {
  757. return;
  758. }
  759. cls.mark = class_mark;
  760. if (!cls.used_by_vp.empty()) {
  761. for (const auto& mp : cls.used_by_vp) {
  762. ++tr << " in " << cls << " for "
  763. << type_name(mp.method->info->method_type_id) << " parameter "
  764. << mp.param << "\n";
  765. indent _(tr);
  766. ++tr << "reserved slots: " << cls.reserved_slots
  767. << " used slots: " << cls.used_slots << "\n";
  768. auto unavailable_slots = cls.used_slots;
  769. detail::merge_into(cls.reserved_slots, unavailable_slots);
  770. ++tr << "unavailable slots: " << unavailable_slots << "\n";
  771. std::size_t slot = 0;
  772. for (; slot < unavailable_slots.size(); ++slot) {
  773. if (!unavailable_slots[slot]) {
  774. break;
  775. }
  776. }
  777. ++tr << "first available slot: " << slot << "\n";
  778. mp.method->slots[mp.param] = slot;
  779. detail::set_bit(cls.used_slots, slot);
  780. detail::set_bit(cls.reserved_slots, slot);
  781. {
  782. ++tr << "reserve slots " << cls.used_slots << " in:\n";
  783. indent _(tr);
  784. for (auto base : cls.transitive_bases) {
  785. ++tr << *base << "\n";
  786. detail::merge_into(cls.used_slots, base->reserved_slots);
  787. }
  788. }
  789. {
  790. ++tr << "assign slots " << cls.used_slots << " in:\n";
  791. indent _(tr);
  792. for (auto covariant : cls.transitive_derived) {
  793. if (&cls != covariant) {
  794. ++tr << *covariant << "\n";
  795. detail::merge_into(
  796. cls.used_slots, covariant->used_slots);
  797. for (auto base : covariant->transitive_bases) {
  798. ++tr << *base << "\n";
  799. detail::merge_into(
  800. cls.used_slots, base->reserved_slots);
  801. }
  802. }
  803. }
  804. }
  805. }
  806. }
  807. for (auto pd : cls.direct_derived) {
  808. assign_lattice_slots(*pd);
  809. }
  810. }
  811. template<class... Policies>
  812. template<class... Options>
  813. void registry<Policies...>::compiler<Options...>::build_dispatch_tables() {
  814. using namespace detail;
  815. for (auto& m : methods) {
  816. ++tr << "Building dispatch table for "
  817. << type_name(m.info->method_type_id) << "\n";
  818. indent _(tr);
  819. auto dims = m.arity();
  820. std::vector<group_map> groups;
  821. groups.resize(dims);
  822. {
  823. std::size_t dim = 0;
  824. for (auto vp : m.vp) {
  825. auto& dim_group = groups[dim];
  826. ++tr << "make groups for param #" << dim << ", class " << *vp
  827. << "\n";
  828. indent _(tr);
  829. for (auto covariant_class : vp->transitive_derived) {
  830. ++tr << "overriders applicable to " << *covariant_class
  831. << "\n";
  832. bitvec mask;
  833. mask.resize(m.overriders.size());
  834. std::size_t group_index = 0;
  835. indent _2(tr);
  836. for (auto& spec : m.overriders) {
  837. if (spec.vp[dim]->transitive_derived.find(
  838. covariant_class) !=
  839. spec.vp[dim]->transitive_derived.end()) {
  840. ++tr << type_name(spec.info->type) << "\n";
  841. mask[group_index] = 1;
  842. }
  843. ++group_index;
  844. }
  845. auto& group = dim_group[mask];
  846. group.classes.push_back(covariant_class);
  847. group.has_concrete_classes = group.has_concrete_classes ||
  848. !covariant_class->is_abstract;
  849. ++tr << "-> mask: " << mask << "\n";
  850. }
  851. ++dim;
  852. }
  853. }
  854. {
  855. std::size_t stride = 1;
  856. m.strides.reserve(dims - 1);
  857. for (std::size_t dim = 1; dim < m.arity(); ++dim) {
  858. stride *= groups[dim - 1].size();
  859. ++tr << " stride for dim " << dim << " = " << stride << "\n";
  860. m.strides.push_back(stride);
  861. }
  862. }
  863. for (std::size_t dim = 0; dim < m.arity(); ++dim) {
  864. indent _(tr);
  865. std::size_t group_num = 0;
  866. for (auto& [mask, group] : groups[dim]) {
  867. ++tr << "groups for dim " << dim << ":\n";
  868. indent _(tr);
  869. ++tr << group_num << " mask " << mask << ":\n";
  870. for (auto cls : group.classes) {
  871. indent _(tr);
  872. ++tr << type_name(cls->type_ids[0]) << "\n";
  873. auto& entry = cls->vtbl[m.slots[dim] - cls->first_slot];
  874. entry.method_index = &m - &methods[0];
  875. entry.vp_index = dim;
  876. entry.group_index = group_num;
  877. }
  878. ++group_num;
  879. }
  880. }
  881. {
  882. ++tr << "building dispatch table\n";
  883. bitvec all(m.overriders.size());
  884. all = ~all;
  885. build_dispatch_table(m, dims - 1, groups.end() - 1, all, true);
  886. if (m.arity() > 1) {
  887. indent _(tr);
  888. m.report.cells = 1;
  889. ++tr << "dispatch table rank: ";
  890. const char* prefix = "";
  891. for (const auto& dim_groups : groups) {
  892. m.report.cells *= dim_groups.size();
  893. tr << prefix << dim_groups.size();
  894. prefix = " x ";
  895. }
  896. prefix = ", concrete only: ";
  897. for (const auto& dim_groups : groups) {
  898. auto cells = std::count_if(
  899. dim_groups.begin(), dim_groups.end(),
  900. [](const auto& group) {
  901. return group.second.has_concrete_classes;
  902. });
  903. tr << prefix << cells;
  904. prefix = " x ";
  905. }
  906. tr << "\n";
  907. }
  908. print(m.report);
  909. accumulate(m.report, report);
  910. }
  911. }
  912. }
  913. template<class... Policies>
  914. template<class... Options>
  915. void registry<Policies...>::compiler<Options...>::build_dispatch_table(
  916. method& m, std::size_t dim,
  917. std::vector<group_map>::const_iterator group_iter, const bitvec& candidates,
  918. bool concrete) {
  919. using namespace detail;
  920. indent _(tr);
  921. std::size_t group_index = 0;
  922. for (const auto& [group_mask, group] : *group_iter) {
  923. auto mask = candidates & group_mask;
  924. if constexpr (has_trace) {
  925. ++tr << "group " << dim << "/" << group_index << " mask " << mask
  926. << "\n";
  927. indent _(tr);
  928. for (auto cls : range{group.classes.begin(), group.classes.end()}) {
  929. ++tr << type_name(cls->type_ids[0]) << "\n";
  930. }
  931. }
  932. if (dim == 0) {
  933. std::vector<overrider*> overriders;
  934. std::size_t i = 0;
  935. for (auto& spec : m.overriders) {
  936. if (mask[i]) {
  937. overriders.push_back(&spec);
  938. }
  939. ++i;
  940. }
  941. if constexpr (has_trace) {
  942. ++tr << "select best of:\n";
  943. indent _(tr);
  944. for (auto& app : overriders) {
  945. ++tr << "#" << app->spec_index << " "
  946. << type_name(app->info->type) << "\n";
  947. }
  948. }
  949. std::vector<overrider*> dominants = overriders;
  950. std::size_t pick, remaining;
  951. select_dominant_overriders(dominants, pick, remaining);
  952. if (remaining == 0) {
  953. indent _(tr);
  954. ++tr << "not implemented\n";
  955. m.dispatch_table.push_back(&m.not_implemented);
  956. ++m.report.not_implemented;
  957. } else {
  958. if constexpr (!has_option<n2216>) {
  959. if (remaining > 1) {
  960. ++tr << "ambiguous\n";
  961. m.dispatch_table.push_back(&m.ambiguous);
  962. ++m.report.ambiguous;
  963. continue;
  964. }
  965. }
  966. auto overrider = dominants[pick];
  967. m.dispatch_table.push_back(overrider);
  968. ++tr;
  969. tr << "-> #" << overrider->spec_index << " "
  970. << type_name(overrider->info->type)
  971. << " pf = " << overrider->info->pf;
  972. if (remaining > 1) {
  973. tr << " (ambiguous)";
  974. ++m.report.ambiguous;
  975. }
  976. tr << "\n";
  977. // -------------------------------------------------------------
  978. // next
  979. // First remove the dominant overriders from the overriders.
  980. // Note that the dominants appear in the overriders in the same
  981. // relative order.
  982. auto candidate = overriders.begin();
  983. remaining = 0;
  984. for (auto dominant : dominants) {
  985. if (*candidate == dominant) {
  986. *candidate = nullptr;
  987. } else {
  988. ++remaining;
  989. }
  990. ++candidate;
  991. }
  992. if (remaining == 0) {
  993. ++tr << "no 'next'\n";
  994. overrider->next = &m.not_implemented;
  995. } else {
  996. if constexpr (has_trace) {
  997. ++tr << "for 'next', select best of:\n";
  998. indent _(tr);
  999. for (auto& app : overriders) {
  1000. if (app) {
  1001. ++tr << "#" << app->spec_index << " "
  1002. << type_name(app->info->type) << "\n";
  1003. }
  1004. }
  1005. }
  1006. select_dominant_overriders(overriders, pick, remaining);
  1007. if constexpr (!has_option<n2216>) {
  1008. if (remaining > 1) {
  1009. ++tr << "ambiguous 'next'\n";
  1010. overrider->next = &m.ambiguous;
  1011. continue;
  1012. }
  1013. }
  1014. auto next_overrider = overriders[pick];
  1015. overrider->next = next_overrider;
  1016. ++tr << "-> #" << next_overrider->spec_index << " "
  1017. << type_name(next_overrider->info->type)
  1018. << " pf = " << next_overrider->info->pf;
  1019. if (remaining > 1) {
  1020. tr << " (ambiguous)";
  1021. // do not increment m.report.ambiguous, for same reason
  1022. }
  1023. tr << "\n";
  1024. }
  1025. }
  1026. } else {
  1027. build_dispatch_table(
  1028. m, dim - 1, group_iter - 1, mask,
  1029. concrete && group.has_concrete_classes);
  1030. }
  1031. ++group_index;
  1032. }
  1033. }
  1034. inline void detail::generic_compiler::accumulate(
  1035. const method_report& partial, report& total) {
  1036. total.cells += partial.cells;
  1037. total.not_implemented += partial.not_implemented != 0;
  1038. total.ambiguous += partial.ambiguous != 0;
  1039. }
  1040. template<class... Policies>
  1041. template<class... Options>
  1042. void registry<Policies...>::compiler<Options...>::write_global_data() {
  1043. using namespace policies;
  1044. using namespace detail;
  1045. auto dispatch_data_size = std::accumulate(
  1046. methods.begin(), methods.end(), std::size_t(0),
  1047. [](std::size_t sum, const method& m) {
  1048. // msvc doesn't like (auto sum, auto& m) (C2187), go figure...
  1049. return sum + m.dispatch_table.size();
  1050. });
  1051. dispatch_data_size = std::accumulate(
  1052. classes.begin(), classes.end(), dispatch_data_size,
  1053. [](auto sum, const auto& cls) { return sum + cls.vtbl.size(); });
  1054. std::vector<detail::word> new_dispatch_data(dispatch_data_size);
  1055. auto gv_first = new_dispatch_data.data();
  1056. [[maybe_unused]] auto gv_last = gv_first + dispatch_data_size;
  1057. auto gv_iter = gv_first;
  1058. ++tr << "Initializing multi-method dispatch tables at " << gv_iter << "\n";
  1059. for (auto& m : methods) {
  1060. if (m.info->arity() == 1) {
  1061. // Uni-methods just need an index in the method table.
  1062. m.info->slots_strides_ptr[0] = m.slots[0];
  1063. } else {
  1064. auto strides_iter = std::copy(
  1065. m.slots.begin(), m.slots.end(), m.info->slots_strides_ptr);
  1066. std::copy(m.strides.begin(), m.strides.end(), strides_iter);
  1067. if constexpr (has_trace) {
  1068. ++tr << rflush(4, dispatch_data_size) << " " << " method #"
  1069. << m.dispatch_table[0]->method_index << " "
  1070. << type_name(m.info->method_type_id) << "\n";
  1071. indent _(tr);
  1072. for (auto& entry : m.dispatch_table) {
  1073. ++tr << "spec #" << entry->spec_index << " "
  1074. << spec_name(m, entry) << "\n";
  1075. }
  1076. }
  1077. m.gv_dispatch_table = gv_iter;
  1078. BOOST_ASSERT(gv_iter + m.dispatch_table.size() <= gv_last);
  1079. gv_iter = std::transform(
  1080. m.dispatch_table.begin(), m.dispatch_table.end(), gv_iter,
  1081. [](auto spec) { return spec->pf; });
  1082. }
  1083. }
  1084. ++tr << "Setting 'next' pointers\n";
  1085. for (auto& m : methods) {
  1086. indent _(tr);
  1087. ++tr << "method #" << " " << type_name(m.info->method_type_id) << "\n";
  1088. for (auto& overrider : m.overriders) {
  1089. if (overrider.next) {
  1090. ++tr << "#" << overrider.spec_index << " "
  1091. << spec_name(m, &overrider) << " -> ";
  1092. tr << "#" << overrider.next->spec_index << " "
  1093. << spec_name(m, overrider.next);
  1094. *overrider.info->next =
  1095. reinterpret_cast<void (*)()>(overrider.next->pf);
  1096. } else {
  1097. tr << "none";
  1098. }
  1099. tr << "\n";
  1100. }
  1101. }
  1102. ++tr << "Initializing v-tables at " << gv_iter << "\n";
  1103. for (auto& cls : classes) {
  1104. *cls.static_vptr = gv_iter - cls.first_slot;
  1105. ++tr << rflush(4, gv_iter - gv_first) << " " << gv_iter << " vtbl for "
  1106. << cls << " slots " << cls.first_slot << "-"
  1107. << (cls.first_slot + cls.vtbl.size() - 1) << "\n";
  1108. indent _(tr);
  1109. for (auto& entry : cls.vtbl) {
  1110. ++tr << "method #" << entry.method_index << " ";
  1111. auto& method = methods[entry.method_index];
  1112. if (method.arity() == 1) {
  1113. auto spec = method.dispatch_table[entry.group_index];
  1114. tr << "spec #" << spec->spec_index << "\n";
  1115. indent _(tr);
  1116. ++tr << type_name(method.info->method_type_id) << "\n";
  1117. ++tr << spec_name(method, spec);
  1118. BOOST_ASSERT(gv_iter + 1 <= gv_last);
  1119. *gv_iter++ = spec->pf;
  1120. } else {
  1121. tr << "vp #" << entry.vp_index << " group #"
  1122. << entry.group_index << "\n";
  1123. indent _2(tr);
  1124. ++tr << type_name(method.info->method_type_id);
  1125. BOOST_ASSERT(gv_iter + 1 <= gv_last);
  1126. if (entry.vp_index == 0) {
  1127. *gv_iter++ = std::uintptr_t(
  1128. method.gv_dispatch_table + entry.group_index);
  1129. } else {
  1130. *gv_iter++ = entry.group_index;
  1131. }
  1132. }
  1133. tr << "\n";
  1134. }
  1135. }
  1136. ++tr << rflush(4, dispatch_data_size) << " " << gv_iter << " end\n";
  1137. if constexpr (has_vptr) {
  1138. vptr::initialize(*this, options);
  1139. }
  1140. new_dispatch_data.swap(dispatch_data);
  1141. }
  1142. template<class... Policies>
  1143. template<class... Options>
  1144. void registry<Policies...>::compiler<Options...>::select_dominant_overriders(
  1145. std::vector<overrider*>& candidates, std::size_t& pick,
  1146. std::size_t& remaining) {
  1147. pick = 0;
  1148. remaining = 0;
  1149. for (size_t i = 0; i < candidates.size(); ++i) {
  1150. if (candidates[i]) {
  1151. for (size_t j = i + 1; j < candidates.size(); ++j) {
  1152. if (candidates[j]) {
  1153. if (is_more_specific(candidates[i], candidates[j])) {
  1154. candidates[j] = nullptr;
  1155. } else if (is_more_specific(candidates[j], candidates[i])) {
  1156. candidates[i] = nullptr;
  1157. break; // this one is dead
  1158. }
  1159. }
  1160. }
  1161. }
  1162. if (candidates[i]) {
  1163. pick = i;
  1164. ++remaining;
  1165. }
  1166. }
  1167. if (remaining <= 1) {
  1168. return;
  1169. }
  1170. if constexpr (has_option<n2216>) {
  1171. if (!candidates[pick]->covariant_return_type) {
  1172. return;
  1173. }
  1174. remaining = 0;
  1175. for (size_t i = 0; i < candidates.size(); ++i) {
  1176. if (candidates[i]) {
  1177. for (size_t j = i + 1; j < candidates.size(); ++j) {
  1178. if (candidates[j]) {
  1179. BOOST_ASSERT(candidates[i] != candidates[j]);
  1180. if (candidates[i]->covariant_return_type->is_base_of(
  1181. candidates[j]->covariant_return_type)) {
  1182. candidates[i] = nullptr;
  1183. } else if (candidates[j]
  1184. ->covariant_return_type->is_base_of(
  1185. candidates[i]
  1186. ->covariant_return_type)) {
  1187. candidates[j] = nullptr;
  1188. }
  1189. }
  1190. }
  1191. }
  1192. if (candidates[i]) {
  1193. pick = i;
  1194. ++remaining;
  1195. }
  1196. }
  1197. }
  1198. }
  1199. template<class... Policies>
  1200. template<class... Options>
  1201. auto registry<Policies...>::compiler<Options...>::is_more_specific(
  1202. const overrider* a, const overrider* b) -> bool {
  1203. bool result = false;
  1204. auto a_iter = a->vp.begin(), a_last = a->vp.end(), b_iter = b->vp.begin();
  1205. for (; a_iter != a_last; ++a_iter, ++b_iter) {
  1206. if (*a_iter != *b_iter) {
  1207. if ((*b_iter)->transitive_derived.find(*a_iter) !=
  1208. (*b_iter)->transitive_derived.end()) {
  1209. result = true;
  1210. } else if (
  1211. (*a_iter)->transitive_derived.find(*b_iter) !=
  1212. (*a_iter)->transitive_derived.end()) {
  1213. return false;
  1214. }
  1215. }
  1216. }
  1217. return result;
  1218. }
  1219. template<class... Policies>
  1220. template<class... Options>
  1221. auto registry<Policies...>::compiler<Options...>::is_base(
  1222. const overrider* a, const overrider* b) -> bool {
  1223. bool result = false;
  1224. auto a_iter = a->vp.begin(), a_last = a->vp.end(), b_iter = b->vp.begin();
  1225. for (; a_iter != a_last; ++a_iter, ++b_iter) {
  1226. if (*a_iter != *b_iter) {
  1227. if ((*a_iter)->transitive_derived.find(*b_iter) ==
  1228. (*a_iter)->transitive_derived.end()) {
  1229. return false;
  1230. } else {
  1231. result = true;
  1232. }
  1233. }
  1234. }
  1235. return result;
  1236. }
  1237. template<class... Policies>
  1238. template<class... Options>
  1239. void registry<Policies...>::compiler<Options...>::print(
  1240. const method_report& r) const {
  1241. ++tr;
  1242. if (r.cells) {
  1243. // only for multi-methods, uni-methods don't have dispatch tables
  1244. ++tr << r.cells << " dispatch table cells, ";
  1245. }
  1246. tr << r.not_implemented << " not implemented, " << r.ambiguous
  1247. << " ambiguous\n";
  1248. }
  1249. //! Initialize a registry.
  1250. //!
  1251. //! Initialize the @ref registry passed as an explicit function template
  1252. //! argument, or @ref default_registry if the registry is not specified. The
  1253. //! default can be changed by defining {{BOOST_OPENMETHOD_DEFAULT_REGISTRY}}.
  1254. //! Option objects can be passed to change the behavior of the function.
  1255. //! Currently two options exist:
  1256. //! @li @ref trace Enable tracing of the initialization process.
  1257. //! @li @ref n2216 Enable resolution of ambiguities according to the N2216
  1258. //! paper.
  1259. //!
  1260. //! `initialize` must be called, typically at the beginning of `main`, before
  1261. //! using any of the methods in a registry. It sets up the v-tables,
  1262. //! multi-method dispatch tables, and any other data required by the policies.
  1263. //!
  1264. //! The function returns an object of an unspecified type that contains a
  1265. //! `report` member, itself an object of an unspecified type, thatcontains the
  1266. //! following members:
  1267. //! @li `std::size_t cells`: The number of cells in all multi-method dispatch
  1268. //! tables.
  1269. //! @li `std::size_t not_implemented`: The number of multi-method dispatch tables that
  1270. //! contain at least one not implemented entry.
  1271. //! @li `std::size_t ambiguous`: The number of multi-method dispatch tables that contain at
  1272. //! least one ambiguous entry.
  1273. //!
  1274. //! @note
  1275. //! A translation unit that calls `initialize` must include the
  1276. //! `<boost/openmethod/initialize.hpp>` header.
  1277. //!
  1278. //! @tparam Registry The registry to initialize.
  1279. //! @tparam Options... Zero or more option types, deduced from the function
  1280. //! arguments.
  1281. //! @param options Zero or more option objects.
  1282. //! @return An object of an unspecified type.
  1283. //!
  1284. //! @par Errors
  1285. //!
  1286. //! @li @ref missing_class: A class used in a virtual parameter was not
  1287. //! registered.
  1288. //! @li The registry's policies may report additional errors.
  1289. //!
  1290. //! @par Example
  1291. //!
  1292. //! Initialize the default registry with tracing enabled, and exit with an error
  1293. //! message if there were any possibility of a @reg bad_call error. User may run
  1294. //! the program again after setting environment variable
  1295. //! `BOOST_OPENMETHOD_TRACE` to `1` to troubleshoot.
  1296. //!
  1297. //! @code
  1298. //! #include <iostream>
  1299. //!
  1300. //! #include <boost/openmethod.hpp>
  1301. //! #include <boost/openmethod/initialize.hpp>
  1302. //!
  1303. //! int main() {
  1304. //! namespace bom = boost::openmethod;
  1305. //! auto report = bom::initialize(bom::trace::from_env()).report;
  1306. //!
  1307. //! if (report.not_implemented != 0 || report.ambiguous != 0) {
  1308. //! std::cerr << "missing overriders or ambiguous methods\n";
  1309. //! return 1;
  1310. //! }
  1311. //!
  1312. //! // ...
  1313. //! }
  1314. //! @endcode
  1315. template<class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY, class... Options>
  1316. inline auto initialize(Options&&... options) {
  1317. if (detail::odr_check<Registry>::count > 1) {
  1318. // Multiple definitions of default_registry detected.
  1319. // This indicates an ODR violation.
  1320. // Signal a final_error using the error handler, then abort.
  1321. if constexpr (Registry::has_error_handler) {
  1322. Registry::error_handler::error(odr_violation());
  1323. }
  1324. std::abort();
  1325. }
  1326. typename Registry::template compiler<Options...> comp(
  1327. std::forward<Options>(options)...);
  1328. comp.initialize();
  1329. return comp;
  1330. }
  1331. namespace detail {
  1332. template<typename, class Policy, class... Options>
  1333. struct has_finalize_aux : std::false_type {};
  1334. template<class Policy, class... Options>
  1335. struct has_finalize_aux<
  1336. std::void_t<decltype(Policy::finalize(
  1337. std::declval<std::tuple<Options...>>()))>,
  1338. Policy, Options...> : std::true_type {};
  1339. } // namespace detail
  1340. template<class... Policies>
  1341. template<class... Options>
  1342. auto registry<Policies...>::finalize(Options... opts) -> void {
  1343. std::tuple<Options...> options(opts...); // gcc-8 doesn't like CTAD here
  1344. mp11::mp_for_each<policy_list>([&options](auto policy) {
  1345. using fn = typename decltype(policy)::template fn<registry>;
  1346. if constexpr (detail::has_finalize_aux<void, fn, Options...>::value) {
  1347. fn::finalize(options);
  1348. }
  1349. });
  1350. dispatch_data.clear();
  1351. initialized = false;
  1352. }
  1353. //! Release resources held by registry.
  1354. //!
  1355. //! `finalize` may be called to release any resources allocated by
  1356. //! @ref registry::initialize.
  1357. //!
  1358. //! @note
  1359. //! A translation unit that contains a call to `finalize` must include the
  1360. //! `<boost/openmethod/initialize.hpp>` header.
  1361. //!
  1362. //! @tparam Registry The registry to finalize.
  1363. //! @tparam Options... Zero or more option types, deduced from the function
  1364. //! arguments.
  1365. //! @param options Zero or more option objects.
  1366. template<class Registry = BOOST_OPENMETHOD_DEFAULT_REGISTRY, class... Options>
  1367. inline auto finalize(Options&&... opts) -> void {
  1368. Registry::finalize(std::forward<Options>(opts)...);
  1369. }
  1370. } // namespace boost::openmethod
  1371. #ifdef _MSC_VER
  1372. #pragma warning(pop)
  1373. #endif
  1374. #endif