Skip to content
This repository was archived by the owner on Mar 4, 2026. It is now read-only.

Commit d7a4e1b

Browse files
committed
fix incremental class registration
1 parent 00c32c1 commit d7a4e1b

File tree

4 files changed

+42
-51
lines changed

4 files changed

+42
-51
lines changed

examples/synopsis.cpp

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,12 @@ class Dolphin : public Animal {};
1919

2020
#include <yorel/yomm2/keywords.hpp>
2121

22-
register_classes(Animal, Dog, Bulldog, Cat, Dolphin);
22+
// classes must be registered
23+
register_classes(Animal, Dog, Cat, Dolphin);
24+
// but it does not have to be in one call to 'register_classes', as long as
25+
// inheritance relationships can be deduced - this allows *adding* classes to an
26+
// existing collection of classes
27+
register_classes(Dog, Bulldog);
2328

2429
// open method with single virtual argument <=> virtual function "from outside"
2530
declare_method(std::string, kick, (virtual_<Animal&>));

include/yorel/yomm2/runtime.hpp

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,7 @@ struct rt_arg {
2828
};
2929

3030
struct rt_class {
31-
explicit rt_class(const class_info* info) : info(info) {
32-
}
33-
34-
const class_info* info;
31+
bool is_abstract{false};
3532
std::vector<const std::type_info*> ti_ptrs;
3633
std::vector<rt_class*> transitive_bases;
3734
std::vector<rt_class*> direct_bases;
@@ -47,7 +44,7 @@ struct rt_class {
4744
detail::word* mptr;
4845

4946
auto name() const {
50-
return info->name();
47+
return ti_ptrs[0]->name();
5148
}
5249
};
5350

src/yomm2.cpp

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,7 @@ operator<<(std::ostream& os, Container<rt_class*, T...>& classes) {
132132
os << "(";
133133
const char* sep = "";
134134
for (auto cls : classes) {
135-
os << sep << cls->info->name();
135+
os << sep << cls->name();
136136
sep = ", ";
137137
}
138138

@@ -188,32 +188,34 @@ void runtime::augment_classes() {
188188
}
189189
}
190190

191-
auto& entry = class_map[std::type_index(*cr.ti)];
191+
auto& rtc = class_map[std::type_index(*cr.ti)];
192192

193-
if (entry == nullptr) {
194-
classes.emplace_front(&cr);
195-
entry = &classes.front();
193+
if (rtc == nullptr) {
194+
rtc = &classes.emplace_back();
195+
rtc->is_abstract = cr.is_abstract;
196196
}
197197

198198
// In the unlikely case that a class does have more than one
199199
// associated ti*, collect them in a vector. We don't use an
200200
// unordered_set because, again, this situation is highly unlikely,
201-
// and, were it to occurr, the number of distinct ti*s would
201+
// and, were it to occur, the number of distinct ti*s would
202202
// probably be small.
203203
if (std::find(
204-
entry->ti_ptrs.begin(), entry->ti_ptrs.end(), cr.ti) ==
205-
entry->ti_ptrs.end()) {
206-
entry->ti_ptrs.push_back(cr.ti);
204+
rtc->ti_ptrs.begin(), rtc->ti_ptrs.end(), cr.ti) ==
205+
rtc->ti_ptrs.end()) {
206+
rtc->ti_ptrs.push_back(cr.ti);
207207
}
208208
}
209209
}
210210

211211
// All known classes now have exactly one associated rt_class* in the map.
212212
// Collect the bases.
213213

