[svn] r6193: nemerle/trunk/macros/Memoize.n
d
svnadmin at nemerle.org
Wed Apr 19 16:26:53 CEST 2006
Log:
Add full memoization support.
Author: d
Date: Wed Apr 19 16:26:52 2006
New Revision: 6193
Modified:
nemerle/trunk/macros/Memoize.n
Modified: nemerle/trunk/macros/Memoize.n
==============================================================================
--- nemerle/trunk/macros/Memoize.n (original)
+++ nemerle/trunk/macros/Memoize.n Wed Apr 19 16:26:52 2006
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2005 The University of Wroclaw.
+ * Copyright (c) 2006 The University of Wroclaw.
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -27,60 +27,86 @@
*/
+
using Nemerle.Collections;
using Nemerle.Compiler;
using Nemerle.Compiler.Parsetree;
-
namespace Nemerle
{
+ /**
+ * This macro implements memoization (with the default option Scope = Instance),
+ * as well as something closer to aggressive sharing, when Scope = Class is used.
+ * A Synchronized = true | false option is also available, to set thread safety.
+ */
[Nemerle.MacroUsage (Nemerle.MacroPhase.WithTypedMembers,
Nemerle.MacroTargets.Method)]
- macro Memoize (tb : TypeBuilder, meth : MethodBuilder, params opts : list [PExpr])
- {
- def _is_static = meth.IsStatic;
- mutable invalid = null;
- mutable invalid_is_null = false;
- mutable synch = true;
-
+ macro Memoize (tb : TypeBuilder, meth : MethodBuilder, params opts : list [PExpr]) {
+ mutable scope = "Instance";
+ mutable synch = false;
foreach (o in opts) {
- | <[ InvalidValue = null ]> =>
- invalid = <[ null ]>;
- invalid_is_null = true;
-
- | <[ InvalidValue = $expr ]> =>
- when (invalid != null) Message.Error ("invalid value specified more than once");
- invalid = expr;
-
- | <[ Synchronized = $(x : bool) ]> =>
- synch = x;
-
- | _ => Message.Error ($"unrecognized parameter: $o")
+ | <[ Scope = Instance ]> => scope = "Instance"
+ | <[ Scope = Class ]> => scope = "Class"
+ | <[ Scope = $other ]> =>
+ Message.Error ($"Invalid parameter: Scope = $other. Valid options are Instance (default) and Class.")
+ | <[ Synchronized = $(opt : bool) ]> => synch = opt
+ | <[ Synchronized = $other ]> =>
+ Message.Error ($"Invalid parameter: Synchronized = $other. Valid options are true and false (default).")
+ | _ => () // for backwards compatibility
}
-
- def store = Macros.NewSymbol ("storage");
- def is_cached =
- if (invalid == null) {
- def x = Macros.NewSymbol ("is_cached");
- tb.Define (<[ decl: private mutable $(x : name) : bool; ]>);
- <[ $(x : name) ]>
+ def parms = meth.GetParameters ();
+ match (parms) {
+ | [] =>
+ def cached_value = Macros.NewSymbol ("cached_value");
+ def is_cached = Macros.NewSymbol ("is_cached");
+ match (scope) {
+ | "Instance" =>
+ tb.Define (<[ decl: mutable $(cached_value : name) : $(meth.ReturnType : typed); ]>);
+ tb.Define (<[ decl: mutable $(is_cached : name) : bool; ]>)
+ | "Class" =>
+ tb.Define (<[ decl: static mutable $(cached_value : name) : $(meth.ReturnType : typed); ]>);
+ tb.Define (<[ decl: static mutable $(is_cached : name) : bool; ]>)
+ | _ => () // unreachable
}
- else
- <[ $(store : name) != $invalid ]>;
-
- if (invalid != null && ! invalid_is_null)
- tb.Define (<[ decl: private mutable $(store : name) : $(meth.ReturnType : typed) = $invalid; ]>);
- else
- tb.Define (<[ decl: private mutable $(store : name) : $(meth.ReturnType : typed); ]>);
-
meth.Body = <[
- if ($is_cached)
- $(store : name)
- else {
- $(store : name) = $(meth.Body);
- $(if (invalid == null) <[ $is_cached = true ]> else <[ () ]>);
- $(store : name)
+ when (! $(is_cached : name)) {
+ $(cached_value : name) = $(meth.Body);
+ $(is_cached : name) = true;
}
+ $(cached_value : name)
]>
+ | (prm :: _) =>
+ def cache = Macros.NewSymbol ("cache");
+ match (MType.ConstructFunctionType (meth.GetHeader ())) {
+ | Fun (t1, t2) =>
+ match (scope) {
+ | "Instance" => tb.Define (<[ decl: mutable $(cache : name) : Hashtable [$(t1 : typed), $(t2 : typed)]; ]>);
+ | "Class" => tb.Define (<[ decl: static mutable $(cache : name) : Hashtable [$(t1 : typed), $(t2 : typed)]; ]>);
+ | _ => () // unreachable
+ }
+ | _ => Message.Error ("This code should not be reached.")
+ }
+ def parm_values = if (parms.Length > 1)
+ <[ (.. $(List.Map (parms, fun (p) { <[ $(p.name : usesite) ]> })) )]>
+ else
+ <[ $(prm.name : usesite) ]>;
+ meth.Body = <[
+ when ($(cache : name) == null)
+ // Can't this initialization by done without the additional check each time ?
+ $(cache : name) = Hashtable ();
+
+ match ($(cache : name).Get ($parm_values)) {
+ | Some (ret) => ret
+ | None =>
+ def ret = $(meth.Body);
+ // Does that code make sense ?;] I've never used threading stuff before..
+ $(if (synch)
+ <[ lock ($(cache : name)) { $(cache : name).Add ($parm_values, ret) } ]>
+ else
+ <[ $(cache : name).Add ($parm_values, ret) ]>);
+ ret
+ }
+ ]>;
+ }
}
}
More information about the svn
mailing list