1. 03 Feb, 2020 4 commits
    • Eric Myhre's avatar
      Map key and value assemblers invalidate self more aggressively when finished. · 0301dbad
      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.
      0301dbad
    • Eric Myhre's avatar
      NodeAssembler.Done -> NodeAssembler.Finish. · f92f20eb
      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.
      f92f20eb
    • Eric Myhre's avatar
      Some effort to reduce cost of indirections needed for nested map assembly. · 00db3ff6
      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.
      00db3ff6
    • Eric Myhre's avatar
      Dedup assignment code in untyped map values. · 24b53d90
      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.
      24b53d90
  2. 02 Feb, 2020 1 commit
    • Eric Myhre's avatar
      Finish recursive untyped map building. Tests. · 50275d24
      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.
      50275d24
  3. 01 Feb, 2020 2 commits
    • Eric Myhre's avatar
      More of String style and builders; a hackme doc; more interface constraints. · 2f04140c
      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.)
      2f04140c
    • Eric Myhre's avatar
  4. 22 Jan, 2020 1 commit
    • Eric Myhre's avatar
      More new map implementation. · 631a8e30
      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.
      631a8e30
  5. 13 Jan, 2020 1 commit
    • Eric Myhre's avatar
      Here's some stuff that can benchmark! · c51fb607
      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...
      c51fb607