/*! Sunrise Data Dictionary Library * * @brief a library for hashtable storage of arbitrary data objects * with built-in reference counting and guaranteed order iteration. * * Version 1.00 revision 27 (pre-release) * * @file dd_data_dictionary.h * general purpose data dictionary * * @author Benjamin Kowarsch * * @note The author's true email address is herewith specifically excluded * from the license of this software. You are _not permitted_ to make the * author's true email address available to any third party. You may only * pass on the modified version of the email address as presented above. * * (C) 2006 Sunrise Telephone Systems Ltd. All rights reserved. * * @cond LICENSE_TERMS * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * Under no circumstances is it permitted for any licensee to take credit for * the creation of the Software, to claim authorship or ownership in the * Software or in any other way give the impression that they have created * the Software. Credit to the true authors and copyright holders of the * Software is absolutely mandatory and must be given as follows: * * Software packages incorporating the Software or substantial portions of it * shall display a copyright notice for the Software in the same manner as * they display any other copyright notice; shall display an authorship * notice for the Software in the same manner as they display any other * authorship notice; and shall display the license terms or a reference to * the license terms of the Software in the same manner as they display any * other license or license reference. * * GUI-based or GUI-alike interactive installers installing the Software or * substantial portions of it, shall display the Software's copyright notice, * authorship notice and license terms in full during the installation * process. Other installers such as shell command driven package installers * on Unix systems shall display copyright, authorship and license in the * same manner as for any other software. Installers shall allow users to * install the license file for the Software along with the Software itself. * * Software which makes use of but does not incorporate, nor bundle, nor * install the Software or substantial portions of it, is NOT required to * display any copyright, authorship, license terms or license reference for * the Software. Static linking to the Software constitutes 'incorporating', * dynamic linking to the Software constitutes 'making use of' the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * In countries and territories where the above no-warranty disclaimer is * not permissible by applicable law, the following terms apply: * * NO PERMISSION TO USE THE SOFTWARE IS GRANTED AND THE SOFTWARE MUST NOT BE * USED AT ALL IN SUCH COUNTRIES AND TERRITORIES WHERE THE ABOVE NO-WARRANTY * DISCLAIMER IS NOT PERMISSIBLE AND INVALIDATED BY APPLICABLE LAW. HOWEVER, * THE COPYRIGHT HOLDERS HEREBY WAIVE THEIR RIGHT TO PURSUE OFFENDERS AS LONG * AS THEY OTHERWISE ABIDE BY THE TERMS OF THE LICENSE AS APPLICABLE FOR USE * OF THE SOFTWARE IN COUNTRIES AND TERRITORIES WHERE THE ABOVE NO-WARRANTY * DISCLAIMER IS PERMITTED BY APPLICABLE LAW. THIS WAIVER DOES NOT CONSTITUTE * A LICENSE TO USE THE SOFTWARE IN COUNTRIES AND TERRITORIES WHERE THE ABOVE * NO-WARRANTY DISCLAIMER IS NOT PERMISSIBLE AND INVALIDATED BY APPLICABLE * LAW. ANY LIABILITY OF ANY KIND IS CATEGORICALLY RULED OUT AT ALL TIMES. * * @endcond */ #ifndef _DD_DATA_DICTIONARY_H #define _DD_DATA_DICTIONARY_H #include "dd_types.h" #include "dd_macros.h" #include "dd_status_codes.h" #include "dd_hash_functions.h" // -------------------------------------------------------------------------- // Opaque dictionary type // -------------------------------------------------------------------------- // // WARNING: Objects of this opaque type should only be accessed through this // public interface. DO NOT EVER attempt to bypass the public interface. // // The internal data structure of this opaque type is HIDDEN and MAY CHANGE // at any time WITHOUT NOTICE. The meaning of some internal pointer fields // may change dynamically at runtime. Accessing this internal data structure // directly other than through the functions in this public interface is // UNSAFE and may result in an inconsistent program state or a crash. typedef void *dd_dictionary; // -------------------------------------------------------------------------- // Opaque enumerator type // -------------------------------------------------------------------------- // // WARNING: Objects of this opaque type should only be accessed through this // public interface. DO NOT EVER attempt to bypass the public interface. // // The internal data structure of this opaque type is HIDDEN and MAY CHANGE // at any time WITHOUT NOTICE. The meaning of some internal pointer fields // may change dynamically at runtime. Accessing this internal data structure // directly other than through the functions in this public interface is // UNSAFE and may result in an inconsistent program state or a crash. typedef void *dd_enumerator; // -------------------------------------------------------------------------- // Event codes // -------------------------------------------------------------------------- typedef /* dd_event */ enum { /* triggered when ... */ DD_WILL_INSERT_OBJECT, /* ... an object is about to be added */ DD_DID_INSERT_OBJECT, /* ... an object has just been added */ DD_WILL_REMOVE_OBJECT, /* ... an object is about to be removed */ DD_DID_REMOVE_OBJECT, /* ... an object has just been removed */ /* to or from a dictionary, */ DD_WILL_DISPOSE_DICT, /* ... dictionary is about to be free'd */ DD_DID_DISPOSE_DICT /* ... dictionary has just been free'd */ } dd_event; // end dd_event // -------------------------------------------------------------------------- // Object copy function type // -------------------------------------------------------------------------- // // Function pointer type for object content copy functions. The first // argument of the function is the source object, the second argument is the // target object for the copy operation. typedef void (*dd_object_copy_function) (void *, void *); // -------------------------------------------------------------------------- // Object event handler function type // -------------------------------------------------------------------------- // // Function pointer type for object event handler functions. typedef void (*dd_object_event_handler) (void *); // -------------------------------------------------------------------------- // function: dd_new_dictionary() // -------------------------------------------------------------------------- // // Creates and returns a new empty dictionary. The size of the dictionary's // hashtable will be set to the default hastable size as returned by function // dd_default_hashtable_size(). // // Returns NULL if the dictionary could not be created. dd_dictionary dd_new_dictionary(); // -------------------------------------------------------------------------- // function: dd_new_dictionary_with_capacity(capacity) // -------------------------------------------------------------------------- // // Creates and returns a new empty dictionary of arbitrary size. The actual // size of the dictionary's hashtable will be set to the return value of // function dd_hashtable_size_for_requested_minimum() for value . // // If is 0, the actual hashtable size will be set to the default // as returned by dd_default_hashtable_size(), by default this value is 257. // // Returns NULL if the dictionary could not be created. dd_dictionary dd_new_dictionary_with_capacity(cardinal capacity); // -------------------------------------------------------------------------- // function: dd_set_hash_function_for_dictionary(dict, hashf) // -------------------------------------------------------------------------- // // Sets the hash function of dictionary to the function passed in // , which must be of type dd_hash_function. // // If no hash function is set, the default hash function as returned by // function dd_default_hash_function() will be used. The factory default is // hash function dd_SDBM_hash_string(). // // This operation is only allowed on empty dictionaries. dd_status dd_set_hash_function_for_dictionary(dd_dictionary dict, dd_hash_function hashf); // -------------------------------------------------------------------------- // function: dd_set_object_copy_function_for_dictionary(dict, copyf) // -------------------------------------------------------------------------- // // Sets the object content copy function of dictionary to the function // passed in , which must be of type dd_object_copy_function. // // By default no object content copy function is set and the replacement of // objects for keys already present in the dictionary is _not_ permitted. // // If an object content copy function is set, adding an object for a key that // is already present in the dictionary will copy the contents of the new // object into the object stored in the dictionary, thereby effectively // replacing the stored object. // // This operation is only allowed on empty dictionaries. dd_status dd_set_object_copy_function_for_dictionary(dd_dictionary dict, dd_object_copy_function copyf); // -------------------------------------------------------------------------- // function: dd_set_object_event_handler_for_dictionary(dict, evt, handler) // -------------------------------------------------------------------------- // // Sets the object event handler of dictionary for event to // the event handler function passed in , which must be of type // dd_object_event_handler. By default no event handlers are set. // // Note: Depending on how objects will be managed, setting object event // handlers will be required to ensure the release or deallocation of objects // stored in the dictionary. There are three usage scenarios: // // 1) Automatic Garbage Collection // // When using automatic garbage collection, for example the Boehm garbage // collector, the garbage collector owns all objects and manages them // automatically. No event handlers will be needed to assist in the // garbage collection process. // // 2) External Reference Counting // // When using a reference counting system external to the dictionary, the // external reference counting system owns all objects and manages them // semi-automatically with the assistance of 'retain' and 'release' calls. // // Functions which represent the 'retain' and 'release' operations of // the external reference counting system need to be registered with the // dictionary as event handlers for events DD_WILL_INSERT_OBJECT and // DD_DID_REMOVE_OBJECT respectively. Doing so will ensure that the // dictionary will participate in the external reference counting scheme // by automatically retaining objects when they are added and releasing // them when they are removed. // // When external reference counting is used, library functions which // provide a parameter in their argument list should _always_ be // called with the parameter set to 'true' and the caller should // then release objects obtained from the dictionary when the caller does // no longer need them. Function dd_release_object_for_key() is provided // for this purpose. // // 3) Built-in Reference Counting // // When there is no automatic garbage collection nor any external // reference counting system available, the built-in reference counting // facility should be used to manage objects stored in the dictionary. In // this case, the dictionary assumes ownership of all objects added to it. // // An object deallocator function needs to be registered with the // dictionary as event handler for event DD_DID_REMOVE_OBJECT. Doing so // will ensure that ownership of objects added to the dictionary passes to // the dictionary and that objects will automatically be deallocated // when they are removed from the dictionary. // // When built-in reference counting is used, library functions which // provide a parameter in their argument list should _always_ be // called with the parameter set to 'true' and the caller should // then release objects obtained from the dictionary when the caller does // no longer need them. Function dd_release_object_for_key() is provided // for this purpose. // // CAUTION! Objects added to a dictionary should always be managed in one of // the ways described above. One should _not_ attempt to deallocate objects // manually because objects will not immediately be removed from a dictionary // when function dd_remove_object_for_key() is called. The only way to know // for certain when an object has been removed from the dictionary is to // register an event handler for event DD_DID_REMOVE_OBJECT as described // under usage scenario #3 ("Built-in Reference Counting"). // // This operation is only allowed on empty dictionaries. dd_status dd_set_object_event_handler_for_dictionary(dd_dictionary dict, dd_event event, dd_object_event_handler handler); // -------------------------------------------------------------------------- // function: dd_add_object_for_key(dict, key, object) // -------------------------------------------------------------------------- // // Adds the key and its associated value to dictionary . // // Keys are added to the dictionary by value, objects are added by reference. // Keys must not be empty strings and objects must not be NULL. // // If key is already present in dictionary and an object content // copy function has been set for the dictionary, then the content of the // previously stored stored object associated with will be replaced by // the content of object . // // If key is already presnet in dictionary and no object content // copy function has been set for the dictionary, then the previously stored // object associated with key will remain unchanged and status code // DD_OBJECT_REPLACEMENT_NOT_PERMITTED will be returned. dd_status dd_add_object_for_key(dd_dictionary dict, const char *key, void *object); // -------------------------------------------------------------------------- // function: dd_object_for_key(dict, key, retain) // -------------------------------------------------------------------------- // // Returns the pointer to object associated with key stored in // dictionary . If retain flag is set, the entry's retain // counter will be incremented and it will need to be released explicitly. // // Returns NULL if the key is not present in . void* dd_object_for_key(dd_dictionary dict, const char *key, bool retain); // -------------------------------------------------------------------------- // function: dd_retain_count_for_key(dict, key) // -------------------------------------------------------------------------- // // Returns the retain counter of the entry associated with key in // dictionary . Returns 0 if is not present in the dictionary, // returns -1 if is an empty string or NULL or if is NULL. // // Note: The initial retain counter for a newly created entry is always 1. int dd_retain_count_for_key(dd_dictionary dict, const char *key); // -------------------------------------------------------------------------- // function: dd_release_object_for_key(dict, key) // -------------------------------------------------------------------------- // // Decrements the retain counter of key 's entry in dictionary // and thereby releases a previous retain operation. If, as a result, the // entry's retain counter reaches 1 and it had earlier been marked for // removal, then it will be removed from the dictionary immediately. dd_status dd_release_object_for_key(dd_dictionary dict, const char *key); // -------------------------------------------------------------------------- // function: dd_remove_object_for_key(dict, key) // -------------------------------------------------------------------------- // // Requests the removal of the entry associated with from dictionary // . If the entry's retain counter is 1 at the time this function is // called, the entry will be removed immediately. If the entry's retain // counter is larger than 1, the entry will be marked for removal and it // will be removed from the dictionary when its retain counter reaches 1. dd_status dd_remove_object_for_key(dd_dictionary dict, const char *key); // -------------------------------------------------------------------------- // function: dd_key_for_hash(dict, hash, retain) // -------------------------------------------------------------------------- // // Returns the pointer to key for hash value if is stored // in dictionary . If retain flag is set, the entry's retain // counter will be incremented and it will need to be released explicitly. // // Returns a pointer to an empty C string ("\0") if there is no key for // hash value stored in dictionary . Returns NULL if dictionary // is NULL. // // Note: This function is predominantly of interest when the dictionary is to // be used as a symbol lookup table for lexers and parsers which typically // require the ability to do reverse lookups for keys. However, if no object // storage and no iteration is required for the desired symbol lookup table, // the symbol table specific API ("dd_symbol_table.h") should be used. const char* dd_key_for_hash(dd_dictionary dict, cardinal hash, bool retain); // -------------------------------------------------------------------------- // function: dd_object_count(dict) // -------------------------------------------------------------------------- // // Returns the number of objects stored in dictionary . Returns 0 if // dictionary is empty, returns -1 if is NULL. int dd_object_count(dd_dictionary dict); // -------------------------------------------------------------------------- // function: dd_hashtable_size_for_dictionary(dict) // -------------------------------------------------------------------------- // // Returns the hashtable size of dictionary . Returns -1 if dictionary // is NULL. int dd_hashtable_size_for_dictionary(dd_dictionary dict); // -------------------------------------------------------------------------- // function: dd_hashtable_load_for_dictionary(dict) // -------------------------------------------------------------------------- // // Returns the hashtable load factor of dictionary . Returns -1 if // dictionary is NULL. int dd_hashtable_load_for_dictionary(dd_dictionary dict); // -------------------------------------------------------------------------- // function: dd_new_enumerator_from_dictionary(dict, reverse_order) // -------------------------------------------------------------------------- // // Creates and returns a new enumerator object representing an ordered list // of all keys and objects in dictionary . The list order follows the // order in which the objects were added to . If flag // is set, the list order is reversed. // // Returns NULL if dictionary is NULL or empty. dd_enumerator dd_new_enumerator_for_dictionary(dd_dictionary dict, bool reverse_order); // -------------------------------------------------------------------------- // function: dd_next_key_and_object_in_enumeration(enum, key, obj, retain) // -------------------------------------------------------------------------- // // Retrieves key and object for the next item in enumerator to // return the key in and its object in , then moves the // enumerator's item pointer to the successor item. Both key and object are // returned by reference. If retain flag is set, the entry's retain // counter will be incremented and it will need to be released explicitly. // // Returns NULL in and if is invalid or if the // end of the list of items in has been reached. dd_status dd_next_key_and_object_in_enumeration(dd_enumerator enumerator, char *key, void *object, bool retain); // -------------------------------------------------------------------------- // function: dd_dictionary_for_enumerator(enumerator) // -------------------------------------------------------------------------- // // Returns the dictionary from which enumerator was created. dd_dictionary dd_dictionary_for_enumerator(dd_enumerator enumerator); // -------------------------------------------------------------------------- // function: dd_reset_enumerator(enumerator) // -------------------------------------------------------------------------- // // Resets the item pointer of enumerator to point to the first // item. Corresponding entries will be retained and released automatically. dd_status dd_reset_enumerator(dd_enumerator enumerator); // -------------------------------------------------------------------------- // function: dd_dispose_enumerator(enumerator) // -------------------------------------------------------------------------- // // Releases the entry to which the enumerator 's item pointer is // pointing to and disposes of . dd_status dd_dispose_enumerator(dd_enumerator enumerator); // -------------------------------------------------------------------------- // function: dd_dispose_dictionary(dict) // -------------------------------------------------------------------------- // // Requests disposal of dictionary and the removal of all objects // stored in it. Once a disposal is pending, objects can no longer be added // to the dictionary. The dictionary will be deallocated when the reference // counters of all objects stored in it are 0. dd_status dd_dispose_dictionary(dd_dictionary dict); #endif // END OF FILE