Support fuer Mapper-Setmethoden
Setmethoden koennen zusammen mit einem neuen Modus SETMAPPED
eingetragen werden. In diesem Fall speichert die Setmethode
den Wert nicht selber, sondern gibt ihn nur zurueck und die
Propertyverwaltung speichert den neuen Wert.
Das ermoeglicht (wiederverwendbare, generische) Funktionen
als Mapper.
Change-Id: Ief259dc4ccad9bc0e9138ab964edeb6a2b408949
diff --git a/doc/lfun/Set b/doc/lfun/Set
index d654027..bef7161 100644
--- a/doc/lfun/Set
+++ b/doc/lfun/Set
@@ -67,14 +67,29 @@
Property nicht mehr ueber SetProp() aenderbar
(damit entfallen auch SET_METHOD, _set_'name')
+
+ SETMAPPED
+
+ Die Set-Methode speichert den Werte nicht selber, sondern gibt
+ ihn zurueck, das Property-System speichert ihn dann.
+ WARNUNG: Dieses Flag nicht per Hand manipulieren.
+
F_SET_METHOD
Aendert den Eintrag fuer eine SetMethod - eine Closure, die anstatt
des Setzens der Property beim Aufruf von SetProp mit 'Value'
aufgerufen wird.
+ F_SET_MAPPER
+ Setzt wie F_SET_METHOD eine Set-Methode (Closure), welche aber den Wert
+ der Property beim Aufruf nicht selber (durch Aufruf von Set()) setzt,
+ sondern den Wert zurueckgeben muss, der gesetzt werden soll.
+ Bsp. #'copy um vor dem Speichern eine Kopie zu erstellen
F_QUERY_METHOD
Aendert den Eintrag fuer eine QueryMethod - eine Closure, die anstatt
des Lesens der Property beim Aufruf von QueryProp aufgerufen wird.
-
+ Diese bekommt den gespeicherten Wert der Property uebergeben und muss
+ den an den Aufrufer von QueryProp() zurueckzugebenden Wert
+ zurueckgeben.
+ Bsp: #'copy, um eine Kopie des gespeicherten Wertes zurueckzugeben
RUeCKGABEWERT
=============
@@ -127,9 +142,7 @@
// Loeschen des SAVE-Flags
Set(P_XYZ, SAVE, F_MODE_AD);
-
-
- // Negieren des bisherigen SAVE-Flags
+ // Negieren (Umschalten) des bisherigen SAVE-Flags
Set(P_XYZ, SAVE, F_MODE);
// Hinweis: das Setzen des Flags funktioniert mittels F_MODE nur dann,
// wenn sichergestellt ist, dass es vorher nicht gesetzt war. Die
@@ -157,6 +170,12 @@
other->Set(P_XYZ, #'bar, F_QUERY_METHOD);
...
+ // Setzen/Nutzen eines Mappers (F_SET_MAPPER) zum Skalieren
+ int scale(int val) {return val * 100;}
+ Set(P_XYZ, #'scale, F_SET_MAPPER);
+ int unscale(int val) {return val / 100;}
+ Set(P_XYZ, #'unscale, F_QUERY_METHOD);
+
// Der Vollstaendigkeit halber sei das Aendern einer Property unter
// Umgehung von Set-Methoden angegeben. Es ist aber aus o.g. Gruenden
// zu empfehlen, diese Variante nicht zu verwenden.
diff --git a/obj/tools/MGtool.c b/obj/tools/MGtool.c
index 800bcca..228e336 100644
--- a/obj/tools/MGtool.c
+++ b/obj/tools/MGtool.c
@@ -16,6 +16,7 @@
#include <driver_info.h>
#include <rtlimits.h>
#include <properties.h>
+#include <thing/properties.h>
#include <moving.h>
#include "/secure/wizlevels.h"
@@ -399,6 +400,7 @@
tmp&PROTECTED ? flags+=({"PRO"}) : flags+=({" "});
tmp&SECURED ? flags+=({"SEC"}) : flags+=({" "});
tmp&NOSETMETHOD ? flags+=({"NSM"}) : flags+=({" "});
+ tmp&SETMAPPED ? flags+=({"SMA"}) : flags+=({" "});
return ""+implode(flags,"|");
}
diff --git a/std/thing/properties.c b/std/thing/properties.c
index 2864a2c..d289de1 100644
--- a/std/thing/properties.c
+++ b/std/thing/properties.c
@@ -108,7 +108,16 @@
case F_MODE: prop[F_MODE][name]^= Value;
if (!prop[F_MODE][name]) prop[F_MODE]-=([name]);
return prop[F_MODE][name];
+
+ // Query- und Setmethoden laufen ab hier durch.
case F_SET_METHOD:
+ case F_SET_MAPPER:
+ // SETMAPPED passend setzen
+ if (Type==F_SET_METHOD)
+ prop[F_MODE][name] &= ~SETMAPPED;
+ else
+ prop[F_MODE][name] |= SETMAPPED;
+ // Ab hier alles gleich
// -1 als Setz-Methode: Nosetmethod setzen
if (Value == -1)
{
@@ -116,7 +125,7 @@
prop[F_MODE][name] |= NOSETMETHOD;
return 0;
}
- // Kein break!
+ // Kein break! Rest wie Querymethod
case F_QUERY_METHOD:
// Ungebundene Lambda_Closure? Heutzutage ein Fehler.
if (closurep(Value) && !query_closure_object(Value))
@@ -148,8 +157,9 @@
{
mixed result;
+ int mode = prop[F_MODE][name];
// NOSETMETHOD: Darf nicht gesetzt werden
- if (prop[F_MODE][name] & NOSETMETHOD ) return -1;
+ if (mode & NOSETMETHOD ) return -1;
// Set-Method abfragen, so vorhanden
// TODO: nachdem alle moeglichen Werte als Set-Methode illegal sind, auf
@@ -174,6 +184,11 @@
{
prop[F_SET_METHOD]-=([name]);
}
+ else // Erfolgreicher call
+ {
+ if (mode & SETMAPPED) // SM hat noch nicht selber gesetzt
+ result = Set( name, result, F_VALUE, extern||extern_call() );
+ }
// Wenn dieser Aufruf closure_call gesetzt hat, wieder loeschen.
// Da 0 ein gueltiger Wert ist, wird um eins dekrementiert, damit das Flag
@@ -181,7 +196,7 @@
if (set_closure_call) --closure_call;
// Und zurueckgeben
- return result;
+ return result;
}
// _set_*-Methode vorhanden? falls ja, aufrufen.
diff --git a/sys/thing/properties.h b/sys/thing/properties.h
index c472af5..be7a6cd 100644
--- a/sys/thing/properties.h
+++ b/sys/thing/properties.h
@@ -13,6 +13,12 @@
#define F_SET_METHOD 2
#define F_QUERY_METHOD 3
+// The following are used as type flags for Set(), but they do not index
+// <prop>, therfore they have a negative sign.
+//
+// F_SET_MAPPER sets F_SET_METHOD, but additionally sets the mode SETMAPPED
+// automatically
+#define F_SET_MAPPER -F_SET_METHOD
// Flags for Set() to modify/manipulate F_MODE of a property in bit-wise
// manner
#define F_MODE_AS 4
@@ -23,6 +29,7 @@
#define PROTECTED 128 // only this_object() can change the values
#define SECURED 256 // like PROTECTED, but never resetable
#define NOSETMETHOD 512 // Keine Set-Methode => Nicht mofifizierbar
+#define SETMAPPED 0x4000 // Setmethod only maps, not sets
// Problem with the following: shadows, default methods etc. may change the
// result at runtime and they do not save that much time (or even at all?)
// because of the apply cache of the driver. Not used since 1995. But