Skip to content

Commit

Permalink
Use Entry + opener bool instead of polymorphism
Browse files Browse the repository at this point in the history
This caused more performance gain than I expected. Shaved off a few
hundred ms off tests, the almost canonical `100_000 times: []` and
others of the like run also in some 100s of ms less on my PC. I guess
since billions (ish?) of calls to Entry are made, every little bit of
indirection along the way matters -- a lot. I won't say I learned
anything new but then I did. Huh.
  • Loading branch information
homonoidian committed Oct 10, 2023
1 parent 06df779 commit 54e35ec
Show file tree
Hide file tree
Showing 6 changed files with 23 additions and 27 deletions.
4 changes: 2 additions & 2 deletions src/novika/capabilities/impl/essential.cr
Original file line number Diff line number Diff line change
Expand Up @@ -951,7 +951,7 @@ module Novika::Capabilities::Impl
form = stack.drop
name = stack.drop
block = stack.drop.a(Block)
block.at name, OpenEntry.new(form)
block.at name, Entry.new(form, opener: true)
end

target.at("entry:submit", <<-END
Expand Down Expand Up @@ -1113,7 +1113,7 @@ module Novika::Capabilities::Impl
end

entry = store.entry_for(name)
if entry.is_a?(OpenEntry)
if entry.opener?
caller.inject(Word.new("open"))
end

Expand Down
2 changes: 1 addition & 1 deletion src/novika/capabilities/system.cr
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ module Novika::Capabilities
def suggest?(word : String, prior : String) : {Quote, Block}?
return unless entry = @carrier.entry_for?(SUGGEST)

if entry.is_a?(OpenEntry)
if entry.opener?
# If entry is an opener entry, we should get the title and
# the results from the stack.
stack = Block.with(Quote.new(prior), Quote.new(word))
Expand Down
32 changes: 14 additions & 18 deletions src/novika/dict.cr
Original file line number Diff line number Diff line change
Expand Up @@ -172,35 +172,31 @@ module Novika
class Entry
include Schedulable

# Returns the form currently held by this entry.
getter form : Form
getter? opener
getter form

def initialize(@form)
def initialize(@form : Form, @opener = false)
end

# See the same method in `Form`.
delegate :effect, :onto, to: form
delegate :effect, :onto, to: @form

# :ditto:
def on_open(engine : Engine) : Nil
onto(engine.stack)
@opener ? @form.on_open(engine) : onto(engine.stack)
end

nil
def schedule(engine : Engine, stack : Block)
@opener ? @form.schedule(engine, stack) : super
end

# Makes *form* the value form of this entry.
def submit(@form) : self
self
def schedule!(engine : Engine, stack : Block)
@opener ? @form.schedule!(engine, stack) : super
end

def_equals_and_hash form
end
def submit(@form)
self
end

# A kind of entry that, when opened, in turn opens its
# value form.
class OpenEntry < Entry
# See the same method in `Form`.
delegate :on_open, :schedule, :schedule!, to: form
def_equals_and_hash @form, @opener
end

# Implementors act like a form-to-form mapping where entry
Expand Down
6 changes: 3 additions & 3 deletions src/novika/forms/block.cr
Original file line number Diff line number Diff line change
Expand Up @@ -968,7 +968,7 @@ module Novika
end

def opener?(name : Form) : Bool
entry_for(name).is_a?(OpenEntry)
entry_for(name).opener?
end

def pusher?(name : Form) : Bool
Expand Down Expand Up @@ -1009,7 +1009,7 @@ module Novika

# :ditto:
def at(name : String, desc = "a builtin", &code : Engine, Block ->) : self
at Word.new(name), OpenEntry.new Builtin.new(name, desc, code)
at Word.new(name), Entry.new(Builtin.new(name, desc, code), opener: true)
end

# Yields forms from left to right until the block returns `true`
Expand Down Expand Up @@ -1326,7 +1326,7 @@ module Novika
if has_dict? && !dict.empty?
io << " ·"
dict.each do |name, entry|
io << " " << (entry.is_a?(OpenEntry) ? "@" : "$") << "{" << name << " :: "
io << " " << (entry.opener? ? "@" : "$") << "{" << name << " :: "
entry.effect(io)
io << "}"
end
Expand Down
2 changes: 1 addition & 1 deletion src/novika/forms/foreign.cr
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ module Novika
# blocks work: they "inherit" their doc comment from their prototype.
fn = ForeignFunction.new(self, ffi_fn, fdecl.prototype.comment?)

this.at(opener_name, OpenEntry.new(fn))
this.at(opener_name, Entry.new(fn, opener: true))
end

def on_open(engine : Engine) : self
Expand Down
4 changes: 2 additions & 2 deletions src/novika/image.cr
Original file line number Diff line number Diff line change
Expand Up @@ -405,14 +405,14 @@ module Novika
def melt(assembler, block)
k = key.not_nil!.to_form(assembler)
v = value.not_nil!.to_form(assembler)
block.at(k, (opens ? OpenEntry : Entry).new(v))
block.at(k, Entry.new(v, opens))
end

def self.new(key : Form, entry : Entry)
frozen = new
frozen.key = TypedSnapshot.new(key)
frozen.value = TypedSnapshot.new(entry.form)
frozen.opens = entry.is_a?(OpenEntry)
frozen.opens = entry.opener?
frozen
end
end
Expand Down

0 comments on commit 54e35ec

Please sign in to comment.