cache.fz
# This file is part of the Fuzion language implementation.
#
# The Fuzion language implementation is free software: you can redistribute it
# and/or modify it under the terms of the GNU General Public License as published
# by the Free Software Foundation, version 3 of the License.
#
# The Fuzion language implementation is distributed in the hope that it will be
# useful, but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
# License for more details.
#
# You should have received a copy of the GNU General Public License along with The
# Fuzion language implementation. If not, see <https://www.gnu.org/licenses/>.
# -----------------------------------------------------------------------
#
# Tokiwa Software GmbH, Germany
#
# Source code of Fuzion standard library feature cache
#
# Author: Michael Lill (michael.lill@tokiwa.software)
#
# -----------------------------------------------------------------------
# cache result of f for cache key T
#
# This is best explained by the following example:
#
# ex_cache is
# # here we define the cache keys by which the results of the function will
# # be cached in the global cache
# cache_key(val sorted_array i32) is
# # ^-------- the actual type we want to cache
# # ^------- a feature declaring a type which we use as a cache key
# # wrapping the actual data we want to cache
# cache_kex(val i32) is
# # similarly, here, i32 => the actual type we want to cache and cache_kex
# # is the wrapping cache key
#
# # suppose now, that we have two functions fn and fm, which take no arguments but
# # which need a very long time for their calculations.
#
# fn Function cache_key := (() ->
# time.nano.sleep (time.durations.seconds 2)
# cache_key (sorted_array_of [6,4,1,9]))
#
# fm Function cache_kex := (() ->
# time.nano.sleep (time.durations.seconds 3)
# cache_kex 42)
#
# # we define two more wrappers, which will actually call the functions if
# # their value is not in the cache, or return the stored value if already
# # computed
# from_cache => (cache cache_key fn).val
# # ^--- will only be computed the first time we run from_cache
# from_cachf => (cache cache_kex fm).val
#
# say from_cache # will take two seconds
# say from_cache # will take virtually no time
# say from_cachf # will take three seconds
# say from_cache # will take virtually no time
# say from_cachf # will take virtually no time
# say from_cachf # will take virtually no time
#
# The cache implemented works on a global level.
#
public cache(T type, f () -> T) T =>
# use wrapper type because we do not want to prevent
# the use of `state` for type T
cache_item(val T) is
if !(effect.is_installed (state unit cache_item))
_ := state unit cache_item unit (cache_item f()) effect_mode.default
state_get cache_item
.val
last changed: 2024-03-07