/* * Copyright (c) 2016 MariaDB Corporation Ab * * Use of this software is governed by the Business Source License included * in the LICENSE.TXT file and at www.mariadb.com/bsl. * * Change Date: 2019-07-01 * * On the date above, in accordance with the Business Source License, use * of this software will be governed by version 2 or later of the General * Public License. */ #include #include #include static slist_cursor_t* slist_cursor_init(slist_t* list); static slist_t* slist_init_ex(bool create_cursors); static slist_node_t* slist_node_init(void* data, slist_cursor_t* cursor); static void slist_add_node(slist_t* list, slist_node_t* node); #if defined(NOT_USED) static slist_node_t* slist_node_get_next(slist_node_t* curr_node); static slist_node_t* slist_get_first(slist_t* list); static slist_cursor_t* slist_get_cursor(slist_t* list); #endif /*< NOT_USED */ /** End of static function declarations */ static slist_t* slist_init_ex(bool create_cursors) { slist_t* list; list = (slist_t*) MXS_CALLOC(1, sizeof (slist_t)); MXS_ABORT_IF_NULL(list); list->slist_chk_top = CHK_NUM_SLIST; list->slist_chk_tail = CHK_NUM_SLIST; if (create_cursors) { list->slist_cursors_list = slist_init_ex(false); } return list; } static slist_node_t* slist_node_init(void* data, slist_cursor_t* cursor) { slist_node_t* node; node = (slist_node_t*) MXS_CALLOC(1, sizeof (slist_node_t)); MXS_ABORT_IF_NULL(node); node->slnode_chk_top = CHK_NUM_SLIST_NODE; node->slnode_chk_tail = CHK_NUM_SLIST_NODE; node->slnode_data = data; CHK_SLIST_NODE(node); if (cursor != NULL) { node->slnode_cursor_refcount += 1; cursor->slcursor_pos = node; } return node; } static void slist_add_node(slist_t* list, slist_node_t* node) { CHK_SLIST(list); CHK_SLIST_NODE(node); if (list->slist_tail != NULL) { CHK_SLIST_NODE(list->slist_tail); CHK_SLIST_NODE(list->slist_head); ss_dassert(list->slist_tail->slnode_next == NULL); list->slist_tail->slnode_next = node; } else { list->slist_head = node; } list->slist_tail = node; node->slnode_list = list; list->slist_nelems += 1; CHK_SLIST(list); } #if defined(NOT_USED) static slist_node_t* slist_node_get_next(slist_node_t* curr_node) { CHK_SLIST_NODE(curr_node); if (curr_node->slnode_next != NULL) { CHK_SLIST_NODE(curr_node->slnode_next); return (curr_node->slnode_next); } return NULL; } static slist_node_t* slist_get_first(slist_t* list) { CHK_SLIST(list); if (list->slist_head != NULL) { CHK_SLIST_NODE(list->slist_head); return list->slist_head; } return NULL; } static slist_cursor_t* slist_get_cursor(slist_t* list) { CHK_SLIST(list); slist_cursor_t* c; c = slist_cursor_init(list); return c; } #endif /*< NOT_USED */ static slist_cursor_t* slist_cursor_init(slist_t* list) { CHK_SLIST(list); slist_cursor_t* c; c = (slist_cursor_t *) MXS_CALLOC(1, sizeof (slist_cursor_t)); MXS_ABORT_IF_NULL(c); c->slcursor_chk_top = CHK_NUM_SLIST_CURSOR; c->slcursor_chk_tail = CHK_NUM_SLIST_CURSOR; c->slcursor_list = list; /** Set cursor position is list is not empty */ if (list->slist_head != NULL) { list->slist_head->slnode_cursor_refcount += 1; c->slcursor_pos = list->slist_head; } /** Add cursor to cursor list */ slist_add_node(list->slist_cursors_list, slist_node_init(c, NULL)); CHK_SLIST_CURSOR(c); return c; } /** * @node Create a cursor and a list with cursors supported. 19.6.2013 : * supports only cursor per list. * * Parameters: * @param void - * * * @return returns a pointer to cursor, which is not positioned * because the list is empty. * * * @details (write detailed description here) * */ slist_cursor_t* slist_init(void) { slist_t* list; slist_cursor_t* slc; list = slist_init_ex(true); CHK_SLIST(list); slc = slist_cursor_init(list); CHK_SLIST_CURSOR(slc); return slc; } /** * @node moves cursor to the first node of list. * * Parameters: * @param c - * * * @return true if there is first node in the list * false is the list is empty. * * * @details (write detailed description here) * */ bool slcursor_move_to_begin(slist_cursor_t* c) { bool succp = true; slist_t* list; CHK_SLIST_CURSOR(c); list = c->slcursor_list; CHK_SLIST(list); c->slcursor_pos = list->slist_head; if (c->slcursor_pos == NULL) { succp = false; } return succp; } /** * @node moves cursor to next node * * Parameters: * @param c - * * * @return true in success, false is there is no next node on the list. * * * @details (write detailed description here) * */ bool slcursor_step_ahead(slist_cursor_t* c) { bool succp = false; slist_node_t* node; CHK_SLIST_CURSOR(c); CHK_SLIST_NODE(c->slcursor_pos); node = c->slcursor_pos->slnode_next; if (node != NULL) { CHK_SLIST_NODE(node); c->slcursor_pos = node; succp = true; } return succp; } void* slcursor_get_data(slist_cursor_t* c) { slist_node_t* node; void* data = NULL; CHK_SLIST_CURSOR(c); node = c->slcursor_pos; if (node != NULL) { CHK_SLIST_NODE(node); data = node->slnode_data; } return data; } /** * @node Add data to the list by using cursor. * * Parameters: * @param c - * * * @param data - * * * @return void * * * @details (write detailed description here) * */ void slcursor_add_data(slist_cursor_t* c, void* data) { slist_t* list; slist_node_t* pos; CHK_SLIST_CURSOR(c); list = c->slcursor_list; CHK_SLIST(list); if (c->slcursor_pos != NULL) { CHK_SLIST_NODE(c->slcursor_pos); } ss_dassert(list->slist_tail->slnode_next == NULL); pos = slist_node_init(data, c); slist_add_node(list, pos); CHK_SLIST(list); CHK_SLIST_CURSOR(c); } /** * Remove the node currently pointed by the cursor from the slist. This does not delete the data in the * node but will delete the structure pointing to that data. This is useful when * the user wants to free the allocated memory. After node removal, the cursor * will point to the node before the removed node. * @param c Cursor pointing to the data node to be removed */ void slcursor_remove_data(slist_cursor_t* c) { slist_node_t* node = c->slcursor_pos; int havemore = slist_size(c); slcursor_move_to_begin(c); if (node == c->slcursor_pos) { c->slcursor_list->slist_head = c->slcursor_list->slist_head->slnode_next; slcursor_move_to_begin(c); atomic_add((int*) &node->slnode_list->slist_nelems, -1); atomic_add((int*) &node->slnode_cursor_refcount, -1); if (node->slnode_cursor_refcount == 0) { MXS_FREE(node); } return; } while (havemore) { if (c->slcursor_pos->slnode_next == node) { c->slcursor_pos->slnode_next = node->slnode_next; atomic_add((int*) &node->slnode_list->slist_nelems, -1); atomic_add((int*) &node->slnode_cursor_refcount, -1); if (node->slnode_cursor_refcount == 0) { MXS_FREE(node); } return; } havemore = slcursor_step_ahead(c); } } /** * Return the size of the slist. * @param c slist cursor which refers to a list * @return nummber of elements in the list */ size_t slist_size(slist_cursor_t* c) { return c->slcursor_list->slist_nelems; } void slist_done(slist_cursor_t* c) { bool succp; void* data; succp = slcursor_move_to_begin(c); while (succp) { data = slcursor_get_data(c); MXS_FREE(data); succp = slcursor_step_ahead(c); } MXS_FREE(c->slcursor_list); MXS_FREE(c); } /** End of list implementation */