mirror of
https://github.com/gnustep/libs-base.git
synced 2025-04-23 00:41:02 +00:00
*** empty log message ***
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/base/trunk@909 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
73f762fe23
commit
a2a3de7eec
21 changed files with 7997 additions and 0 deletions
503
Source/NSHashTable.m
Normal file
503
Source/NSHashTable.m
Normal file
|
@ -0,0 +1,503 @@
|
|||
/* NSHashTable 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:54:09 EST 1994
|
||||
* Updated: Sat Feb 10 15:59:11 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/NSHashTable.h>
|
||||
#include <Foundation/atoz.h>
|
||||
#include <objects/hash.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
/* These are to increase readabilty locally. */
|
||||
typedef unsigned int (*NSHT_hash_func_t)(NSHashTable *, const void *);
|
||||
typedef BOOL (*NSHT_isEqual_func_t)(NSHashTable *,
|
||||
const void *,
|
||||
const void *);
|
||||
typedef void (*NSHT_retain_func_t)(NSHashTable *, const void *);
|
||||
typedef void (*NSHT_release_func_t)(NSHashTable *, void *);
|
||||
typedef NSString *(*NSHT_describe_func_t)(NSHashTable *, const void *);
|
||||
|
||||
/** Standard NSHashTable callbacks **/
|
||||
|
||||
const NSHashTableCallBacks NSIntHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_int_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_int_is_equal,
|
||||
(NSHT_retain_func_t) fn_null_function,
|
||||
(NSHT_release_func_t) fn_null_function,
|
||||
(NSHT_describe_Func_t) _NSLF_int_describe
|
||||
};
|
||||
|
||||
const NSHashTableCallBacks NSNonOwnedPointerHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_void_p_is_equal,
|
||||
(NSHT_retain_func_t) fn_null_function,
|
||||
(NSHT_release_func_t) fn_null_function,
|
||||
(NSHT_describe_func_t) _NSLF_void_p_describe
|
||||
};
|
||||
|
||||
const NSHashTableCallBacks NSNonRetainedObjectsHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_id_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_id_is_equal,
|
||||
(NSHT_retain_func_t) fn_null_function,
|
||||
(NSHT_release_func_t) fn_null_function,
|
||||
(NSHT_describe_func_t) _NSLF_id_describe
|
||||
};
|
||||
|
||||
const NSHashTableCallBacks NSObjectsHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_id_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_id_is_equal,
|
||||
(NSHT_retain_func_t) _NSLF_id_retain,
|
||||
(NSHT_release_func_t) _NSLF_id_object,
|
||||
(NSHT_describe_func_t) _NSLF_id_describe
|
||||
};
|
||||
|
||||
const NSHashTableCallBacks NSOwnedPointerHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_void_p_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_void_p_is_equal,
|
||||
(NSHT_retain_func_t) fn_null_function,
|
||||
(NSHT_release_func_t) _NSLF_void_p_release,
|
||||
(NSHT_describe_func_t) _NSLF_void_p_describe
|
||||
};
|
||||
|
||||
const NSHashTableCallBacks NSPointerToStructHashCallBacks =
|
||||
{
|
||||
(NSHT_hash_func_t) _NSLF_int_p_hash,
|
||||
(NSHT_isEqual_func_t) _NSLF_int_p_is_equal,
|
||||
(NSHT_retain_func_t) fn_null_function,
|
||||
(NSHT_release_func_t) fn_null_function,
|
||||
(NSHT_describe_func_t) _NSLF_int_p_describe
|
||||
};
|
||||
|
||||
/** Macros **/
|
||||
|
||||
#define NSHT_ZONE(T) \
|
||||
((NSZone *)((fn_hash_allocs((fn_hash_t *)(T))).user_data))
|
||||
|
||||
#define NSHT_CALLBACKS(T) \
|
||||
(*((NSHashTableCallBacks *)(__void_p__(fn_hash_extra((fn_hash_t *)(T))))))
|
||||
|
||||
#define NSHT_DESCRIBE(T, P) \
|
||||
NSHT_CALLBACKS((T)).describe((T), (P))
|
||||
|
||||
/** Dummy callbacks **/
|
||||
|
||||
size_t
|
||||
_NSHT_hash(fn_generic_t element, void *table)
|
||||
{
|
||||
return NSHT_CALLBACKS(table).hash((NSHashTable *)table,
|
||||
__void_p__(element));
|
||||
}
|
||||
|
||||
int
|
||||
_NSHT_compare(fn_generic_t element1,
|
||||
fn_generic_t element2,
|
||||
void *table)
|
||||
{
|
||||
return !(NSHT_CALLBACKS(table).isEqual((NSHashTable *)table,
|
||||
__void_p__(element1),
|
||||
__void_p__(element2)));
|
||||
}
|
||||
|
||||
int
|
||||
_NSHT_is_equal(fn_generic_t element1,
|
||||
fn_generic_t element2,
|
||||
void *table)
|
||||
{
|
||||
return NSHT_CALLBACKS(table).isEqual((NSHashTable *) table,
|
||||
__void_p__(element1),
|
||||
__void_p__(element2));
|
||||
}
|
||||
|
||||
fn_generic_t
|
||||
_NSHT_retain(fn_generic_t element, void *table)
|
||||
{
|
||||
NSHT_CALLBACKS(table).retain((NSHashTable *)table,
|
||||
__void_p__(element));
|
||||
return element;
|
||||
}
|
||||
|
||||
void
|
||||
_NSHT_release(fn_generic_t element, void *table)
|
||||
{
|
||||
NSHT_CALLBACKS(table).release(table, __void_p__(element));
|
||||
return;
|
||||
}
|
||||
|
||||
/* These are wrappers for getting at the real callbacks. */
|
||||
const fn_callbacks_t _NSHT_callbacks =
|
||||
{
|
||||
_NSHT_hash,
|
||||
_NSHT_compare,
|
||||
_NSHT_is_equal,
|
||||
_NSHT_retain,
|
||||
_NSHT_release,
|
||||
(fn_describe_func_t)fn_null_function,
|
||||
0
|
||||
};
|
||||
|
||||
/** Extra, extra **/
|
||||
|
||||
/* Make a copy of a hash table's callbacks. */
|
||||
fn_generic_t
|
||||
_NSHT_extra_retain(fn_generic_t extra, void *table)
|
||||
{
|
||||
/* Pick out the callbacks in EXTRA. */
|
||||
NSHashTableCallBacks *callBacks = (NSHashTableCallBacks *)__void_p__(extra);
|
||||
|
||||
/* Find our zone. */
|
||||
NSZone *zone = NSHT_ZONE(table);
|
||||
|
||||
/* A pointer to some new callbacks. */
|
||||
NSHashTableCallbacks *newCallBacks;
|
||||
|
||||
/* Set aside space for our new callbacks in the right zone. */
|
||||
newCallBacks = (NSHashTableCallBacks *)NSZoneMalloc(zone,
|
||||
sizeof(NSHashTableCallBacks));
|
||||
|
||||
/* Copy CALLBACKS into NEWCALLBACKS. */
|
||||
*newCallBacks = *callBacks;
|
||||
|
||||
/* Stuff NEWCALLBACKS into EXTRA. */
|
||||
__void_p__(extra) = newCallBacks;
|
||||
|
||||
/* Return our new EXTRA. */
|
||||
return extra;
|
||||
}
|
||||
|
||||
void
|
||||
_NSHT_extra_release(fn_generic_t extra, void *table)
|
||||
{
|
||||
void *ptr = __void_p__(extra);
|
||||
NSZone *zone = NSHT_ZONE(table);
|
||||
|
||||
if (ptr != NULL)
|
||||
NSZoneFree(zone, ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The idea here is that these callbacks ensure that the
|
||||
* NSHashTableCallbacks which are associated with a given NSHashTable
|
||||
* remain so throughout the life of the table and its copies. */
|
||||
fn_callbacks_t _NSHT_extra_callbacks =
|
||||
{
|
||||
(fn_hash_func_t) fn_generic_hash,
|
||||
(fn_is_equal_func_t) fn_generic_is_equal,
|
||||
(fn_compare_func_t) fn_generic_compare,
|
||||
_NSHT_extra_retain,
|
||||
_NSHT_extra_release,
|
||||
(fn_describe_func_t) fn_null_function,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Creating NSHashTables **/
|
||||
|
||||
NSHashTable *
|
||||
NSCreateHashTableWithZone(NSHashTableCallBacks callBacks,
|
||||
unsigned int capacity,
|
||||
NSZone *zone)
|
||||
{
|
||||
NSHashTable *table;
|
||||
fn_callbacks_t callbacks;
|
||||
fn_allocs_t allocs;
|
||||
|
||||
/* These callbacks just look in the TABLE's extra and uses the
|
||||
* callbacks there. See above for precise definitions. */
|
||||
callbacks = _NSHT_callbacks;
|
||||
allocs = fn_allocs_for_zone(zone);
|
||||
|
||||
/* Then we build the table. */
|
||||
table = fn_hash_with_allocs_with_callbacks(allocs, callbacks);
|
||||
|
||||
if (table != NULL)
|
||||
{
|
||||
fn_generic_t extra;
|
||||
|
||||
/* Resize TABLE to CAPACITY. */
|
||||
fn_hash_resize(table, capacity);
|
||||
|
||||
/* Set aside space for the NSHashTableExtra. */
|
||||
__void_p__(extra) = &callBacks;
|
||||
|
||||
/* Add EXTRA to TABLE. This takes care of everything for us. */
|
||||
fn_hash_set_extra_callbacks(table, _NSHT_extra_callbacks);
|
||||
fn_hash_set_extra(table, extra);
|
||||
}
|
||||
|
||||
/* Wah-hoo! */
|
||||
return table;
|
||||
}
|
||||
|
||||
NSHashTable *
|
||||
NSCreateHashTable(NSHashTableCallBacks callBacks,
|
||||
unsigned int capacity)
|
||||
{
|
||||
return NSCreateHashTableWithZone(callBacks, capacity, NULL);
|
||||
}
|
||||
|
||||
/** Copying **/
|
||||
|
||||
NSHashTable *
|
||||
NSCopyHashTableWithZone(NSHashTable *table, NSZone *zone)
|
||||
{
|
||||
fn_allocs_t allocs;
|
||||
NSHashTable *new_table;
|
||||
|
||||
/* Due to the wonders of modern Libfn technology, everything we care
|
||||
* about is automagically transferred. */
|
||||
allocs = fn_allocs_for_zone(zone);
|
||||
new_table = fn_hash_copy_with_allocs(table, allocs);
|
||||
|
||||
return new_table;
|
||||
}
|
||||
|
||||
/** Destroying **/
|
||||
|
||||
void
|
||||
NSFreeHashTable(NSHashTable *table)
|
||||
{
|
||||
/* Due to the wonders of modern Libfn technology, everything we care
|
||||
* about is automagically and safely destroyed. */
|
||||
fn_hash_dealloc(table);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Resetting **/
|
||||
|
||||
void
|
||||
NSResetHashTable(NSHashTable *table)
|
||||
{
|
||||
fn_hash_empty(table);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Comparing **/
|
||||
|
||||
BOOL
|
||||
NSCompareHashTables(NSHashTable *table1, NSHashTable *table2)
|
||||
{
|
||||
return (fn_hash_is_equal_to_hash(table1, table2) ? YES : NO);
|
||||
}
|
||||
|
||||
/** Counting **/
|
||||
|
||||
unsigned int
|
||||
NSCountHashTable(NSHashTable *table)
|
||||
{
|
||||
return (unsigned int) fn_hash_count(table);
|
||||
}
|
||||
|
||||
/** Retrieving **/
|
||||
|
||||
void *
|
||||
NSHashGet(NSHashTable *table, const void *pointer)
|
||||
{
|
||||
fn_generic_t element;
|
||||
fn_generic_t member;
|
||||
|
||||
/* Stuff POINTER into (the `void *' facet of) ELEMENT. */
|
||||
__void_p__(element) = pointer;
|
||||
|
||||
/* Look up ELEMENT in TABLE. */
|
||||
member = fn_hash_element(table, element);
|
||||
|
||||
/* Return the `void *' facet of MEMBER. */
|
||||
return __void_p__(member);
|
||||
}
|
||||
|
||||
NSArray *
|
||||
NSAllHashTableObjects(NSHashTable *table)
|
||||
{
|
||||
NSArray *array;
|
||||
fn_generic_t *elements;
|
||||
id *objects;
|
||||
unsigned int count;
|
||||
|
||||
/* FIXME: We should really be locking TABLE somehow, to insure
|
||||
* the thread-safeness of this method. */
|
||||
|
||||
/* Get an array of the (generically-typed) elements of TABLE. */
|
||||
elements = fn_hash_all_elements(table);
|
||||
|
||||
/* How many thing are in TABLE? */
|
||||
count = NSCountHashTable(table);
|
||||
|
||||
/* Make enough room for our array of `id's together with a
|
||||
* terminating `nil' that we add below. */
|
||||
objects = fn_calloc(fn_hash_allocs(table), count + 1, sizeof(id));
|
||||
|
||||
/* Step through the generic array and copy the `id' facet of each
|
||||
* into the corresponding member of the objects array. Remember
|
||||
* that this function is only suppossed to be called when TABLE
|
||||
* contains objects. Otherwise, everything goes to hell remarkably
|
||||
* quickly. */
|
||||
for (i = 0; i < count; ++i)
|
||||
objects[i] = __id__(elements[i]);
|
||||
|
||||
/* `nil' terminate OBJECTS. */
|
||||
objects[i] = nil;
|
||||
|
||||
/* Build the NSArray to return. */
|
||||
array = [[NSArray alloc] initWithObjects:objects count:count];
|
||||
|
||||
/* Free up all the space we allocated here. */
|
||||
fn_free(fn_hash_allocs(table), elements);
|
||||
fn_free(fn_hash_allocs(table), objects);
|
||||
|
||||
/* FIXME: Should ARRAY returned be `autorelease'd? */
|
||||
return [array autorelease];
|
||||
}
|
||||
|
||||
/** Enumerating **/
|
||||
|
||||
NSHashEnumerator
|
||||
NSEnumerateHashTable(NSHashTable *table)
|
||||
{
|
||||
return fn_hash_enumerator(table);
|
||||
}
|
||||
|
||||
void *
|
||||
NSNextHashEnumeratorItem(NSHashEnumerator *enumerator)
|
||||
{
|
||||
fn_generic_t element;
|
||||
|
||||
/* Grab the next element. */
|
||||
fn_hash_enumerator_next_element(enumerator, &element);
|
||||
|
||||
/* Return ELEMENT's `void *' facet. */
|
||||
return __void_p__(element);
|
||||
}
|
||||
|
||||
/** Adding **/
|
||||
|
||||
void
|
||||
NSHashInsert(NSHashTable *table, const void *pointer)
|
||||
{
|
||||
fn_generic_t element;
|
||||
|
||||
/* Stuff POINTER into ELEMENT. */
|
||||
__void_p__(element) = (void *)pointer;
|
||||
|
||||
/* Place ELEMENT in TABLE. */
|
||||
fn_hash_add_element(table, element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
NSHashInsertKnownAbsent(NSHashTable *table, const void *pointer)
|
||||
{
|
||||
fn_generic_t element;
|
||||
|
||||
__void_p__(element) = pointer;
|
||||
|
||||
if (fn_hash_contains_element(table, element))
|
||||
{
|
||||
/* 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:@"Attempted reinsertion of \"%@\" into a hash table.",
|
||||
NSHT_DESCRIBE(table, pointer)];
|
||||
}
|
||||
else
|
||||
{
|
||||
fn_hash_add_element_known_absent(table, element);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
NSHashInsertIfAbsent(NSHashTable *table, const void *pointer)
|
||||
{
|
||||
fn_generic_t element;
|
||||
|
||||
/* Stuff POINTER into ELEMENT. */
|
||||
__void_p__(element) = (void *)pointer;
|
||||
|
||||
/* Place ELEMENT in TABLE. */
|
||||
element = fn_hash_add_element_if_absent(table, element);
|
||||
|
||||
/* Return the `void *' facet of ELEMENT. */
|
||||
return __void_p__(element);
|
||||
}
|
||||
|
||||
/** Removing **/
|
||||
|
||||
void
|
||||
NSHashRemove(NSHashTable *table, const void *pointer)
|
||||
{
|
||||
fn_generic_t element;
|
||||
|
||||
/* Stuff POINTER into ELEMENT. */
|
||||
__void_p__(element) = pointer;
|
||||
|
||||
/* Remove ELEMENT from TABLE. */
|
||||
fn_hash_remove_element(table, element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Describing **/
|
||||
|
||||
/* FIXME: Make this nicer. I don't know what is desired here, though.
|
||||
* If somebody has a clear idea of what this string should look like,
|
||||
* please tell me, and I'll make it happen. */
|
||||
NSString *
|
||||
NSStringFromHashTable(NSHashTable *table)
|
||||
{
|
||||
NSString *string;
|
||||
NSHashEnumerator enumerator;
|
||||
void *pointer;
|
||||
|
||||
/* This will be our string. */
|
||||
string = [NSMutableString string];
|
||||
|
||||
/* Get an enumerator for TABLE. */
|
||||
enumerator = NSEnumerateHashTable(table);
|
||||
|
||||
/* Iterate over the elements of TABLE, appending the description of
|
||||
* each to the mutable string STRING. */
|
||||
while ((pointer = NSNextHashEnumeratorItem(&enumerator)) != NULL)
|
||||
[string appendFormat:@"%@;", NSHT_DESCRIBE(table, pointer)];
|
||||
|
||||
/* Note that this string'll need to be `retain'ed. */
|
||||
/* FIXME: Should I `autorelease' STRING? I think so. */
|
||||
return [string autorelease];
|
||||
}
|
||||
|
612
Source/NSMapTable.m
Normal file
612
Source/NSMapTable.m
Normal file
|
@ -0,0 +1,612 @@
|
|||
/* 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: Sat Feb 10 16:00:25 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSArray.h>
|
||||
#include <Foundation/NSException.h>
|
||||
#include <Foundation/_NSLibfn.h>
|
||||
#include <Foundation/NSMapTable.h>
|
||||
#include <fn/map.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
/* This is for keeping track of information... */
|
||||
typedef struct _NSMT_extra NSMT_extra_t;
|
||||
|
||||
struct _NSMT_extra
|
||||
{
|
||||
NSMapTableKeyCallBacks keyCallBacks;
|
||||
NSMapTableValueCallBacks valueCallBacks;
|
||||
};
|
||||
|
||||
/* These are to increase readabilty locally. */
|
||||
typedef unsigned int (*NSMT_hash_func_t)(NSMapTable *, const void *);
|
||||
typedef BOOL (*NSMT_is_equal_func_t)(NSMapTable *, const void *,
|
||||
const void *);
|
||||
typedef void (*NSMT_retain_func_t)(NSMapTable *, const void *);
|
||||
typedef void (*NSMT_release_func_t)(NSMapTable *, void *);
|
||||
typedef NSString *(*NSMT_describe_func_t)(NSMapTable *, const void *);
|
||||
|
||||
const NSMapTableKeyCallBacks NSIntMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_int_hash,
|
||||
(NSMT_is_equal_func_t) _NS_int_is_equal,
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_int_describe,
|
||||
(const void *) 0
|
||||
};
|
||||
|
||||
const NSMapTableKeyCallBacks NSNonOwnedPointerMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_void_p_hash,
|
||||
(NSMT_is_equal_func_t) _NS_void_p_is_equal,
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_void_p_describe,
|
||||
(const void *) NULL
|
||||
};
|
||||
|
||||
const NSMapTableKeyCallBacks NSNonOwnedPointerOrNullMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_void_p_hash,
|
||||
(NSMT_is_equal_func_t) _NS_void_p_is_equal,
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_void_p_describe,
|
||||
/* FIXME: Oh my. Is this really ok? I did it in a moment of
|
||||
* weakness. A fit of madness, I say! And if this is wrong, what
|
||||
* *should* it be?!? */
|
||||
(const void *) -1
|
||||
};
|
||||
|
||||
const NSMapTableKeyCallBacks NSNonRetainedObjectMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_id_hash,
|
||||
(NSMT_is_equal_func_t) _NS_id_is_equal,
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_id_describe,
|
||||
(const void *) NULL
|
||||
};
|
||||
|
||||
const NSMapTableKeyCallBacks NSObjectMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_id_hash,
|
||||
(NSMT_is_equal_func_t) _NS_id_is_equal,
|
||||
(NSMT_retain_func_t) _NS_id_retain,
|
||||
(NSMT_release_func_t) _NS_id_release,
|
||||
(NSMT_describe_func_t) _NS_id_describe,
|
||||
(const void *) NULL
|
||||
};
|
||||
|
||||
const NSMapTableKeyCallBacks NSOwnedPointerMapKeyCallBacks =
|
||||
{
|
||||
(NSMT_hash_func_t) _NS_void_p_hash,
|
||||
(NSMT_is_equal_func_t) _NS_void_p_is_equal,
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) _NS_void_p_release,
|
||||
(NSMT_describe_func_t) _NS_void_p_describe,
|
||||
(const void *) NULL
|
||||
};
|
||||
|
||||
const NSMapTableValueCallBacks NSIntMapValueCallBacks =
|
||||
{
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_int_describe
|
||||
};
|
||||
|
||||
const NSMapTableValueCallBacks NSNonOwnedPointerMapValueCallBacks =
|
||||
{
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) fn_null_function,
|
||||
(NSMT_describe_func_t) _NS_void_p_describe
|
||||
};
|
||||
|
||||
const NSMapTableValueCallBacks NSObjectMapValueCallBacks =
|
||||
{
|
||||
(NSMT_retain_func_t) _NS_id_retain,
|
||||
(NSMT_release_func_t) _NS_id_release,
|
||||
(NSMT_describe_func_t) _NS_id_describe
|
||||
};
|
||||
|
||||
const NSMapTableValueCallBacks NSOwnedPointerMapValueCallBacks =
|
||||
{
|
||||
(NSMT_retain_func_t) fn_null_function,
|
||||
(NSMT_release_func_t) _NS_void_p_release,
|
||||
(NSMT_describe_func_t) _NS_void_p_describe
|
||||
};
|
||||
|
||||
/** Macros **/
|
||||
|
||||
#define NSMT_ZONE(T) \
|
||||
((NSZone *)((fn_map_allocs((fn_map_t *)(T))).user_data))
|
||||
|
||||
#define NSMT_EXTRA(T) \
|
||||
((NSMT_extra_t *)(__void_p__(fn_map_extra((fn_map_t *)(T)))))
|
||||
|
||||
#define NSMT_KEY_CALLBACKS(T) \
|
||||
((NSMT_EXTRA((T)))->keyCallBacks)
|
||||
|
||||
#define NSMT_VALUE_CALLBACKS(T) \
|
||||
((NSMT_EXTRA((T)))->valueCallBacks)
|
||||
|
||||
#define NSMT_DESCRIBE_KEY(T, P) \
|
||||
NSMT_KEY_CALLBACKS((T)).describe((T), (P))
|
||||
|
||||
#define NSMT_DESCRIBE_VALUE(T, P) \
|
||||
NSMT_VALUE_CALLBACKS((T)).describe((T), (P))
|
||||
|
||||
/** Dummy callbacks **/
|
||||
|
||||
size_t
|
||||
_NSMT_key_hash(fn_generic_t element, void *table)
|
||||
{
|
||||
return NSMT_KEY_CALLBACKS(table).hash((NSMapTable *)table,
|
||||
__void_p__(element));
|
||||
}
|
||||
|
||||
int
|
||||
_NSMT_key_compare(fn_generic_t element1,
|
||||
fn_generic_t element2,
|
||||
void *table)
|
||||
{
|
||||
return !(NSMT_KEY_CALLBACKS(table).isEqual((NSMapTable *)table,
|
||||
__void_p__(element1),
|
||||
__void_p__(element2)));
|
||||
}
|
||||
|
||||
int
|
||||
_NSMT_key_is_equal(fn_generic_t element1,
|
||||
fn_generic_t element2,
|
||||
void *table)
|
||||
{
|
||||
return NSMT_KEY_CALLBACKS(table).isEqual((NSMapTable *) table,
|
||||
__void_p__(element1),
|
||||
__void_p__(element2));
|
||||
}
|
||||
|
||||
fn_generic_t
|
||||
_NSMT_key_retain(fn_generic_t element, void *table)
|
||||
{
|
||||
NSMT_KEY_CALLBACKS(table).retain((NSMapTable *)table,
|
||||
__void_p__(element));
|
||||
return element;
|
||||
}
|
||||
|
||||
void
|
||||
_NSMT_key_release(fn_generic_t element, void *table)
|
||||
{
|
||||
NSMT_KEY_CALLBACKS(table).release(table, __void_p__(element));
|
||||
return;
|
||||
}
|
||||
|
||||
fn_generic_t
|
||||
_NSMT_value_retain(fn_generic_t element, void *table)
|
||||
{
|
||||
NSMT_VALUE_CALLBACKS(table).retain((NSMapTable *)table,
|
||||
__void_p__(element));
|
||||
return element;
|
||||
}
|
||||
|
||||
void
|
||||
_NSMT_value_release(fn_generic_t element, void *table)
|
||||
{
|
||||
NSMT_VALUE_CALLBACKS(table).release(table, __void_p__(element));
|
||||
return;
|
||||
}
|
||||
|
||||
/* These are wrappers for getting at the real callbacks. */
|
||||
fn_callbacks_t _NSMT_key_callbacks =
|
||||
{
|
||||
_NSMT_key_hash,
|
||||
_NSMT_key_compare,
|
||||
_NSMT_key_is_equal,
|
||||
_NSMT_key_retain,
|
||||
_NSMT_key_release,
|
||||
(fn_describe_func_t)fn_null_function,
|
||||
0
|
||||
};
|
||||
|
||||
fn_callbacks_t
|
||||
_NSMT_callbacks_for_key_callbacks(NSMapTableKeyCallBacks keyCallBacks)
|
||||
{
|
||||
fn_callbacks_t cb = _NSMT_key_callbacks;
|
||||
|
||||
__void_p__(cb.not_an_item_marker) = (void *)(keyCallBacks.notAKeyMarker);
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
fn_callbacks_t _NSMT_value_callbacks =
|
||||
{
|
||||
(fn_hash_func_t) fn_generic_hash,
|
||||
(fn_compare_func_t) fn_generic_compare,
|
||||
(fn_is_equal_func_t) fn_generic_is_equal,
|
||||
_NSMT_value_retain,
|
||||
_NSMT_value_release,
|
||||
(fn_describe_func_t)fn_null_function,
|
||||
0
|
||||
};
|
||||
|
||||
/** Extra, extra **/
|
||||
|
||||
/* Make a copy of a hash table's callbacks. */
|
||||
fn_generic_t
|
||||
_NSMT_extra_retain(fn_generic_t g, void *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(NSMT_ZONE(table),
|
||||
sizeof(NSMT_extra_t));
|
||||
|
||||
/* Copy the old callbacks into NEW_EXTRA. */
|
||||
*new_extra = *((NSMT_extra_t *)(__void_p__(g)))
|
||||
|
||||
/* Stuff NEW_EXTRA into G. */
|
||||
__void_p__(g) = new_extra;
|
||||
|
||||
/* Return our new EXTRA. */
|
||||
return g;
|
||||
}
|
||||
|
||||
void
|
||||
_NSMT_extra_release(fn_generic_t extra, void *table)
|
||||
{
|
||||
void *ptr = __void_p__(extra);
|
||||
NSZone *zone = NSMT_ZONE(table);
|
||||
|
||||
if (ptr != NULL)
|
||||
NSZoneFree(zone, ptr);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* The idea here is that these callbacks ensure that the
|
||||
* NSMapTableCallbacks which are associated with a given NSMapTable
|
||||
* remain so throughout the life of the table and its copies. */
|
||||
fn_callbacks_t _NSMT_extra_callbacks =
|
||||
{
|
||||
(fn_hash_func_t) fn_generic_hash,
|
||||
(fn_is_equal_func_t) fn_generic_is_equal,
|
||||
(fn_compare_func_t) fn_generic_compare,
|
||||
_NSMT_extra_retain,
|
||||
_NSMT_extra_release,
|
||||
(fn_describe_func_t) fn_null_function,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ****/
|
||||
|
||||
/** Creating an NSMapTable **/
|
||||
|
||||
NSMapTable *
|
||||
NSCreateMapTableWithZone(NSMapTableKeyCallBacks keyCallBacks,
|
||||
NSMapTableValueCallBacks valueCallBacks,
|
||||
unsigned capacity,
|
||||
NSZone *zone)
|
||||
{
|
||||
NSMapTable *table;
|
||||
fn_callbacks_t key_callbacks, value_callbacks;
|
||||
fn_allocs_t alloc;
|
||||
|
||||
/* Transform the callbacks we were given. */
|
||||
key_callbacks = _NSMT_callbacks_for_key_callbacks(keyCallBacks);
|
||||
value_callbacks = _NSMT_value_callbacks;
|
||||
|
||||
/* Get some useful allocs. */
|
||||
alloc = fn_allocs_for_zone(zone);
|
||||
|
||||
/* Create a map table. */
|
||||
table = fn_map_with_allocs_with_callbacks(allocs, key_callbacks,
|
||||
value_callbacks);
|
||||
|
||||
/* Adjust the capacity of TABLE. */
|
||||
fn_map_resize(table, capacity);
|
||||
|
||||
if (table != NULL)
|
||||
{
|
||||
NSMapTableExtras *extras;
|
||||
|
||||
/* Set aside space for the NSMapTableExtras. */
|
||||
extras = _NSNewMapTableExtrasWithZone(zone);
|
||||
extras->keyCallBacks = keyCallBacks;
|
||||
extras->valueCallBacks = valueCallBacks;
|
||||
|
||||
table->extras = extras;
|
||||
}
|
||||
|
||||
return table;
|
||||
}
|
||||
|
||||
NSMapTable *
|
||||
NSCreateMapTable(NSMapTableKeyCallBacks keyCallBacks,
|
||||
NSMapTableValueCallBacks valueCallBacks,
|
||||
unsigned int capacity)
|
||||
{
|
||||
return NSCreateMapTableWithZone(keyCallBacks,
|
||||
valueCallBacks,
|
||||
capacity,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* FIXME: CODE THIS! */
|
||||
NSMapTable *
|
||||
NSCopyMapTableWithZone(NSMapTable *table, NSZone *zone)
|
||||
{
|
||||
fn_allocs_t allocs;
|
||||
NSMapTable *new_table;
|
||||
|
||||
allocs = fn_allocs_for_zone(zone);
|
||||
new_table = fn_map_copy_with_allocs(table, alloc);
|
||||
|
||||
return new_table;
|
||||
}
|
||||
|
||||
/** Freeing an NSMapTable **/
|
||||
|
||||
void
|
||||
NSFreeMapTable(NSMapTable *table)
|
||||
{
|
||||
fn_map_dealloc(table);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
NSResetMapTable(NSMapTable *table)
|
||||
{
|
||||
fn_map_empty(table);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Comparing two NSMapTables **/
|
||||
|
||||
BOOL
|
||||
NSCompareMapTables(NSMapTable *table1, NSMapTable *table2)
|
||||
{
|
||||
return fn_map_is_equal_map(table1, table2) ? YES : NO;
|
||||
}
|
||||
|
||||
/** Getting the number of items in an NSMapTable **/
|
||||
|
||||
unsigned int
|
||||
NSCountMapTable(NSMapTable *table)
|
||||
{
|
||||
return (unsigned int) fn_map_count(table);
|
||||
}
|
||||
|
||||
/** Retrieving items from an NSMapTable **/
|
||||
|
||||
BOOL
|
||||
NSMapMember(NSMapTable *table, const void *key,
|
||||
void **originalKey, void **value)
|
||||
{
|
||||
fn_generic_t k, ok, v;
|
||||
int i;
|
||||
|
||||
/* Stuff KEY into K. */
|
||||
__void_p__(k) = key;
|
||||
|
||||
/* Check for K in TABLE. */
|
||||
i = fn_map_key_and_value(table, k, &ok, &v);
|
||||
|
||||
/* Put the `void *' facet of OK and V into ORIGINALKEY and VALUE. */
|
||||
if (originalKey != NULL)
|
||||
*originalKey = __void_p__(ok);
|
||||
if (value != NULL)
|
||||
*value = __void_p__(v);
|
||||
|
||||
/* Indicate our state of success. */
|
||||
return i ? YES : NO;
|
||||
}
|
||||
|
||||
void *
|
||||
NSMapGet(NSMapTable *table, const void *key)
|
||||
{
|
||||
return fn_map_value(table, key);
|
||||
}
|
||||
|
||||
NSMapEnumerator
|
||||
NSEnumerateMapTable(NSMapTable *table)
|
||||
{
|
||||
return fn_map_enumerator(table);
|
||||
}
|
||||
|
||||
BOOL
|
||||
NSNextMapEnumeratorPair(NSMapEnumerator *enumerator,
|
||||
void **key, void **value)
|
||||
{
|
||||
fn_generic_t k, v;
|
||||
int i;
|
||||
|
||||
/* Get the next pair. */
|
||||
i = fn_map_enumerator_next_key_and_value(enumerator, &k, &v);
|
||||
|
||||
/* Put the `void *' facet of K and V into KEY and VALUE. */
|
||||
*key = __void_p__(k);
|
||||
*value = __void_p__(v);
|
||||
|
||||
/* Indicate our success or failure. */
|
||||
return i ? YES : NO;
|
||||
}
|
||||
|
||||
NSArray *
|
||||
NSAllMapTableKeys(NSMapTable *table)
|
||||
{
|
||||
NSArray *array;
|
||||
fn_generic_t *keys;
|
||||
id *objects;
|
||||
unsigned int count;
|
||||
|
||||
count = fn_map_count(table);
|
||||
keys = fn_map_all_keys(table);
|
||||
objects = fn_calloc(fn_set_allocs(table), count + 1, sizeof(id));
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
objects[i] = __id__(keys[i]);
|
||||
|
||||
objects[i] = nil;
|
||||
|
||||
array = [[NSArray alloc] initWithObjects:objects count:count];
|
||||
|
||||
fn_free(fn_map_allocs(table), keys);
|
||||
fn_free(fn_map_allocs(table), objects);
|
||||
|
||||
/* FIXME: Should ARRAY returned be `autorelease'd? */
|
||||
return [array autorelease];
|
||||
}
|
||||
|
||||
NSArray *
|
||||
NSAllMapTableValues(NSMapTable *table)
|
||||
{
|
||||
NSArray *array;
|
||||
fn_generic_t *values;
|
||||
id *objects;
|
||||
unsigned int count;
|
||||
|
||||
count = fn_map_count(table);
|
||||
values = fn_map_all_values(table);
|
||||
objects = fn_calloc(fn_set_allocs(table), count + 1, sizeof(id));
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
objects[i] = __id__(values[i]);
|
||||
|
||||
objects[i] = nil;
|
||||
|
||||
array = [[NSArray alloc] initWithObjects:objects count:count];
|
||||
|
||||
fn_free(fn_map_allocs(table), keys);
|
||||
fn_free(fn_map_allocs(table), objects);
|
||||
|
||||
/* FIXME: Should ARRAY returned be `autorelease'd? */
|
||||
return [array autorelease];
|
||||
}
|
||||
|
||||
/** Adding items to an NSMapTable **/
|
||||
|
||||
void
|
||||
NSMapInsert(NSMapTable *table, const void *key, const void *value)
|
||||
{
|
||||
fn_generic_t k, v;
|
||||
|
||||
/* Stuff KEY and VALUE into K and V. */
|
||||
__void_p__(k) = key;
|
||||
__void_p__(v) = value;
|
||||
|
||||
/* Put K -> V into TABLE. */
|
||||
fn_map_at_key_put_value(table, k, v);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
NSMapInsertIfAbsent(NSMapTable *table, const void *key, const void *value)
|
||||
{
|
||||
fn_generic_t k, v, m;
|
||||
|
||||
/* Stuff KEY and VALUE into K and V. */
|
||||
__void_p__(k) = key;
|
||||
__void_p__(v) = value;
|
||||
|
||||
/* Put K -> V into TABLE. */
|
||||
m = fn_map_at_key_put_value_if_absent(table, k, v);
|
||||
|
||||
/* Return the `void *' facet of M. */
|
||||
return __void_p__(m);
|
||||
}
|
||||
|
||||
void
|
||||
NSMapInsertKnownAbsent(NSMapTable *table, const void *key, const void *value)
|
||||
{
|
||||
fn_generic_t k, v;
|
||||
|
||||
/* Stuff KEY and VALUE into K and V. */
|
||||
__void_p__(k) = key;
|
||||
__void_p__(v) = value;
|
||||
|
||||
/* Is the key already in the table? */
|
||||
if (fn_map_contains_key(table, k))
|
||||
{
|
||||
/* Ooh. Bad. The docs say to raise an exception! */
|
||||
/* FIXME: I should make this much more informative. */
|
||||
[NSException raise:NSInvalidArgumentException
|
||||
format:@"That key's already in the table."];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Well, we know it's not there, so... */
|
||||
fn_map_at_key_put_value_known_absent(table, k, v);
|
||||
}
|
||||
|
||||
/* Yah-hoo! */
|
||||
return;
|
||||
}
|
||||
|
||||
/** Removing items from an NSMapTable **/
|
||||
|
||||
void
|
||||
NSMapRemove(NSMapTable *table, const void *key)
|
||||
{
|
||||
fn_map_remove_key(table, key);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Getting an NSString representation of an NSMapTable **/
|
||||
|
||||
NSString *
|
||||
NSStringFromMapTable(NSMapTable *table)
|
||||
{
|
||||
NSString *string;
|
||||
NSMapEnumerator enumerator;
|
||||
NSMapTableKeyCallBacks keyCallBacks;
|
||||
NSMapTableValueCallBacks valueCallBacks;
|
||||
void *key, *value;
|
||||
|
||||
/* Get an empty mutable string. */
|
||||
string = [NSMutableString string];
|
||||
|
||||
/* 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),
|
||||
(valueCallBacks.describe)(table, value)];
|
||||
|
||||
/* Note that this string'll need to be `retain'ed. */
|
||||
/* FIXME: Should I be `autorelease'ing it? */
|
||||
return [string autorelease];
|
||||
}
|
46
Source/abort.c
Normal file
46
Source/abort.c
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* A hookable abort function.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 12:31:57 EST 1996
|
||||
* Updated: Sat Feb 10 12:31:57 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <objects/abort.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
static void (*__objects_abort) (void) = NULL;
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
void
|
||||
objects_abort (void)
|
||||
{
|
||||
if (__objects_abort != NULL)
|
||||
(__objects_abort) ();
|
||||
else
|
||||
abort ();
|
||||
return;
|
||||
}
|
81
Source/allocs.c
Normal file
81
Source/allocs.c
Normal file
|
@ -0,0 +1,81 @@
|
|||
/* Modular memory management through structures.
|
||||
* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Thu Oct 13 23:45:49 EDT 1994
|
||||
* Updated: Sat Feb 10 15:19:32 EST 1996
|
||||
* Serial: 96.02.10.03
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/allocs.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
static objects_allocs_t __objects_allocs_standard =
|
||||
{
|
||||
(objects_malloc_func_t) malloc,
|
||||
(objects_calloc_func_t) calloc,
|
||||
(objects_realloc_func_t) realloc,
|
||||
(objects_free_func_t) free,
|
||||
(void *) 0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
objects_allocs_t
|
||||
objects_allocs_standard (void)
|
||||
{
|
||||
return __objects_allocs_standard;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_malloc (objects_allocs_t allocs, size_t s)
|
||||
{
|
||||
return (*(allocs.malloc)) (s, allocs.user_data);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_calloc (objects_allocs_t allocs, size_t n, size_t s)
|
||||
{
|
||||
return (*(allocs.calloc)) (n, s, allocs.user_data);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_realloc (objects_allocs_t allocs, void *p, size_t s)
|
||||
{
|
||||
return (*(allocs.realloc)) (p, s, allocs.user_data);
|
||||
}
|
||||
|
||||
void
|
||||
objects_free (objects_allocs_t allocs, void *p)
|
||||
{
|
||||
(*(allocs.free)) (p, allocs.user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
size_t
|
||||
objects_next_power_of_two (size_t beat)
|
||||
{
|
||||
size_t start = 1;
|
||||
while ((start <= beat) && (start <<= 1));
|
||||
return start;
|
||||
}
|
904
Source/array.c
Normal file
904
Source/array.c
Normal file
|
@ -0,0 +1,904 @@
|
|||
/* A (pretty good) implementation of a sparse array.
|
||||
* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Thu Mar 2 02:28:50 EST 1994
|
||||
* Updated: Sat Feb 10 16:16:12 EST 1996
|
||||
* Serial: 96.02.10.02
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/allocs.h>
|
||||
#include <objects/callbacks.h>
|
||||
#include <objects/abort.h>
|
||||
#include <objects/array.h>
|
||||
#include <objects/hash.h>
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Background functions **/
|
||||
|
||||
size_t
|
||||
_objects_array_fold_index (size_t index, size_t slot_count)
|
||||
{
|
||||
return (slot_count ? (index % slot_count) : 0);
|
||||
}
|
||||
|
||||
size_t
|
||||
_objects_array_internal_index (objects_array_t * array, size_t index)
|
||||
{
|
||||
return _objects_array_fold_index (index, array->slot_count);
|
||||
}
|
||||
|
||||
objects_array_slot_t *
|
||||
_objects_array_slot_for_index (objects_array_t * array, size_t index)
|
||||
{
|
||||
return (array->slots + _objects_array_internal_index (array, index));
|
||||
}
|
||||
|
||||
objects_array_bucket_t *
|
||||
_objects_array_bucket_for_index (objects_array_t * array, size_t index)
|
||||
{
|
||||
objects_array_slot_t *slot;
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
/* First, we translate the index into a bucket index to find our
|
||||
* candidate for the bucket. */
|
||||
slot = _objects_array_slot_for_index (array, index);
|
||||
bucket = *slot;
|
||||
|
||||
/* But we need to check to see whether this is really the bucket we
|
||||
* wanted. */
|
||||
if (bucket != NULL && bucket->index == index)
|
||||
/* Bucket `index' exists, and we've got it, so... */
|
||||
return bucket;
|
||||
else
|
||||
/* Either no bucket or some other bucket is where bucket `index'
|
||||
* would be, if it existed. So... */
|
||||
return NULL;
|
||||
}
|
||||
|
||||
objects_array_bucket_t *
|
||||
_objects_array_new_bucket (objects_array_t * array, size_t index, void *element)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
bucket = (objects_array_bucket_t *) objects_malloc (objects_array_allocs (array),
|
||||
sizeof (objects_array_bucket_t));
|
||||
if (bucket != NULL)
|
||||
{
|
||||
objects_retain (objects_array_element_callbacks (array), element, array);
|
||||
bucket->index = index;
|
||||
bucket->element = element;
|
||||
}
|
||||
return bucket;
|
||||
}
|
||||
|
||||
void
|
||||
_objects_array_free_bucket (objects_array_t * array, objects_array_bucket_t * bucket)
|
||||
{
|
||||
if (bucket != NULL)
|
||||
{
|
||||
objects_release (objects_array_element_callbacks (array), bucket->element, array);
|
||||
objects_free (objects_array_allocs (array), bucket);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
objects_array_slot_t *
|
||||
_objects_array_new_slots (objects_array_t * array, size_t slot_count)
|
||||
{
|
||||
return (objects_array_slot_t *) objects_calloc (objects_array_allocs (array),
|
||||
slot_count,
|
||||
sizeof (objects_array_slot_t));
|
||||
}
|
||||
|
||||
void
|
||||
_objects_array_free_slots (objects_array_t * array, objects_array_slot_t * slots)
|
||||
{
|
||||
if (slots != NULL)
|
||||
objects_free (objects_array_allocs (array), slots);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_objects_array_empty_slot (objects_array_t * array, objects_array_slot_t * slot)
|
||||
{
|
||||
if (*slot != NULL)
|
||||
{
|
||||
/* Get rid of the bucket. */
|
||||
_objects_array_free_bucket (array, *slot);
|
||||
|
||||
/* Mark the slot as empty. */
|
||||
*slot = NULL;
|
||||
|
||||
/* Keep the element count accurate */
|
||||
--(array->element_count);
|
||||
}
|
||||
|
||||
/* And return. */
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
_objects_array_insert_bucket (objects_array_t * array, objects_array_bucket_t * bucket)
|
||||
{
|
||||
objects_array_slot_t *slot;
|
||||
|
||||
slot = _objects_array_slot_for_index (array, bucket->index);
|
||||
|
||||
/* We're adding a bucket, so the current set of sorted slots is now
|
||||
* invalidated. */
|
||||
if (array->sorted_slots != NULL)
|
||||
{
|
||||
_objects_array_free_slots (array, array->sorted_slots);
|
||||
array->sorted_slots = NULL;
|
||||
}
|
||||
|
||||
if ((*slot) == NULL)
|
||||
{
|
||||
/* There's nothing there, so we can put `bucket' there. */
|
||||
*slot = bucket;
|
||||
|
||||
/* Increment the array's bucket counter. */
|
||||
++(array->element_count);
|
||||
return;
|
||||
}
|
||||
if ((*slot)->index == bucket->index)
|
||||
{
|
||||
/* There's a bucket there, and it has the same index as `bucket'.
|
||||
* So we get rid of the old one, and put the new one in its
|
||||
* place. */
|
||||
_objects_array_free_bucket (array, *slot);
|
||||
*slot = bucket;
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Now we get to fiddle around with things to make the world a
|
||||
* better place... */
|
||||
|
||||
size_t new_slot_count;
|
||||
objects_array_slot_t *new_slots; /* This guy holds the buckets while we
|
||||
* muck about with them. */
|
||||
size_t d; /* Just a counter */
|
||||
|
||||
/* FIXME: I *really* wish I had a way of generating
|
||||
* statistically better initial values for this variable. So
|
||||
* I'll run a few tests and see... And is there a better
|
||||
* algorithm, e.g., a better collection of sizes in the sense
|
||||
* that the likelyhood of fitting everything in earlier is
|
||||
* high? Well, enough mumbling. */
|
||||
/* At any rate, we're guaranteed to need at least this many. */
|
||||
new_slot_count = array->element_count + 1;
|
||||
|
||||
do
|
||||
{
|
||||
/* First we make a new pile of slots for the buckets. */
|
||||
new_slots = _objects_array_new_slots (array, new_slot_count);
|
||||
|
||||
if (new_slots == NULL)
|
||||
objects_abort ();
|
||||
|
||||
/* Then we put the new bucket in the pile. */
|
||||
new_slots[_objects_array_fold_index (bucket->index,
|
||||
new_slot_count)] = bucket;
|
||||
|
||||
/* Now loop and try to place the others. Upon collision
|
||||
* with a previously inserted bucket, try again with more
|
||||
* `new_slots'. */
|
||||
for (d = 0; d < array->slot_count; ++d)
|
||||
{
|
||||
if (array->slots[d] != NULL)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
i = _objects_array_fold_index (array->slots[d]->index,
|
||||
new_slot_count);
|
||||
|
||||
if (new_slots[i] == NULL)
|
||||
{
|
||||
new_slots[i] = array->slots[d];
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A collision. Clean up and try again. */
|
||||
|
||||
/* Free the current set of new buckets. */
|
||||
_objects_array_free_slots (array, new_slots);
|
||||
|
||||
/* Bump up the number of new buckets. */
|
||||
++new_slot_count;
|
||||
|
||||
/* Break out of the `for' loop. */
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (d < array->slot_count);
|
||||
|
||||
if (array->slots != NULL)
|
||||
_objects_array_free_slots (array, array->slots);
|
||||
|
||||
array->slots = new_slots;
|
||||
array->slot_count = new_slot_count;
|
||||
++(array->element_count);
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
_objects_array_compare_slots (const objects_array_slot_t * slot1,
|
||||
const objects_array_slot_t * slot2)
|
||||
{
|
||||
if (slot1 == slot2)
|
||||
return 0;
|
||||
if (*slot1 == NULL)
|
||||
return 1;
|
||||
if (*slot2 == NULL)
|
||||
return -1;
|
||||
|
||||
if ((*slot1)->index < (*slot2)->index)
|
||||
return -1;
|
||||
else if ((*slot1)->index > (*slot2)->index)
|
||||
return 1;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
typedef int (*qsort_compare_func_t) (const void *, const void *);
|
||||
|
||||
void
|
||||
_objects_array_make_sorted_slots (objects_array_t * array)
|
||||
{
|
||||
objects_array_slot_t *new_slots;
|
||||
|
||||
/* If there're already some sorted slots, then they're valid, and
|
||||
* we're done. */
|
||||
if (array->sorted_slots != NULL)
|
||||
return;
|
||||
|
||||
/* Make some new slots. */
|
||||
new_slots = _objects_array_new_slots (array, array->slot_count);
|
||||
|
||||
/* Copy the pointers to buckets into the new slots. */
|
||||
memcpy (new_slots, array->slots, (array->slot_count
|
||||
* sizeof (objects_array_slot_t)));
|
||||
|
||||
/* Sort the new slots. */
|
||||
qsort (new_slots, array->slot_count, sizeof (objects_array_slot_t),
|
||||
(qsort_compare_func_t) _objects_array_compare_slots);
|
||||
|
||||
/* Put the newly sorted slots in the `sorted_slots' element of the
|
||||
* array structure. */
|
||||
array->sorted_slots = new_slots;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
objects_array_bucket_t *
|
||||
_objects_array_enumerator_next_bucket (objects_array_enumerator_t * enumerator)
|
||||
{
|
||||
if (enumerator->is_sorted)
|
||||
{
|
||||
if (enumerator->is_ascending)
|
||||
{
|
||||
if (enumerator->array->sorted_slots == NULL)
|
||||
return NULL;
|
||||
|
||||
if (enumerator->index < enumerator->array->element_count)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
bucket = enumerator->array->sorted_slots[enumerator->index];
|
||||
++(enumerator->index);
|
||||
return bucket;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (enumerator->array->sorted_slots == NULL)
|
||||
return NULL;
|
||||
|
||||
if (enumerator->index > 0)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
--(enumerator->index);
|
||||
bucket = enumerator->array->sorted_slots[enumerator->index];
|
||||
return bucket;
|
||||
}
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
if (enumerator->array->slots == NULL)
|
||||
return NULL;
|
||||
|
||||
for (bucket = NULL;
|
||||
(enumerator->index < enumerator->array->slot_count
|
||||
&& bucket == NULL);
|
||||
++(enumerator->index))
|
||||
{
|
||||
bucket = enumerator->array->slots[enumerator->index];
|
||||
}
|
||||
|
||||
return bucket;
|
||||
}
|
||||
}
|
||||
|
||||
/** Statistics **/
|
||||
|
||||
size_t
|
||||
objects_array_count (objects_array_t * array)
|
||||
{
|
||||
return array->element_count;
|
||||
}
|
||||
|
||||
size_t
|
||||
objects_array_capacity (objects_array_t * array)
|
||||
{
|
||||
return array->slot_count;
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_check (objects_array_t * array)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_is_empty (objects_array_t * array)
|
||||
{
|
||||
return objects_array_count (array) != 0;
|
||||
}
|
||||
|
||||
/** Emptying **/
|
||||
|
||||
void
|
||||
objects_array_empty (objects_array_t * array)
|
||||
{
|
||||
size_t c;
|
||||
|
||||
/* Just empty each slot out, one by one. */
|
||||
for (c = 0; c < array->slot_count; ++c)
|
||||
_objects_array_empty_slot (array, array->slots + c);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Creating **/
|
||||
|
||||
objects_array_t *
|
||||
objects_array_alloc_with_allocs (objects_allocs_t allocs)
|
||||
{
|
||||
objects_array_t *array;
|
||||
|
||||
/* Get a new array. */
|
||||
array = _objects_array_alloc_with_allocs (allocs);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_alloc (void)
|
||||
{
|
||||
return objects_array_alloc_with_allocs (objects_allocs_standard ());
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_with_allocs (objects_allocs_t allocs)
|
||||
{
|
||||
return objects_array_init (objects_array_alloc_with_allocs (allocs));
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_with_allocs_with_callbacks (objects_allocs_t allocs,
|
||||
objects_callbacks_t callbacks)
|
||||
{
|
||||
return objects_array_init_with_callbacks (objects_array_alloc_with_allocs (allocs),
|
||||
callbacks);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_with_callbacks (objects_callbacks_t callbacks)
|
||||
{
|
||||
return objects_array_init_with_callbacks (objects_array_alloc (), callbacks);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_of_char_p (void)
|
||||
{
|
||||
return objects_array_with_callbacks (objects_callbacks_for_char_p);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_of_void_p (void)
|
||||
{
|
||||
return objects_array_with_callbacks (objects_callbacks_for_void_p);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_of_owned_void_p (void)
|
||||
{
|
||||
return objects_array_with_callbacks (objects_callbacks_for_owned_void_p);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_of_int (void)
|
||||
{
|
||||
return objects_array_with_callbacks (objects_callbacks_for_int);
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_of_id (void)
|
||||
{
|
||||
return objects_array_with_callbacks (objects_callbacks_for_id);
|
||||
}
|
||||
|
||||
/** Initializing **/
|
||||
|
||||
objects_array_t *
|
||||
objects_array_init_with_callbacks (objects_array_t * array, objects_callbacks_t callbacks)
|
||||
{
|
||||
if (array != NULL)
|
||||
{
|
||||
/* The default capacity is 15. */
|
||||
size_t capacity = 15;
|
||||
|
||||
/* Record the element callbacks. */
|
||||
array->callbacks = objects_callbacks_standardize (callbacks);
|
||||
|
||||
/* Initialize ARRAY's information. */
|
||||
array->element_count = 0;
|
||||
array->slot_count = capacity + 1;
|
||||
|
||||
/* Make some new slots. */
|
||||
array->slots = _objects_array_new_slots (array, capacity + 1);
|
||||
|
||||
/* Get the sorted slots ready for later use. */
|
||||
array->sorted_slots = NULL;
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_init (objects_array_t * array)
|
||||
{
|
||||
return objects_array_init_with_callbacks (array,
|
||||
objects_callbacks_standard());
|
||||
}
|
||||
|
||||
objects_array_t *
|
||||
objects_array_init_from_array (objects_array_t * array, objects_array_t * old_array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
size_t index;
|
||||
void *element;
|
||||
|
||||
/* Initialize ARRAY in the usual way. */
|
||||
objects_array_init_with_callbacks (array,
|
||||
objects_array_element_callbacks (old_array));
|
||||
|
||||
/* Get an enumerator for OLD_ARRAY. */
|
||||
enumerator = objects_array_enumerator (old_array);
|
||||
|
||||
/* Step through OLD_ARRAY's elements, putting them at the proper
|
||||
* index in ARRAY. */
|
||||
while (objects_array_enumerator_next_index_and_element (&enumerator,
|
||||
&index, &element))
|
||||
{
|
||||
objects_array_at_index_put_element (array, index, element);
|
||||
}
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/** Destroying **/
|
||||
|
||||
void
|
||||
objects_array_dealloc (objects_array_t * array)
|
||||
{
|
||||
if (array != NULL)
|
||||
{
|
||||
/* Empty out ARRAY. */
|
||||
objects_array_empty (array);
|
||||
|
||||
/* Free up its slots. */
|
||||
_objects_array_free_slots (array, array->slots);
|
||||
|
||||
/* FIXME: What about ARRAY's sorted slots? */
|
||||
|
||||
/* Free up ARRAY itself. */
|
||||
_objects_array_dealloc (array);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Searching **/
|
||||
|
||||
void *
|
||||
objects_array_element_at_index (objects_array_t * array, size_t index)
|
||||
{
|
||||
objects_array_bucket_t *bucket = _objects_array_bucket_for_index (array, index);
|
||||
|
||||
if (bucket != NULL)
|
||||
return bucket->element;
|
||||
else
|
||||
/* If `bucket' is NULL, then the requested index is unused. */
|
||||
/* There's no bucket, so... */
|
||||
return objects_array_not_an_element_marker (array);
|
||||
}
|
||||
|
||||
size_t
|
||||
objects_array_index_of_element (objects_array_t * array, void *element)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < array->slot_count; ++i)
|
||||
{
|
||||
objects_array_bucket_t *bucket = array->slots[i];
|
||||
|
||||
if (bucket != NULL)
|
||||
if (objects_is_equal (objects_array_element_callbacks (array),
|
||||
bucket->element,
|
||||
element,
|
||||
array))
|
||||
return bucket->index;
|
||||
}
|
||||
|
||||
return i;
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_contains_element (objects_array_t * array, void *element)
|
||||
{
|
||||
/* Note that this search is quite inefficient. */
|
||||
return objects_array_index_of_element (array, element) < (array->slot_count);
|
||||
}
|
||||
|
||||
void **
|
||||
objects_array_all_elements (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
void **elements;
|
||||
size_t count, i;
|
||||
|
||||
count = objects_array_count (array);
|
||||
|
||||
/* Set aside space to hold the elements. */
|
||||
elements = (void **) objects_calloc (objects_array_allocs (array),
|
||||
count + 1,
|
||||
sizeof (void *));
|
||||
|
||||
enumerator = objects_array_enumerator (array);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
objects_array_enumerator_next_element (&enumerator, elements + i);
|
||||
|
||||
elements[i] = objects_array_not_an_element_marker (array);
|
||||
|
||||
/* We're done, so heave it back. */
|
||||
return elements;
|
||||
}
|
||||
|
||||
void **
|
||||
objects_array_all_elements_ascending (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
void **elements;
|
||||
size_t count, i;
|
||||
|
||||
count = objects_array_count (array);
|
||||
|
||||
/* Set aside space to hold the elements. */
|
||||
elements = (void **) objects_calloc (objects_array_allocs (array),
|
||||
count + 1,
|
||||
sizeof (void *));
|
||||
|
||||
enumerator = objects_array_ascending_enumerator (array);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
objects_array_enumerator_next_element (&enumerator, elements + i);
|
||||
|
||||
elements[i] = objects_array_not_an_element_marker (array);
|
||||
|
||||
/* We're done, so heave it back. */
|
||||
return elements;
|
||||
}
|
||||
|
||||
void **
|
||||
objects_array_all_elements_descending (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
void **elements;
|
||||
size_t count, i;
|
||||
|
||||
count = objects_array_count (array);
|
||||
|
||||
/* Set aside space to hold the elements. */
|
||||
elements = (void **) objects_calloc (objects_array_allocs (array),
|
||||
count + 1,
|
||||
sizeof (void *));
|
||||
|
||||
enumerator = objects_array_descending_enumerator (array);
|
||||
|
||||
for (i = 0; i < count; ++i)
|
||||
objects_array_enumerator_next_element (&enumerator, elements + i);
|
||||
|
||||
elements[i] = objects_array_not_an_element_marker (array);
|
||||
|
||||
/* We're done, so heave it back. */
|
||||
return elements;
|
||||
}
|
||||
|
||||
/** Removing **/
|
||||
|
||||
void
|
||||
objects_array_remove_element_at_index (objects_array_t * array, size_t index)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
/* Get the bucket that might be there. */
|
||||
bucket = _objects_array_bucket_for_index (array, index);
|
||||
|
||||
/* If there's a bucket at the index, then we empty its slot out. */
|
||||
if (bucket != NULL)
|
||||
_objects_array_empty_slot (array, _objects_array_slot_for_index (array, index));
|
||||
|
||||
/* Finally, we return. */
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_array_remove_element_known_present (objects_array_t * array,
|
||||
void *element)
|
||||
{
|
||||
objects_array_remove_element_at_index (array,
|
||||
objects_array_index_of_element (array,
|
||||
element));
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_array_remove_element (objects_array_t * array, void *element)
|
||||
{
|
||||
if (objects_array_contains_element (array, element))
|
||||
objects_array_remove_element_known_present (array, element);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Adding **/
|
||||
|
||||
void *
|
||||
objects_array_at_index_put_element (objects_array_t * array,
|
||||
size_t index,
|
||||
void *element)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
/* Clean out anything that's already there. */
|
||||
objects_array_remove_element_at_index (array, index);
|
||||
|
||||
/* Make a bucket for our information. */
|
||||
bucket = _objects_array_new_bucket (array, index, element);
|
||||
|
||||
/* Put our bucket in the array. */
|
||||
_objects_array_insert_bucket (array, bucket);
|
||||
|
||||
return element;
|
||||
}
|
||||
|
||||
/** Enumerating **/
|
||||
|
||||
objects_array_enumerator_t
|
||||
objects_array_ascending_enumerator (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
|
||||
enumerator.array = array;
|
||||
enumerator.is_sorted = 1;
|
||||
enumerator.is_ascending = 1;
|
||||
enumerator.index = 0;
|
||||
|
||||
_objects_array_make_sorted_slots (array);
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
objects_array_enumerator_t
|
||||
objects_array_descending_enumerator (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
|
||||
enumerator.array = array;
|
||||
enumerator.is_sorted = 1;
|
||||
enumerator.is_ascending = 0;
|
||||
/* The `+ 1' is so that we have `0' as a known ending condition.
|
||||
* See `_objects_array_enumerator_next_bucket()'. */
|
||||
enumerator.index = array->element_count + 1;
|
||||
|
||||
_objects_array_make_sorted_slots (array);
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
objects_array_enumerator_t
|
||||
objects_array_enumerator (objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
|
||||
enumerator.array = array;
|
||||
enumerator.is_sorted = 0;
|
||||
enumerator.is_ascending = 0;
|
||||
enumerator.index = 0;
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_enumerator_next_index_and_element (objects_array_enumerator_t * enumerator,
|
||||
size_t * index,
|
||||
void **element)
|
||||
{
|
||||
objects_array_bucket_t *bucket;
|
||||
|
||||
bucket = _objects_array_enumerator_next_bucket (enumerator);
|
||||
|
||||
if (bucket != NULL)
|
||||
{
|
||||
if (element != NULL)
|
||||
*element = bucket->element;
|
||||
if (index != NULL)
|
||||
*index = bucket->index;
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (element != NULL)
|
||||
*element = objects_array_not_an_element_marker (enumerator->array);
|
||||
if (index != NULL)
|
||||
*index = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_enumerator_next_element (objects_array_enumerator_t * enumerator,
|
||||
void **element)
|
||||
{
|
||||
return objects_array_enumerator_next_index_and_element (enumerator,
|
||||
NULL,
|
||||
element);
|
||||
}
|
||||
|
||||
int
|
||||
objects_array_enumerator_next_index (objects_array_enumerator_t * enumerator,
|
||||
size_t * index)
|
||||
{
|
||||
return objects_array_enumerator_next_index_and_element (enumerator,
|
||||
index,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/** Comparing **/
|
||||
|
||||
int
|
||||
objects_array_is_equal_to_array (objects_array_t * array1, objects_array_t * array2)
|
||||
{
|
||||
size_t a, b;
|
||||
void *m, *n;
|
||||
objects_array_enumerator_t e, f;
|
||||
|
||||
a = objects_array_count (array1);
|
||||
b = objects_array_count (array2);
|
||||
|
||||
if (a < b)
|
||||
return (b - a);
|
||||
if (a > b)
|
||||
return (a - b);
|
||||
|
||||
/* Get ascending enumerators for each of the two arrays. */
|
||||
e = objects_array_ascending_enumerator (array1);
|
||||
e = objects_array_ascending_enumerator (array1);
|
||||
|
||||
while (objects_array_enumerator_next_index_and_element (&e, &a, &m)
|
||||
&& objects_array_enumerator_next_index_and_element (&f, &b, &n))
|
||||
{
|
||||
int c, d;
|
||||
|
||||
if (a < b)
|
||||
return (b - a);
|
||||
if (a > b)
|
||||
return (a - b);
|
||||
|
||||
c = objects_compare (objects_array_element_callbacks (array1), m, n, array1);
|
||||
if (c != 0)
|
||||
return c;
|
||||
|
||||
d = objects_compare (objects_array_element_callbacks (array2), n, m, array2);
|
||||
if (d != 0)
|
||||
return d;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Mapping **/
|
||||
|
||||
objects_array_t *
|
||||
objects_array_map_elements (objects_array_t * array,
|
||||
void *(*fcn) (void *, void *),
|
||||
void *user_data)
|
||||
{
|
||||
/* FIXME: Code this. */
|
||||
return array;
|
||||
}
|
||||
|
||||
/** Miscellaneous **/
|
||||
|
||||
objects_hash_t *
|
||||
objects_hash_init_from_array (objects_hash_t * hash, objects_array_t * array)
|
||||
{
|
||||
objects_array_enumerator_t enumerator;
|
||||
void *element;
|
||||
|
||||
/* NOTE: If ARRAY contains multiple elements of the same equivalence
|
||||
* class, it is indeterminate which will end up in HASH. This
|
||||
* shouldn't matter, though. */
|
||||
enumerator = objects_array_enumerator (array);
|
||||
|
||||
/* Just walk through ARRAY's elements and add them to HASH. */
|
||||
while (objects_array_enumerator_next_element (&enumerator, &element))
|
||||
objects_hash_add_element (hash, element);
|
||||
|
||||
return hash;
|
||||
}
|
||||
|
||||
// objects_chash_t *
|
||||
// objects_chash_init_from_array (objects_chash_t * chash, objects_array_t * array)
|
||||
// {
|
||||
// objects_array_enumerator_t enumerator;
|
||||
// void *element;
|
||||
//
|
||||
// /* NOTE: If ARRAY contains multiple elements of the same equivalence
|
||||
// * class, it is indeterminate which will end up in CHASH. This
|
||||
// * shouldn't matter, though. */
|
||||
// enumerator = objects_array_enumerator (array);
|
||||
//
|
||||
// /* Just walk through ARRAY's elements and add them to CHASH. */
|
||||
// while (objects_array_enumerator_next_element (&enumerator, &element))
|
||||
// objects_chash_add_element (chash, element);
|
||||
//
|
||||
// return chash;
|
||||
// }
|
||||
|
77
Source/atoz.m
Normal file
77
Source/atoz.m
Normal file
|
@ -0,0 +1,77 @@
|
|||
/* Handling the interface between allocs and zones.
|
||||
* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Oct 15 10:34:02 EDT 1994
|
||||
* Updated: Sat Feb 10 15:20:41 EST 1996
|
||||
* Serial: 96.02.10.02
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <Foundation/NSObject.h>
|
||||
#include <Foundation/NSString.h>
|
||||
#include <Foundation/NSZone.h>
|
||||
#include <objects/allocs.h>
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Handling Libobjects Allocs **/
|
||||
|
||||
void *
|
||||
_objects_zone_malloc(size_t s, void *z)
|
||||
{
|
||||
return NSZoneMalloc((NSZone *)z, s);
|
||||
}
|
||||
|
||||
void *
|
||||
_objects_zone_calloc(size_t n, size_t s, void *z)
|
||||
{
|
||||
return NSZoneCalloc((NSZone *)z, n, s);
|
||||
}
|
||||
|
||||
void *
|
||||
_objects_zone_realloc(void *p, size_t s, void *z)
|
||||
{
|
||||
return NSZoneRealloc((NSZone *)z, p, s);
|
||||
}
|
||||
|
||||
void
|
||||
_objects_zone_free(void *p, void *z)
|
||||
{
|
||||
NSZoneFree((NSZone *)z, p);
|
||||
return;
|
||||
}
|
||||
|
||||
objects_allocs_t
|
||||
objects_allocs_for_zone(NSZone *zone)
|
||||
{
|
||||
objects_allocs_t allocs =
|
||||
{
|
||||
_objects_zone_malloc,
|
||||
_objects_zone_calloc,
|
||||
_objects_zone_realloc,
|
||||
_objects_zone_free,
|
||||
zone
|
||||
};
|
||||
|
||||
return allocs;
|
||||
}
|
||||
|
129
Source/callbacks-char_p.c
Normal file
129
Source/callbacks-char_p.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/* Callbacks for strings of `char'.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 22:04:38 EST 1996
|
||||
* Updated: Sun Feb 11 01:40:09 EST 1996
|
||||
* Serial: 96.02.11.05
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objects/callbacks.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_char_p =
|
||||
{
|
||||
(objects_hash_func_t) objects_char_p_hash,
|
||||
(objects_compare_func_t) objects_char_p_compare,
|
||||
(objects_is_equal_func_t) objects_char_p_is_equal,
|
||||
(objects_retain_func_t) objects_char_p_retain,
|
||||
(objects_release_func_t) objects_char_p_release,
|
||||
(objects_describe_func_t) objects_char_p_describe,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
size_t
|
||||
objects_char_p_hash(void *cptr)
|
||||
{
|
||||
register char *s = (char *) cptr;
|
||||
register size_t h = 0;
|
||||
register size_t c = 0;
|
||||
|
||||
while (*s != '\0')
|
||||
h ^= *(s++) << (c++);
|
||||
|
||||
return h;
|
||||
}
|
||||
|
||||
int
|
||||
objects_char_p_compare(void *cptr, void *dptr)
|
||||
{
|
||||
register char *s = (char *) cptr;
|
||||
register char *t = (char *) dptr;
|
||||
|
||||
if (s == t)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
register char c;
|
||||
register char d;
|
||||
|
||||
while ((c = *(s++)) == (d = *(s++)))
|
||||
if (c == '\0')
|
||||
return 0;
|
||||
|
||||
return (c - d);
|
||||
}
|
||||
}
|
||||
|
||||
/* Determines whether or not CPTR is the same (`NUL'-terminated)
|
||||
* character string as DPTR. Returns true if CPTR and DPTR are the same,
|
||||
* and false otherwise. Note that we are performing no
|
||||
* internationalization here. CPTR and DPTR are taken to be C strings
|
||||
* in the default (seven or) eight bit character encoding. */
|
||||
int
|
||||
objects_char_p_is_equal(register void *cptr, register void *dptr)
|
||||
{
|
||||
register char *s = (char *) cptr;
|
||||
register char *t = (char *) dptr;
|
||||
|
||||
if (s == t)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
register char c;
|
||||
register char d;
|
||||
|
||||
while ((c = *(s++)) == (d = *(t++)))
|
||||
if (c == '\0')
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void *
|
||||
objects_char_p_retain(void *cptr)
|
||||
{
|
||||
return cptr;
|
||||
}
|
||||
|
||||
void
|
||||
objects_char_p_release(void *cptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_char_p_describe(void *cptr)
|
||||
{
|
||||
/* FIXME: Code this. But first, figure out what it should do, OK? */
|
||||
return 0;
|
||||
}
|
||||
|
93
Source/callbacks-id.m
Normal file
93
Source/callbacks-id.m
Normal file
|
@ -0,0 +1,93 @@
|
|||
/* Callbacks for the Objective-C object type.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 15:55:51 EST 1996
|
||||
* Updated: Sun Feb 11 01:42:20 EST 1996
|
||||
* Serial: 96.02.11.05
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objects/callbacks.h>
|
||||
#include <objects/stdobjects.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_id =
|
||||
{
|
||||
(objects_hash_func_t) objects_id_hash,
|
||||
(objects_compare_func_t) objects_id_compare,
|
||||
(objects_is_equal_func_t) objects_id_is_equal,
|
||||
(objects_retain_func_t) objects_id_retain,
|
||||
(objects_release_func_t) objects_id_release,
|
||||
(objects_describe_func_t) objects_id_describe,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/* FIXME: It sure would be nice if we had a way of checking whether
|
||||
* or not these objects responded to the messages we're sending them here.
|
||||
* We need a way that is independent of whether we have GNUStep objects,
|
||||
* NEXTSTEP objects, or GNU objects. We could certainly just use the
|
||||
* same trick that the `respondsToSelector:' method uses, but I'd hoped
|
||||
* that there was already a built-in call to do this sort of thing. */
|
||||
|
||||
size_t
|
||||
objects_id_hash(void *obj)
|
||||
{
|
||||
return (size_t)[(id)obj hash];
|
||||
}
|
||||
|
||||
int
|
||||
objects_id_compare(void *obj, void *jbo)
|
||||
{
|
||||
return (int)[(id)obj compare:(id)jbo];
|
||||
}
|
||||
|
||||
int
|
||||
objects_id_is_equal(void *obj, void *jbo)
|
||||
{
|
||||
return (int)[(id)obj isEqual:(id)jbo];
|
||||
}
|
||||
|
||||
void *
|
||||
objects_id_retain(void *obj)
|
||||
{
|
||||
return [(id)obj retain];
|
||||
}
|
||||
|
||||
void
|
||||
objects_id_release(void *obj)
|
||||
{
|
||||
[(id)obj release];
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_id_describe(void *obj)
|
||||
{
|
||||
/* FIXME: Harrumph. Make all of these describe functions live
|
||||
* in harmony. Please. */
|
||||
return [(id)obj describe];
|
||||
}
|
||||
|
84
Source/callbacks-int.c
Normal file
84
Source/callbacks-int.c
Normal file
|
@ -0,0 +1,84 @@
|
|||
/* Callbacks for `int' (and smaller) things.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 15:55:51 EST 1996
|
||||
* Updated: Sun Feb 11 01:47:14 EST 1996
|
||||
* Serial: 96.02.11.03
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objects/callbacks.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_int =
|
||||
{
|
||||
(objects_hash_func_t) objects_int_hash,
|
||||
(objects_compare_func_t) objects_int_compare,
|
||||
(objects_is_equal_func_t) objects_int_is_equal,
|
||||
(objects_retain_func_t) objects_int_retain,
|
||||
(objects_release_func_t) objects_int_release,
|
||||
(objects_describe_func_t) objects_int_describe,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
size_t
|
||||
objects_int_hash(void *i)
|
||||
{
|
||||
return (size_t)((int)i);
|
||||
}
|
||||
|
||||
int
|
||||
objects_int_compare(void *i, void *j)
|
||||
{
|
||||
return ((int)i) - ((int)j);
|
||||
}
|
||||
|
||||
int
|
||||
objects_int_is_equal(void *i, void *j)
|
||||
{
|
||||
return ((int)i) == ((int)j);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_int_retain(void *i)
|
||||
{
|
||||
return i;
|
||||
}
|
||||
|
||||
void
|
||||
object_int_release(void *i)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_int_describe(void *i)
|
||||
{
|
||||
/* FIXME: Code this. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
87
Source/callbacks-int_p.c
Normal file
87
Source/callbacks-int_p.c
Normal file
|
@ -0,0 +1,87 @@
|
|||
/* Callbacks for pointers to `int' and (maybe) structures whose first
|
||||
* field is an `int'. Maybe.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 15:55:51 EST 1996
|
||||
* Updated: Sun Feb 11 01:49:55 EST 1996
|
||||
* Serial: 96.02.11.04
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objects/callbacks.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_int_p =
|
||||
{
|
||||
(objects_hash_func_t) objects_int_p_hash,
|
||||
(objects_compare_func_t) objects_int_p_compare,
|
||||
(objects_is_equal_func_t) objects_int_p_is_equal,
|
||||
(objects_retain_func_t) objects_int_p_retain,
|
||||
(objects_release_func_t) objects_int_p_release,
|
||||
(objects_describe_func_t) objects_int_p_describe,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
size_t
|
||||
objects_int_p_hash(void *iptr)
|
||||
{
|
||||
return (size_t)(*((int *)iptr));
|
||||
}
|
||||
|
||||
/* FIXME: Are these next two correct? These seem rather useless to me. */
|
||||
|
||||
int
|
||||
objects_int_p_compare(void *iptr, void *jptr)
|
||||
{
|
||||
return *((int *)iptr) - *((int *)jptr);
|
||||
}
|
||||
|
||||
int
|
||||
objects_int_p_is_equal(void *iptr, void *jptr)
|
||||
{
|
||||
return *((int *)iptr) == *((int *)jptr);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_int_p_retain(void *iptr)
|
||||
{
|
||||
return iptr;
|
||||
}
|
||||
|
||||
void
|
||||
objects_int_p_release(void *iptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_int_p_describe(void *iptr)
|
||||
{
|
||||
/* FIXME: Code this. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
129
Source/callbacks-void_p.c
Normal file
129
Source/callbacks-void_p.c
Normal file
|
@ -0,0 +1,129 @@
|
|||
/* Callbacks for pointers to `void'.
|
||||
* Copyright (C) 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sat Feb 10 22:04:38 EST 1996
|
||||
* Updated: Sun Feb 11 01:09:34 EST 1996
|
||||
* Serial: 96.02.11.03
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <objects/callbacks.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_void_p =
|
||||
{
|
||||
(objects_hash_func_t) objects_void_p_hash,
|
||||
(objects_compare_func_t) objects_void_p_compare,
|
||||
(objects_is_equal_func_t) objects_void_p_is_equal,
|
||||
(objects_retain_func_t) objects_void_p_retain,
|
||||
(objects_release_func_t) objects_void_p_release,
|
||||
0
|
||||
};
|
||||
|
||||
objects_callbacks_t objects_callbacks_for_owned_void_p =
|
||||
{
|
||||
(objects_hash_func_t) objects_owned_void_p_hash,
|
||||
(objects_compare_func_t) objects_owned_void_p_compare,
|
||||
(objects_is_equal_func_t) objects_owned_void_p_is_equal,
|
||||
(objects_retain_func_t) objects_owned_void_p_retain,
|
||||
(objects_release_func_t) objects_owned_void_p_release,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
size_t
|
||||
objects_void_p_hash(void *cptr)
|
||||
{
|
||||
return ((size_t) cptr)/4;
|
||||
}
|
||||
|
||||
int
|
||||
objects_void_p_compare(void *cptr, void *dptr)
|
||||
{
|
||||
if (cptr == dptr)
|
||||
return 0;
|
||||
else if (cptr < dptr)
|
||||
return -1;
|
||||
else /* if (cptr > dptr) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
objects_void_p_is_equal(register void *cptr, register void *dptr)
|
||||
{
|
||||
return (cptr == dptr);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_void_p_retain(void *cptr)
|
||||
{
|
||||
return cptr;
|
||||
}
|
||||
|
||||
void
|
||||
objects_void_p_release(void *cptr)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
size_t
|
||||
objects_owned_void_p_hash(void *cptr)
|
||||
{
|
||||
/* We divide by 4 because many machines align
|
||||
* memory on word boundaries. */
|
||||
return ((size_t) cptr)/4;
|
||||
}
|
||||
|
||||
int
|
||||
objects_owned_void_p_compare(void *cptr, void *dptr)
|
||||
{
|
||||
if (cptr == dptr)
|
||||
return 0;
|
||||
else if (cptr < dptr)
|
||||
return -1;
|
||||
else /* if (cptr > dptr) */
|
||||
return 1;
|
||||
}
|
||||
|
||||
int
|
||||
objects_owned_void_p_is_equal(register void *cptr, register void *dptr)
|
||||
{
|
||||
return (cptr == dptr);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_owned_void_p_retain(void *cptr)
|
||||
{
|
||||
return cptr;
|
||||
}
|
||||
|
||||
void
|
||||
objects_owned_void_p_release(void *cptr)
|
||||
{
|
||||
free(cptr);
|
||||
return;
|
||||
}
|
||||
|
||||
|
141
Source/callbacks.c
Normal file
141
Source/callbacks.c
Normal file
|
@ -0,0 +1,141 @@
|
|||
/* Handling various types in a uniform manner.
|
||||
* Copyright (C) 1994, 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sun Oct 9 13:14:41 EDT 1994
|
||||
* Updated: Sun Feb 11 01:33:41 EST 1996
|
||||
* Serial: 96.02.10.07
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/callbacks.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
/* WARNING: Don't change this unless you know what you're getting into! */
|
||||
static objects_callbacks_t ___objects_callbacks_standard =
|
||||
{
|
||||
(objects_hash_func_t) objects_void_p_hash,
|
||||
(objects_compare_func_t) objects_void_p_compare,
|
||||
(objects_is_equal_func_t) objects_void_p_is_equal,
|
||||
(objects_retain_func_t) objects_void_p_retain,
|
||||
(objects_release_func_t) objects_void_p_release,
|
||||
(objects_describe_func_t) objects_void_p_describe,
|
||||
0
|
||||
};
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Getting the standard callbacks **/
|
||||
|
||||
objects_callbacks_t
|
||||
objects_callbacks_standard(void)
|
||||
{
|
||||
return ___objects_callbacks_standard;
|
||||
}
|
||||
|
||||
/** Standardizing callbacks **/
|
||||
|
||||
objects_callbacks_t
|
||||
objects_callbacks_standardize(objects_callbacks_t callbacks)
|
||||
{
|
||||
if (callbacks.hash == 0)
|
||||
callbacks.hash = objects_callbacks_standard().hash;
|
||||
if (callbacks.compare == 0 && callbacks.is_equal == 0)
|
||||
{
|
||||
callbacks.compare = objects_callbacks_standard().compare;
|
||||
callbacks.is_equal = objects_callbacks_standard().is_equal;
|
||||
}
|
||||
if (callbacks.retain == 0)
|
||||
callbacks.retain = objects_callbacks_standard().retain;
|
||||
if (callbacks.release == 0)
|
||||
callbacks.release = objects_callbacks_standard().release;
|
||||
|
||||
return callbacks;
|
||||
}
|
||||
|
||||
/** Using callbacks **/
|
||||
|
||||
size_t
|
||||
objects_hash (objects_callbacks_t callbacks, void *thing, void *user_data)
|
||||
{
|
||||
if (callbacks.hash != 0)
|
||||
return callbacks.hash(thing, user_data);
|
||||
else
|
||||
return objects_callbacks_standard().hash(thing, user_data);
|
||||
}
|
||||
|
||||
int
|
||||
objects_compare (objects_callbacks_t callbacks,
|
||||
void *thing1,
|
||||
void *thing2,
|
||||
void *user_data)
|
||||
{
|
||||
if (callbacks.compare != 0)
|
||||
return callbacks.compare(thing1, thing2, user_data);
|
||||
else if (callbacks.is_equal != 0)
|
||||
return !(callbacks.is_equal(thing1, thing2, user_data));
|
||||
else
|
||||
return objects_callbacks_standard().compare(thing1, thing2, user_data);
|
||||
}
|
||||
|
||||
int
|
||||
objects_is_equal (objects_callbacks_t callbacks,
|
||||
void *thing1,
|
||||
void *thing2,
|
||||
void *user_data)
|
||||
{
|
||||
if (callbacks.is_equal != 0)
|
||||
return callbacks.is_equal(thing1, thing2, user_data);
|
||||
else if (callbacks.compare != 0)
|
||||
return !(callbacks.compare(thing1, thing2, user_data));
|
||||
else
|
||||
return objects_callbacks_standard().is_equal(thing1, thing2, user_data);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_retain (objects_callbacks_t callbacks, void *thing, void *user_data)
|
||||
{
|
||||
if (callbacks.retain != 0)
|
||||
return callbacks.retain(thing, user_data);
|
||||
else
|
||||
return objects_callbacks_standard().retain(thing, user_data);
|
||||
}
|
||||
|
||||
void
|
||||
objects_release (objects_callbacks_t callbacks, void *thing, void *user_data)
|
||||
{
|
||||
if (callbacks.release != 0)
|
||||
callbacks.release(thing, user_data);
|
||||
else
|
||||
objects_callbacks_standard().release(thing, user_data);
|
||||
return;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_describe(objects_callbacks_t callbacks, void *thing, void *user_data)
|
||||
{
|
||||
if (callbacks.release != 0)
|
||||
return callbacks.describe(thing, user_data);
|
||||
else
|
||||
return objects_callbacks_standard().describe(thing, user_data);
|
||||
}
|
||||
|
1026
Source/data.c
Normal file
1026
Source/data.c
Normal file
File diff suppressed because it is too large
Load diff
1037
Source/hash.c
Normal file
1037
Source/hash.c
Normal file
File diff suppressed because it is too large
Load diff
906
Source/list.c
Normal file
906
Source/list.c
Normal file
|
@ -0,0 +1,906 @@
|
|||
/* A (pretty good) list implementation.
|
||||
* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Tue Sep 5 17:23:50 EDT 1995
|
||||
* Updated: Sat Feb 10 14:50:36 EST 1996
|
||||
* Serial: 96.02.10.03
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/allocs.h>
|
||||
#include <objects/callbacks.h>
|
||||
#include <objects/list.h>
|
||||
#include <objects/hash.h>
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Background functions **/
|
||||
|
||||
inline void
|
||||
_objects_list_remove_node_from_its_list (objects_list_node_t * node)
|
||||
{
|
||||
if (node->list->first_node == node)
|
||||
node->list->first_node = node->next_in_list;
|
||||
if (node->list->last_node == node)
|
||||
node->list->last_node = node->prev_in_list;
|
||||
if (node->next_in_list != NULL)
|
||||
node->next_in_list->prev_in_list = node->prev_in_list;
|
||||
if (node->prev_in_list != NULL)
|
||||
node->prev_in_list->next_in_list = node->next_in_list;
|
||||
|
||||
node->list->node_count -= 1;
|
||||
node->list->element_count -= 1;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
objects_list_node_t *
|
||||
_objects_list_new_node (objects_list_t * list, void *element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = objects_malloc (objects_list_allocs (list), sizeof (objects_list_node_t));
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
node->list = list;
|
||||
node->next_in_list = NULL;
|
||||
node->prev_in_list = NULL;
|
||||
objects_retain (objects_list_element_callbacks (list), element, list);
|
||||
node->element = element;
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
void
|
||||
_objects_list_free_node (objects_list_t * list, objects_list_node_t * node)
|
||||
{
|
||||
objects_release (objects_list_element_callbacks (node->list), node->element, node->list);
|
||||
objects_free (objects_list_allocs (list), node);
|
||||
return;
|
||||
}
|
||||
|
||||
inline objects_list_node_t *
|
||||
_objects_list_nth_node (objects_list_t * list, long int n)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
node = list->last_node;
|
||||
++n;
|
||||
|
||||
while (node != NULL && n != 0)
|
||||
{
|
||||
node = node->prev_in_list;
|
||||
++n;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* (n >= 0) */
|
||||
{
|
||||
node = list->first_node;
|
||||
|
||||
while (node != NULL && n != 0)
|
||||
{
|
||||
node = node->next_in_list;
|
||||
--n;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
inline objects_list_node_t *
|
||||
_objects_list_nth_node_for_element (objects_list_t * list,
|
||||
long int n,
|
||||
void *element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
node = list->last_node;
|
||||
|
||||
++n;
|
||||
|
||||
while (node != NULL && n != 0)
|
||||
{
|
||||
if (objects_is_equal (objects_list_element_callbacks (list), element, node->element, list))
|
||||
++n;
|
||||
if (n != 0)
|
||||
node = node->prev_in_list;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
node = list->first_node;
|
||||
|
||||
while (node != NULL && n != 0)
|
||||
{
|
||||
if (objects_is_equal (objects_list_element_callbacks (list), element, node->element, list))
|
||||
--n;
|
||||
if (n != 0)
|
||||
node = node->next_in_list;
|
||||
}
|
||||
}
|
||||
|
||||
return node;
|
||||
}
|
||||
|
||||
inline objects_list_node_t *
|
||||
_objects_list_enumerator_next_node (objects_list_enumerator_t * enumerator)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
/* Remember ENUMERATOR's current node. */
|
||||
node = enumerator->node;
|
||||
|
||||
/* If NODE is a real node, then we need to increment ENUMERATOR's
|
||||
* current node to the next node in ENUMERATOR's list. */
|
||||
if (node != NULL)
|
||||
{
|
||||
if (enumerator->forward)
|
||||
enumerator->node = enumerator->node->next_in_list;
|
||||
else /* (!enumerator->forward) */
|
||||
enumerator->node = enumerator->node->prev_in_list;
|
||||
}
|
||||
|
||||
/* Send back NODE. */
|
||||
return node;
|
||||
}
|
||||
|
||||
/** Gathering statistics **/
|
||||
|
||||
size_t
|
||||
objects_list_count (objects_list_t * list)
|
||||
{
|
||||
return list->element_count;
|
||||
}
|
||||
|
||||
size_t
|
||||
objects_list_capacity (objects_list_t * list)
|
||||
{
|
||||
return list->element_count;
|
||||
}
|
||||
|
||||
int
|
||||
objects_list_check (objects_list_t * list)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
objects_list_contains_element (objects_list_t * list, void *element)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
void *member;
|
||||
|
||||
objects_list_enumerator (list);
|
||||
|
||||
while (objects_list_enumerator_next_element (&enumerator, &member))
|
||||
if (objects_compare (objects_list_element_callbacks (list), element, member, list))
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
objects_list_is_empty (objects_list_t * list)
|
||||
{
|
||||
return objects_list_count (list) == 0;
|
||||
}
|
||||
|
||||
/** Enumerating **/
|
||||
|
||||
objects_list_enumerator_t
|
||||
objects_list_enumerator (objects_list_t * list)
|
||||
{
|
||||
return objects_list_forward_enumerator (list);
|
||||
}
|
||||
|
||||
objects_list_enumerator_t
|
||||
objects_list_forward_enumerator (objects_list_t * list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
|
||||
/* Update the access time. */
|
||||
_objects_list_set_access_time (list);
|
||||
|
||||
/* Make sure ENUMERATOR knows its list. */
|
||||
enumerator.list = list;
|
||||
|
||||
/* Start ENUMERATOR at LIST's first node. */
|
||||
enumerator.node = list->first_node;
|
||||
|
||||
/* ENUMERATOR walks forward. */
|
||||
enumerator.forward = 1;
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
objects_list_enumerator_t
|
||||
objects_list_reverse_enumerator (objects_list_t * list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
|
||||
/* Make sure ENUMERATOR knows its list. */
|
||||
enumerator.list = list;
|
||||
|
||||
/* Start ENUMERATOR at LIST's first node. */
|
||||
enumerator.node = list->last_node;
|
||||
|
||||
/* ENUMERATOR walks backward. */
|
||||
enumerator.forward = 0;
|
||||
|
||||
return enumerator;
|
||||
}
|
||||
|
||||
int
|
||||
objects_list_enumerator_next_element (objects_list_enumerator_t * enumerator,
|
||||
void **element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
/* Try and get the next node in the enumeration represented by
|
||||
* ENUMERATOR. */
|
||||
node = _objects_list_enumerator_next_node (enumerator);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
/* If NODE is real, then return the element it contains. */
|
||||
if (element != NULL)
|
||||
*element = node->element;
|
||||
|
||||
/* Indicate that the enumeration continues. */
|
||||
return 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* If NODE isn't real, then we return the ``bogus'' indicator. */
|
||||
if (element != NULL)
|
||||
*element = objects_list_not_an_element_marker (enumerator->list);
|
||||
|
||||
/* Indicate that the enumeration is over. */
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
/** Searching **/
|
||||
|
||||
void *
|
||||
objects_list_element (objects_list_t * list, void *element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node_for_element (list, 0, element);
|
||||
|
||||
if (node != NULL)
|
||||
return node->element;
|
||||
else
|
||||
return objects_list_not_an_element_marker (list);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_nth_element (objects_list_t * list, long int n)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node (list, n);
|
||||
|
||||
if (node != NULL)
|
||||
return node->element;
|
||||
else
|
||||
return objects_list_not_an_element_marker (list);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_first_element (objects_list_t * list)
|
||||
{
|
||||
if (list->first_node != NULL)
|
||||
return list->first_node->element;
|
||||
else
|
||||
return objects_list_not_an_element_marker (list);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_last_element (objects_list_t * list)
|
||||
{
|
||||
if (list->last_node != NULL)
|
||||
return list->last_node->element;
|
||||
else
|
||||
return objects_list_not_an_element_marker (list);
|
||||
}
|
||||
|
||||
/** Obtaining elements **/
|
||||
|
||||
void **
|
||||
objects_list_all_elements (objects_list_t * list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
void **array;
|
||||
size_t i;
|
||||
|
||||
array = objects_calloc (objects_list_allocs (list),
|
||||
objects_list_count (list) + 1,
|
||||
sizeof (void *));
|
||||
|
||||
for (i = 0; objects_list_enumerator_next_element (&enumerator, array + i); ++i);
|
||||
|
||||
return array;
|
||||
}
|
||||
|
||||
/** Adding elements **/
|
||||
|
||||
void *
|
||||
objects_list_append_element (objects_list_t * list, void *element)
|
||||
{
|
||||
return objects_list_at_index_insert_element (list, -1, element);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_append_element_if_absent (objects_list_t * list, void *element)
|
||||
{
|
||||
return objects_list_at_index_insert_element_if_absent (list, -1, element);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_prepend_element (objects_list_t * list, void *element)
|
||||
{
|
||||
return objects_list_at_index_insert_element (list, 0, element);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_prepend_element_if_absent (objects_list_t * list, void *element)
|
||||
{
|
||||
return objects_list_at_index_insert_element_if_absent (list, 0, element);
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_at_index_insert_element (objects_list_t * list,
|
||||
long int n,
|
||||
void *element)
|
||||
{
|
||||
objects_list_node_t *anode, *bnode, *new_node, *node;
|
||||
|
||||
node = _objects_list_nth_node (list, n);
|
||||
new_node = _objects_list_new_node (list, element);
|
||||
|
||||
if (new_node == NULL)
|
||||
objects_abort ();
|
||||
|
||||
if (n < 0)
|
||||
{
|
||||
if (node == NULL)
|
||||
{
|
||||
anode = NULL;
|
||||
bnode = list->first_node;
|
||||
}
|
||||
else
|
||||
/* (node != NULL) */
|
||||
{
|
||||
anode = node;
|
||||
bnode = node->next_in_list;
|
||||
}
|
||||
}
|
||||
else
|
||||
/* (n >= 0) */
|
||||
{
|
||||
if (node == NULL)
|
||||
{
|
||||
anode = list->last_node;
|
||||
bnode = NULL;
|
||||
}
|
||||
else
|
||||
/* (node != NULL) */
|
||||
{
|
||||
anode = node->prev_in_list;
|
||||
bnode = node;
|
||||
}
|
||||
}
|
||||
|
||||
new_node->prev_in_list = anode;
|
||||
new_node->next_in_list = bnode;
|
||||
|
||||
if (anode != NULL)
|
||||
anode->next_in_list = new_node;
|
||||
if (bnode != NULL)
|
||||
bnode->prev_in_list = new_node;
|
||||
|
||||
if (list->last_node == anode)
|
||||
list->last_node = new_node;
|
||||
if (list->first_node == bnode)
|
||||
list->first_node = new_node;
|
||||
|
||||
list->node_count += 1;
|
||||
list->element_count += 1;
|
||||
|
||||
return new_node->element;
|
||||
}
|
||||
|
||||
void *
|
||||
objects_list_at_index_insert_element_if_absent (objects_list_t * list,
|
||||
long int n,
|
||||
void *element)
|
||||
{
|
||||
if (!objects_list_contains_element (list, element))
|
||||
return objects_list_at_index_insert_element (list, n, element);
|
||||
else
|
||||
return objects_list_element (list, element);
|
||||
}
|
||||
|
||||
/** Removing elements **/
|
||||
|
||||
void
|
||||
objects_list_remove_nth_occurrance_of_element (objects_list_t * list,
|
||||
long int n,
|
||||
void *element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node_for_element (list, n, element);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
_objects_list_remove_node_from_its_list (node);
|
||||
_objects_list_free_node (list, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_remove_element (objects_list_t * list, void *element)
|
||||
{
|
||||
objects_list_remove_nth_occurrance_of_element (list, 0, element);
|
||||
return;
|
||||
}
|
||||
|
||||
inline void
|
||||
objects_list_remove_nth_element (objects_list_t * list, long int n)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node (list, n);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
_objects_list_remove_node_from_its_list (node);
|
||||
_objects_list_free_node (list, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_remove_first_element (objects_list_t * list)
|
||||
{
|
||||
objects_list_remove_nth_element (list, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_remove_last_element (objects_list_t * list)
|
||||
{
|
||||
objects_list_remove_nth_element (list, -1);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Emptying **/
|
||||
|
||||
void
|
||||
objects_list_empty (objects_list_t * list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
objects_list_node_t *node;
|
||||
|
||||
enumerator = objects_list_enumerator (list);
|
||||
|
||||
while ((node = _objects_list_enumerator_next_node (&enumerator)) != NULL)
|
||||
{
|
||||
_objects_list_remove_node_from_its_list (node);
|
||||
_objects_list_free_node (list, node);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Replacing **/
|
||||
|
||||
void
|
||||
objects_list_replace_nth_occurrance_of_element (objects_list_t * list,
|
||||
long int n,
|
||||
void *old_element,
|
||||
void *new_element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node_for_element (list, n, old_element);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
objects_retain (objects_list_element_callbacks (list), new_element, list);
|
||||
objects_release (objects_list_element_callbacks (list), node->element, list);
|
||||
node->element = new_element;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_replace_element (objects_list_t * list,
|
||||
void *old_element,
|
||||
void *new_element)
|
||||
{
|
||||
objects_list_replace_nth_occurrance_of_element (list, 0, old_element, new_element);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_replace_nth_element (objects_list_t * list,
|
||||
long int n,
|
||||
void *new_element)
|
||||
{
|
||||
objects_list_node_t *node;
|
||||
|
||||
node = _objects_list_nth_node (list, n);
|
||||
|
||||
if (node != NULL)
|
||||
{
|
||||
objects_retain (objects_list_element_callbacks (list), new_element, list);
|
||||
objects_release (objects_list_element_callbacks (list), node->element, list);
|
||||
node->element = new_element;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_replace_first_element (objects_list_t * list,
|
||||
void *new_element)
|
||||
{
|
||||
objects_list_replace_nth_element (list, 0, new_element);
|
||||
return;
|
||||
}
|
||||
|
||||
void
|
||||
objects_list_replace_last_element (objects_list_t * list,
|
||||
void *new_element)
|
||||
{
|
||||
objects_list_replace_nth_element (list, -1, new_element);
|
||||
return;
|
||||
}
|
||||
|
||||
/** Creating **/
|
||||
|
||||
objects_list_t *
|
||||
objects_list_alloc_with_allocs (objects_allocs_t allocs)
|
||||
{
|
||||
objects_list_t *list;
|
||||
|
||||
list = _objects_list_alloc_with_allocs (allocs);
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_alloc (void)
|
||||
{
|
||||
return objects_list_alloc_with_allocs (objects_allocs_standard ());
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list (void)
|
||||
{
|
||||
return objects_list_init (objects_list_alloc ());
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_with_allocs (objects_allocs_t allocs)
|
||||
{
|
||||
return objects_list_init (objects_list_alloc_with_allocs (allocs));
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_with_allocs_with_callbacks (objects_allocs_t allocs,
|
||||
objects_callbacks_t callbacks)
|
||||
{
|
||||
return objects_list_init_with_callbacks (objects_list_alloc_with_allocs (allocs),
|
||||
callbacks);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_with_callbacks (objects_callbacks_t callbacks)
|
||||
{
|
||||
return objects_list_init_with_callbacks (objects_list_alloc (), callbacks);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_of_char_p (void)
|
||||
{
|
||||
return objects_list_with_callbacks (objects_callbacks_for_char_p);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_of_int (void)
|
||||
{
|
||||
return objects_list_with_callbacks (objects_callbacks_for_int);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_of_void_p (void)
|
||||
{
|
||||
return objects_list_with_callbacks (objects_callbacks_for_void_p);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_of_owned_void_p (void)
|
||||
{
|
||||
return objects_list_with_callbacks (objects_callbacks_for_owned_void_p);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_of_id (void)
|
||||
{
|
||||
return objects_list_with_callbacks (objects_callbacks_for_id);
|
||||
}
|
||||
|
||||
/** Initializing **/
|
||||
|
||||
objects_list_t *
|
||||
objects_list_init (objects_list_t * list)
|
||||
{
|
||||
return objects_list_init_with_callbacks (list, objects_callbacks_standard());
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_init_with_callbacks (objects_list_t * list, objects_callbacks_t callbacks)
|
||||
{
|
||||
if (list != NULL)
|
||||
{
|
||||
list->callbacks = callbacks;
|
||||
list->element_count = 0;
|
||||
list->node_count = 0;
|
||||
list->first_node = NULL;
|
||||
list->last_node = NULL;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_init_from_list (objects_list_t * list, objects_list_t * old_list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
void *element;
|
||||
|
||||
if (list != NULL)
|
||||
{
|
||||
list->callbacks = objects_list_element_callbacks (old_list);
|
||||
list->element_count = 0;
|
||||
list->node_count = 0;
|
||||
list->first_node = NULL;
|
||||
list->last_node = NULL;
|
||||
|
||||
if (old_list != NULL)
|
||||
{
|
||||
/* Get a forward enumerator for OLD_LIST. */
|
||||
enumerator = objects_list_forward_enumerator (old_list);
|
||||
|
||||
/* Walk from the beginning to the end of OLD_LIST, and add each
|
||||
* element to the end of LIST. */
|
||||
while (objects_list_enumerator_next_element (&enumerator, &element))
|
||||
objects_list_at_index_insert_element (list, -1, element);
|
||||
}
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Destroying **/
|
||||
|
||||
void
|
||||
objects_list_dealloc (objects_list_t * list)
|
||||
{
|
||||
/* Empty LIST out. */
|
||||
objects_list_empty (list);
|
||||
|
||||
/* Get rid of LIST. */
|
||||
_objects_list_dealloc (list);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Comparing **/
|
||||
|
||||
int
|
||||
objects_list_is_equal_to_list (objects_list_t * list, objects_list_t * other_list)
|
||||
{
|
||||
/* FIXME: Code this. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/** Concatenating **/
|
||||
|
||||
objects_list_t *
|
||||
objects_list_append_list (objects_list_t * base_list, objects_list_t * suffix_list)
|
||||
{
|
||||
return objects_list_at_index_insert_list (base_list, -1, suffix_list);
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_prepend_list (objects_list_t * base_list, objects_list_t * prefix_list)
|
||||
{
|
||||
return objects_list_at_index_insert_list (base_list, 0, prefix_list);
|
||||
}
|
||||
|
||||
/* FIXME: I was lazy when I wrote this next one. It can easily be
|
||||
* sped up. Do it. */
|
||||
objects_list_t *
|
||||
objects_list_at_index_insert_list (objects_list_t * base_list,
|
||||
long int n,
|
||||
objects_list_t * infix_list)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
void *element;
|
||||
|
||||
if (n < 0)
|
||||
enumerator = objects_list_forward_enumerator (infix_list);
|
||||
else /* (n >= 0) */
|
||||
enumerator = objects_list_reverse_enumerator (infix_list);
|
||||
|
||||
while (objects_list_enumerator_next_element (&enumerator, &element))
|
||||
objects_list_at_index_insert_element (base_list, n, element);
|
||||
|
||||
return base_list;
|
||||
}
|
||||
|
||||
/** Copying **/
|
||||
|
||||
objects_list_t *
|
||||
objects_list_copy (objects_list_t * old_list)
|
||||
{
|
||||
/* FIXME: Should I be using `objects_allocs_standard()' or
|
||||
* `objects_list_allocs(old_list)'? */
|
||||
return objects_list_copy_with_allocs (old_list, objects_list_allocs (old_list));
|
||||
}
|
||||
|
||||
objects_list_t *
|
||||
objects_list_copy_with_allocs (objects_list_t * old_list, objects_allocs_t allocs)
|
||||
{
|
||||
objects_list_t *list;
|
||||
|
||||
/* Allocate a new (low-level) copy of OLD_LIST. */
|
||||
list = _objects_list_copy_with_allocs (old_list, allocs);
|
||||
|
||||
/* Fill it in. */
|
||||
return objects_list_init_from_list (list, old_list);
|
||||
}
|
||||
|
||||
/** Mapping **/
|
||||
|
||||
objects_list_t *
|
||||
objects_list_map_elements (objects_list_t * list,
|
||||
void *(*fcn) (void *, void *),
|
||||
void *user_data)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
objects_list_node_t *node;
|
||||
|
||||
enumerator = objects_list_enumerator (list);
|
||||
|
||||
while ((node = _objects_list_enumerator_next_node (&enumerator)) != NULL)
|
||||
{
|
||||
void *element;
|
||||
|
||||
element = (*fcn) (node->element, user_data);
|
||||
|
||||
/* NOTE: I'm accessing the callbacks directly for a little
|
||||
* efficiency. */
|
||||
objects_retain (list->callbacks, element, list);
|
||||
objects_release (list->callbacks, node->element, list);
|
||||
|
||||
node->element = element;
|
||||
}
|
||||
|
||||
return list;
|
||||
}
|
||||
|
||||
/** Creating other collections from lists **/
|
||||
|
||||
objects_hash_t *
|
||||
objects_hash_init_from_list (objects_hash_t * hash, objects_list_t * list)
|
||||
{
|
||||
if (hash != NULL)
|
||||
{
|
||||
objects_list_enumerator_t enumerator;
|
||||
void *element;
|
||||
|
||||
/* Make a note of the callbacks for HASH. */
|
||||
hash->callbacks = objects_list_element_callbacks (list);
|
||||
|
||||
/* Zero out the various counts. */
|
||||
hash->node_count = 0;
|
||||
hash->bucket_count = 0;
|
||||
hash->element_count = 0;
|
||||
|
||||
/* Zero out the pointers. */
|
||||
hash->first_node = NULL;
|
||||
hash->buckets = NULL;
|
||||
|
||||
/* Resize HASH to the given CAPACITY. */
|
||||
objects_hash_resize (hash, objects_list_capacity (list));
|
||||
|
||||
/* Get an element enumerator for LIST. */
|
||||
enumerator = objects_list_enumerator (list);
|
||||
|
||||
/* Add LIST's elements to HASH, one at a time. Note that if LIST
|
||||
* contains multiple elements from the same equivalence class, it
|
||||
* is indeterminate which will end up in HASH. But this shouldn't
|
||||
* be a problem. */
|
||||
while (objects_list_enumerator_next_element (&enumerator, &element))
|
||||
objects_hash_add_element (hash, element);
|
||||
}
|
||||
|
||||
/* Return the newly initialized HASH. */
|
||||
return hash;
|
||||
}
|
||||
|
||||
// objects_chash_t *
|
||||
// objects_chash_init_from_list (objects_chash_t * chash, objects_list_t * list)
|
||||
// {
|
||||
// if (chash != NULL)
|
||||
// {
|
||||
// objects_list_enumerator_t enumerator;
|
||||
// void *element;
|
||||
//
|
||||
// /* Make a note of the callbacks for CHASH. */
|
||||
// chash->callbacks = objects_list_element_callbacks (list);
|
||||
//
|
||||
// /* Zero out the various counts. */
|
||||
// chash->node_count = 0;
|
||||
// chash->bucket_count = 0;
|
||||
// chash->element_count = 0;
|
||||
//
|
||||
// /* Zero out the pointers. */
|
||||
// chash->first_node = NULL;
|
||||
// chash->buckets = NULL;
|
||||
//
|
||||
// /* Resize CHASH to the given CAPACITY. */
|
||||
// objects_chash_resize (chash, objects_list_capacity (list));
|
||||
//
|
||||
// /* Get an element enumerator for LIST. */
|
||||
// enumerator = objects_list_enumerator (list);
|
||||
//
|
||||
// /* Add LIST's elements to CHASH, one at a time. Note that if LIST
|
||||
// * contains multiple elements from the same equivalence class, it
|
||||
// * is indeterminate which will end up in CHASH. But this shouldn't
|
||||
// * be a problem. */
|
||||
// while (objects_list_enumerator_next_element (&enumerator, &element))
|
||||
// objects_chash_add_element (chash, element);
|
||||
// }
|
||||
//
|
||||
// /* Return the newly initialized CHASH. */
|
||||
// return chash;
|
||||
// }
|
||||
|
1235
Source/map.c
Normal file
1235
Source/map.c
Normal file
File diff suppressed because it is too large
Load diff
368
Source/md5.c
Normal file
368
Source/md5.c
Normal file
|
@ -0,0 +1,368 @@
|
|||
|
||||
/* md5.c - Functions to compute MD5 message digest of files or memory blocks
|
||||
according to the definition of MD5 in RFC 1321 from April 1992.
|
||||
Copyright (C) 1995 Software Foundation, Inc.
|
||||
|
||||
This program 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; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
|
||||
|
||||
/* Written by Ulrich Drepper <drepper@gnu.ai.mit.edu>. */
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
#endif
|
||||
|
||||
#include <sys/types.h>
|
||||
|
||||
#if STDC_HEADERS
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#else
|
||||
#ifndef HAVE_MEMCPY
|
||||
#define memcpy(d, s, n) bcopy ((s), (d), (n))
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "md5.h"
|
||||
|
||||
#ifdef WORDS_BIGENDIAN
|
||||
#define SWAP(n) \
|
||||
(((n) << 24) | (((n) & 0xff00) << 8) | (((n) >> 8) & 0xff00) | ((n) >> 24))
|
||||
#else
|
||||
#define SWAP(n) (n)
|
||||
#endif
|
||||
|
||||
|
||||
/* This array contains the bytes used to pad the buffer to the next
|
||||
64-byte boundary. (RFC 1321, 3.1: Step 1) */
|
||||
static const unsigned char fillbuf[64] =
|
||||
{0x80, 0 /* , 0, 0, ... */ };
|
||||
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
(RFC 1321, 3.3: Step 3) */
|
||||
void
|
||||
md5_init_ctx (ctx)
|
||||
struct md5_ctx *ctx;
|
||||
{
|
||||
ctx->A = 0x67452301;
|
||||
ctx->B = 0xefcdab89;
|
||||
ctx->C = 0x98badcfe;
|
||||
ctx->D = 0x10325476;
|
||||
}
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result must
|
||||
be in little endian byte order. */
|
||||
void *
|
||||
md5_read_ctx (ctx, resbuf)
|
||||
const struct md5_ctx *ctx;
|
||||
void *resbuf;
|
||||
{
|
||||
((md5_uint32 *) resbuf)[0] = SWAP (ctx->A);
|
||||
((md5_uint32 *) resbuf)[1] = SWAP (ctx->B);
|
||||
((md5_uint32 *) resbuf)[2] = SWAP (ctx->C);
|
||||
((md5_uint32 *) resbuf)[3] = SWAP (ctx->D);
|
||||
|
||||
return resbuf;
|
||||
}
|
||||
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
resulting message digest number will be written into the 16 bytes
|
||||
beginning at RESBLOCK. */
|
||||
int
|
||||
md5_stream (stream, resblock)
|
||||
FILE *stream;
|
||||
void *resblock;
|
||||
{
|
||||
/* Important: BLOCKSIZE must be a multiple of 64. */
|
||||
#define BLOCKSIZE 4096
|
||||
struct md5_ctx ctx;
|
||||
md5_uint32 len[2];
|
||||
char buffer[BLOCKSIZE + 72];
|
||||
size_t pad, sum;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx (&ctx);
|
||||
|
||||
len[0] = 0;
|
||||
len[1] = 0;
|
||||
|
||||
/* Iterate over full file contents. */
|
||||
while (1)
|
||||
{
|
||||
/* We read the file in blocks of BLOCKSIZE bytes. One call of the
|
||||
computation function processes the whole buffer so that with the
|
||||
next round of the loop another block can be read. */
|
||||
size_t n;
|
||||
sum = 0;
|
||||
|
||||
/* Read block. Take care for partial reads. */
|
||||
do
|
||||
{
|
||||
n = fread (buffer, 1, BLOCKSIZE - sum, stream);
|
||||
|
||||
sum += n;
|
||||
}
|
||||
while (sum < BLOCKSIZE && n != 0);
|
||||
if (n == 0 && ferror (stream))
|
||||
return 1;
|
||||
|
||||
/* RFC 1321 specifies the possible length of the file up to 2^64 bits.
|
||||
Here we only compute the number of bytes. Do a double word
|
||||
increment. */
|
||||
len[0] += sum;
|
||||
if (len[0] < sum)
|
||||
++len[1];
|
||||
|
||||
/* If end of file is reached, end the loop. */
|
||||
if (n == 0)
|
||||
break;
|
||||
|
||||
/* Process buffer with BLOCKSIZE bytes. Note that
|
||||
BLOCKSIZE % 64 == 0
|
||||
*/
|
||||
md5_process_block (buffer, BLOCKSIZE, &ctx);
|
||||
}
|
||||
|
||||
/* We can copy 64 byte because the buffer is always big enough. FILLBUF
|
||||
contains the needed bits. */
|
||||
memcpy (&buffer[sum], fillbuf, 64);
|
||||
|
||||
/* Compute amount of padding bytes needed. Alignment is done to
|
||||
(N + PAD) % 64 == 56
|
||||
There is always at least one byte padded. I.e. even the alignment
|
||||
is correctly aligned 64 padding bytes are added. */
|
||||
pad = sum & 63;
|
||||
pad = pad >= 56 ? 64 + 56 - pad : 56 - pad;
|
||||
|
||||
/* Put the 64-bit file length in *bits* at the end of the buffer. */
|
||||
*(md5_uint32 *) & buffer[sum + pad] = SWAP (len[0] << 3);
|
||||
*(md5_uint32 *) & buffer[sum + pad + 4] = SWAP ((len[1] << 3)
|
||||
| (len[0] >> 29));
|
||||
|
||||
/* Process last bytes. */
|
||||
md5_process_block (buffer, sum + pad + 8, &ctx);
|
||||
|
||||
/* Construct result in desired memory. */
|
||||
md5_read_ctx (&ctx, resblock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
void *
|
||||
md5_buffer (buffer, len, resblock)
|
||||
const char *buffer;
|
||||
size_t len;
|
||||
void *resblock;
|
||||
{
|
||||
struct md5_ctx ctx;
|
||||
char restbuf[64 + 72];
|
||||
size_t blocks = len & ~63;
|
||||
size_t pad, rest;
|
||||
|
||||
/* Initialize the computation context. */
|
||||
md5_init_ctx (&ctx);
|
||||
|
||||
/* Process whole buffer but last len % 64 bytes. */
|
||||
md5_process_block (buffer, blocks, &ctx);
|
||||
|
||||
/* REST bytes are not processed yet. */
|
||||
rest = len - blocks;
|
||||
/* Copy to own buffer. */
|
||||
memcpy (restbuf, &buffer[blocks], rest);
|
||||
/* Append needed fill bytes at end of buffer. We can copy 64 byte
|
||||
because the buffer is always big enough. */
|
||||
memcpy (&restbuf[rest], fillbuf, 64);
|
||||
|
||||
/* PAD bytes are used for padding to correct alignment. Note that
|
||||
always at least one byte is padded. */
|
||||
pad = rest >= 56 ? 64 + 56 - rest : 56 - rest;
|
||||
|
||||
/* Put length of buffer in *bits* in last eight bytes. */
|
||||
*(md5_uint32 *) & restbuf[rest + pad] = (md5_uint32) SWAP (len << 3);
|
||||
*(md5_uint32 *) & restbuf[rest + pad + 4] = (md5_uint32) SWAP (len >> 29);
|
||||
|
||||
/* Process last bytes. */
|
||||
md5_process_block (restbuf, rest + pad + 8, &ctx);
|
||||
|
||||
/* Put result in desired memory area. */
|
||||
return md5_read_ctx (&ctx, resblock);
|
||||
}
|
||||
|
||||
|
||||
/* These are the four functions used in the four steps of the MD5 algorithm
|
||||
and defined in the RFC 1321. The first function is a little bit optimized
|
||||
(as found in Colin Plumbs public domain implementation). */
|
||||
/* #define FF(b, c, d) ((b & c) | (~b & d)) */
|
||||
#define FF(b, c, d) (d ^ (b & (c ^ d)))
|
||||
#define FG(b, c, d) FF (d, b, c)
|
||||
#define FH(b, c, d) (b ^ c ^ d)
|
||||
#define FI(b, c, d) (c ^ (b | ~d))
|
||||
|
||||
/* Process LEN bytes of BUFFER, accumulating context into CTX.
|
||||
It is assumed that LEN % 64 == 0. */
|
||||
|
||||
void
|
||||
md5_process_block (buffer, len, ctx)
|
||||
const void *buffer;
|
||||
size_t len;
|
||||
struct md5_ctx *ctx;
|
||||
{
|
||||
md5_uint32 correct_words[16];
|
||||
const md5_uint32 *words = buffer;
|
||||
size_t nwords = len / sizeof (md5_uint32);
|
||||
const md5_uint32 *endp = words + nwords;
|
||||
md5_uint32 A = ctx->A;
|
||||
md5_uint32 B = ctx->B;
|
||||
md5_uint32 C = ctx->C;
|
||||
md5_uint32 D = ctx->D;
|
||||
|
||||
/* Process all bytes in the buffer with 64 bytes in each round of
|
||||
the loop. */
|
||||
while (words < endp)
|
||||
{
|
||||
md5_uint32 *cwp = correct_words;
|
||||
md5_uint32 A_save = A;
|
||||
md5_uint32 B_save = B;
|
||||
md5_uint32 C_save = C;
|
||||
md5_uint32 D_save = D;
|
||||
|
||||
/* First round: using the given function, the context and a constant
|
||||
the next context is computed. Because the algorithms processing
|
||||
unit is a 32-bit word and it is determined to work on words in
|
||||
little endian byte order we perhaps have to change the byte order
|
||||
before the computation. To reduce the work for the next steps
|
||||
we store the swapped words in the array CORRECT_WORDS. */
|
||||
|
||||
#define OP(a, b, c, d, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += FF (b, c, d) + (*cwp++ = SWAP (*words)) + T; \
|
||||
++words; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* It is unfortunate that C does not provide an operator for
|
||||
cyclic rotation. Hope the C compiler is smart enough. */
|
||||
#define CYCLIC(w, s) (w = (w << s) | (w >> (32 - s)))
|
||||
|
||||
/* Before we start, one word to the strange constants.
|
||||
They are defined in RFC 1321 as
|
||||
|
||||
T[i] = (int) (4294967296.0 * fabs (sin (i))), i=1..64
|
||||
*/
|
||||
|
||||
/* Round 1. */
|
||||
OP (A, B, C, D, 7, 0xd76aa478);
|
||||
OP (D, A, B, C, 12, 0xe8c7b756);
|
||||
OP (C, D, A, B, 17, 0x242070db);
|
||||
OP (B, C, D, A, 22, 0xc1bdceee);
|
||||
OP (A, B, C, D, 7, 0xf57c0faf);
|
||||
OP (D, A, B, C, 12, 0x4787c62a);
|
||||
OP (C, D, A, B, 17, 0xa8304613);
|
||||
OP (B, C, D, A, 22, 0xfd469501);
|
||||
OP (A, B, C, D, 7, 0x698098d8);
|
||||
OP (D, A, B, C, 12, 0x8b44f7af);
|
||||
OP (C, D, A, B, 17, 0xffff5bb1);
|
||||
OP (B, C, D, A, 22, 0x895cd7be);
|
||||
OP (A, B, C, D, 7, 0x6b901122);
|
||||
OP (D, A, B, C, 12, 0xfd987193);
|
||||
OP (C, D, A, B, 17, 0xa679438e);
|
||||
OP (B, C, D, A, 22, 0x49b40821);
|
||||
|
||||
/* For the second to fourth round we have the possibly swapped words
|
||||
in CORRECT_WORDS. Redefine the macro to take an additional first
|
||||
argument specifying the function to use. */
|
||||
#undef OP
|
||||
#define OP(f, a, b, c, d, k, s, T) \
|
||||
do \
|
||||
{ \
|
||||
a += f (b, c, d) + correct_words[k] + T; \
|
||||
CYCLIC (a, s); \
|
||||
a += b; \
|
||||
} \
|
||||
while (0)
|
||||
|
||||
/* Round 2. */
|
||||
OP (FG, A, B, C, D, 1, 5, 0xf61e2562);
|
||||
OP (FG, D, A, B, C, 6, 9, 0xc040b340);
|
||||
OP (FG, C, D, A, B, 11, 14, 0x265e5a51);
|
||||
OP (FG, B, C, D, A, 0, 20, 0xe9b6c7aa);
|
||||
OP (FG, A, B, C, D, 5, 5, 0xd62f105d);
|
||||
OP (FG, D, A, B, C, 10, 9, 0x02441453);
|
||||
OP (FG, C, D, A, B, 15, 14, 0xd8a1e681);
|
||||
OP (FG, B, C, D, A, 4, 20, 0xe7d3fbc8);
|
||||
OP (FG, A, B, C, D, 9, 5, 0x21e1cde6);
|
||||
OP (FG, D, A, B, C, 14, 9, 0xc33707d6);
|
||||
OP (FG, C, D, A, B, 3, 14, 0xf4d50d87);
|
||||
OP (FG, B, C, D, A, 8, 20, 0x455a14ed);
|
||||
OP (FG, A, B, C, D, 13, 5, 0xa9e3e905);
|
||||
OP (FG, D, A, B, C, 2, 9, 0xfcefa3f8);
|
||||
OP (FG, C, D, A, B, 7, 14, 0x676f02d9);
|
||||
OP (FG, B, C, D, A, 12, 20, 0x8d2a4c8a);
|
||||
|
||||
/* Round 3. */
|
||||
OP (FH, A, B, C, D, 5, 4, 0xfffa3942);
|
||||
OP (FH, D, A, B, C, 8, 11, 0x8771f681);
|
||||
OP (FH, C, D, A, B, 11, 16, 0x6d9d6122);
|
||||
OP (FH, B, C, D, A, 14, 23, 0xfde5380c);
|
||||
OP (FH, A, B, C, D, 1, 4, 0xa4beea44);
|
||||
OP (FH, D, A, B, C, 4, 11, 0x4bdecfa9);
|
||||
OP (FH, C, D, A, B, 7, 16, 0xf6bb4b60);
|
||||
OP (FH, B, C, D, A, 10, 23, 0xbebfbc70);
|
||||
OP (FH, A, B, C, D, 13, 4, 0x289b7ec6);
|
||||
OP (FH, D, A, B, C, 0, 11, 0xeaa127fa);
|
||||
OP (FH, C, D, A, B, 3, 16, 0xd4ef3085);
|
||||
OP (FH, B, C, D, A, 6, 23, 0x04881d05);
|
||||
OP (FH, A, B, C, D, 9, 4, 0xd9d4d039);
|
||||
OP (FH, D, A, B, C, 12, 11, 0xe6db99e5);
|
||||
OP (FH, C, D, A, B, 15, 16, 0x1fa27cf8);
|
||||
OP (FH, B, C, D, A, 2, 23, 0xc4ac5665);
|
||||
|
||||
/* Round 4. */
|
||||
OP (FI, A, B, C, D, 0, 6, 0xf4292244);
|
||||
OP (FI, D, A, B, C, 7, 10, 0x432aff97);
|
||||
OP (FI, C, D, A, B, 14, 15, 0xab9423a7);
|
||||
OP (FI, B, C, D, A, 5, 21, 0xfc93a039);
|
||||
OP (FI, A, B, C, D, 12, 6, 0x655b59c3);
|
||||
OP (FI, D, A, B, C, 3, 10, 0x8f0ccc92);
|
||||
OP (FI, C, D, A, B, 10, 15, 0xffeff47d);
|
||||
OP (FI, B, C, D, A, 1, 21, 0x85845dd1);
|
||||
OP (FI, A, B, C, D, 8, 6, 0x6fa87e4f);
|
||||
OP (FI, D, A, B, C, 15, 10, 0xfe2ce6e0);
|
||||
OP (FI, C, D, A, B, 6, 15, 0xa3014314);
|
||||
OP (FI, B, C, D, A, 13, 21, 0x4e0811a1);
|
||||
OP (FI, A, B, C, D, 4, 6, 0xf7537e82);
|
||||
OP (FI, D, A, B, C, 11, 10, 0xbd3af235);
|
||||
OP (FI, C, D, A, B, 2, 15, 0x2ad7d2bb);
|
||||
OP (FI, B, C, D, A, 9, 21, 0xeb86d391);
|
||||
|
||||
/* Add the starting values of the context. */
|
||||
A += A_save;
|
||||
B += B_save;
|
||||
C += C_save;
|
||||
D += D_save;
|
||||
}
|
||||
|
||||
/* Put checksum in context given as argument. */
|
||||
ctx->A = A;
|
||||
ctx->B = B;
|
||||
ctx->C = C;
|
||||
ctx->D = D;
|
||||
}
|
115
Source/md5.h
Normal file
115
Source/md5.h
Normal file
|
@ -0,0 +1,115 @@
|
|||
/* md5.h - Declaration of functions and data types used for MD5 sum
|
||||
computing library functions.
|
||||
Copyright (C) 1995 Free Software Foundation, Inc.
|
||||
|
||||
This program 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; either version 2, or (at your option)
|
||||
any later version.
|
||||
|
||||
This program 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 this program; if not, write to the Free Software
|
||||
Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
|
||||
|
||||
#ifndef _MD5_H
|
||||
#define _MD5_H
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#if defined HAVE_LIMITS_H || _LIBC
|
||||
#include <limits.h>
|
||||
#endif
|
||||
|
||||
/* The following contortions are an attempt to use the C preprocessor
|
||||
to determine an unsigned integral type that is 32 bits wide. An
|
||||
alternative approach is to use autoconf's AC_CHECK_SIZEOF macro, but
|
||||
doing that would require that the configure script compile and *run*
|
||||
the resulting executable. Locally running cross-compiled executables
|
||||
is usually not possible. */
|
||||
|
||||
#if defined __STDC__ && __STDC__
|
||||
#define UINT_MAX_32_BITS 4294967295U
|
||||
#else
|
||||
#define UINT_MAX_32_BITS 0xFFFFFFFF
|
||||
#endif
|
||||
|
||||
/* If UINT_MAX isn't defined, assume it's a 32-bit type.
|
||||
This should be valid for all systems GNU cares about because
|
||||
that doesn't include 16-bit systems, and only modern systems
|
||||
(that certainly have <limits.h>) have 64+-bit integral types. */
|
||||
|
||||
#ifndef UINT_MAX
|
||||
#define UINT_MAX UINT_MAX_32_BITS
|
||||
#endif
|
||||
|
||||
#if UINT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned int md5_uint32;
|
||||
#else
|
||||
#if USHRT_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned short md5_uint32;
|
||||
#else
|
||||
#if ULONG_MAX == UINT_MAX_32_BITS
|
||||
typedef unsigned long md5_uint32;
|
||||
#else
|
||||
/* The following line is intended to evoke an error.
|
||||
Using #error is not portable enough. */
|
||||
"Cannot determine unsigned 32-bit data type."
|
||||
#endif
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#undef __P
|
||||
#if defined (__STDC__) && __STDC__
|
||||
#define __P(x) x
|
||||
#else
|
||||
#define __P(x) ()
|
||||
#endif
|
||||
|
||||
/* Structure to save state of computation between the single steps. */
|
||||
struct md5_ctx
|
||||
{
|
||||
md5_uint32 A;
|
||||
md5_uint32 B;
|
||||
md5_uint32 C;
|
||||
md5_uint32 D;
|
||||
};
|
||||
|
||||
/*
|
||||
* The following three functions are build up the low level used in
|
||||
* the functions `md5_stream' and `md5_buffer'.
|
||||
*/
|
||||
|
||||
/* Initialize structure containing state of computation.
|
||||
(RFC 1321, 3.3: Step 3) */
|
||||
void md5_init_ctx __P ((struct md5_ctx * ctx));
|
||||
|
||||
/* Starting with the result of former calls of this function (or the
|
||||
initialzation function update the context for the next LEN bytes
|
||||
starting at BUFFER.
|
||||
It is necessary that LEN is a multiple of 64!!! */
|
||||
void md5_process_block __P ((const void *buffer, size_t len,
|
||||
struct md5_ctx * ctx));
|
||||
|
||||
/* Put result from CTX in first 16 bytes following RESBUF. The result is
|
||||
always in little endian byte order, so that a byte-wise output yields
|
||||
to the wanted ASCII representation of the message digest. */
|
||||
void *md5_read_ctx __P ((const struct md5_ctx * ctx, void *resbuf));
|
||||
|
||||
|
||||
/* Compute MD5 message digest for bytes read from STREAM. The
|
||||
resulting message digest number will be written into the 16 bytes
|
||||
beginning at RESBLOCK. */
|
||||
int md5_stream __P ((FILE * stream, void *resblock));
|
||||
|
||||
/* Compute MD5 message digest for LEN bytes beginning at BUFFER. The
|
||||
result is always in little endian byte order, so that a byte-wise
|
||||
output yields to the wanted ASCII representation of the message
|
||||
digest. */
|
||||
void *md5_buffer __P ((const char *buffer, size_t len, void *resblock));
|
||||
|
||||
#endif
|
59
Source/number.c
Normal file
59
Source/number.c
Normal file
|
@ -0,0 +1,59 @@
|
|||
/* Structure counters and functions for getting at them.
|
||||
* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Sun Dec 3 00:23:13 EST 1995
|
||||
* Updated: Sat Feb 10 13:52:15 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/number.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
size_t ___objects_number_allocated = 0;
|
||||
size_t ___objects_number_deallocated = 0;
|
||||
size_t ___objects_number_serial = 0;
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/* Returns the number of Libobjects structures allocated. */
|
||||
size_t
|
||||
objects_number_allocated(void)
|
||||
{
|
||||
return ___objects_number_allocated;
|
||||
}
|
||||
|
||||
/* Returns the number of Libobjects structures deallocated. */
|
||||
size_t
|
||||
objects_number_deallocated(void)
|
||||
{
|
||||
return ___objects_number_deallocated;
|
||||
}
|
||||
|
||||
/* Returns the next serial number to be handed out. */
|
||||
size_t
|
||||
objects_number_serial(void)
|
||||
{
|
||||
return ___objects_number_serial;
|
||||
}
|
||||
|
276
Source/x-basics.c.in
Normal file
276
Source/x-basics.c.in
Normal file
|
@ -0,0 +1,276 @@
|
|||
/* Basic functions for @XX@ structures.
|
||||
* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Tue Dec 12 12:33:01 EST 1995
|
||||
* Updated: Sat Feb 10 09:08:35 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/allocs.h>
|
||||
#include <objects/number.h>
|
||||
#include <objects/magic.h>
|
||||
#include <objects/@XX@.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
#define __@XX@__ 1
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
/** Magic **/
|
||||
|
||||
/* Returns XX's magic number. */
|
||||
int
|
||||
objects_@XX@_magic (objects_@XX@_t *xx)
|
||||
{
|
||||
return xx->magic;
|
||||
}
|
||||
|
||||
/** Allocs **/
|
||||
|
||||
/* Returns the allocs used to create and maintain XX. */
|
||||
objects_allocs_t
|
||||
objects_@XX@_allocs (objects_@XX@_t *xx)
|
||||
{
|
||||
return xx->allocs;
|
||||
}
|
||||
|
||||
/** Names **/
|
||||
|
||||
/* Returns the name that was given to XX. */
|
||||
const char *
|
||||
objects_@XX@_name (objects_@XX@_t *xx)
|
||||
{
|
||||
return xx->name;
|
||||
}
|
||||
|
||||
/* Gives XX a name. Space is allocated, and the contents of the
|
||||
* NUL-terminated NAME are copied. Deallocating XX frees up the
|
||||
* space. I.e., it is not the responsibility of the programmer to
|
||||
* keep track of space allocated for this procedure. */
|
||||
const char *
|
||||
objects_@XX@_set_name (objects_@XX@_t *xx, const char *name)
|
||||
{
|
||||
/* Figure out how much space we need. */
|
||||
size_t len = strlen (name);
|
||||
char *old_name = xx->name;
|
||||
|
||||
/* Allocate space for the new name. (Don't forget the extra space
|
||||
* for the terminating `NUL'. */
|
||||
xx->name = (char *) objects_malloc (xx->allocs, len + 1);
|
||||
|
||||
/* If the allocation was successful, copy the new name over and get
|
||||
* rid of the old name. */
|
||||
if (xx->name != NULL)
|
||||
{
|
||||
/* Copy over the new name. */
|
||||
strncpy (xx->name, name, len);
|
||||
|
||||
/* Free up any space we set aside for any older name. */
|
||||
if (old_name != NULL)
|
||||
objects_free (xx->allocs, old_name);
|
||||
}
|
||||
|
||||
return xx->name;
|
||||
}
|
||||
|
||||
/* Takes away XX's name. */
|
||||
void
|
||||
objects_@XX@_unset_name (objects_@XX@_t *xx)
|
||||
{
|
||||
/* Free it. */
|
||||
if (xx->name != NULL)
|
||||
objects_free (xx->allocs, xx->name);
|
||||
|
||||
/* Reset it. */
|
||||
xx->name = NULL;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Number **/
|
||||
|
||||
/* Returns the (process-wide) unique number given to the Libobjects
|
||||
* structure XX. See <objects/number.h> for more info. */
|
||||
size_t
|
||||
objects_@XX@_number (objects_@XX@_t *xx)
|
||||
{
|
||||
return xx->number;
|
||||
}
|
||||
|
||||
/* Gives XX a new (process-wide) unique number. Numbers are not
|
||||
* reused. See <objects/number.h> for more info. */
|
||||
size_t
|
||||
_objects_@XX@_set_serial_number (objects_@XX@_t *xx)
|
||||
{
|
||||
size_t old_number;
|
||||
|
||||
old_number = xx->number;
|
||||
xx->number = (___objects_number_serial)++;
|
||||
|
||||
return old_number;
|
||||
}
|
||||
|
||||
/** Extras **/
|
||||
|
||||
/* Sets the callbacks associated with XX's ``extra''. NOTE: This must
|
||||
* be done before calling `objects_@XX@_set_extra()', as these callbacks
|
||||
* are used in that routine. */
|
||||
objects_callbacks_t
|
||||
objects_@XX@_set_extra_callbacks (objects_@XX@_t *xx, objects_callbacks_t callbacks)
|
||||
{
|
||||
objects_callbacks_t old_callbacks;
|
||||
|
||||
/* Remember the old callbacks for later. */
|
||||
old_callbacks = xx->extra_callbacks;
|
||||
|
||||
/* Set the new callbacks. */
|
||||
xx->extra_callbacks = callbacks;
|
||||
|
||||
/* Release the old contents. */
|
||||
objects_release (old_callbacks, xx->extra, xx);
|
||||
|
||||
/* Set the contents to something noticible. */
|
||||
xx->extra = (xx->extra_callbacks).not_an_item_marker;
|
||||
|
||||
return old_callbacks;
|
||||
}
|
||||
|
||||
/* Returns the callbacks associated with XX's ``extra''. */
|
||||
objects_callbacks_t
|
||||
objects_@XX@_extra_callbacks (objects_@XX@_t *xx, objects_callbacks_t callbacks)
|
||||
{
|
||||
return xx->extra_callbacks;
|
||||
}
|
||||
|
||||
/* Returns XX's ``extra'', a little extra space that each Libobjects
|
||||
* structure carries around with it. Its use is
|
||||
* implementation-dependent. */
|
||||
void *
|
||||
objects_@XX@_extra (objects_@XX@_t *xx)
|
||||
{
|
||||
return xx->extra;
|
||||
}
|
||||
|
||||
/* Sets XX's ``extra'', a little extra space that each Libobjects structure
|
||||
* carries around with it. Its use is implementation-dependent. */
|
||||
void *
|
||||
objects_@XX@_set_extra (objects_@XX@_t *xx, void *extra)
|
||||
{
|
||||
void *old_extra;
|
||||
|
||||
/* Out with the old, and in with the new. */
|
||||
old_extra = xx->extra;
|
||||
xx->extra = objects_retain (xx->extra_callbacks, extra, xx);
|
||||
objects_release (xx->extra_callbacks, old_extra, xx);
|
||||
|
||||
return old_extra;
|
||||
}
|
||||
|
||||
/* Resets XX's ``extra''. */
|
||||
void
|
||||
objects_@XX@_unset_extra (objects_@XX@_t *xx)
|
||||
{
|
||||
/* Release XX's extra. */
|
||||
objects_release (xx->extra_callbacks, xx->extra, xx);
|
||||
|
||||
/* Reset XX's extra. */
|
||||
xx->extra = (xx->extra_callbacks).not_an_item_marker;
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/** Low-level Creation and Destruction **/
|
||||
|
||||
/* Handles the universal, low-level allocation of Libobjects structures. */
|
||||
objects_@XX@_t *
|
||||
_objects_@XX@_alloc_with_allocs (objects_allocs_t allocs)
|
||||
{
|
||||
objects_@XX@_t *xx;
|
||||
|
||||
/* Try to allocate some space for XX. */
|
||||
xx = objects_malloc (allocs, sizeof (objects_@XX@_t));
|
||||
|
||||
/* The `objects_malloc()' was successful. */
|
||||
if (xx != NULL)
|
||||
{
|
||||
_objects_@XX@_set_serial_number (xx);
|
||||
xx->magic = _OBJECTS_MAGIC_@XX@;
|
||||
xx->name = NULL;
|
||||
xx->allocs = allocs;
|
||||
xx->extra_callbacks = objects_callbacks_for_void_p;
|
||||
xx->extra = 0;
|
||||
|
||||
/* Increment the counter of allocated Libobjects structures. */
|
||||
++(___objects_number_allocated);
|
||||
}
|
||||
|
||||
return xx;
|
||||
}
|
||||
|
||||
/* Handles the universal, low-level deallocation of Libobjects structures. */
|
||||
void
|
||||
_objects_@XX@_dealloc (objects_@XX@_t *xx)
|
||||
{
|
||||
/* Make sure XX is valid. */
|
||||
if (xx != NULL)
|
||||
{
|
||||
/* Free up any space we needed to keep track of XX's name. */
|
||||
if (xx->name != NULL)
|
||||
objects_free (objects_@XX@_allocs (xx), xx->name);
|
||||
|
||||
/* Release XX's extra. */
|
||||
objects_@XX@_unset_extra (xx);
|
||||
|
||||
/* Free up XX itself. */
|
||||
objects_free (objects_@XX@_allocs (xx), xx);
|
||||
|
||||
/* Increment the counter of deallocated Libobjects structures. */
|
||||
++(___objects_number_deallocated);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
/* Handles the low-level copying of Libobjects structures. */
|
||||
objects_@XX@_t *
|
||||
_objects_@XX@_copy_with_allocs (objects_@XX@_t *xx, objects_allocs_t allocs)
|
||||
{
|
||||
objects_@XX@_t *new;
|
||||
|
||||
/* Create a new structure. */
|
||||
new = _objects_@XX@_alloc_with_allocs (allocs);
|
||||
|
||||
if (new != NULL)
|
||||
{
|
||||
/* Copy over XX's name. */
|
||||
objects_@XX@_set_name (new, objects_@XX@_name (xx));
|
||||
|
||||
/* Copy over XX's extras. */
|
||||
objects_@XX@_set_extra_callbacks (new, xx->extra_callbacks);
|
||||
objects_@XX@_set_extra (new, xx->extra);
|
||||
}
|
||||
|
||||
return new;
|
||||
}
|
||||
|
89
Source/x-callbacks.c.in
Normal file
89
Source/x-callbacks.c.in
Normal file
|
@ -0,0 +1,89 @@
|
|||
/* Getting callbacks from @YY@ structures.
|
||||
* Copyright (C) 1995, 1996 Free Software Foundation, Inc.
|
||||
*
|
||||
* Author: Albin L. Jones <Albin.L.Jones@Dartmouth.EDU>
|
||||
* Created: Mon Dec 11 02:44:09 EST 1995
|
||||
* Updated: Sat Feb 10 10:08:59 EST 1996
|
||||
* Serial: 96.02.10.01
|
||||
*
|
||||
* This file is part of the GNU Objective C Class 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., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*
|
||||
*/
|
||||
|
||||
/**** Included Headers *******************************************************/
|
||||
|
||||
#include <objects/callbacks.h>
|
||||
#include <objects/@YY@.h>
|
||||
|
||||
/**** Type, Constant, and Macro Definitions **********************************/
|
||||
|
||||
#define __@YY@__ 1
|
||||
|
||||
/**** Function Implementations ***********************************************/
|
||||
|
||||
#ifdef __map__
|
||||
|
||||
/** Callbacks **/
|
||||
|
||||
/* Returns the callbacks associated with YY's keys. */
|
||||
objects_callbacks_t
|
||||
objects_@YY@_key_callbacks (objects_@YY@_t * yy)
|
||||
{
|
||||
return yy->key_callbacks;
|
||||
}
|
||||
|
||||
/* Returns the ``bogus'' marker associated with YY's keys. */
|
||||
void *
|
||||
objects_@YY@_not_a_key_marker (objects_@YY@_t *yy)
|
||||
{
|
||||
return (yy->key_callbacks).not_an_item_marker;
|
||||
}
|
||||
|
||||
/* Returns the callbacks associated with YY's values. */
|
||||
objects_callbacks_t
|
||||
objects_@YY@_value_callbacks (objects_@YY@_t *yy)
|
||||
{
|
||||
return yy->value_callbacks;
|
||||
}
|
||||
|
||||
/* Returns the ``bogus'' marker associated with YY's values. */
|
||||
void *
|
||||
objects_@YY@_not_a_value_marker (objects_@YY@_t *yy)
|
||||
{
|
||||
return (yy->value_callbacks).not_an_item_marker;
|
||||
}
|
||||
|
||||
#else /* !__map__ */
|
||||
|
||||
/** Callbacks **/
|
||||
|
||||
/* Returns the callbacks associated with YY's elements. */
|
||||
objects_callbacks_t
|
||||
objects_@YY@_element_callbacks (objects_@YY@_t *yy)
|
||||
{
|
||||
return yy->callbacks;
|
||||
}
|
||||
|
||||
/* Returns the ``bogus'' marker associated with YY's elements. */
|
||||
void *
|
||||
objects_@YY@_not_an_element_marker (objects_@YY@_t *yy)
|
||||
{
|
||||
return (yy->callbacks).not_an_item_marker;
|
||||
}
|
||||
|
||||
#endif /* __map__ */
|
||||
|
Loading…
Reference in a new issue