Skip to content

Commit

Permalink
Implements memoization using instance variables per method
Browse files Browse the repository at this point in the history
Resolves #243
  • Loading branch information
jemmaissroff committed Dec 9, 2021
1 parent a97cd40 commit 7599f30
Show file tree
Hide file tree
Showing 2 changed files with 25 additions and 15 deletions.
31 changes: 16 additions & 15 deletions lib/memo_wise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -200,7 +200,7 @@ def #{method_name}

klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
_memo_wise_hash = (@_memo_wise[#{index}] ||= {})
_memo_wise_hash = (#{MemoWise::InternalAPI.method_name_to_sym(klass, method_name)} ||= {})
_memo_wise_output = _memo_wise_hash[#{key}]
if _memo_wise_output || _memo_wise_hash.key?(#{key})
_memo_wise_output
Expand All @@ -226,7 +226,7 @@ def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
# faster than `Hash#fetch`.
klass.module_eval <<~HEREDOC, __FILE__, __LINE__ + 1
def #{method_name}(#{MemoWise::InternalAPI.args_str(method)})
_memo_wise_hash = (@_memo_wise[#{index}] ||= {})
_memo_wise_hash = (#{MemoWise::InternalAPI.method_name_to_sym(klass, method_name)} ||= {})
_memo_wise_key = #{MemoWise::InternalAPI.key_str(method)}
_memo_wise_output = _memo_wise_hash[_memo_wise_key]
if _memo_wise_output || _memo_wise_hash.key?(_memo_wise_key)
Expand Down Expand Up @@ -453,7 +453,7 @@ def preset_memo_wise(method_name, *args, **kwargs)
return
end

hash = (@_memo_wise[index] ||= {})
hash = MemoWise::InternalAPI.memo_wise_hash(self, method_name)

case method_arguments
when MemoWise::InternalAPI::ONE_REQUIRED_POSITIONAL then hash[args.first] = yield
Expand Down Expand Up @@ -540,8 +540,8 @@ def reset_memo_wise(method_name = nil, *args, **kwargs)
raise ArgumentError, "Provided args when method_name = nil" unless args.empty?
raise ArgumentError, "Provided kwargs when method_name = nil" unless kwargs.empty?

@_memo_wise.clear
@_memo_wise_sentinels.clear
# Clear any instance variables created by memo_wise
instance_variables.select { _1.to_s.start_with?("@_memo_wise") }.map { eval("#{_1}.clear") }
return
end

Expand All @@ -554,38 +554,39 @@ def reset_memo_wise(method_name = nil, *args, **kwargs)
method = method(method_name)
method_arguments = MemoWise::InternalAPI.method_arguments(method)
index = api.index(method_name)
memo_wise_hash = MemoWise::InternalAPI.memo_wise_hash(self, method_name)

case method_arguments
when MemoWise::InternalAPI::NONE
@_memo_wise_sentinels[index] = nil
@_memo_wise[index] = nil
when MemoWise::InternalAPI::ONE_REQUIRED_POSITIONAL
if args.empty?
@_memo_wise[index]&.clear
memo_wise_hash&.clear
else
@_memo_wise[index]&.delete(args.first)
memo_wise_hash&.delete(args.first)
end
when MemoWise::InternalAPI::ONE_REQUIRED_KEYWORD
if kwargs.empty?
@_memo_wise[index]&.clear
memo_wise_hash&.clear
else
@_memo_wise[index]&.delete(kwargs.first.last)
memo_wise_hash&.delete(kwargs.first.last)
end
when MemoWise::InternalAPI::SPLAT
if args.empty?
@_memo_wise[index]&.clear
memo_wise_hash&.clear
else
@_memo_wise[index]&.delete(args)
memo_wise_hash&.delete(args)
end
when MemoWise::InternalAPI::DOUBLE_SPLAT
if kwargs.empty?
@_memo_wise[index]&.clear
memo_wise_hash&.clear
else
@_memo_wise[index]&.delete(kwargs)
memo_wise_hash&.delete(kwargs)
end
else # MemoWise::InternalAPI::MULTIPLE_REQUIRED, MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
if args.empty? && kwargs.empty?
@_memo_wise[index]&.clear
memo_wise_hash&.clear
else
key = if method_arguments == MemoWise::InternalAPI::SPLAT_AND_DOUBLE_SPLAT
[args, kwargs]
Expand All @@ -594,7 +595,7 @@ def reset_memo_wise(method_name = nil, *args, **kwargs)
type == :req ? args[i] : kwargs[name] # rubocop:disable Metrics/BlockNesting
end
end
@_memo_wise[index]&.delete(key)
memo_wise_hash&.delete(key)
end
end
end
Expand Down
9 changes: 9 additions & 0 deletions lib/memo_wise/internal_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,15 @@ def validate_memo_wised!(method_name)
end
end

def self.memo_wise_hash(klass, method_name)
klass.instance_variable_get(method_name_to_sym(klass, method_name)) ||
klass.instance_variable_set(method_name_to_sym(klass, method_name), {})
end

def self.method_name_to_sym(klass, method_name)
"@_memo_wise_#{method_name}".gsub("?", "__q__").to_sym
end

private

# @return [Class] where we look for method definitions
Expand Down

0 comments on commit 7599f30

Please sign in to comment.