//:://///////////////////////////////////////////// //:: Set-like storage data type include //:: inc_set //::////////////////////////////////////////////// /** @file This file defines a "data type" that behaves like a set. It is implemented as an extension of the arrays defined in prc_inc_array. Operations: - Get number of entities in the set. O(1) - Store an entity in the set. O(1) - Remove an entity from the set. O(n) - Determine if the set contains a given entity. O(1) - Get operations on the underlying array The memory complexity is O(n), specifically 2n(m + c), where n is the number of entities stored in the set, m is the memory taken up the local variable store of a member entity and c is a constant overhead from disambiguation strings. Note that a set can contain only contain one instance of any specific entity. Any attempts to add an entity to a set that is already a member of will return with success, but do nothing. For example, if a set contains {"Foo", "Bar, 123, OBJECT_INVALID} calling set_add_string(container, setname, "Foo") will return SDL_SUCCESS, but not modify the contents of the set. @author Ornedan @date Created - 2006.09.16 */ //::////////////////////////////////////////////// //::////////////////////////////////////////////// ////////////////////////////////////////////////// /* Function prototypes */ ////////////////////////////////////////////////// /** * Creates a new set on the given storage object. If a set with * the same name already exists, the function fails. * * @param store The object to use as holder for the set * @param name The name of the set * @return SDL_SUCCESS if the set was successfully created, * one of SDL_ERROR_* on error. */ int set_create(object store, string name); /** * Deletes a set, deleting all local variables it consists of. * * @param store The object which holds the set to delete * @param name The name of the set * @return SDL_SUCCESS if the set was successfully deleted, * one of SDL_ERROR_* on error */ int set_delete(object store, string name); /** * Adds a string to the set. * * @param store The object holding the set * @param name The name of the set * @param entry The string to add * @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error. */ int set_add_string(object store, string name, string entry); /** * Adds a integer to the set. * * @param store The object holding the set * @param name The name of the set * @param entry The integer to add * @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error. */ int set_add_int(object store, string name, int entry); /** * Adds a float to the set. * * @param store The object holding the set * @param name The name of the set * @param entry The float to add * @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error. */ int set_add_float(object store, string name, float entry); /** * Adds a object to the set. * * @param store The object holding the set * @param name The name of the set * @param entry The object to add * @return SDL_SUCCESS if the addition was successfull, SDL_ERROR_* on error. */ int set_add_object(object store, string name, object entry); /** * Determines whether the set contains the given string. * * @param store The object holding the set * @param name The name of the set * @param entity The string to test * @return TRUE if the set contains entry, FALSE otherwise */ int set_contains_string(object store, string name, string entity); /** * Determines whether the set contains the given integer. * * @param store The object holding the set * @param name The name of the set * @param entity The integer to test * @return TRUE if the set contains entry, FALSE otherwise */ int set_contains_int(object store, string name, int entity); /** * Determines whether the set contains the given float. * * @param store The object holding the set * @param name The name of the set * @param entity The float to test * @return TRUE if the set contains entry, FALSE otherwise */ int set_contains_float(object store, string name, float entity); /** * Determines whether the set contains the given object. * * @param store The object holding the set * @param name The name of the set * @param entity The object to test * @return TRUE if the set contains entry, FALSE otherwise */ int set_contains_object(object store, string name, object entity); /** * Removes the given string from the set, if it is a member. * * @param store The object holding the set * @param name The name of the set * @param entity The string to remove */ void set_remove_string(object store, string name, string entity); /** * Removes the given integer from the set, if it is a member. * * @param store The object holding the set * @param name The name of the set * @param entity The integer to remove */ void set_remove_int(object store, string name, int entity); /** * Removes the given float from the set, if it is a member. * * @param store The object holding the set * @param name The name of the set * @param entity The float to remove */ void set_remove_float(object store, string name, float entity); /** * Removes the given object from the set, if it is a member. * * @param store The object holding the set * @param name The name of the set * @param entity The object to remove */ void set_remove_object(object store, string name, object entity); /** * Gets the type of the i:th member of the set. * * @param store The object holding the set * @param name The name of the set * @param i The index of the member the type of which to retrieve * @return One of the ENTITY_TYPE_* defined in inc_heap, or 0 in case of error */ int set_get_member_type(object store, string name, int i); /** * Gets the i:th member of the set as a string. * * NOTE: If the member is actually not a string, the return * value in undefined. As such, always check the real * type of the member first using set_get_member_type(). * * @param store The object holding the set * @param name The name of the set * @param i The index to retrieve the string from * @return The value contained at the index on success, * "" on error */ string set_get_string(object store, string name, int i); /** * Gets the i:th member of the set as an integer. * * NOTE: If the member is actually not an integer, the return * value in undefined. As such, always check the real * type of the member first using set_get_member_type(). * * @param store The object holding the set * @param name The name of the set * @param i The index to retrieve the string from * @return The value contained at the index on success, * 0 on error */ int set_get_int(object store, string name, int i); /** * Gets the i:th member of the set as an float. * * NOTE: If the member is actually not an float, the return * value in undefined. As such, always check the real * type of the member first using set_get_member_type(). * * @param store The object holding the set * @param name The name of the set * @param i The index to retrieve the string from * @return The value contained at the index on success, * 0.0 on error */ float set_get_float(object store, string name, int i); /** * Gets the i:th member of the set as an object. * * NOTE: If the member is actually not an object, the return * value in undefined. As such, always check the real * type of the member first using set_get_member_type(). * * @param store The object holding the set * @param name The name of the set * @param i The index to retrieve the string from * @return The value contained at the index on success, * OBJECT_INVALID on error */ object set_get_object(object store, string name, int i); /** * Gets the number of members in the set * * @param store The object holding the set * @param name The name of the set * @return The size of the set, or -1 if the specified * set does not exist. */ int set_get_size(object store, string name); /** * Checks whether the given set exists. * * @param store The object holding the set * @param name The name of the set * @return TRUE if the set exists, FALSE otherwise. */ int set_exists(object store, string name); ////////////////////////////////////////////////// /* Includes */ ////////////////////////////////////////////////// // prc_inc_array access is via inc_heap //#include "prc_inc_array" #include "inc_debug" #include "inc_heap" ////////////////////////////////////////////////// /* Internal Constants */ ////////////////////////////////////////////////// const string _PRC_SET_PREFIX = "@@@set"; ////////////////////////////////////////////////// /* Internal functions */ ////////////////////////////////////////////////// /** Internal function. * Performs the real addition operation. * * @param store The object holding the set * @param name The name of the set * @param entry String form of the entity to be stored in the set * @param isobject Whether the entity being stored is an object. Objects need special handling * @param obj The object being stored, if any */ int _inc_set_set_add_aux(object store, string name, string entry, int isobject = FALSE, object obj = OBJECT_INVALID) { // Sanity checks if(!set_exists(store, name)) return SDL_ERROR_DOES_NOT_EXIST; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Set the presence marker to be the index where the entity will be stored + 1 to avoid storing a 0 int index = array_get_size(store, name); SetLocalInt(store, name + entry, index + 1); // Store the member's value in the array if(isobject) { if(DEBUG) { Assert(array_set_object(store, name, index, obj) == SDL_SUCCESS, "array_set_object(store, name, index, obj) == SDL_SUCCESS", "", "inc_set", "_inc_set_set_add_aux" ); return SDL_SUCCESS; } else { return array_set_object(store, name, index, obj); } } else { if(DEBUG) { Assert(array_set_string(store, name, index, entry) == SDL_SUCCESS, "array_set_string(store, name, index, entry) == SDL_SUCCESS", "", "inc_set", "_inc_set_set_add_aux" ); return SDL_SUCCESS; } else { return array_set_string(store, name, index, entry); } } } /** Internal function. * Determines whether the set contains the given entity. * * @param store The object holding the set * @param name The name of the set * @param entity The presence string for the entity to test * @return TRUE if the set contains the entity, FALSE otherwise */ int _inc_set_set_contains_aux(object store, string name, string entity) { // Sanity check if(!set_exists(store, name)) return FALSE; // Get the value of the presence marker and normalise to TRUE / FALSE return GetLocalInt(store, _PRC_SET_PREFIX + name + entity) != 0; } /** Internal function. * Removes the given entity from the set. * * @param store The object holding the set * @param name The name of the set * @param entity The presence string for the entity to remove */ void _inc_set_set_remove_aux(object store, string name, string entity) { // Set does not exist or exists, but does not contain the given entity. Nothing to do if(!_inc_set_set_contains_aux(store, name, entity)) return; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Get the index where the entity is stored and the size of the underlying array int index = GetLocalInt(store, name + entity) - 1; int size = array_get_size(store, name); string raw; object obj; // Move each element in the array after the one being removed back by one for(index = index + 1; index < size; index++) { // Determine what's stored here raw = array_get_string(store, name, index); // Different handling for objects vs everything else if(raw == "OBJECT") { obj = array_get_object(store, name, index); // Move back array_set_object(store, name, index - 1, obj); // Update the marker value SetLocalInt(store, name + "O" + ObjectToString(obj), index/* - 1 + 1 */); } else { // Move back array_set_string(store, name, index - 1, raw); // Update the marker value SetLocalInt(store, name + raw, index/* - 1 + 1 */); } } // Delete the marker local DeleteLocalInt(store, name + entity); // Shrink the array array_shrink(store, name, size - 1); } ////////////////////////////////////////////////// /* Function definitions */ ////////////////////////////////////////////////// int set_create(object store, string name) { // Sanity checks if(!GetIsObjectValid(store)) return SDL_ERROR_NOT_VALID_OBJECT; if(name == "") return SDL_ERROR_INVALID_PARAMETER; if(set_exists(store, name)) return SDL_ERROR_ALREADY_EXISTS; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // All OK, create the underlying array return array_create(store, name); } int set_delete(object store, string name) { // Sanity check if(!set_exists(store, name)) return SDL_ERROR_DOES_NOT_EXIST; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Loop over all members, getting deleting the presence indicator local int size = array_get_size(store, name); int i; string raw, member; for(i = 0; i < size; i++) { // Get the raw data stored in the array. // NOTE: This relies on internal details of the array implementation. Specifically, objects having a string containing "OBJECT" // stored in their position raw = array_get_string(store, name, i); // Construct the presence marker name. Special handling for objects if(raw == "OBJECT") member = name + "O" + ObjectToString(array_get_object(store, name, i)); else member = name + raw; // Delete the marker DeleteLocalInt(store, member); } // Clean up the underlying array if(DEBUG) { Assert(array_delete(store, name) == SDL_SUCCESS, "array_delete(store, name) == SDL_SUCCESS", "", "inc_set", "set_delete"); return SDL_SUCCESS; } else { return array_delete(store, name); } } int set_add_string(object store, string name, string entry) { // Convert the entry to the storable string form entry = "S" + entry; // If the set already contains the entry being added, nothing happens if(_inc_set_set_contains_aux(store, name, entry)) return SDL_SUCCESS; return _inc_set_set_add_aux(store, name, entry); } int set_add_int(object store, string name, int entry) { // Convert the entry to the storable string form string strentry = "I" + IntToString(entry); // If the set already contains the entry being added, nothing happens if(_inc_set_set_contains_aux(store, name, strentry)) return SDL_SUCCESS; return _inc_set_set_add_aux(store, name, strentry); } int set_add_float(object store, string name, float entry) { // Convert the entry to the storable string form string strentry = "F" + FloatToString(entry); // If the set already contains the entry being added, nothing happens if(_inc_set_set_contains_aux(store, name, strentry)) return SDL_SUCCESS; return _inc_set_set_add_aux(store, name, strentry); } int set_add_object(object store, string name, object entry) { // Convert the entry to the storable string form string strentry = "O" + ObjectToString(entry); // If the set already contains the entry being added, nothing happens if(_inc_set_set_contains_aux(store, name, strentry)) return SDL_SUCCESS; return _inc_set_set_add_aux(store, name, strentry, TRUE, entry); } int set_get_member_type(object store, string name, int i) { // Sanity check if(!set_exists(store, name) || i >= set_get_size(store, name)) return 0; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Grab the first character of the raw string, it determines type string type = GetSubString(array_get_string(store, name, i), 0, 1); // First character in the string determines type if (type == "F") return ENTITY_TYPE_FLOAT; else if(type == "I") return ENTITY_TYPE_INTEGER; else if(type == "O") return ENTITY_TYPE_OBJECT; else if(type == "S") return ENTITY_TYPE_STRING; else return 0; } int set_contains_string(object store, string name, string entity) { return _inc_set_set_contains_aux(store, name, "S" + entity); } int set_contains_int(object store, string name, int entity) { return _inc_set_set_contains_aux(store, name, "I" + IntToString(entity)); } int set_contains_float(object store, string name, float entity) { return _inc_set_set_contains_aux(store, name, "F" + FloatToString(entity)); } int set_contains_object(object store, string name, object entity) { return _inc_set_set_contains_aux(store, name, "O" + ObjectToString(entity)); } void set_remove_string(object store, string name, string entity) { _inc_set_set_remove_aux(store, name, "S" + entity); } void set_remove_int(object store, string name, int entity) { _inc_set_set_remove_aux(store, name, "I" + IntToString(entity)); } void set_remove_float(object store, string name, float entity) { _inc_set_set_remove_aux(store, name, "F" + FloatToString(entity)); } void set_remove_object(object store, string name, object entity) { _inc_set_set_remove_aux(store, name, "O" + ObjectToString(entity)); } string set_get_string(object store, string name, int i) { // Sanity check if(!set_exists(store, name) || i >= set_get_size(store, name)) return ""; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Chop off the first character from the raw string and return the rest string raw = array_get_string(store, name, i); return GetSubString(raw, 1, GetStringLength(raw)); } int set_get_int(object store, string name, int i) { // Sanity check if(!set_exists(store, name) || i >= set_get_size(store, name)) return 0; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Chop off the first character from the raw string and return the rest string raw = array_get_string(store, name, i); return StringToInt(GetSubString(raw, 1, GetStringLength(raw))); } float set_get_float(object store, string name, int i) { // Sanity check if(!set_exists(store, name) || i >= set_get_size(store, name)) return 0.0f; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; // Chop off the first character from the raw string and return the rest string raw = array_get_string(store, name, i); return StringToFloat(GetSubString(raw, 1, GetStringLength(raw))); } object set_get_object(object store, string name, int i) { // Sanity check if(!set_exists(store, name) || i >= set_get_size(store, name)) return OBJECT_INVALID; // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; return array_get_object(store, name, i); } int set_get_size(object store, string name) { // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; return array_get_size(store, name); } int set_exists(object store, string name) { // Generate real name for accessing array functions name = _PRC_SET_PREFIX + name; return array_exists(store, name); } // Test main //void main() {}