mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-25 17:51:01 +00:00
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@4853 72102866-910b-0410-8b05-ffd578937521
453 lines
11 KiB
Objective-C
453 lines
11 KiB
Objective-C
/* NSMapTable implementation for GNUStep.
|
|
* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
|
*
|
|
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
|
* Created: Mon Dec 12 23:59:57 EST 1994
|
|
* Updated: Sun Mar 17 18:37:12 EST 1996
|
|
* Serial: 96.03.17.31
|
|
*
|
|
* This file is part of the GNUstep Base Library.
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library 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
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the Free
|
|
* Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111 USA. */
|
|
|
|
/**** Included Headers *******************************************************/
|
|
|
|
#include <config.h>
|
|
#include <Foundation/NSObject.h>
|
|
#include <Foundation/NSString.h>
|
|
#include <Foundation/NSArray.h>
|
|
#include <Foundation/NSException.h>
|
|
#include <Foundation/NSZone.h>
|
|
#include <Foundation/NSMapTable.h>
|
|
#include <base/o_map.h>
|
|
#include "NSCallBacks.h"
|
|
|
|
/** Dummy callbacks... **/
|
|
|
|
size_t
|
|
_NSMT_key_hash (const void *element, const void *table)
|
|
{
|
|
return NSMT_KEY_CALLBACKS(table).hash((NSMapTable *)table,
|
|
element);
|
|
}
|
|
|
|
int
|
|
_NSMT_key_compare (const void *element1, const void *element2,
|
|
const void *table)
|
|
{
|
|
return !(NSMT_KEY_CALLBACKS(table).isEqual((NSMapTable *)table,
|
|
element1,
|
|
element2));
|
|
}
|
|
|
|
int
|
|
_NSMT_key_is_equal (const void *element1, const void *element2,
|
|
const void *table)
|
|
{
|
|
return NSMT_KEY_CALLBACKS(table).isEqual((NSMapTable *) table,
|
|
element1,
|
|
element2);
|
|
}
|
|
|
|
void *
|
|
_NSMT_key_retain (const void *element, const void *table)
|
|
{
|
|
NSMT_KEY_CALLBACKS(table).retain((NSMapTable *)table, element);
|
|
return (void*) element;
|
|
}
|
|
|
|
void
|
|
_NSMT_key_release (void *element, void *table)
|
|
{
|
|
NSMT_KEY_CALLBACKS(table).release ((NSMapTable*)table, element);
|
|
return;
|
|
}
|
|
|
|
NSString *
|
|
_NSMT_key_describe(const void *element, void *table)
|
|
{
|
|
return nil;
|
|
}
|
|
|
|
void *
|
|
_NSMT_value_retain (const void *element, const void *table)
|
|
{
|
|
NSMT_VALUE_CALLBACKS(table).retain((NSMapTable *)table, element);
|
|
return (void *) element;
|
|
}
|
|
|
|
void
|
|
_NSMT_value_release (void *element, const void *table)
|
|
{
|
|
NSMT_VALUE_CALLBACKS(table).release((NSMapTable *)table, element);
|
|
return;
|
|
}
|
|
|
|
NSString *
|
|
_NSMT_value_describe(const void *element, const void *table)
|
|
{
|
|
/* FIXME: Code this. */
|
|
return nil;
|
|
}
|
|
|
|
/* These are wrappers for getting at the real callbacks. */
|
|
o_callbacks_t _NSMT_key_callbacks =
|
|
{
|
|
(o_hash_func_t) _NSMT_key_hash,
|
|
(o_compare_func_t) _NSMT_key_compare,
|
|
(o_is_equal_func_t) _NSMT_key_is_equal,
|
|
(o_retain_func_t) _NSMT_key_retain,
|
|
(o_release_func_t) _NSMT_key_release,
|
|
(o_describe_func_t) _NSMT_key_describe,
|
|
0 /* This gets changed...See just below. */
|
|
};
|
|
|
|
static inline o_callbacks_t
|
|
_NSMT_callbacks_for_key_callbacks(NSMapTableKeyCallBacks keyCallBacks)
|
|
{
|
|
o_callbacks_t cbs = _NSMT_key_callbacks;
|
|
|
|
cbs.not_an_item_marker = keyCallBacks.notAKeyMarker;
|
|
|
|
return cbs;
|
|
}
|
|
|
|
o_callbacks_t _NSMT_value_callbacks =
|
|
{
|
|
(o_hash_func_t) o_non_owned_void_p_hash,
|
|
(o_compare_func_t) o_non_owned_void_p_compare,
|
|
(o_is_equal_func_t) o_non_owned_void_p_is_equal,
|
|
(o_retain_func_t) _NSMT_value_retain,
|
|
(o_release_func_t) _NSMT_value_release,
|
|
(o_describe_func_t) _NSMT_value_describe,
|
|
0 /* Not needed, really, for OpenStep...And so, ignored here. */
|
|
};
|
|
|
|
/** Extra, extra **/
|
|
|
|
/* Make a copy of a hash table's callbacks. */
|
|
const void *
|
|
_NSMT_extra_retain(_NSMT_extra_t *extra, NSMapTable *table)
|
|
{
|
|
/* A pointer to some space for new callbacks. */
|
|
_NSMT_extra_t *new_extra;
|
|
|
|
/* Set aside space for our new callbacks in the right zone. */
|
|
new_extra = (_NSMT_extra_t *)NSZoneMalloc(o_map_zone(table),
|
|
sizeof(_NSMT_extra_t));
|
|
|
|
/* Copy the old callbacks into NEW_EXTRA. */
|
|
*new_extra = *extra;
|
|
|
|
/* Return our new EXTRA. */
|
|
return new_extra;
|
|
}
|
|
|
|
void
|
|
_NSMT_extra_release(void *extra, NSMapTable *table)
|
|
{
|
|
if (extra != 0)
|
|
NSZoneFree(o_map_zone(table), extra);
|
|
|
|
return;
|
|
}
|
|
|
|
NSString *
|
|
_NSMT_extra_describe(const void *extra, NSMapTable *table)
|
|
{
|
|
/* FIXME: Code this. */
|
|
return nil;
|
|
}
|
|
|
|
/* The basic idea here is that these callbacks ensure that the
|
|
* NSMapTable...Callbacks which are associated with a given NSMapTable
|
|
* remain so throughout the life of the table and its copies. */
|
|
o_callbacks_t _NSMT_extra_callbacks =
|
|
{
|
|
(o_hash_func_t) o_non_owned_void_p_hash,
|
|
(o_compare_func_t) o_non_owned_void_p_compare,
|
|
(o_is_equal_func_t) o_non_owned_void_p_is_equal,
|
|
(o_retain_func_t) _NSMT_extra_retain,
|
|
(o_release_func_t)_NSMT_extra_release,
|
|
(o_describe_func_t)_NSMT_extra_describe,
|
|
0
|
|
};
|
|
|
|
/**** Function Implementations ****/
|
|
|
|
/** Creating an NSMapTable **/
|
|
|
|
inline NSMapTable *
|
|
NSCreateMapTableWithZone(NSMapTableKeyCallBacks keyCallBacks,
|
|
NSMapTableValueCallBacks valueCallBacks,
|
|
unsigned capacity,
|
|
NSZone *zone)
|
|
{
|
|
NSMapTable *table;
|
|
o_callbacks_t key_callbacks, value_callbacks;
|
|
|
|
/* Transform the callbacks we were given. */
|
|
key_callbacks = _NSMT_callbacks_for_key_callbacks(keyCallBacks);
|
|
value_callbacks = _NSMT_value_callbacks;
|
|
|
|
/* Create a map table. */
|
|
table = o_map_with_zone_with_callbacks(zone, key_callbacks,
|
|
value_callbacks);
|
|
|
|
/* Adjust the capacity of TABLE. */
|
|
o_map_resize(table, capacity);
|
|
|
|
if (table != 0)
|
|
{
|
|
_NSMT_extra_t extra;
|
|
|
|
/* Set aside space for TABLE's extra. */
|
|
extra.keyCallBacks = keyCallBacks;
|
|
extra.valueCallBacks = valueCallBacks;
|
|
|
|
/* These callbacks are defined above. */
|
|
o_map_set_extra_callbacks(table, _NSMT_extra_callbacks);
|
|
|
|
/* We send a pointer because that's all the room we have.
|
|
* The callbacks make a copy of these extras, so we needn't
|
|
* worry about the way they disappear real soon now. */
|
|
o_map_set_extra(table, &extra);
|
|
}
|
|
|
|
return table;
|
|
}
|
|
|
|
NSMapTable *
|
|
NSCreateMapTable(NSMapTableKeyCallBacks keyCallBacks,
|
|
NSMapTableValueCallBacks valueCallBacks,
|
|
unsigned int capacity)
|
|
{
|
|
return NSCreateMapTableWithZone(keyCallBacks, valueCallBacks,
|
|
capacity, NSDefaultMallocZone());
|
|
}
|
|
|
|
NSMapTable *
|
|
NSCopyMapTableWithZone(NSMapTable *table, NSZone *zone)
|
|
{
|
|
NSMapTable *new_table;
|
|
|
|
new_table = o_map_copy_with_zone(table, zone);
|
|
|
|
return new_table;
|
|
}
|
|
|
|
/** Freeing an NSMapTable **/
|
|
|
|
void
|
|
NSFreeMapTable(NSMapTable *table)
|
|
{
|
|
o_map_dealloc(table);
|
|
return;
|
|
}
|
|
|
|
void
|
|
NSResetMapTable(NSMapTable *table)
|
|
{
|
|
o_map_empty(table);
|
|
return;
|
|
}
|
|
|
|
/** Comparing two NSMapTables... **/
|
|
|
|
BOOL
|
|
NSCompareMapTables(NSMapTable *table1, NSMapTable *table2)
|
|
{
|
|
return o_map_is_equal_to_map(table1, table2) ? YES : NO;
|
|
}
|
|
|
|
/** Getting the number of items in an NSMapTable **/
|
|
|
|
unsigned int
|
|
NSCountMapTable(NSMapTable *table)
|
|
{
|
|
return (unsigned int) o_map_count(table);
|
|
}
|
|
|
|
/** Retrieving items from an NSMapTable **/
|
|
|
|
BOOL
|
|
NSMapMember(NSMapTable *table, const void *key,
|
|
void **originalKey, void **value)
|
|
{
|
|
int i;
|
|
|
|
/* Check for K in TABLE. */
|
|
i = o_map_key_and_value_at_key(table, (const void **)originalKey,
|
|
(const void **)value, key);
|
|
|
|
/* Indicate our state of success. */
|
|
return i ? YES : NO;
|
|
}
|
|
|
|
void *
|
|
NSMapGet(NSMapTable *table, const void *key)
|
|
{
|
|
return (void *) o_map_value_at_key(table, key);
|
|
}
|
|
|
|
NSMapEnumerator
|
|
NSEnumerateMapTable(NSMapTable *table)
|
|
{
|
|
return o_map_enumerator_for_map(table);
|
|
}
|
|
|
|
BOOL
|
|
NSNextMapEnumeratorPair(NSMapEnumerator *enumerator,
|
|
void **key, void **value)
|
|
{
|
|
int i;
|
|
|
|
/* Get the next pair. */
|
|
i = o_map_enumerator_next_key_and_value(enumerator,
|
|
(const void **)key,
|
|
(const void **)value);
|
|
|
|
/* Indicate our success or failure. */
|
|
return i ? YES : NO;
|
|
}
|
|
|
|
NSArray *
|
|
NSAllMapTableKeys(NSMapTable *table)
|
|
{
|
|
NSMutableArray *keyArray;
|
|
NSMapEnumerator enumerator;
|
|
id key = nil;
|
|
|
|
/* Create our mutable key array. */
|
|
keyArray = [NSMutableArray arrayWithCapacity:NSCountMapTable(table)];
|
|
|
|
/* Get an enumerator for TABLE. */
|
|
enumerator = NSEnumerateMapTable(table);
|
|
|
|
/* Step through TABLE... */
|
|
while (NSNextMapEnumeratorPair(&enumerator, (void **)(&key), 0))
|
|
[keyArray addObject:key];
|
|
|
|
return keyArray;
|
|
}
|
|
|
|
NSArray *
|
|
NSAllMapTableValues(NSMapTable *table)
|
|
{
|
|
NSMapEnumerator enumerator;
|
|
NSMutableArray *valueArray;
|
|
id value = nil;
|
|
|
|
/* Create our mutable value array. */
|
|
valueArray = [NSMutableArray arrayWithCapacity:NSCountMapTable(table)];
|
|
|
|
/* Get an enumerator for TABLE. */
|
|
enumerator = NSEnumerateMapTable(table);
|
|
|
|
/* Step through TABLE... */
|
|
while (NSNextMapEnumeratorPair(&enumerator, 0, (void **)(&value)))
|
|
[valueArray addObject:value];
|
|
|
|
return valueArray;
|
|
}
|
|
|
|
/** Adding items to an NSMapTable... **/
|
|
|
|
void
|
|
NSMapInsert(NSMapTable *table, const void *key, const void *value)
|
|
{
|
|
/* Put KEY -> VALUE into TABLE. */
|
|
o_map_at_key_put_value(table, key, value);
|
|
|
|
return;
|
|
}
|
|
|
|
void *
|
|
NSMapInsertIfAbsent(NSMapTable *table, const void *key, const void *value)
|
|
{
|
|
if (o_map_contains_key (table, key))
|
|
return (void *) o_map_key_at_key(table, key);
|
|
else
|
|
{
|
|
/* Put KEY -> VALUE into TABLE. */
|
|
o_map_at_key_put_value_known_absent (table, key, value);
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
void
|
|
NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value)
|
|
{
|
|
/* Is the key already in the table? */
|
|
if (o_map_contains_key(table, key))
|
|
{
|
|
/* FIXME: I should make this give the user/programmer more
|
|
* information. Not difficult to do, just something for a later
|
|
* date. */
|
|
[NSException raise:NSInvalidArgumentException
|
|
format:@"NSMapTable: illegal reinsertion of: %s -> %s",
|
|
[NSMT_DESCRIBE_KEY(table, key) cString],
|
|
[NSMT_DESCRIBE_VALUE(table, value) cString]];
|
|
}
|
|
else
|
|
{
|
|
/* Well, we know it's not there, so... */
|
|
o_map_at_key_put_value_known_absent (table, key, value);
|
|
}
|
|
|
|
/* Yah-hoo! */
|
|
return;
|
|
}
|
|
|
|
/** Removing items from an NSMapTable **/
|
|
|
|
void
|
|
NSMapRemove(NSMapTable *table, const void *key)
|
|
{
|
|
o_map_remove_key (table, key);
|
|
return;
|
|
}
|
|
|
|
/** Getting an NSString representation of an NSMapTable **/
|
|
|
|
NSString *
|
|
NSStringFromMapTable(NSMapTable *table)
|
|
{
|
|
NSMutableString *string;
|
|
NSMapEnumerator enumerator;
|
|
NSMapTableKeyCallBacks keyCallBacks;
|
|
NSMapTableValueCallBacks valueCallBacks;
|
|
void *key, *value;
|
|
|
|
/* Get an empty mutable string. */
|
|
string = [NSMutableString stringWithCapacity:0];
|
|
|
|
/* Pull the NSMapTable...CallBacks out of the mess. */
|
|
keyCallBacks = NSMT_KEY_CALLBACKS(table);
|
|
valueCallBacks = NSMT_VALUE_CALLBACKS(table);
|
|
|
|
/* Get an enumerator for our table. */
|
|
enumerator = NSEnumerateMapTable(table);
|
|
|
|
/* Now, just step through the elements of the table, and add their
|
|
* descriptions to the string. */
|
|
while (NSNextMapEnumeratorPair(&enumerator, &key, &value))
|
|
[string appendFormat:@"%@ = %@;",
|
|
[(keyCallBacks.describe)(table, key) cString],
|
|
[(valueCallBacks.describe)(table, value) cString]];
|
|
|
|
/* Note that this string'll need to be `retain'ed. */
|
|
return string;
|
|
}
|