Module: Nanoc::Int::Memoization Private

Included in:
OutdatednessChecker, PluginRegistry, RuleDSL::RuleMemoryCalculator
Defined in:
lib/nanoc/base/memoization.rb

Overview

This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.

Adds support for memoizing functions.

Since:

  • 3.2.0

Defined Under Namespace

Classes: Value, Wrapper

Constant Summary collapse

NONE =

This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.

Since:

  • 3.2.0

Object.new

Instance Method Summary collapse

Instance Method Details

#memoize(method_name) ⇒ void

This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.

This method returns an undefined value.

Memoizes the method with the given name. The modified method will cache the results of the original method, so that calling a method twice with the same arguments will short-circuit and return the cached results immediately.

Memoization assumes that the current object as well as the function arguments are immutable. Mutating the object or the arguments will not cause memoized methods to recalculate their results. There is no way to un-memoize a result, and calculation results will remain in memory even if they are no longer needed.

Examples:

A fast fib function due to memoization


class FibFast

  extend Nanoc::Int::Memoization

  def run(n)
    if n == 0
      0
    elsif n == 1
      1
    else
      run(n-1) + run(n-2)
    end
  end
  memoize :run

end

Parameters:

  • method_name (Symbol, String)

    The name of the method to memoize

Since:

  • 3.2.0



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# File 'lib/nanoc/base/memoization.rb', line 70

def memoize(method_name)
  original_method_name = '__nonmemoized_' + method_name.to_s
  alias_method original_method_name, method_name

  define_method(method_name) do |*args|
    @__memoization_cache ||= {}
    @__memoization_cache[method_name] ||= {}
    method_cache = @__memoization_cache[method_name]

    value = NONE
    if method_cache.key?(args)
      object = method_cache[args].ref.object
      value = object ? object.value : NONE
    end

    if value.equal?(NONE)
      send(original_method_name, *args).tap do |r|
        method_cache[args] = Wrapper.new(Ref::SoftReference.new(Value.new(r)))
      end
    else
      value
    end
  end
end