- 03 Feb, 2020 4 commits
-
-
Eric Myhre authored
This prevents later mutation by holding onto an assembler too long. (*Getting* the child assemblers is fenced by the 'state' field; but since none of the child assembler methods check the 'state', some defense is needed there. Invalidating the pointer back up is it: this invalidation overhold of child assemblers once the user already has them into a nonissue by making any mutations fail.) I did a few extra-long benchmark runs to make sure this extra footwork doesn't cost any noticable time. It does not; it's within the margins of error on a benchtime=4m run.
-
Eric Myhre authored
We use the word "done" as the predicate in iterators; therefore it's confusing to also use it as a verb for *doing* completion elsewhere. "Finish" also has the advantage of sounding slightly more active -- which it is, since it's often involved in housekeeping and, well, *finishing* assignment within the enclosing parent value, as well as in evaluating validations for types that have them.
-
Eric Myhre authored
The original goal of insuring there's minimal speed costs turned out to be a red herring because it was already doing pretty reasonable things; but instead, the quest generated a little learning about assembly size. Comments about that continue to accumulate in the currently-backburner'd map+structs codegen file, where they are most relevant because of the question of whether to handle struct fields with generation of copious small types.
-
Eric Myhre authored
In the assembly, this ends up inlined, so there's no reduction in size, but there's also no reduction in speed.
-
- 02 Feb, 2020 1 commit
-
-
Eric Myhre authored
Can you believe this required another wrapper type? But indeed: this is the case: when building a recursive value, it is necessary for us to do some actions after that recursed operation becomes 'done'. In this case, we have to both kick the parent state machine along, and also finish the actual assignment into the map! (In codegen maps, the latter need isn't true, for fun pointer dance reasons, but the need for state machine kicking -- as well as having the error checking branch to make sure any validation succeeded! -- is still applicable.) Tests all pass.
-
- 01 Feb, 2020 2 commits
-
-
Eric Myhre authored
Starting to use a short little snippet of interface constraints at the top of every file is starting to feel useful again, both as a compiler sanity check and as a short readable inventory of the file. The hackme accumulates and clarifies a bunch of notes I found myself needing to make in one place as I try to settle the high level rules. It's mostly for the "ipldfree" implementations, and will move to that package when we're done with our research branch here and start moving things into their final places. A few things might be more general; I'll sort those out into some separate file later. And plainString now has the full complement of NodeStyle, NodeBuilder, and all the other interfaces. In parallel but not committed here, I'm working on the 'any' node implementation for this new generation of "ipldfree". That's turning out a bit more special (isn't everything in this project?) than expected: the ideal operation for NodeBuilder and NodeAssembler actually diverge, because the builder would like to return rather more less and more granular memory, whereas the assembler has no freedom to do so; this is the first occurance of such a divergence. So that's fun! (I wonder if something like this will also come up for union types, later on.)
-
Eric Myhre authored
-
- 22 Jan, 2020 1 commit
-
-
Eric Myhre authored
Includes duplicate key checks that were previously missing. Overall, checks many more invariants. There are now "*_ValueAssembler" types involved in both the 'free'/generic implementation, and the codegen implementation: in both cases, it's needed for several tasks, mostly revolving around the "Done" method (or anything else that causes doneness, e.g. any of the scalar "Assign*" methods): - to make sure the map assembly doesn't move on until the value assembly is finished! Need to do this to make it possible to maintain any other invariant over the whole tree! - to do state machine keeping on the map assembler - to do any integrity checks that the map itself demands - and in some cases, to actually commit the entry itself (although in some cases, pointer funtimes at key finish time are enough). The introduction of these '*_KeyAssembler' and '*_ValueAssembler' types is somewhat frustrating, because they add more memory, more vtable interactions (sometimes; in codegen, the compiler can inline them out), and just plain more SLOC. Particularly irritatingly, they require a pointer back to their parent assembler... even though in practice, they're always embedded *in* that same structure, so it's a predictable offset from their own pointer. But I couldn't easily seem to see a way around that (shy of using unsafe or other extreme nastiness), so, I'm just bitting the bullet and moving on with that. (I even briefly experimented with using type aliases to be able to decorate additional methods contextually onto the same struct memory, hoping that I'd be able to choose which type's set of methods I apply. (I know this is possible internally -- if one writes assembler, that's *what the calls are like*: you grab the function definition from a table of functions per type, and then you apply it to some memory!) This would make it possible to put all the child assembler functions on the same memory as the parent assembler that embeds them, and thus save us the cyclic pointers! But alas, no. Attempting to do this will run aground on "duplicate method" errors quite quickly. Aliases were not meant to do this.) There's some new tests, in addition to benchmarks. 'plainMap', destined to be part of the next version of the 'ipldfree' package, is now complete, and passes tests. A couple key tests are commented out, because they require a bump in version of the go-wish library, and I'm going to sort that in a separate commit. They do pass, though, otherwise. Some NodeStyle implementations are introduced, and now those are the way to get builders for those nodes, and all the tests and benchmarks use them. The placeholder 'NewBuilder*' methods are gone. There are some open questions about what naming pattern to use for exporting symbols for NodeStyles. Some comments regard this, but it's a topic to engage in more earnest later. Benchmarks have been renamed for slightly more consistency and an eye towards additional benchmarks we're likely to add shortly. Some new documentation file are added! These are a bit ramshackle, because they're written as an issue of note occurs to me, but there are enough high-level rules that should be held the same across various implementations of Node and NodeAssembler that writing them in a doc outside the code began to seem wise.
-
- 13 Jan, 2020 1 commit
-
-
Eric Myhre authored
(Thank goodness. Been in theoryland for a while.) There's somewhat more content here than necessary for the benchmark that's presently runnable; right now only the Map_K_T implementation is targetted. I want benchmarks of things with complex keys in codegen and also benchmarks of the runtime/generic/free impls soon, so they can all be compared. There's also a quick fliff of stdlib map usage in a wee benchmark to give us some baselines... And there's also a quick fliff of stdlib json unmarshalling for the same reason. It's not fair, to be sure: the json thing is doing work parsing, and allocating strings (whereas the other two get to use compile-time const strings)... but it sure would be embarassing if we *failed* to beat that speed, right? So it's there to keep it in mind. Some off-the-cuff results: ``` BenchmarkBaselineNativeMapAssignSimpleKeys-8 6815284 175 ns/op 256 B/op 2 allocs/op BenchmarkBaselineJsonUnmarshalMapSimpleKeys-8 724059 1644 ns/op 608 B/op 14 allocs/op BenchmarkFeedGennedMapSimpleKeys-8 2932563 410 ns/op 176 B/op 8 allocs/op ``` This pretty good. If we're *only* half the speed of the native maps... that's actually reallyreally good, considering we're doing more work to keep things ordered, to say nothing of all the other interface support efforts we have to do. But 8 allocs? No. That was not the goal. This should be better. Time to dig...
-