#include #include #include #include #include #include "../include/skiplist.h" // Define a node that contains key and value pair. struct my_node { // Metadata for skiplist node. sl_node snode; // My data here: {int, int} pair. int key; int value; }; // Define a comparison function for `my_node`. static int my_cmp(sl_node *a, sl_node *b, void *aux) { // Get `my_node` from skiplist node `a` and `b`. struct my_node *aa, *bb; aa = sl_get_entry(a, struct my_node, snode); bb = sl_get_entry(b, struct my_node, snode); // aa < bb: return neg // aa == bb: return 0 // aa > bb: return pos if (aa->key < bb->key) return -1; if (aa->key > bb->key) return 1; return 0; } #define NUM_NODES 10000 int main() { // seed the PRNG srandom((unsigned)(time(NULL) | getpid())); sl_raw slist; // Initialize skiplist. sl_init(&slist, my_cmp); // << Insertion >> // Allocate & insert NUM_NODES KV pairs: {0, 0}, {1, 10}, {2, 20}. struct my_node *nodes[NUM_NODES]; for (int i = 0; i < NUM_NODES; ++i) { // Allocate memory. nodes[i] = (struct my_node *)malloc(sizeof(struct my_node)); // Initialize node. sl_init_node(&nodes[i]->snode); // Assign key and value. nodes[i]->key = i; nodes[i]->value = i * 10; // Insert into skiplist. sl_insert(&slist, &nodes[i]->snode); } // << Point lookup >> for (int i = 0; i < NUM_NODES; ++i) { // Define a query. struct my_node query; int min = 1, max = NUM_NODES - 1; int k = min + (int)random() / (RAND_MAX / (max - min + 1) + 1); query.key = k; // Find a skiplist node `cursor`. sl_node *cursor = sl_find(&slist, &query.snode); // If `cursor` is NULL, key doesn't exist. if (!cursor) continue; // Get `my_node` from `cursor`. // Note: found->snode == *cursor struct my_node *found = sl_get_entry(cursor, struct my_node, snode); printf("[point lookup] key: %d, value: %d\n", found->key, found->value); if (found->key != found->value / 10) { printf("FAILURE: key: %d * 10 != value: %d\n", found->key, found->value); exit(-1); } // Release `cursor` (== &found->snode). // Other thread cannot free `cursor` until `cursor` is released. sl_release_node(cursor); } // << Erase >> // Erase the KV pair for key 1: {1, 10}. { // Define a query. struct my_node query; query.key = 1; // Find a skiplist node `cursor`. sl_node *cursor = sl_find(&slist, &query.snode); // Get `my_node` from `cursor`. // Note: found->snode == *cursor struct my_node *found = sl_get_entry(cursor, struct my_node, snode); printf("[erase] key: %d, value: %d\n", found->key, found->value); // Detach `found` from skiplist. sl_erase_node(&slist, &found->snode); // Release `found`, to free its memory. sl_release_node(&found->snode); // Free `found` after it becomes safe. sl_wait_for_free(&found->snode); sl_free_node(&found->snode); free(found); } // << Iteration >> { // Get the first cursor. sl_node *cursor = sl_begin(&slist); while (cursor) { // Get `entry` from `cursor`. // Note: entry->snode == *cursor struct my_node *entry = sl_get_entry(cursor, struct my_node, snode); printf("[iteration] key: %d, value: %d\n", entry->key, entry->value); // Get next `cursor`. cursor = sl_next(&slist, cursor); // Release `entry`. sl_release_node(&entry->snode); } } // << Destroy >> { // Iterate and free all nodes. sl_node *cursor = sl_begin(&slist); while (cursor) { struct my_node *entry = sl_get_entry(cursor, struct my_node, snode); printf("[destroy] key: %d, value: %d\n", entry->key, entry->value); // Get next `cursor`. cursor = sl_next(&slist, cursor); // Detach `entry` from skiplist. sl_erase_node(&slist, &entry->snode); // Release `entry`, to free its memory. sl_release_node(&entry->snode); // Free `entry` after it becomes safe. sl_wait_for_free(&entry->snode); sl_free_node(&entry->snode); free(entry); } } // Free skiplist. sl_free(&slist); return 0; }