Skip to content

Commit

Permalink
Merge 89f1571 into a014477
Browse files Browse the repository at this point in the history
  • Loading branch information
notEthan committed Jan 18, 2023
2 parents a014477 + 89f1571 commit ebb0ebf
Show file tree
Hide file tree
Showing 2 changed files with 51 additions and 45 deletions.
46 changes: 1 addition & 45 deletions lib/jsi/util/private.rb
Expand Up @@ -6,6 +6,7 @@ module JSI
# @api private
module Util::Private
autoload :AttrStruct, 'jsi/util/private/attr_struct'
autoload :MemoMap, 'jsi/util/private/memo_map'

EMPTY_ARY = [].freeze

Expand Down Expand Up @@ -103,51 +104,6 @@ def hash
end
end

class MemoMap
Result = AttrStruct[*%w(
value
inputs
inputs_hash
)]

class Result
end

def initialize(key_by: nil, &block)
@key_by = key_by
@block = block

# each result has its own mutex to update its memoized value thread-safely
@result_mutexes = {}
# another mutex to thread-safely initialize each result mutex
@result_mutexes_mutex = Mutex.new

@results = {}
end

def [](**inputs)
if @key_by
key = @key_by.call(**inputs)
else
key = inputs
end
result_mutex = @result_mutexes_mutex.synchronize do
@result_mutexes[key] ||= Mutex.new
end

result_mutex.synchronize do
inputs_hash = inputs.hash
if @results.key?(key) && inputs_hash == @results[key].inputs_hash && inputs == @results[key].inputs
@results[key].value
else
value = @block.call(**inputs)
@results[key] = Result.new(value: value, inputs: inputs, inputs_hash: inputs_hash)
value
end
end
end
end

module Memoize
def self.extended(object)
object.send(:jsi_initialize_memos)
Expand Down
50 changes: 50 additions & 0 deletions lib/jsi/util/private/memo_map.rb
@@ -0,0 +1,50 @@
# frozen_string_literal: true

module JSI
module Util::Private
class MemoMap
Result = AttrStruct[*%w(
value
inputs
inputs_hash
)]

class Result
end

def initialize(key_by: nil, &block)
@key_by = key_by
@block = block

# each result has its own mutex to update its memoized value thread-safely
@result_mutexes = {}
# another mutex to thread-safely initialize each result mutex
@result_mutexes_mutex = Mutex.new

@results = {}
end

def [](**inputs)
if @key_by
key = @key_by.call(**inputs)
else
key = inputs
end
result_mutex = @result_mutexes_mutex.synchronize do
@result_mutexes[key] ||= Mutex.new
end

result_mutex.synchronize do
inputs_hash = inputs.hash
if @results.key?(key) && inputs_hash == @results[key].inputs_hash && inputs == @results[key].inputs
@results[key].value
else
value = @block.call(**inputs)
@results[key] = Result.new(value: value, inputs: inputs, inputs_hash: inputs_hash)
value
end
end
end
end
end
end

0 comments on commit ebb0ebf

Please sign in to comment.