214-
for (auto& rtc : classes) {
215-
for (auto base_iter = rtc.info->first_base;
216-
base_iter != rtc.info->last_base; ++base_iter) {
214+
for (auto& cr : cat.classes) {
215+
auto& rtc = class_map[std::type_index(*cr.ti)];
216+
217+
for (auto base_iter = cr.first_base;
218+
base_iter != cr.last_base; ++base_iter) {
217219
auto rtb = class_map[std::type_index(**base_iter)];
218220

219221
if (!rtb) {
@@ -223,10 +225,10 @@ void runtime::augment_classes() {
223225
abort();
224226
}
225227

226-
if (&rtc != rtb) {
228+
if (rtc != rtb) {
227229
// At compile time we collected the class as its own improper
228230
// base, as per std::is_base_of. Eliminate that.
229-
rtc.transitive_bases.push_back(rtb);
231+
rtc->transitive_bases.push_back(rtb);
230232
}
231233
}
232234
}
@@ -455,7 +457,7 @@ std::vector<rt_class*> runtime::layer_classes() {
455457
(*class_iter)->layer = layer;
456458

457459
if constexpr (bool(trace_enabled & TRACE_RUNTIME)) {
458-
trace << " " << (*class_iter)->info->name();
460+
trace << " " << (*class_iter)->name();
459461
}
460462

461463
class_iter = input.erase(class_iter);
@@ -482,7 +484,7 @@ void runtime::allocate_slots() {
482484
++trace << mp.method->info->name << "#" << mp.param << ": slot "
483485
<< slot << "\n";
484486
with_indent YOMM2_GENSYM(trace);
485-
++trace << cls->info->name();
487+
++trace << cls->name();
486488

487489
if (mp.method->slots.size() <= mp.param) {
488490
mp.method->slots.resize(mp.param + 1);
@@ -516,7 +518,7 @@ void runtime::allocate_slot_down(rt_class* cls, size_t slot) {
516518

517519
cls->mark = class_visit;
518520

519-
trace << " " << cls->info->name();
521+
trace << " " << cls->name();
520522

521523
assert(slot >= cls->next_slot);
522524

@@ -542,7 +544,7 @@ void runtime::allocate_slot_up(rt_class* cls, size_t slot) {
542544

543545
cls->mark = class_visit;
544546

545-
trace << " " << cls->info->name();
547+
trace << " " << cls->name();
546548

547549
assert(slot >= cls->next_slot);
548550
cls->next_slot = slot + 1;
@@ -576,12 +578,12 @@ void runtime::build_dispatch_tables() {
576578
for (auto vp : m.vp) {
577579
auto& dim_group = groups[dim];
578580
++trace << "make groups for param #" << dim << ", class "
579-
<< vp->info->name() << "\n";
581+
<< vp->name() << "\n";
580582
with_indent YOMM2_GENSYM(trace);
581583

582584
for (auto covariant_classes : vp->covariant_classes) {
583585
++trace << "specs applicable to "
584-
<< covariant_classes->info->name() << "\n";
586+
<< covariant_classes->name() << "\n";
585587
bitvec mask;
586588
mask.resize(m.specs.size());
587589

@@ -601,7 +603,7 @@ void runtime::build_dispatch_tables() {
601603
auto& group = dim_group[mask];
602604
group.classes.push_back(covariant_classes);
603605
group.has_concrete_classes = group.has_concrete_classes ||
604-
!covariant_classes->info->is_abstract;
606+
!covariant_classes->is_abstract;
605607

606608
++trace << "-> mask: " << mask << "\n";
607609
}
@@ -636,7 +638,7 @@ void runtime::build_dispatch_tables() {
636638
with_indent YOMM2_GENSYM(trace);
637639
for (auto cls :
638640
range{group.classes.begin(), group.classes.end()}) {
639-
++trace << tip{cls->info->ti} << "\n";
641+
++trace << tip{cls->ti_ptrs[0]} << "\n";
640642
}
641643
}
642644
++group_num;
@@ -741,7 +743,7 @@ void runtime::build_dispatch_table(
741743
<< "\n";
742744
with_indent YOMM2_GENSYM(trace);
743745
for (auto cls : range{group.classes.begin(), group.classes.end()}) {
744-
++trace << tip{cls->info->ti} << "\n";
746+
++trace << tip{cls->ti_ptrs[0]} << "\n";
745747
}
746748
}
747749

@@ -967,7 +969,7 @@ void runtime::install_gv() {
967969

968970
if constexpr (bool(trace_enabled & TRACE_RUNTIME)) {
969971
++trace << std::setw(4) << ctx.gv.size() << " mtbl for "
970-
<< cls.info->name() << ": " << cls.mptr << "\n";
972+
<< cls.name() << ": " << cls.mptr << "\n";
971973
}
972974

973975
if (cls.first_used_slot != -1) {
@@ -1000,7 +1002,7 @@ void runtime::optimize() {
10001002
for (auto cls : m.vp[0]->covariant_classes) {
10011003
auto pf = m.dispatch_table[cls->mptr[slot].i];
10021004
if constexpr (bool(trace_enabled & TRACE_RUNTIME)) {
1003-
++trace << cls->info->name() << " mtbl[" << slot
1005+
++trace << cls->name() << " mtbl[" << slot
10041006
<< "] = " << pf << " (function)"
10051007
<< "\n";
10061008
}
@@ -1011,7 +1013,7 @@ void runtime::optimize() {
10111013
auto pw = m.gv_dispatch_table + cls->mptr[slot].i;
10121014

10131015
if constexpr (bool(trace_enabled & TRACE_RUNTIME)) {
1014-
++trace << " " << cls->info->name() << " mtbl[" << slot
1016+
++trace << " " << cls->name() << " mtbl[" << slot
10151017
<< "] = gv+" << (pw - ctx.hash_table) << "\n";
10161018
}
10171019

tests/runtime.cpp

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -169,11 +169,11 @@ struct Jet : Expense {};
169169
using test_policy = test_policy_<Role>;
170170
// any type from this namespace would work.
171171

172-
use_classes<
173-
test_policy, Role, Employee, Manager, Founder, Expense, Public, Bus, Metro,
174-
Taxi, Jet>
172+
use_classes<test_policy, Role, Employee, Manager, Founder, Expense>
175173
YOMM2_GENSYM;
176174

175+
use_classes<test_policy, Expense, Public, Bus, Metro, Taxi, Jet> YOMM2_GENSYM;
176+
177177
YOMM2_DECLARE(double, pay, (virtual_<const Employee&>), test_policy);
178178

179179
YOMM2_DECLARE(
@@ -216,20 +216,6 @@ BOOST_AUTO_TEST_CASE(runtime_test) {
216216

217217
rt.augment_classes();
218218

219-
BOOST_TEST_REQUIRE(
220-
rt.classes.size() == test_policy::catalog.classes.size());
221-
222-
{
223-
auto c_iter = test_policy::catalog.classes.begin();
224-
auto r_iter = rt.classes.rbegin();
225-
226-
while (r_iter != rt.classes.rend()) {
227-
BOOST_TEST(r_iter->info == &*c_iter);
228-
++c_iter;
229-
++r_iter;
230-
}
231-
}
232-
233219
auto role = get<Role>(rt);
234220
auto employee = get<Employee>(rt);
235221
auto manager = get<Manager>(rt);
@@ -305,7 +291,8 @@ BOOST_AUTO_TEST_CASE(runtime_test) {
305291
BOOST_TEST(jet->direct_derived.size() == 0);
306292

307293
BOOST_TEST(
308-
sstr(role->covariant_classes) == sstr(role, employee, founder, manager));
294+
sstr(role->covariant_classes) ==
295+
sstr(role, employee, founder, manager));
309296
BOOST_TEST(sstr(founder->covariant_classes) == sstr(founder));
310297
BOOST_TEST(
311298
sstr(expense->covariant_classes) ==
@@ -813,7 +800,7 @@ BOOST_AUTO_TEST_CASE(test_allocate_slots_mi) {
813800
BOOST_REQUIRE(s1 <= 4);
814801
in_use[s1] = true;
815802
}
816-
803+
817804
for (auto m2 : methods) {
818805
if (m1 == m2) {
819806
continue;

0 commit comments

Comments
 (0)