diff --git a/dev/TODO.txt b/dev/TODO.txt index 68abe56d..6b55cada 100644 --- a/dev/TODO.txt +++ b/dev/TODO.txt @@ -1,3 +1,5 @@ +- mipmaps are darker than the orginal in both srgb and linear modes? see e.g. puzzlewindow.lobster + - Default ignoring return values is a really bad default, wonder if it is too late to change? Ideally it would error on ignored return values unless the function explicitly marks a return value as ignorable. diff --git a/dev/src/builtins.cpp b/dev/src/builtins.cpp index 4ca38ba1..0247dc61 100644 --- a/dev/src/builtins.cpp +++ b/dev/src/builtins.cpp @@ -751,7 +751,7 @@ nfr("tan", "angle", "F}", "F}", [](StackPtr &sp, VM &) { VECTOROP(tan(f.fval() * RAD)); }); nfr("sincos", "angle", "F", "F}:2", - "the normalized vector indicated by angle (in degrees), same as xy { cos(angle), sin(angle) }", + "the normalized vector indicated by angle (in degrees), same as float2 { cos(angle), sin(angle) }", [](StackPtr &sp, VM &) { auto a = Pop(sp).fval(); PushVec(sp, double2(cos(a * RAD), sin(a * RAD))); diff --git a/dev/src/lobster/vmdata.h b/dev/src/lobster/vmdata.h index f9f8ad62..6b24eaed 100644 --- a/dev/src/lobster/vmdata.h +++ b/dev/src/lobster/vmdata.h @@ -378,7 +378,7 @@ struct ToFlexBufferContext { bool ignore_unsupported_types = false; bool cycle_detect = false; - set seen_objects; + map seen_objects; iint max_depth = 100; iint cur_depth = 0; @@ -386,7 +386,8 @@ struct ToFlexBufferContext { string max_depth_hit; flexbuffers::Builder::Value max_depth_hit_value; string cycle_hit; - flexbuffers::Builder::Value cycle_hit_value; + + PrintPrefs pp = PrintPrefs(2, 50, true, -1); ToFlexBufferContext(VM &vm, size_t initial_size, flexbuffers::BuilderFlag flags) : vm(vm), builder(initial_size, flags) {} diff --git a/dev/src/vmdata.cpp b/dev/src/vmdata.cpp index 5ca12b7f..0eef7457 100644 --- a/dev/src/vmdata.cpp +++ b/dev/src/vmdata.cpp @@ -614,16 +614,28 @@ void ElemToFlexBuffer(ToFlexBufferContext &fbc, const TypeInfo &ti, } void LObject::ToFlexBuffer(ToFlexBufferContext &fbc) { + // Terrible C++: we need 2 variables to track this, because we can't init inserted_it + // with end() because it may get invalidated by the insert, and trying to test + // against the default constructed iterator is UB. + bool inserted = false; + map::iterator inserted_it; if (fbc.cycle_detect) { - if (fbc.seen_objects.find(this) == fbc.seen_objects.end()) { - fbc.seen_objects.insert(this); + auto it = fbc.seen_objects.find(this); + if (it == fbc.seen_objects.end()) { + inserted = true; + inserted_it = fbc.seen_objects.insert({ this, flexbuffers::Builder::Value{} }).first; } else { - fbc.cycle_hit = TypeName(fbc.vm); - if (fbc.cycle_hit_value.type_ == flexbuffers::FBT_NULL) { - fbc.builder.String("(dup_ref)"); - fbc.cycle_hit_value = fbc.builder.LastValue(); + if (it->second.type_ == flexbuffers::FBT_NULL) { + // A true cycle, object referred to while not finished. + fbc.cycle_hit = TypeName(fbc.vm); + string sd; + append(sd, "(cycle_ref: ", (size_t)this, ": "); + ToString(fbc.vm, sd, fbc.pp); + append(sd, ")"); + fbc.builder.String(sd); } else { - fbc.builder.ReuseValue(fbc.cycle_hit_value); + // Just a DAG ref, we just make the FlexBuffer a DAG as well! + fbc.builder.ReuseValue(it->second); } return; } @@ -655,6 +667,9 @@ void LObject::ToFlexBuffer(ToFlexBufferContext &fbc) { ElemToFlexBuffer(fbc, eti, i, 1, Elems(), fname, stti.elemtypes[i].defval); } fbc.builder.EndMap(start); + if (inserted) { + inserted_it->second = fbc.builder.LastValue(); + } } void LVector::ToFlexBuffer(ToFlexBufferContext &fbc) {