MacMemo is a simple library introducing @memoize
macro annotation for simple function memoization.
Annotated functions are wrapped with boilerplate code which uses Guava CacheBuilder
(or any other cache implementation - see 'Custom memo cache builders' section) to save
returned values for given argument list. Memoization is scoped for particular class instance.
Available for Scala 2.11 and 2.12
Example usage:
import com.softwaremill.macmemo.memoize
class GraphBuilder {
@memoize(maxSize = 20000, expiresAfter = 2 hours)
def creatGraph(elementCount: Int): Graph = {
someExpensiveCode()
}
}
Parameters (for more details see Guava docs):
- maxSize: Specifies the maximum number of entries the cache may contain.
- expiresAfter: Specifies that each entry should be automatically removed from the cache once a fixed duration has elapsed after the entry's creation, or the most recent replacement of its value.
- concurrencyLevel: Guides the allowed concurrency among update operations.
The jars are deployed to Sonatype's OSS repository. To use MacMemo in your project, add a dependency:
libraryDependencies += "com.softwaremill.macmemo" %% "macros" % "0.4"
You also need to add a special compiler plugin to your buildSettings
:
addCompilerPlugin("org.scalamacros" % "paradise" % "2.1.0" cross CrossVersion.full)
In order to disable MacMemo for tests, add following test options to your buildSettings
:
testOptions in Test += Tests.Setup(() => System.setProperty("macmemo.disable", "true"))
The print debugging information on what MacMemo does when generating code, set the
macmemo.debug
system property. E.g. with SBT, just add a System.setProperty("macmemo.debug", "")
line to your
build file.
One may want to use more sophisticated cache provider, than simple Guava Cache.
It's possible to leverage any of existing cache providers like memcached or even NoSQL databases like Redis,
by bringing appropriate implicit com.softwaremill.macmemo.MemoCacheBuilder
instance into
memoized class scope (the scope of the method definition, not it's usage, e.g: companion object, implicit val within class
or an explicit imports available in scope of class definition)
See MemoCacheBuilder.guavaMemoCacheBuilder
in macmemo/macros/src/main/scala/com/softwaremill/macmemo/MemoCacheBuilder.scala
,
macros/src/test/scala/com/softwaremill/macmemo/TestMemoCacheBuilder.scala
and
macros/src/test/scala/com/softwaremill/macmemo/examples/MemoCacheBuilderResolutionSpec.scala
for custom builder implementation and usage examples.
Whenever custom memo builder cannot be found in class definition scope, appropriate compiler info message will be emitted:
[info] /path/to/sources/SomeFancyNamedFile.scala:42: Cannot find custom memo builder for method 'someMethodName' - default builder will be used
[info] @memoize(maxSize = 2, 15 days)
[info] ^
Currently there is no way to turn them off.
Special thanks to Adam Warski for his clever MacWire library and all other inspirations :)