/*#io
Map ioDoc(
docCopyright("Steve Dekorte", 2002)
docLicense("BSD revised")
docObject("Map")
docDescription("A key/value dictionary appropriate for holding large key/value collections.")
docCategory("DataStructures")
*/
#include "IoMap.h"
#include "IoObject.h"
#include "IoState.h"
#include "IoCFunction.h"
#include "IoSeq.h"
#include "IoState.h"
#include "IoNumber.h"
#include "IoList.h"
#include "IoBlock.h"
#define HASHIVAR(self) ((Hash *)IoObject_dataPointer(self))
IoTag *IoMap_tag(void *state)
{
IoTag *tag = IoTag_newWithName_("Map");
tag->state = state;
tag->freeFunc = (TagFreeFunc *)IoMap_free;
tag->cloneFunc = (TagCloneFunc *)IoMap_rawClone;
tag->markFunc = (TagMarkFunc *)IoMap_mark;
tag->writeToStoreOnStreamFunc = (TagWriteToStoreOnStreamFunc *)IoMap_writeToStore_stream_;
tag->readFromStoreOnStreamFunc = (TagReadFromStoreOnStreamFunc *)IoMap_readFromStore_stream_;
return tag;
}
void IoMap_writeToStore_stream_(IoMap *self, IoStore *store, BStream *stream)
{
Hash *hash = HASHIVAR(self);
IoObject *k = Hash_firstKey(hash);
while (k)
{
IoObject *v = (IoObject *)Hash_at_(hash, k);
BStream_writeTaggedInt32_(stream, IoStore_pidForObject_(store, k));
BStream_writeTaggedInt32_(stream, IoStore_pidForObject_(store, v));
k = Hash_nextKey(hash);
}
BStream_writeTaggedInt32_(stream, 0);
}
void IoMap_readFromStore_stream_(IoMap *self, IoStore *store, BStream *stream)
{
Hash *hash = HASHIVAR(self);
for (;;)
{
int k, v;
k = BStream_readTaggedInt32(stream);
if (k == 0)
{
break;
}
v = BStream_readTaggedInt32(stream);
Hash_at_put_(hash, IoStore_objectWithPid_(store, k), IoStore_objectWithPid_(store, v));
}
}
IoMap *IoMap_proto(void *state)
{
IoMethodTable methodTable[] = {
{"empty", IoMap_empty},
{"at", IoMap_at},
{"atPut", IoMap_atPut},
{"atIfAbsentPut", IoMap_atIfAbsentPut},
{"size", IoMap_size},
{"keys", IoMap_keys},
{"values", IoMap_values},
{"foreach", IoMap_foreach},
{"hasKey", IoMap_hasKey},
{"hasValue", IoMap_hasValue},
{"removeAt", IoMap_removeAt},
{NULL, NULL},
};
IoObject *self = IoObject_new(state);
self->tag = IoMap_tag(state);
IoObject_setDataPointer_(self, Hash_new());
IoState_registerProtoWithFunc_((IoState *)state, self, IoMap_proto);
IoObject_addMethodTable_(self, methodTable);
return self;
}
IoMap *IoMap_rawClone(IoMap *proto)
{
IoObject *self = IoObject_rawClonePrimitive(proto);
IoObject_setDataPointer_(self, Hash_clone(HASHIVAR(proto)));
return self;
}
IoMap *IoMap_new(void *state)
{
IoObject *proto = IoState_protoWithInitFunction_((IoState *)state, IoMap_proto);
return IOCLONE(proto);
}
void IoMap_free(IoMap *self)
{
Hash_free(HASHIVAR(self));
}
void IoMap_mark(IoMap *self)
{
Hash_doOnKeyAndValue_(HASHIVAR(self), (ListDoCallback *)IoObject_shouldMark);
}
void IoMap_rawAtPut(IoMap *self, IoSymbol *k, IoObject *v)
{
Hash_at_put_(HASHIVAR(self), IOREF(k), IOREF(v));
}
Hash *IoMap_rawHash(IoMap *self)
{
return HASHIVAR(self);
}
// -----------------------------------------------------------
IoObject *IoMap_empty(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("empty", "Removes all keys from the receiver. Returns self.")
*/
Hash_clean(HASHIVAR(self));
return self;
}
IoObject *IoMap_rawAt(IoMap *self, IoSymbol *k)
{
return Hash_at_(HASHIVAR(self), k);
}
IoObject *IoMap_at(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("at(keyString, optionalDefaultValue)",
"Returns the value for the key keyString. Returns nil if the key is absent. ")
*/
IoSymbol *k = IoMessage_locals_symbolArgAt_(m, locals, 0);
void *result = Hash_at_(HASHIVAR(self), k);
if (!result && IoMessage_argCount(m) > 1)
{
return IoMessage_locals_valueArgAt_(m, locals, 1);
}
return (result) ? result : IONIL(self);
}
IoObject *IoMap_atPut(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("atPut(keyString, aValue)",
"Inserts/sets aValue with the key keyString. Returns self. ")
*/
IoSymbol *k = IoMessage_locals_symbolArgAt_(m, locals, 0);
IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 1);
IoMap_rawAtPut(self, k, v);
return self;
}
IoObject *IoMap_atIfAbsentPut(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("atIfAbsentPut(keyString, aValue)",
"Inserts/sets aValue with the key keyString if the
key is not already present. Returns self. ")
*/
IoSymbol *k = IoMessage_locals_symbolArgAt_(m, locals, 0);
if (Hash_at_(HASHIVAR(self), k) == NULL)
{
IoObject *v = IoMessage_locals_valueArgAt_(m, locals, 1);
IoMap_rawAtPut(self, k, v);
}
return self;
}
IoObject *IoMap_size(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("size",
"Returns the number of key/value pairs in the receiver.")
*/
return IONUMBER(Hash_count(HASHIVAR(self)));
}
IoObject *IoMap_hasKey(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("hasKey(keyString)",
"Returns true if the key is present or false otherwise.")
*/
IoSymbol *k = IoMessage_locals_symbolArgAt_(m, locals, 0);
return IOBOOL(self, Hash_at_(HASHIVAR(self), k) != NULL);
}
IoObject *IoMap_removeAt(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("removeAt(keyString)",
"Removes the specified keyString if present. Returns self. ")
*/
IoSymbol *k = IoMessage_locals_symbolArgAt_(m, locals, 0);
Hash_removeKey_(HASHIVAR(self), k);
return self;
}
IoObject *IoMap_hasValue(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("hasValue(aValue)",
"Returns true if the value is one of the Map's values or false otherwise.")
*/
IoList *values = IoMap_values(self, locals, m);
return IoList_contains(values, locals, m);
}
IoList *IoMap_rawKeys(IoMap *self)
{
IoList *list = IoList_new(IOSTATE);
IoObject *key = (IoObject *)Hash_firstKey(HASHIVAR(self));
while (key)
{
IoList_rawAppend_(list, key);
key = Hash_nextKey(HASHIVAR(self));
}
return list;
}
IoList *IoMap_keys(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("keys", "Returns a List of the receivers keys.")
*/
return IoMap_rawKeys(self);
}
IoObject *IoMap_values(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("values",
"Returns a List of the receivers values.")
*/
IoList *list = IoList_new(IOSTATE);
IoObject *key = (IoObject *)Hash_firstKey(HASHIVAR(self));
while (key)
{
IoList_rawAppend_(list, (IoObject *)Hash_at_(HASHIVAR(self), key));
key = Hash_nextKey(HASHIVAR(self));
}
return list;
}
IoObject *IoMap_foreach(IoMap *self, IoObject *locals, IoMessage *m)
{
/*#io
docSlot("foreach(optionalKey, value, message)",
"""For each key value pair, sets the locals key to
the key and value to the value and executes message.
Example:
<pre>aMap foreach(k, v, writeln(k, " = ", v))
aMap foreach(v, write(v))</pre>
Example use with a block:
<pre>myBlock = block(k, v, write(k, " = ", v, "\n"))
aMap foreach(k, v, myBlock(k, v))</pre>""")
*/
IoState *state = IOSTATE;
IoSymbol *keyName, *valueName;
IoMessage *doMessage;
IoObject *key = (IoObject *)Hash_firstKey(HASHIVAR(self));
IoObject *result = IONIL(self);
IoMessage_foreachArgs(m, self, &keyName, &valueName, &doMessage);
IoState_pushRetainPool(state);
while (key)
{
IoState_clearTopPool(state);
{
IoObject *value = (IoObject *)Hash_at_(HASHIVAR(self), key);
if (keyName)
{
IoObject_setSlot_to_(locals, keyName, key);
}
IoObject_setSlot_to_(locals, valueName, value);
IoMessage_locals_performOn_(doMessage, locals, locals);
key = Hash_nextKey(HASHIVAR(self));
if (IoState_handleStatus(IOSTATE))
{
goto done;
}
}
}
done:
IoState_popRetainPoolExceptFor_(state, result);
return result;
}
syntax highlighted by Code2HTML, v. 0.9.1