From 61249e1e93139c1eb1db351802665c088d6b41e3 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 22:34:01 -0700 Subject: [PATCH 01/12] Remove date and example from Int64Queue/TierQueue documentation --- src/core/data_structures/int64_queue.c | 2 -- src/core/data_structures/int64_queue.h | 16 ---------------- src/core/types/tier_queue.h | 2 -- 3 files changed, 20 deletions(-) diff --git a/src/core/data_structures/int64_queue.c b/src/core/data_structures/int64_queue.c index 46e4b1f9..1b0aabd8 100644 --- a/src/core/data_structures/int64_queue.c +++ b/src/core/data_structures/int64_queue.c @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Implementation of int64_t queue using dynamic array. - * @version 1.0.1 - * @date 2025-04-26 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: diff --git a/src/core/data_structures/int64_queue.h b/src/core/data_structures/int64_queue.h index a6763b16..00041b2d 100644 --- a/src/core/data_structures/int64_queue.h +++ b/src/core/data_structures/int64_queue.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief int64_t queue using dynamic array. - * @version 1.0.1 - * @date 2025-04-26 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -32,20 +30,6 @@ /** * @brief int64_t queue using dynamic array. - * - * @example - * #include - * #include - * - * Int64Queue myqueue; - * Int64QueueInit(&myqueue); - * Int64QueuePush(&myqueue, -1); - * Int64QueuePush(&myqueue, 2); - * printf("%" PRId64, Int64QueuePop(&myqueue)); // -1 - * Int64QueuePush(&myqueue, -3); - * printf("%" PRId64, Int64QueuePop(&myqueue)); // 2 - * printf("%" PRId64, Int64QueuePop(&myqueue)); // -3 - * Int64QueueDestroy(&myqueue); */ typedef struct Int64Queue { int64_t *array; /**< Internal dynamic array storing the items. */ diff --git a/src/core/types/tier_queue.h b/src/core/types/tier_queue.h index a9945d50..d2d1a610 100644 --- a/src/core/types/tier_queue.h +++ b/src/core/types/tier_queue.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Tier queue. - * @version 1.0.1 - * @date 2024-12-10 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: From b0dfb3eb57a580ab4212046009b8525a5640b3fd Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 22:43:30 -0700 Subject: [PATCH 02/12] Convert TierQueue into a header-only library --- src/core/types/tier_queue.c | 48 ------------------------------------- src/core/types/tier_queue.h | 26 ++++++++++++++------ 2 files changed, 19 insertions(+), 55 deletions(-) delete mode 100644 src/core/types/tier_queue.c diff --git a/src/core/types/tier_queue.c b/src/core/types/tier_queue.c deleted file mode 100644 index 8785bae4..00000000 --- a/src/core/types/tier_queue.c +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file tier_queue.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Tier queue implementation. - * @version 1.0.1 - * @date 2024-12-10 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/tier_queue.h" - -#include - -#include "core/data_structures/int64_queue.h" -#include "core/types/base.h" - -void TierQueueInit(TierQueue *queue) { Int64QueueInit(queue); } - -void TierQueueDestroy(TierQueue *queue) { Int64QueueDestroy(queue); } - -bool TierQueueEmpty(const TierQueue *queue) { return Int64QueueIsEmpty(queue); } - -int64_t TierQueueSize(const TierQueue *queue) { return Int64QueueSize(queue); } - -bool TierQueuePush(TierQueue *queue, Tier tier) { - return Int64QueuePush(queue, tier); -} - -Tier TierQueuePop(TierQueue *queue) { return Int64QueuePop(queue); } - -Tier TierQueueFront(const TierQueue *queue) { return Int64QueueFront(queue); } diff --git a/src/core/types/tier_queue.h b/src/core/types/tier_queue.h index d2d1a610..fdb0b982 100644 --- a/src/core/types/tier_queue.h +++ b/src/core/types/tier_queue.h @@ -35,16 +35,22 @@ typedef Int64Queue TierQueue; /** @brief Initializes QUEUE. */ -void TierQueueInit(TierQueue *queue); +static inline void TierQueueInit(TierQueue *queue) { Int64QueueInit(queue); } /** @brief Destroys QUEUE. */ -void TierQueueDestroy(TierQueue *queue); +static inline void TierQueueDestroy(TierQueue *queue) { + Int64QueueDestroy(queue); +} /** @brief Returns true if QUEUE is empty, or false otherwise. */ -bool TierQueueEmpty(const TierQueue *queue); +static inline bool TierQueueEmpty(const TierQueue *queue) { + return Int64QueueIsEmpty(queue); +} /** @brief Returns the number of items in QUEUE. */ -int64_t TierQueueSize(const TierQueue *queue); +static inline int64_t TierQueueSize(const TierQueue *queue) { + return Int64QueueSize(queue); +} /** * @brief Pushes TIER into the QUEUE. @@ -52,12 +58,18 @@ int64_t TierQueueSize(const TierQueue *queue); * @return true on success, * @return false otherwise. */ -bool TierQueuePush(TierQueue *queue, Tier tier); +static inline bool TierQueuePush(TierQueue *queue, Tier tier) { + return Int64QueuePush(queue, tier); +} /** @brief Pops the item at the front of the QUEUE and returns it. */ -Tier TierQueuePop(TierQueue *queue); +static inline Tier TierQueuePop(TierQueue *queue) { + return Int64QueuePop(queue); +} /** @brief Returns the tier at the front of the QUEUE without popping it. */ -Tier TierQueueFront(const TierQueue *queue); +static inline Tier TierQueueFront(const TierQueue *queue) { + return Int64QueueFront(queue); +} #endif // GAMESMANONE_CORE_TYPES_TIER_QUEUE_H_ From e498b62f206332a4509a7945b8a713270bcc708d Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 22:48:34 -0700 Subject: [PATCH 03/12] Convert some API to static inline --- src/core/data_structures/int64_queue.c | 60 ++++---------------------- src/core/data_structures/int64_queue.h | 40 ++++++++++++++--- 2 files changed, 41 insertions(+), 59 deletions(-) diff --git a/src/core/data_structures/int64_queue.c b/src/core/data_structures/int64_queue.c index 1b0aabd8..e0ca7f9e 100644 --- a/src/core/data_structures/int64_queue.c +++ b/src/core/data_structures/int64_queue.c @@ -3,7 +3,7 @@ * @author Robert Shi (robertyishi@berkeley.edu) * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia - * @brief Implementation of int64_t queue using dynamic array. + * @brief Implementation of Int64Queue. * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -24,17 +24,15 @@ #include "core/data_structures/int64_queue.h" -#include #include #include #include -#include #include #include "core/gamesman_memory.h" static bool Expand(Int64Queue *queue) { - int64_t new_capacity = queue->capacity == 0 ? 1 : queue->capacity * 2; + int64_t new_capacity = queue->capacity == 0 ? 16 : queue->capacity * 2; int64_t *new_array = (int64_t *)GamesmanMalloc(new_capacity * sizeof(int64_t)); if (!new_array) { @@ -52,63 +50,21 @@ static bool Expand(Int64Queue *queue) { queue->front * sizeof(int64_t)); queue->array = new_array; queue->capacity = new_capacity; - return true; -} -// Function to initialize the queue -void Int64QueueInit(Int64Queue *queue) { - queue->array = NULL; - queue->capacity = 0; - queue->front = 0; - queue->size = 0; -} - -// Function to destroy the queue and free the allocated memory -void Int64QueueDestroy(Int64Queue *queue) { - GamesmanFree(queue->array); - queue->array = NULL; - queue->capacity = 0; - queue->front = 0; - queue->size = 0; + return true; } -// Function to check if the queue is empty -bool Int64QueueIsEmpty(const Int64Queue *queue) { return (queue->size == 0); } - -// Function to check the size of the queue -int64_t Int64QueueSize(const Int64Queue *queue) { return queue->size; } - // Function to add an element to the queue bool Int64QueuePush(Int64Queue *queue, int64_t item) { if (queue->size == queue->capacity) { - if (!Expand(queue)) return false; + if (!Expand(queue)) { + return false; + } } - assert(queue->size < queue->capacity); + int64_t back = (queue->front + queue->size) % queue->capacity; queue->array[back] = item; ++queue->size; - return true; -} - -// Function to remove an element from the queue -int64_t Int64QueuePop(Int64Queue *queue) { - if (Int64QueueIsEmpty(queue)) { - fprintf(stderr, "Int64QueuePop: popping from an empty queue.\n"); - return 0; - } - int64_t element = queue->array[queue->front]; - queue->front = (queue->front + 1) % queue->capacity; - --queue->size; - - return element; -} - -int64_t Int64QueueFront(const Int64Queue *queue) { - if (Int64QueueIsEmpty(queue)) { - fprintf(stderr, "Int64QueueFront: peaking into an empty queue.\n"); - return 0; - } - - return queue->array[queue->front]; + return true; } diff --git a/src/core/data_structures/int64_queue.h b/src/core/data_structures/int64_queue.h index 00041b2d..79a2384f 100644 --- a/src/core/data_structures/int64_queue.h +++ b/src/core/data_structures/int64_queue.h @@ -3,7 +3,7 @@ * @author Robert Shi (robertyishi@berkeley.edu) * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia - * @brief int64_t queue using dynamic array. + * @brief Dynamic int64_t queue. * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -26,8 +26,11 @@ #define GAMESMANONE_CORE_DATA_STRUCTURES_INT64_QUEUE_H_ #include +#include #include +#include "core/gamesman_memory.h" + /** * @brief int64_t queue using dynamic array. */ @@ -39,16 +42,31 @@ typedef struct Int64Queue { } Int64Queue; /** @brief Initializes QUEUE. */ -void Int64QueueInit(Int64Queue *queue); +static inline void Int64QueueInit(Int64Queue *queue) { + queue->array = NULL; + queue->capacity = 0; + queue->front = 0; + queue->size = 0; +} /** @brief Destroys QUEUE. */ -void Int64QueueDestroy(Int64Queue *queue); +static inline void Int64QueueDestroy(Int64Queue *queue) { + GamesmanFree(queue->array); + queue->array = NULL; + queue->capacity = 0; + queue->front = 0; + queue->size = 0; +} /** @brief Returns true if QUEUE is empty, or false otherwise. */ -bool Int64QueueIsEmpty(const Int64Queue *queue); +static inline bool Int64QueueIsEmpty(const Int64Queue *queue) { + return (queue->size == 0); +} /** @brief Returns the number of items in QUEUE. */ -int64_t Int64QueueSize(const Int64Queue *queue); +static inline int64_t Int64QueueSize(const Int64Queue *queue) { + return queue->size; +} /** * @brief Pushes ELEMENT into the QUEUE. @@ -59,9 +77,17 @@ int64_t Int64QueueSize(const Int64Queue *queue); bool Int64QueuePush(Int64Queue *queue, int64_t item); /** @brief Pops the item at the front of the QUEUE and returns it. */ -int64_t Int64QueuePop(Int64Queue *queue); +static inline int64_t Int64QueuePop(Int64Queue *queue) { + int64_t element = queue->array[queue->front]; + queue->front = (queue->front + 1) % queue->capacity; + --queue->size; + + return element; +} /** @brief Returns the item at the front of the QUEUE without popping it. */ -int64_t Int64QueueFront(const Int64Queue *queue); +static inline int64_t Int64QueueFront(const Int64Queue *queue) { + return queue->array[queue->front]; +} #endif // GAMESMANONE_CORE_DATA_STRUCTURES_INT64_QUEUE_H_ From 93552012a586437f6957f24aa6a9e22108ef21b4 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 23:28:08 -0700 Subject: [PATCH 04/12] Remove redundant tier_queue.c in CMake configuration --- src/core/types/CMakeLists.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/src/core/types/CMakeLists.txt b/src/core/types/CMakeLists.txt index 97979661..de04e52f 100644 --- a/src/core/types/CMakeLists.txt +++ b/src/core/types/CMakeLists.txt @@ -28,7 +28,6 @@ set(SOURCES ${CMAKE_CURRENT_SOURCE_DIR}/tier_hash_map.c ${CMAKE_CURRENT_SOURCE_DIR}/tier_position_array.c ${CMAKE_CURRENT_SOURCE_DIR}/tier_position_hash_set.c - ${CMAKE_CURRENT_SOURCE_DIR}/tier_queue.c ${CMAKE_CURRENT_SOURCE_DIR}/tier_stack.c) target_sources(gamesman_core PRIVATE ${HEADERS} ${SOURCES}) From c2bebf71c1b92bd9d1742554aae0f14598c30ce1 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 23:33:46 -0700 Subject: [PATCH 05/12] Update Doxygen; replace capacity with capacity mask to avoid integer division --- src/core/data_structures/int64_queue.c | 15 ++--- src/core/data_structures/int64_queue.h | 79 +++++++++++++++++++------- 2 files changed, 68 insertions(+), 26 deletions(-) diff --git a/src/core/data_structures/int64_queue.c b/src/core/data_structures/int64_queue.c index e0ca7f9e..b79b571d 100644 --- a/src/core/data_structures/int64_queue.c +++ b/src/core/data_structures/int64_queue.c @@ -32,7 +32,9 @@ #include "core/gamesman_memory.h" static bool Expand(Int64Queue *queue) { - int64_t new_capacity = queue->capacity == 0 ? 16 : queue->capacity * 2; + const int64_t old_capacity = + queue->capacity_mask ? (int64_t)queue->capacity_mask + 1 : 0; + const int64_t new_capacity = old_capacity ? old_capacity * 2 : 16; int64_t *new_array = (int64_t *)GamesmanMalloc(new_capacity * sizeof(int64_t)); if (!new_array) { @@ -40,29 +42,28 @@ static bool Expand(Int64Queue *queue) { } if (queue->array) { - memcpy(new_array, queue->array, queue->capacity * sizeof(int64_t)); + memcpy(new_array, queue->array, old_capacity * sizeof(int64_t)); GamesmanFree(queue->array); } // Copy wrapped-around elements in the original array. This is safe if // the capacity is at least doubled. - memcpy(&new_array[queue->capacity], new_array, - queue->front * sizeof(int64_t)); + memcpy(&new_array[old_capacity], new_array, queue->front * sizeof(int64_t)); queue->array = new_array; - queue->capacity = new_capacity; + queue->capacity_mask = new_capacity - 1; return true; } // Function to add an element to the queue bool Int64QueuePush(Int64Queue *queue, int64_t item) { - if (queue->size == queue->capacity) { + if (!queue->array || (uint64_t)queue->size == queue->capacity_mask + 1) { if (!Expand(queue)) { return false; } } - int64_t back = (queue->front + queue->size) % queue->capacity; + int64_t back = (queue->front + queue->size) & queue->capacity_mask; queue->array[back] = item; ++queue->size; diff --git a/src/core/data_structures/int64_queue.h b/src/core/data_structures/int64_queue.h index 79a2384f..be3fc704 100644 --- a/src/core/data_structures/int64_queue.h +++ b/src/core/data_structures/int64_queue.h @@ -2,9 +2,7 @@ * @file int64_queue.h * @author Robert Shi (robertyishi@berkeley.edu) * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia * @brief Dynamic int64_t queue. - * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: * @@ -32,60 +30,103 @@ #include "core/gamesman_memory.h" /** - * @brief int64_t queue using dynamic array. + * @brief `int64_t` queue using dynamic array. + * + * @details No internal states are intended to be inspect or manipulated + * directly. Use the provided API functions instead. */ typedef struct Int64Queue { - int64_t *array; /**< Internal dynamic array storing the items. */ - int64_t front; /**< Index to the element at the front of the queue. */ - int64_t size; /**< Number of elements in the queue. */ - int64_t capacity; /**< Current capacity of the queue. */ + int64_t *array; /**< Internal dynamic array storing the items. */ + int64_t front; /**< Index to the element at the front of the queue. */ + int64_t size; /**< Number of elements in the queue. */ + uint64_t capacity_mask; /**< Current capacity of the queue - 1. */ } Int64Queue; -/** @brief Initializes QUEUE. */ +/** + * @brief Initializes `queue`. + * + * @param[out] queue Pointer to the queue to initialize. + */ static inline void Int64QueueInit(Int64Queue *queue) { queue->array = NULL; - queue->capacity = 0; queue->front = 0; queue->size = 0; + queue->capacity_mask = 0ULL; } -/** @brief Destroys QUEUE. */ +/** + * @brief Destroys `queue`. + * + * @param[in,out] queue Pointer to the queue to destroy. + */ static inline void Int64QueueDestroy(Int64Queue *queue) { GamesmanFree(queue->array); queue->array = NULL; - queue->capacity = 0; queue->front = 0; queue->size = 0; + queue->capacity_mask = 0ULL; } -/** @brief Returns true if QUEUE is empty, or false otherwise. */ +/** + * @brief Returns true if `queue` is empty, or false otherwise. + * + * @param[in] queue Pointer to the queue. + * + * @retval true If the `queue` is empty. + * @retval false Otherwise. + */ static inline bool Int64QueueIsEmpty(const Int64Queue *queue) { return (queue->size == 0); } -/** @brief Returns the number of items in QUEUE. */ +/** + * @brief Returns the number of items in `queue`. + * + * @param[in] queue Pointer to the queue. + * + * @return The number of elements currently stored in the `queue`. + */ static inline int64_t Int64QueueSize(const Int64Queue *queue) { return queue->size; } /** - * @brief Pushes ELEMENT into the QUEUE. + * @brief Pushes `item` into the `queue`. * - * @return true on success, - * @return false otherwise. + * @param[in,out] queue Pointer to the queue. + * @param[in] item The element to push. + * + * @retval true On success. + * @retval false On failure due to memory allocation errors. */ bool Int64QueuePush(Int64Queue *queue, int64_t item); -/** @brief Pops the item at the front of the QUEUE and returns it. */ +/** + * @brief Pops the item at the front of the `queue` and returns it. + * + * @warning Popping an empty queue results in undefined behavior. + * + * @param[in,out] queue Pointer to the queue. + * + * @return The item at the front of the `queue`. + */ static inline int64_t Int64QueuePop(Int64Queue *queue) { int64_t element = queue->array[queue->front]; - queue->front = (queue->front + 1) % queue->capacity; + queue->front = (queue->front + 1) & queue->capacity_mask; --queue->size; return element; } -/** @brief Returns the item at the front of the QUEUE without popping it. */ +/** + * @brief Returns the item at the front of the `queue` without popping it. + * + * @warning Peeking into an empty queue results in undefined behavior. + * + * @param[in] queue Pointer to the queue. + * + * @return The item at the front of the `queue`. + */ static inline int64_t Int64QueueFront(const Int64Queue *queue) { return queue->array[queue->front]; } From 2c6b406fdab6bd62c9f7c970f09ea6db04b76b98 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Thu, 27 Aug 2026 23:47:58 -0700 Subject: [PATCH 06/12] Add unit tests --- .../unit/core/data_structures/CMakeLists.txt | 1 + .../core/data_structures/int64_queue_test.cpp | 426 ++++++++++++++++++ 2 files changed, 427 insertions(+) create mode 100644 tests/unit/core/data_structures/int64_queue_test.cpp diff --git a/tests/unit/core/data_structures/CMakeLists.txt b/tests/unit/core/data_structures/CMakeLists.txt index 614e6a64..8c53b32c 100644 --- a/tests/unit/core/data_structures/CMakeLists.txt +++ b/tests/unit/core/data_structures/CMakeLists.txt @@ -6,6 +6,7 @@ add_library_test(data_structures_test data_structures hash_test.cpp int64_array_test.cpp int64_hash_set_test.cpp + int64_queue_test.cpp int64_to_ptr_chained_hash_map_test.cpp u64x2_hash_set_test.cpp COMPILE_DEFINITIONS diff --git a/tests/unit/core/data_structures/int64_queue_test.cpp b/tests/unit/core/data_structures/int64_queue_test.cpp new file mode 100644 index 00000000..88ff6ab1 --- /dev/null +++ b/tests/unit/core/data_structures/int64_queue_test.cpp @@ -0,0 +1,426 @@ +/** + * @file int64_queue_test.cpp + * @author Generated by Gemini 3.1 Pro + * @author Robert Shi (robertyishi@berkeley.edu): prompts and code review + * @brief Unit and component tests for Int64Queue. + * + * @copyright GamesCrafters research and development group + * SPDX-License-Identifier: GPL-3.0-or-later + * (see root COPYING file or accompanying source file) + */ + +#include + +extern "C" { +#include "core/data_structures/int64_queue.h" +} + +// ============================== Int64QueueInit ============================== + +// Verifies that a newly initialized queue is completely empty and its +// internal state is correctly reset to default values. +TEST(Int64QueueTest, InitSetsQueueToEmptyState) { + Int64Queue queue; + Int64QueueInit(&queue); + + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must report as empty immediately after initialization."; + + EXPECT_EQ(Int64QueueSize(&queue), 0) + << "Queue size must be exactly 0 after initialization."; + + Int64QueueDestroy(&queue); +} + +// ============================= Int64QueueDestroy ============================= + +// Verifies that destroying a queue safely resets its state and cleans up +// internal resources, even if the queue contained elements prior to +// destruction. +TEST(Int64QueueTest, DestroyLeavesQueueInSafeState) { + Int64Queue queue; + Int64QueueInit(&queue); + + // Push an element so the underlying array is guaranteed to be allocated. + EXPECT_TRUE(Int64QueuePush(&queue, 42)) + << "Pushing an element must succeed during setup."; + + Int64QueueDestroy(&queue); + + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must report as empty after being destroyed."; + EXPECT_EQ(Int64QueueSize(&queue), 0) + << "Queue size must be 0 after destruction."; + + // Direct internal state checks prevent undefined behavior on accidental + // reuse. + EXPECT_EQ(queue.size, 0) << "Internal size must be 0 after destruction."; + EXPECT_EQ(queue.array, nullptr) + << "Internal array pointer should be set to nullptr to prevent " + "dangling pointers."; +} + +// ============================= Int64QueueIsEmpty ============================= + +// Verifies that Int64QueueIsEmpty correctly reflects the queue's state +// dynamically as elements are added and removed. +TEST(Int64QueueTest, IsEmptyChangesStateAppropriately) { + Int64Queue queue; + Int64QueueInit(&queue); + + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must be empty immediately after initialization."; + + ASSERT_TRUE(Int64QueuePush(&queue, 100)) << "Push operation failed."; + + EXPECT_FALSE(Int64QueueIsEmpty(&queue)) + << "Queue must not be empty after pushing a single element."; + + Int64QueuePop(&queue); + + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must be empty again after popping its only element."; + + Int64QueueDestroy(&queue); +} + +// ============================== Int64QueueSize ============================== + +// Verifies that Int64QueueSize accurately increments and decrements +// to reflect the exact number of elements currently in the queue. +TEST(Int64QueueTest, SizeTracksPushesAndPopsCorrectly) { + Int64Queue queue; + Int64QueueInit(&queue); + + EXPECT_EQ(Int64QueueSize(&queue), 0) << "Initial size must be 0."; + + // Push multiple items to ensure the size scales up correctly. + for (int64_t i = 0; i < 5; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i * 10)) + << "Push operation failed during setup loop."; + } + + EXPECT_EQ(Int64QueueSize(&queue), 5) + << "Size must equal 5 after exactly 5 successful pushes."; + + Int64QueuePop(&queue); + Int64QueuePop(&queue); + + EXPECT_EQ(Int64QueueSize(&queue), 3) + << "Size must equal 3 after popping 2 elements from the queue."; + + // Drain the remaining elements to test the transition back to empty. + Int64QueuePop(&queue); + Int64QueuePop(&queue); + Int64QueuePop(&queue); + + EXPECT_EQ(Int64QueueSize(&queue), 0) + << "Size must equal 0 after popping all remaining elements."; + + Int64QueueDestroy(&queue); +} + +// ============================= Basic Operations ============================= + +// Verifies that a single element can be pushed into and popped from the +// queue successfully, leaving the queue empty afterward. +TEST(Int64QueueTest, PushAndPopSingleElement) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, 42)) + << "Pushing a single element must succeed."; + + EXPECT_EQ(Int64QueuePop(&queue), 42) + << "Popped value must exactly match the single pushed value."; + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must be empty after popping its only element."; + + Int64QueueDestroy(&queue); +} + +// Verifies that inspecting the front of the queue returns the correct +// element without modifying the queue's size or removing the element. +TEST(Int64QueueTest, FrontReturnsElementWithoutRemovingIt) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, 100)) + << "Pushing an element must succeed."; + + EXPECT_EQ(Int64QueueFront(&queue), 100) + << "Front must return the pushed element."; + + // Call front a second time to prove it does not implicitly mutate state. + EXPECT_EQ(Int64QueueFront(&queue), 100) + << "Consecutive calls to Front must return the exact same element."; + + EXPECT_EQ(Int64QueueSize(&queue), 1) + << "Size must remain 1 after calling Front."; + + Int64QueueDestroy(&queue); +} + +// Verifies that multiple elements pushed into the queue are retrieved +// in the exact same First-In-First-Out (FIFO) order when popped. +TEST(Int64QueueTest, PushAndPopMultipleElementsMaintainsFifoOrder) { + Int64Queue queue; + Int64QueueInit(&queue); + + constexpr int kNumElements = 5; + for (int64_t i = 1; i <= kNumElements; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i)) + << "Failed to push element " << i << " into the queue."; + } + + for (int64_t i = 1; i <= kNumElements; ++i) { + EXPECT_EQ(Int64QueuePop(&queue), i) + << "Elements must be popped in the exact FIFO sequence they were " + "pushed."; + } + + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must be empty after popping all elements."; + + Int64QueueDestroy(&queue); +} + +// Verifies that popping an element correctly advances the internal front +// pointer to expose the next element in the queue. +TEST(Int64QueueTest, FrontUpdatesCorrectlyAfterPop) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, 10)) << "Failed to push first element."; + ASSERT_TRUE(Int64QueuePush(&queue, 20)) << "Failed to push second element."; + + EXPECT_EQ(Int64QueueFront(&queue), 10) + << "Front must initially return the first pushed element."; + + // Remove the first element to force the front pointer to advance. + Int64QueuePop(&queue); + + EXPECT_EQ(Int64QueueFront(&queue), 20) + << "Front must update to the second element after the first is popped."; + + Int64QueueDestroy(&queue); +} + +// =========================== Value Boundary Tests =========================== + +// Verifies that the queue correctly stores and retrieves negative integers +// without memory corruption or sign-extension errors. +TEST(Int64QueueTest, HandlesNegativeValues) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, -1)) + << "Pushing a small negative integer must succeed."; + ASSERT_TRUE(Int64QueuePush(&queue, -999999)) + << "Pushing a large negative integer must succeed."; + + EXPECT_EQ(Int64QueuePop(&queue), -1) + << "The first popped value must perfectly match the first negative " + "integer pushed."; + EXPECT_EQ(Int64QueuePop(&queue), -999999) + << "The second popped value must perfectly match the large negative " + "integer pushed."; + + Int64QueueDestroy(&queue); +} + +// Verifies that the integer zero is treated strictly as a valid data element +// and does not cause logical faults or act as an accidental null/sentinel +// value. +TEST(Int64QueueTest, HandlesZeroValue) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, 0)) << "Pushing zero must succeed."; + + EXPECT_EQ(Int64QueuePop(&queue), 0) + << "The popped value must be exactly zero, preserving its identity as " + "data."; + EXPECT_TRUE(Int64QueueIsEmpty(&queue)) + << "Queue must be empty after popping the zero element."; + + Int64QueueDestroy(&queue); +} + +// Verifies that the absolute numeric extremes of the 64-bit signed integer +// domain are preserved natively to guarantee no unexpected truncation or +// overflow occurs. +TEST(Int64QueueTest, HandlesInt64MinAndMaxValues) { + Int64Queue queue; + Int64QueueInit(&queue); + + ASSERT_TRUE(Int64QueuePush(&queue, INT64_MAX)) + << "Pushing the maximum possible 64-bit signed integer must succeed."; + ASSERT_TRUE(Int64QueuePush(&queue, INT64_MIN)) + << "Pushing the minimum possible 64-bit signed integer must succeed."; + + EXPECT_EQ(Int64QueuePop(&queue), INT64_MAX) + << "The value must remain exactly INT64_MAX without suffering from " + "upper-bound truncation."; + EXPECT_EQ(Int64QueuePop(&queue), INT64_MIN) + << "The value must remain exactly INT64_MIN without suffering from " + "underflow or sign errors."; + + Int64QueueDestroy(&queue); +} + +// ========================== Dynamic Resizing Tests ========================== + +// Verifies that pushing elements beyond the initial capacity triggers dynamic +// memory reallocation while strictly preserving all existing elements in order. +TEST(Int64QueueTest, PushTriggersResizeWithoutDataLoss) { + Int64Queue queue; + Int64QueueInit(&queue); + + constexpr int kPushCount = 1024; + for (int64_t i = 0; i < kPushCount; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i)) + << "Push must succeed even when multiple internal memory " + "reallocations occur."; + } + + EXPECT_EQ(Int64QueueSize(&queue), kPushCount) + << "Queue size must exactly match the number of pushed elements after " + "resizing."; + + for (int64_t i = 0; i < kPushCount; ++i) { + EXPECT_EQ(Int64QueuePop(&queue), i) + << "FIFO order must be preserved perfectly across internal array " + "reallocations."; + } + + Int64QueueDestroy(&queue); +} + +// ==================== Circular Buffer & Dynamic Resizing ==================== + +// Verifies that the internal circular buffer correctly wraps array indices +// when elements shift geographically forward, avoiding unnecessary resizes. +TEST(Int64QueueTest, WraparoundWithoutResize) { + Int64Queue queue; + Int64QueueInit(&queue); + + // A constant sliding window guarantees the internal index advances + // significantly and wraps around any reasonable default capacity without + // ever triggering a resize. + constexpr int kWindowSize = 4; + for (int64_t i = 0; i < kWindowSize; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i)) + << "Initial window pushes must succeed."; + } + + constexpr int kTotalCycles = 1000; + for (int64_t i = kWindowSize; i < kTotalCycles + kWindowSize; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i)) + << "Pushing during the continuous wraparound phase must succeed."; + + EXPECT_EQ(Int64QueuePop(&queue), i - kWindowSize) + << "Popped element must maintain FIFO order as the circular buffer " + "wraps."; + } + + EXPECT_EQ(Int64QueueSize(&queue), kWindowSize) + << "Size must remain completely stable during the sliding window " + "operation."; + + for (int64_t i = kTotalCycles; i < kTotalCycles + kWindowSize; ++i) { + EXPECT_EQ(Int64QueuePop(&queue), i) + << "Remaining elements in the wrapped buffer must drain in exact " + "FIFO order."; + } + + Int64QueueDestroy(&queue); +} + +// Verifies that dynamically resizing a circular buffer when its internal +// pointers are in a wrapped-around state correctly realigns the elements into a +// flat array. +TEST(Int64QueueTest, ResizeWhenQueueIsWrappedAround) { + Int64Queue queue; + Int64QueueInit(&queue); + + // Push an initial element to ensure the underlying array is allocated and + // the capacity_mask is populated with its default initial configuration. + ASSERT_TRUE(Int64QueuePush(&queue, 0)) + << "Initial push to trigger buffer allocation failed."; + + int64_t initial_capacity = queue.capacity_mask + 1; + + // Fill the queue exactly to its capacity boundary to prepare for the wrap. + for (int64_t i = 1; i < initial_capacity; ++i) { + ASSERT_TRUE(Int64QueuePush(&queue, i)) + << "Failed to push elements up to the initial capacity."; + } + + // Pop half the elements to aggressively advance the internal front pointer + // toward the end of the physical array. + int64_t half_cap = initial_capacity / 2; + for (int64_t i = 0; i < half_cap; ++i) { + Int64QueuePop(&queue); + } + + // Push elements until the queue is full again to force the new elements + // to wrap around to the physical beginning of the allocated array. + int64_t current_val = initial_capacity; + while (Int64QueueSize(&queue) < initial_capacity) { + ASSERT_TRUE(Int64QueuePush(&queue, current_val++)) + << "Failed to push element into the wrapped-around portion."; + } + + // Pushing one more element guarantees a resize occurs while the data is + // physically split across the end and the beginning of the underlying + // array. + ASSERT_TRUE(Int64QueuePush(&queue, current_val++)) + << "Pushing beyond capacity must correctly untangle and copy wrapped " + "elements."; + + // Verify the reallocation logic correctly unwrapped the data by checking + // FIFO integrity. + for (int64_t i = half_cap; i < current_val; ++i) { + EXPECT_EQ(Int64QueuePop(&queue), i) + << "Elements must remain perfectly in FIFO sequence after a " + "wrapped-state resize."; + } + + Int64QueueDestroy(&queue); +} + +// Verifies that continuously advancing the internal pointers through the +// circular buffer correctly applies the capacity mask over many iterations. +TEST(Int64QueueTest, RepeatedWraparoundMaintainsIntegrity) { + Int64Queue queue; + Int64QueueInit(&queue); + + constexpr int kIterations = 1000; + int64_t push_counter = 0; + int64_t pop_counter = 0; + + // Repeatedly push and pop in small batches to force the internal indices + // to wrap mathematically using the capacity_mask without ever reallocating. + for (int i = 0; i < kIterations; ++i) { + for (int j = 0; j < 3; ++j) { + ASSERT_TRUE(Int64QueuePush(&queue, push_counter++)) + << "Push must remain stable across high-frequency index " + "wrapping."; + } + + for (int j = 0; j < 3; ++j) { + EXPECT_EQ(Int64QueuePop(&queue), pop_counter++) + << "Data integrity must hold as pointers loop back to zero via " + "the mask."; + } + + EXPECT_EQ(Int64QueueSize(&queue), 0) + << "Batch popping must fully drain the queue before the next cycle " + "to guarantee stability."; + } + + Int64QueueDestroy(&queue); +} + +// ==================== Circular Buffer & Dynamic Resizing ==================== From 24c7482b6d163a1d6ff478db4d1b983941773797 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 21:26:45 -0700 Subject: [PATCH 07/12] Convert MoveArray, PositionArray, TierArray, TierHashMap, TierStack to header-only libraries --- src/core/types/CMakeLists.txt | 7 +-- src/core/types/move_array.c | 53 ----------------------- src/core/types/move_array.h | 29 +++++++++---- src/core/types/position_array.c | 48 -------------------- src/core/types/position_array.h | 26 +++++++---- src/core/types/tier_array.c | 57 ------------------------ src/core/types/tier_array.h | 39 ++++++++++++----- src/core/types/tier_hash_map.c | 77 --------------------------------- src/core/types/tier_hash_map.h | 61 +++++++++++++++----------- src/core/types/tier_stack.c | 44 ------------------- src/core/types/tier_stack.h | 22 ++++++---- 11 files changed, 116 insertions(+), 347 deletions(-) delete mode 100644 src/core/types/move_array.c delete mode 100644 src/core/types/position_array.c delete mode 100644 src/core/types/tier_array.c delete mode 100644 src/core/types/tier_hash_map.c delete mode 100644 src/core/types/tier_stack.c diff --git a/src/core/types/CMakeLists.txt b/src/core/types/CMakeLists.txt index de04e52f..88285c2a 100644 --- a/src/core/types/CMakeLists.txt +++ b/src/core/types/CMakeLists.txt @@ -22,12 +22,7 @@ set(HEADERS ${CMAKE_CURRENT_SOURCE_DIR}/tier_to_ptr_chained_hash_map.h) set(SOURCES - ${CMAKE_CURRENT_SOURCE_DIR}/move_array.c - ${CMAKE_CURRENT_SOURCE_DIR}/position_array.c - ${CMAKE_CURRENT_SOURCE_DIR}/tier_array.c - ${CMAKE_CURRENT_SOURCE_DIR}/tier_hash_map.c ${CMAKE_CURRENT_SOURCE_DIR}/tier_position_array.c - ${CMAKE_CURRENT_SOURCE_DIR}/tier_position_hash_set.c - ${CMAKE_CURRENT_SOURCE_DIR}/tier_stack.c) + ${CMAKE_CURRENT_SOURCE_DIR}/tier_position_hash_set.c) target_sources(gamesman_core PRIVATE ${HEADERS} ${SOURCES}) diff --git a/src/core/types/move_array.c b/src/core/types/move_array.c deleted file mode 100644 index a117ed03..00000000 --- a/src/core/types/move_array.c +++ /dev/null @@ -1,53 +0,0 @@ -/** - * @file move_array.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Dynamic Move array implementation. - * @version 2.0.0 - * @date 2024-12-10 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/move_array.h" - -#include "core/data_structures/int64_array.h" -#include "core/types/base.h" - -void MoveArrayInit(MoveArray *array) { Int64ArrayInit(array); } - -void MoveArrayDestroy(MoveArray *array) { Int64ArrayDestroy(array); } - -bool MoveArrayAppend(MoveArray *array, Move move) { - return Int64ArrayPushBack(array, move); -} - -bool MoveArrayPopBack(MoveArray *array) { - if (array->size <= 0) return false; - --array->size; - return true; -} - -void MoveArraySortExplicit(MoveArray *array, - int (*comp)(const void *, const void *)) { - Int64ArraySortExplicit(array, comp); -} - -bool MoveArrayContains(const MoveArray *array, Move move) { - return Int64ArrayContains(array, move); -} diff --git a/src/core/types/move_array.h b/src/core/types/move_array.h index 980aaa6f..f11fce99 100644 --- a/src/core/types/move_array.h +++ b/src/core/types/move_array.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Dynamic Move array. - * @version 2.0.0 - * @date 2024-12-10 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -36,10 +34,12 @@ typedef Int64Array MoveArray; /** @brief Initializes the move ARRAY to an empty array. */ -void MoveArrayInit(MoveArray *array); +static inline void MoveArrayInit(MoveArray *array) { Int64ArrayInit(array); } /** @brief Destroyes the move ARRAY. */ -void MoveArrayDestroy(MoveArray *array); +static inline void MoveArrayDestroy(MoveArray *array) { + Int64ArrayDestroy(array); +} /** * @brief Appends MOVE to the end of ARRAY. @@ -49,7 +49,9 @@ void MoveArrayDestroy(MoveArray *array); * @return true on success, * @return false otherwise. */ -bool MoveArrayAppend(MoveArray *array, Move move); +static inline bool MoveArrayAppend(MoveArray *array, Move move) { + return Int64ArrayPushBack(array, move); +} /** * @brief Removes the last Move in ARRAY. @@ -58,7 +60,11 @@ bool MoveArrayAppend(MoveArray *array, Move move); * @return true on success, * @return false if ARRAY is empty. */ -bool MoveArrayPopBack(MoveArray *array); +static inline bool MoveArrayPopBack(MoveArray *array) { + if (array->size <= 0) return false; + --array->size; + return true; +} /** * @brief Sorts the move ARRAY in ascending order using the given COMP-arison @@ -70,10 +76,15 @@ bool MoveArrayPopBack(MoveArray *array); * first argument is greater than the second and zero if the arguments are * equivalent. */ -void MoveArraySortExplicit(MoveArray *array, - int (*comp)(const void *, const void *)); +static inline void MoveArraySortExplicit(MoveArray *array, + int (*comp)(const void *, + const void *)) { + Int64ArraySortExplicit(array, comp); +} /** @brief Returns true if ARRAY contains MOVE, or false otherwise. */ -bool MoveArrayContains(const MoveArray *array, Move move); +static inline bool MoveArrayContains(const MoveArray *array, Move move) { + return Int64ArrayContains(array, move); +} #endif // GAMESMANONE_CORE_TYPES_MOVE_ARRAY_H_ diff --git a/src/core/types/position_array.c b/src/core/types/position_array.c deleted file mode 100644 index b6a1de41..00000000 --- a/src/core/types/position_array.c +++ /dev/null @@ -1,48 +0,0 @@ -/** - * @file position_array.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Dynamic Position array implementation. - * @version 1.1.0 - * @date 2025-04-26 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/position_array.h" - -#include "core/data_structures/int64_array.h" -#include "core/gamesman_memory.h" -#include "core/types/base.h" - -void PositionArrayInit(PositionArray *array) { Int64ArrayInit(array); } - -void PositionArrayInitAllocator(PositionArray *array, - GamesmanAllocator *allocator) { - Int64ArrayInitAllocator(array, allocator); -} - -void PositionArrayDestroy(PositionArray *array) { Int64ArrayDestroy(array); } - -bool PositionArrayAppend(PositionArray *array, Position position) { - return Int64ArrayPushBack(array, position); -} - -bool PositionArrayContains(PositionArray *array, Position position) { - return Int64ArrayContains(array, position); -} diff --git a/src/core/types/position_array.h b/src/core/types/position_array.h index 28ae805f..92e99ce5 100644 --- a/src/core/types/position_array.h +++ b/src/core/types/position_array.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Dynamic Position array. - * @version 1.1.0 - * @date 2025-04-26 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -37,13 +35,19 @@ typedef Int64Array PositionArray; /** @brief Initializes the position ARRAY to an empty array. */ -void PositionArrayInit(PositionArray *array); +static inline void PositionArrayInit(PositionArray *array) { + Int64ArrayInit(array); +} -void PositionArrayInitAllocator(PositionArray *array, - GamesmanAllocator *allocator); +static inline void PositionArrayInitAllocator(PositionArray *array, + GamesmanAllocator *allocator) { + Int64ArrayInitAllocator(array, allocator); +} /** @brief Destroyes the position ARRAY. */ -void PositionArrayDestroy(PositionArray *array); +static inline void PositionArrayDestroy(PositionArray *array) { + Int64ArrayDestroy(array); +} /** * @brief Appends POSITION to the end of ARRAY. @@ -53,9 +57,15 @@ void PositionArrayDestroy(PositionArray *array); * @return true on success, * @return false otherwise. */ -bool PositionArrayAppend(PositionArray *array, Position position); +static inline bool PositionArrayAppend(PositionArray *array, + Position position) { + return Int64ArrayPushBack(array, position); +} /** @brief Returns true if ARRAY contains POSITION, or false otherwise. */ -bool PositionArrayContains(PositionArray *array, Position position); +static inline bool PositionArrayContains(PositionArray *array, + Position position) { + return Int64ArrayContains(array, position); +} #endif // GAMESMANONE_CORE_TYPES_POSITION_ARRAY_H_ diff --git a/src/core/types/tier_array.c b/src/core/types/tier_array.c deleted file mode 100644 index da337fa0..00000000 --- a/src/core/types/tier_array.c +++ /dev/null @@ -1,57 +0,0 @@ -/** - * @file tier_array.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Dynamic tier array implementation. - * @version 1.1.0 - * @date 2024-09-07 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/tier_array.h" - -#include "core/data_structures/int64_array.h" -#include "core/types/base.h" - -void TierArrayInit(TierArray *array) { Int64ArrayInit(array); } - -bool TierArrayInitCopy(TierArray *dest, const TierArray *src) { - return Int64ArrayInitCopy(dest, src); -} - -void TierArrayDestroy(TierArray *array) { Int64ArrayDestroy(array); } - -bool TierArrayAppend(TierArray *array, Tier tier) { - return Int64ArrayPushBack(array, tier); -} - -bool TierArrayRemoveUnordered(TierArray *array, Tier tier) { - return Int64ArrayRemoveUnordered(array, tier); -} - -void TierArrayPopBack(TierArray *array) { Int64ArrayPopBack(array); } - -Tier TierArrayBack(const TierArray *array) { return Int64ArrayBack(array); } - -bool TierArrayEmpty(const TierArray *array) { return Int64ArrayEmpty(array); } - -void TierArraySortExplicit(TierArray *array, - int (*comp)(const void *, const void *)) { - Int64ArraySortExplicit(array, comp); -} diff --git a/src/core/types/tier_array.h b/src/core/types/tier_array.h index 488a8d0c..900cf9ad 100644 --- a/src/core/types/tier_array.h +++ b/src/core/types/tier_array.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Dynamic tier array. - * @version 1.1.0 - * @date 2024-09-07 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -36,13 +34,17 @@ typedef Int64Array TierArray; /** @brief Initializes the Tier ARRAY. */ -void TierArrayInit(TierArray *array); +static inline void TierArrayInit(TierArray *array) { Int64ArrayInit(array); } /** @brief Initializes the DEST tier array as a copy of tier array SRC. */ -bool TierArrayInitCopy(TierArray *dest, const TierArray *src); +static inline bool TierArrayInitCopy(TierArray *dest, const TierArray *src) { + return Int64ArrayInitCopy(dest, src); +} /** @brief Destroys the Tier ARRAY. */ -void TierArrayDestroy(TierArray *array); +static inline void TierArrayDestroy(TierArray *array) { + Int64ArrayDestroy(array); +} /** * @brief Appends TIER to the end of the given Tier ARRAY. @@ -52,7 +54,9 @@ void TierArrayDestroy(TierArray *array); * @return true on success, * @return false otherwise. */ -bool TierArrayAppend(TierArray *array, Tier tier); +static inline bool TierArrayAppend(TierArray *array, Tier tier) { + return Int64ArrayPushBack(array, tier); +} /** * @brief Removes the first occurrence of TIER from ARRAY if it exists. @@ -62,22 +66,30 @@ bool TierArrayAppend(TierArray *array, Tier tier); * @return true if TIER exists in ARRAY, or * @return false otherwise. */ -bool TierArrayRemoveUnordered(TierArray *array, Tier tier); +static inline bool TierArrayRemoveUnordered(TierArray *array, Tier tier) { + return Int64ArrayRemoveUnordered(array, tier); +} /** * @brief Pops the item at the back of the ARRAY. Calling this function on an * empty ARRAY results in undefined behavior. */ -void TierArrayPopBack(TierArray *array); +static inline void TierArrayPopBack(TierArray *array) { + Int64ArrayPopBack(array); +} /** * @brief Returns the Tier at the back of the array. Calling this function on an * empty ARRAY results in undefined behavior. */ -Tier TierArrayBack(const TierArray *array); +static inline Tier TierArrayBack(const TierArray *array) { + return Int64ArrayBack(array); +} /** @brief Returns true if ARRAY is empty, or false otherwise. */ -bool TierArrayEmpty(const TierArray *array); +static inline bool TierArrayEmpty(const TierArray *array) { + return Int64ArrayEmpty(array); +} /** * @brief Sorts the given ARRAY according to the given comparison function. @@ -87,7 +99,10 @@ bool TierArrayEmpty(const TierArray *array); * first argument is greater than the second, and zero if the arguments are * equivalent. Both parameters are assumed to be pointers to \c Tier objects. */ -void TierArraySortExplicit(TierArray *array, - int (*comp)(const void *, const void *)); +static inline void TierArraySortExplicit(TierArray *array, + int (*comp)(const void *, + const void *)) { + Int64ArraySortExplicit(array, comp); +} #endif // GAMESMANONE_CORE_TYPES_TIER_ARRAY_H_ diff --git a/src/core/types/tier_hash_map.c b/src/core/types/tier_hash_map.c deleted file mode 100644 index 209ad867..00000000 --- a/src/core/types/tier_hash_map.c +++ /dev/null @@ -1,77 +0,0 @@ -/** - * @file tier_hash_map.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Implementation of linear-probing Tier hash map. - * @version 1.0.1 - * @date 2024-09-02 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/tier_hash_map.h" - -#include - -#include "core/data_structures/int64_hash_map.h" -#include "core/gamesman_memory.h" -#include "core/types/base.h" - -void TierHashMapInit(TierHashMap *map, double max_load_factor) { - Int64HashMapInit(map, max_load_factor); -} - -void TierHashMapInitAllocator(TierHashMap *map, double max_load_factor, - GamesmanAllocator *allocator) { - Int64HashMapInitAllocator(map, max_load_factor, allocator); -} - -void TierHashMapDestroy(TierHashMap *map) { Int64HashMapDestroy(map); } - -TierHashMapIterator TierHashMapGet(TierHashMap *map, Tier key) { - return Int64HashMapGet(map, key); -} - -bool TierHashMapSet(TierHashMap *map, Tier tier, int64_t value) { - return Int64HashMapSet(map, tier, value); -} - -bool TierHashMapContains(const TierHashMap *map, Tier tier) { - return Int64HashMapContains(map, tier); -} - -TierHashMapIterator TierHashMapBegin(TierHashMap *map) { - return Int64HashMapBegin(map); -} - -Tier TierHashMapIteratorKey(const TierHashMapIterator *it) { - return Int64HashMapIteratorKey(it); -} - -int64_t TierHashMapIteratorValue(const TierHashMapIterator *it) { - return Int64HashMapIteratorValue(it); -} - -bool TierHashMapIteratorIsValid(const TierHashMapIterator *it) { - return Int64HashMapIteratorIsValid(it); -} - -bool TierHashMapIteratorNext(TierHashMapIterator *iterator, Tier *tier, - int64_t *value) { - return Int64HashMapIteratorNext(iterator, tier, value); -} diff --git a/src/core/types/tier_hash_map.h b/src/core/types/tier_hash_map.h index 8f51ff46..998013ee 100644 --- a/src/core/types/tier_hash_map.h +++ b/src/core/types/tier_hash_map.h @@ -5,8 +5,6 @@ * Supervised by Dan Garcia * @brief Linear-probing Tier hash map that maps Tiers to 64-bit signed * integers. - * @version 1.0.1 - * @date 2024-09-02 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -55,7 +53,9 @@ typedef Int64HashMapIterator TierHashMapIterator; * value will be set to 0.25 and 0.75, respectively, regardless of the * user-specified value. */ -void TierHashMapInit(TierHashMap *map, double max_load_factor); +static inline void TierHashMapInit(TierHashMap *map, double max_load_factor) { + Int64HashMapInit(map, max_load_factor); +} /** * @brief Initializes the given \p map to an empty map with maximum load @@ -73,11 +73,16 @@ void TierHashMapInit(TierHashMap *map, double max_load_factor); * @param allocator Memory allocator to use. If \c NULL is passed, the effect is * equivalent to calling TierHashMapInit. */ -void TierHashMapInitAllocator(TierHashMap *map, double max_load_factor, - GamesmanAllocator *allocator); +static inline void TierHashMapInitAllocator(TierHashMap *map, + double max_load_factor, + GamesmanAllocator *allocator) { + Int64HashMapInitAllocator(map, max_load_factor, allocator); +} /** @brief Destroys the Tier hash map MAP. */ -void TierHashMapDestroy(TierHashMap *map); +static inline void TierHashMapDestroy(TierHashMap *map) { + Int64HashMapDestroy(map); +} /** * @brief Returns an iterator to the MAP entry containing the given KEY. @@ -89,7 +94,9 @@ void TierHashMapDestroy(TierHashMap *map); * @return TierHashMapIterator pointing to the entry with KEY, or invalid * if KEY is not found in MAP. */ -TierHashMapIterator TierHashMapGet(TierHashMap *map, Tier key); +static inline TierHashMapIterator TierHashMapGet(TierHashMap *map, Tier key) { + return Int64HashMapGet(map, key); +} /** * @brief Sets the entry with key equal to TIER in MAP to the given VALUE and @@ -103,13 +110,17 @@ TierHashMapIterator TierHashMapGet(TierHashMap *map, Tier key); * @return true on success, * @return false otherwise. */ -bool TierHashMapSet(TierHashMap *map, Tier tier, int64_t value); +static inline bool TierHashMapSet(TierHashMap *map, Tier tier, int64_t value) { + return Int64HashMapSet(map, tier, value); +} /** * @brief Returns true if the given MAP contains an entry with key equal to * TIER, or false otherwise. */ -bool TierHashMapContains(const TierHashMap *map, Tier tier); +static inline bool TierHashMapContains(const TierHashMap *map, Tier tier) { + return Int64HashMapContains(map, tier); +} /** * @brief Returns an invalid iterator to the entry before the first entry of @@ -118,18 +129,10 @@ bool TierHashMapContains(const TierHashMap *map, Tier tier); * @note This function is designed to be used in conjunction with * TierHashMapIteratorNext to iterate through all the entries in the Tier hash * map. - * - * @example - * TierHashMapIterator it = TierHashMapBegin(map); - * Tier key; - * int64_t value; - * - * // While the next entry exists... - * while (TierHashMapIteratorNext(&it, &key, &value)) { - * // Do stuff with key and value... - * } */ -TierHashMapIterator TierHashMapBegin(TierHashMap *map); +static inline TierHashMapIterator TierHashMapBegin(TierHashMap *map) { + return Int64HashMapBegin(map); +} /** * @brief Returns the Tier that was used as the key to the entry IT is pointing @@ -140,7 +143,9 @@ TierHashMapIterator TierHashMapBegin(TierHashMap *map); * @param it Tier hash map iterator. * @return Key to the entry. */ -Tier TierHashMapIteratorKey(const TierHashMapIterator *it); +static inline Tier TierHashMapIteratorKey(const TierHashMapIterator *it) { + return Int64HashMapIteratorKey(it); +} /** * @brief Returns the value of the entry IT is pointing to. The user should @@ -151,10 +156,14 @@ Tier TierHashMapIteratorKey(const TierHashMapIterator *it); * @param it Tier hash map iterator. * @return Value of the entry. */ -int64_t TierHashMapIteratorValue(const TierHashMapIterator *it); +static inline int64_t TierHashMapIteratorValue(const TierHashMapIterator *it) { + return Int64HashMapIteratorValue(it); +} /** @brief Returns true if the given IT-erator is valid, or false otherwise. */ -bool TierHashMapIteratorIsValid(const TierHashMapIterator *it); +static inline bool TierHashMapIteratorIsValid(const TierHashMapIterator *it) { + return Int64HashMapIteratorIsValid(it); +} /** * @brief Moves iterator IT to the next valid entry inside the Tier hash map @@ -174,7 +183,9 @@ bool TierHashMapIteratorIsValid(const TierHashMapIterator *it); * @return true if next entry exists, * @return false otherwise. */ -bool TierHashMapIteratorNext(TierHashMapIterator *iterator, Tier *tier, - int64_t *value); +static inline bool TierHashMapIteratorNext(TierHashMapIterator *iterator, + Tier *tier, int64_t *value) { + return Int64HashMapIteratorNext(iterator, tier, value); +} #endif // GAMESMANONE_CORE_TYPES_TIER_HASH_MAP_H_ diff --git a/src/core/types/tier_stack.c b/src/core/types/tier_stack.c deleted file mode 100644 index 0c3d0c89..00000000 --- a/src/core/types/tier_stack.c +++ /dev/null @@ -1,44 +0,0 @@ -/** - * @file tier_stack.c - * @author Robert Shi (robertyishi@berkeley.edu) - * @author GamesCrafters Research Group, UC Berkeley - * Supervised by Dan Garcia - * @brief Tier stack implementation. - * @version 1.0.1 - * @date 2024-12-10 - * - * @copyright This file is part of GAMESMAN, The Finite, Two-person - * Perfect-Information Game Generator released under the GPL: - * - * 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 3 of the License, 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, see . - */ - -#include "core/types/tier_stack.h" - -#include "core/data_structures/int64_array.h" -#include "core/types/base.h" - -void TierStackInit(TierStack *stack) { Int64ArrayInit(stack); } - -void TierStackDestroy(TierStack *stack) { Int64ArrayDestroy(stack); } - -bool TierStackPush(TierStack *stack, Tier tier) { - return Int64ArrayPushBack(stack, tier); -} - -void TierStackPop(TierStack *stack) { Int64ArrayPopBack(stack); } - -Tier TierStackTop(const TierStack *stack) { return Int64ArrayBack(stack); } - -bool TierStackEmpty(const TierStack *stack) { return Int64ArrayEmpty(stack); } diff --git a/src/core/types/tier_stack.h b/src/core/types/tier_stack.h index 5b4ba776..05b2d6a2 100644 --- a/src/core/types/tier_stack.h +++ b/src/core/types/tier_stack.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Tier stack. - * @version 1.0.1 - * @date 2024-12-10 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -36,10 +34,12 @@ typedef Int64Array TierStack; /** @brief Initializes Tier stack STACK. */ -void TierStackInit(TierStack *stack); +static inline void TierStackInit(TierStack *stack) { Int64ArrayInit(stack); } /** @brief Destroys Tier stack STACK. */ -void TierStackDestroy(TierStack *stack); +static inline void TierStackDestroy(TierStack *stack) { + Int64ArrayDestroy(stack); +} /** * @brief Pushes a new TIER into the STACK. @@ -49,7 +49,9 @@ void TierStackDestroy(TierStack *stack); * @return true on success, * @return false otherwise. */ -bool TierStackPush(TierStack *stack, Tier tier); +static inline bool TierStackPush(TierStack *stack, Tier tier) { + return Int64ArrayPushBack(stack, tier); +} /** * @brief Pops a tier from the STACK. Calling this function on an empty STACK @@ -57,7 +59,7 @@ bool TierStackPush(TierStack *stack, Tier tier); * * @param stack Stack to pop the tier from. */ -void TierStackPop(TierStack *stack); +static inline void TierStackPop(TierStack *stack) { Int64ArrayPopBack(stack); } /** * @brief Returns the item at the top of the STACK. Calling this function on an @@ -66,9 +68,13 @@ void TierStackPop(TierStack *stack); * @param stack Stack to peak into. * @return Tier at the top of STACK. */ -Tier TierStackTop(const TierStack *stack); +static inline Tier TierStackTop(const TierStack *stack) { + return Int64ArrayBack(stack); +} /** @brief Returns true if the given STACK is empty, or false otherwise. */ -bool TierStackEmpty(const TierStack *stack); +static inline bool TierStackEmpty(const TierStack *stack) { + return Int64ArrayEmpty(stack); +} #endif // GAMESMANONE_CORE_TYPES_TIER_STACK_H_ From 0669f3a2b35138beb06ffff662fb00e35a1f59ad Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 21:35:25 -0700 Subject: [PATCH 08/12] Remove redundant include and reorder include --- src/core/types/simd.h | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/core/types/simd.h b/src/core/types/simd.h index c24eb853..5223e5a7 100644 --- a/src/core/types/simd.h +++ b/src/core/types/simd.h @@ -29,6 +29,10 @@ #include +#ifdef GAMESMAN_HAS_BMI1 +#include +#endif // GAMESMAN_HAS_BMI1 + /** * @brief 128-bit SIMD vector of 16 signed 8-bit integers. */ @@ -44,12 +48,6 @@ typedef uint8_t U8x16 __attribute__((vector_size(16))); */ typedef uint64_t U64x2 __attribute__((vector_size(16))); -#include - -#ifdef GAMESMAN_HAS_BMI1 -#include -#endif // GAMESMAN_HAS_BMI1 - /** * @brief Extract bits from unsigned 64-bit integer `val` at the corresponding * bit locations specified by mask to contiguous low bits; the remaining From 2b33193dd09fe5fd924c6ef1bdfc9472bf74366a Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 21:49:27 -0700 Subject: [PATCH 09/12] Remove redundant local implementation of Hash128to64 from tier_position_hash_set.h The function was previously moved to a common header --- src/core/types/tier_position_hash_set.c | 37 +------------------------ 1 file changed, 1 insertion(+), 36 deletions(-) diff --git a/src/core/types/tier_position_hash_set.c b/src/core/types/tier_position_hash_set.c index d6ecd439..ab6a233b 100644 --- a/src/core/types/tier_position_hash_set.c +++ b/src/core/types/tier_position_hash_set.c @@ -30,6 +30,7 @@ #include #include +#include "core/data_structures/hash.h" #include "core/gamesman_memory.h" #include "core/types/base.h" @@ -42,42 +43,6 @@ void TierPositionHashSetInit(TierPositionHashSet *set, double max_load_factor) { set->capacity_mask = -1; } -// This function is adapted from Google CityHash -// Copyright (c) 2011 Google, Inc. -// -// 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. -// -// 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. -// -// CityHash, by Geoff Pike and Jyrki Alakuijala -// -// http://code.google.com/p/cityhash/ -static uint64_t Hash128to64(uint64_t lo, uint64_t hi) { - // Murmur-inspired hashing. - const uint64_t kMul = 0x9ddfea08eb382d69ULL; - uint64_t a = (lo ^ hi) * kMul; - a ^= (a >> 47); - uint64_t b = (hi ^ a) * kMul; - b ^= (b >> 47); - b *= kMul; - - return b; -} - static int64_t TierPositionHashSetHash(TierPosition key, int64_t mask) { int64_t a = (int64_t)key.tier; int64_t b = (int64_t)key.position; From 9284472ebd73492e475f3865fc91a54b965ce4a3 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 22:08:47 -0700 Subject: [PATCH 10/12] Update Doxygen for the five header-only libraries --- src/core/types/move_array.h | 55 ++++++++++++++------- src/core/types/position_array.h | 49 +++++++++++++++---- src/core/types/tier_array.h | 87 ++++++++++++++++++++++++--------- src/core/types/tier_hash_set.h | 48 +++++++++--------- src/core/types/tier_stack.h | 55 +++++++++++++++------ 5 files changed, 203 insertions(+), 91 deletions(-) diff --git a/src/core/types/move_array.h b/src/core/types/move_array.h index f11fce99..edbc7681 100644 --- a/src/core/types/move_array.h +++ b/src/core/types/move_array.h @@ -30,35 +30,47 @@ #include "core/data_structures/int64_array.h" #include "core/types/base.h" -/** @brief Dynamic Move array. */ +/** + * @brief Dynamic `Move` array. + */ typedef Int64Array MoveArray; -/** @brief Initializes the move ARRAY to an empty array. */ +/** + * @brief Initializes `array`. + * + * @param[out] array Array to initialize. + */ static inline void MoveArrayInit(MoveArray *array) { Int64ArrayInit(array); } -/** @brief Destroyes the move ARRAY. */ +/** + * @brief Deallocates `array`. + * + * @param[in,out] array Array to deallocate. + */ static inline void MoveArrayDestroy(MoveArray *array) { Int64ArrayDestroy(array); } /** - * @brief Appends MOVE to the end of ARRAY. + * @brief Appends a new `move` to the back of the `array`. + * + * @param[in,out] array Destination array. + * @param[in] move New move. * - * @param array Destination array. - * @param move Move to append. - * @return true on success, - * @return false otherwise. + * @retval true on success. + * @retval false otherwise. */ static inline bool MoveArrayAppend(MoveArray *array, Move move) { return Int64ArrayPushBack(array, move); } /** - * @brief Removes the last Move in ARRAY. + * @brief Pops the move at the back of the `array`. * - * @param array Target array. - * @return true on success, - * @return false if ARRAY is empty. + * @param[in,out] array Array to pop the move from. + * + * @retval true on success. + * @retval false if the array is empty. */ static inline bool MoveArrayPopBack(MoveArray *array) { if (array->size <= 0) return false; @@ -67,13 +79,12 @@ static inline bool MoveArrayPopBack(MoveArray *array) { } /** - * @brief Sorts the move ARRAY in ascending order using the given COMP-arison - * function. + * @brief Sorts the given `array` according to the given comparison function. * - * @param array Array to be sorted. - * @param comp Comparison function which returns ​a negative integer value if + * @param[in,out] array The array to be sorted. + * @param[in] comp Comparison function which returns a negative integer value if * the first argument is less than the second, a positive integer value if the - * first argument is greater than the second and zero if the arguments are + * first argument is greater than the second, and zero if the arguments are * equivalent. */ static inline void MoveArraySortExplicit(MoveArray *array, @@ -82,7 +93,15 @@ static inline void MoveArraySortExplicit(MoveArray *array, Int64ArraySortExplicit(array, comp); } -/** @brief Returns true if ARRAY contains MOVE, or false otherwise. */ +/** + * @brief Returns whether the given `array` contains the given `move`. + * + * @param[in] array Array to check. + * @param[in] move Move to look for. + * + * @retval true if the array contains the move. + * @retval false otherwise. + */ static inline bool MoveArrayContains(const MoveArray *array, Move move) { return Int64ArrayContains(array, move); } diff --git a/src/core/types/position_array.h b/src/core/types/position_array.h index 92e99ce5..f91e76dc 100644 --- a/src/core/types/position_array.h +++ b/src/core/types/position_array.h @@ -31,38 +31,69 @@ #include "core/gamesman_memory.h" #include "core/types/base.h" -/** @brief Dynamic Position array. */ +/** + * @brief Dynamic `Position` array. + */ typedef Int64Array PositionArray; -/** @brief Initializes the position ARRAY to an empty array. */ +/** + * @brief Initializes `array`. + * + * @param[out] array Array to initialize. + */ static inline void PositionArrayInit(PositionArray *array) { Int64ArrayInit(array); } +/** + * @brief Initializes `array` using `allocator` as the underlying memory + * allocator. + * + * @details If `allocator` is `NULL`, the function call is equivalent to + * `PositionArrayInit(array)`. Note that this function does not transfer the + * ownership of `allocator` to the new array object. The caller is responsible + * for releasing its own copy of the allocator. + * + * @param[out] array Array to initialize. + * @param[in,out] allocator Memory allocator to use. + */ static inline void PositionArrayInitAllocator(PositionArray *array, GamesmanAllocator *allocator) { Int64ArrayInitAllocator(array, allocator); } -/** @brief Destroyes the position ARRAY. */ +/** + * @brief Deallocates `array`. + * + * @param[in,out] array Array to deallocate. + */ static inline void PositionArrayDestroy(PositionArray *array) { Int64ArrayDestroy(array); } /** - * @brief Appends POSITION to the end of ARRAY. + * @brief Appends a new `position` to the back of the `array`. + * + * @param[in,out] array Destination array. + * @param[in] position New position. * - * @param array Destination array. - * @param position Position to append. - * @return true on success, - * @return false otherwise. + * @retval true on success. + * @retval false otherwise. */ static inline bool PositionArrayAppend(PositionArray *array, Position position) { return Int64ArrayPushBack(array, position); } -/** @brief Returns true if ARRAY contains POSITION, or false otherwise. */ +/** + * @brief Returns whether the given `array` contains the given `position`. + * + * @param[in] array Array to check. + * @param[in] position Position to look for. + * + * @retval true if the array contains the position. + * @retval false otherwise. + */ static inline bool PositionArrayContains(PositionArray *array, Position position) { return Int64ArrayContains(array, position); diff --git a/src/core/types/tier_array.h b/src/core/types/tier_array.h index 900cf9ad..f564d746 100644 --- a/src/core/types/tier_array.h +++ b/src/core/types/tier_array.h @@ -30,74 +30,115 @@ #include "core/data_structures/int64_array.h" #include "core/types/base.h" -/** @brief Dynamic Tier array. */ +/** + * @brief Dynamic `Tier` array. + */ typedef Int64Array TierArray; -/** @brief Initializes the Tier ARRAY. */ +/** + * @brief Initializes `array`. + * + * @param[out] array Array to initialize. + */ static inline void TierArrayInit(TierArray *array) { Int64ArrayInit(array); } -/** @brief Initializes the DEST tier array as a copy of tier array SRC. */ +/** + * @brief Initializes `dest` array to be a copy of the `src` array. + * + * @details If `src` uses a custom memory allocator, a new reference will be + * copied to the `dest` array. + * + * @param[out] dest Array to initialize. + * @param[in] src Source array to copy from. + * + * @retval true on success. + * @retval false otherwise. + */ static inline bool TierArrayInitCopy(TierArray *dest, const TierArray *src) { return Int64ArrayInitCopy(dest, src); } -/** @brief Destroys the Tier ARRAY. */ +/** + * @brief Deallocates `array`. + * + * @param[in,out] array Array to deallocate. + */ static inline void TierArrayDestroy(TierArray *array) { Int64ArrayDestroy(array); } /** - * @brief Appends TIER to the end of the given Tier ARRAY. + * @brief Appends a new `tier` to the back of the `array`. * - * @param array Destination Tier array. - * @param tier Tier to append. - * @return true on success, - * @return false otherwise. + * @param[in,out] array Destination array. + * @param[in] tier New tier. + * + * @retval true on success. + * @retval false otherwise. */ static inline bool TierArrayAppend(TierArray *array, Tier tier) { return Int64ArrayPushBack(array, tier); } /** - * @brief Removes the first occurrence of TIER from ARRAY if it exists. + * @brief Removes the first occurrence of `tier` from `array`, if it exists. + * + * @param[in,out] array Array of `Tier`. + * @param[in] tier Value to remove. * - * @param array Tier array. - * @param tier Tier to remove. - * @return true if TIER exists in ARRAY, or - * @return false otherwise. + * @retval true if `tier` exists in `array` and was removed. + * @retval false otherwise. */ static inline bool TierArrayRemoveUnordered(TierArray *array, Tier tier) { return Int64ArrayRemoveUnordered(array, tier); } /** - * @brief Pops the item at the back of the ARRAY. Calling this function on an - * empty ARRAY results in undefined behavior. + * @brief Pops the item at the back of the `array`. + * + * @details Calling this function on an empty `array` results in undefined + * behavior. + * + * @param[in,out] array Array to pop the item from. */ static inline void TierArrayPopBack(TierArray *array) { Int64ArrayPopBack(array); } /** - * @brief Returns the Tier at the back of the array. Calling this function on an - * empty ARRAY results in undefined behavior. + * @brief Returns the item at the back of `array`. + * + * @details Calling this function on an empty `array` results in undefined + * behavior. + * + * @param[in] array Array to get the item from. + * + * @return Item at the back of `array`. */ static inline Tier TierArrayBack(const TierArray *array) { return Int64ArrayBack(array); } -/** @brief Returns true if ARRAY is empty, or false otherwise. */ +/** + * @brief Returns whether the given `array` is empty. + * + * @param[in] array Array to check. + * + * @retval true if the array is empty. + * @retval false otherwise. + */ static inline bool TierArrayEmpty(const TierArray *array) { return Int64ArrayEmpty(array); } /** - * @brief Sorts the given ARRAY according to the given comparison function. - * @param array The array to be sorted. - * @param comp Comparison function which returns ​a negative integer value if + * @brief Sorts the given `array` according to the given comparison function. + * + * @param[in,out] array The array to be sorted. + * @param[in] comp Comparison function which returns a negative integer value if * the first argument is less than the second, a positive integer value if the * first argument is greater than the second, and zero if the arguments are - * equivalent. Both parameters are assumed to be pointers to \c Tier objects. + * equivalent. */ static inline void TierArraySortExplicit(TierArray *array, int (*comp)(const void *, diff --git a/src/core/types/tier_hash_set.h b/src/core/types/tier_hash_set.h index e917fb98..cd6e9fbb 100644 --- a/src/core/types/tier_hash_set.h +++ b/src/core/types/tier_hash_set.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Linear-probing Tier hash set. - * @version 2.0.0 - * @date 2025-05-11 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -32,52 +30,52 @@ #include "core/data_structures/int64_hash_set.h" #include "core/types/base.h" -/** @brief Linear-probing Tier hash set using Int64HashSet as underlying type. +/** + * @brief A linear-probing Tier hash set using `Int64HashSet` as the underlying + * type. */ typedef Int64HashSet TierHashSet; /** - * @brief Initializes the given \p set to an empty set with maximum load - * factor \p max_load_factor. + * @brief Initializes a Tier hash set. * - * @param set Set to initialize. - * @param max_load_factor Set maximum load factor of \p set to this value. The - * hash set will automatically expand its capacity if (double)size/capacity is - * greater than \p max_load_factor. A small value trades memory for speed - * whereas a large value trades speed for memory. This value is restricted to be - * in the range [0.25, 0.75] to provide optimal performance. The actual max load - * factor is capped at 0.25 and 0.75 respectively if the user passes a value - * that is smaller than 0.25 or greater than 0.75. + * @param[out] set The `TierHashSet` to initialize. + * @param[in] max_load_factor The maximum load factor, clamped to [0.5, 0.8]. */ static inline void TierHashSetInit(TierHashSet *set, double max_load_factor) { Int64HashSetInit(set, max_load_factor); } -/** @brief Deallocates the given \p set. */ +/** + * @brief Frees the memory associated with the hash set and resets its state. + * + * @param[in,out] set The `TierHashSet` to destroy. + */ static inline void TierHashSetDestroy(TierHashSet *set) { Int64HashSetDestroy(set); } /** - * @brief Tests if \p tier is in \p set. + * @brief Checks if a specific Tier is present in the hash set. + * + * @param[in] set The `TierHashSet` to search. + * @param[in] tier The `Tier` value to look for. * - * @param set Set from which the given \p tier is looked up. - * @param tier Tier value to look for. - * @return true if \p set contains \p tier, or - * @return false otherwise. + * @retval true The `tier` is present in the set. + * @retval false The `tier` is not present, or the set is uninitialized. */ static inline bool TierHashSetContains(const TierHashSet *set, Tier tier) { return Int64HashSetContains(set, tier); } /** - * @brief Adds \p tier to the given \p set or does nothing if \p set - * already contains \p tier. + * @brief Adds a Tier value to the hash set. + * + * @param[in,out] set The `TierHashSet` to add the Tier to. + * @param[in] tier The `Tier` value to add. * - * @param set Set to add \p tier to. - * @param tier Tier to be added. - * @return \c true if \p tier was added into \p set as a new key, or - * @return \c false if \p set already contains \p tier or an error occurred. + * @retval true The `tier` was successfully added. + * @retval false The `tier` already exists, or memory allocation failed. */ static inline bool TierHashSetAdd(TierHashSet *set, Tier tier) { return Int64HashSetAdd(set, tier); diff --git a/src/core/types/tier_stack.h b/src/core/types/tier_stack.h index 05b2d6a2..6919ce96 100644 --- a/src/core/types/tier_stack.h +++ b/src/core/types/tier_stack.h @@ -30,49 +30,72 @@ #include "core/data_structures/int64_array.h" #include "core/types/base.h" -/** @brief Dynamic Tier stack using Int64Array. */ +/** + * @brief Dynamic `Tier` stack using `Int64Array`. + */ typedef Int64Array TierStack; -/** @brief Initializes Tier stack STACK. */ +/** + * @brief Initializes `stack`. + * + * @param[out] stack Stack to initialize. + */ static inline void TierStackInit(TierStack *stack) { Int64ArrayInit(stack); } -/** @brief Destroys Tier stack STACK. */ +/** + * @brief Deallocates `stack`. + * + * @param[in,out] stack Stack to deallocate. + */ static inline void TierStackDestroy(TierStack *stack) { Int64ArrayDestroy(stack); } /** - * @brief Pushes a new TIER into the STACK. + * @brief Pushes a new `tier` into the `stack`. * - * @param stack Destination stack. - * @param tier New tier. - * @return true on success, - * @return false otherwise. + * @param[in,out] stack Destination stack. + * @param[in] tier New tier. + * + * @retval true on success. + * @retval false otherwise. */ static inline bool TierStackPush(TierStack *stack, Tier tier) { return Int64ArrayPushBack(stack, tier); } /** - * @brief Pops a tier from the STACK. Calling this function on an empty STACK - * results in undefined behavior. + * @brief Pops a tier from the `stack`. + * + * @details Calling this function on an empty `stack` results in undefined + * behavior. * - * @param stack Stack to pop the tier from. + * @param[in,out] stack Stack to pop the tier from. */ static inline void TierStackPop(TierStack *stack) { Int64ArrayPopBack(stack); } /** - * @brief Returns the item at the top of the STACK. Calling this function on an - * empty STACK results in undefined behavior. + * @brief Returns the item at the top of the `stack`. + * + * @details Calling this function on an empty `stack` results in undefined + * behavior. + * + * @param[in] stack Stack to peek into. * - * @param stack Stack to peak into. - * @return Tier at the top of STACK. + * @return Tier at the top of `stack`. */ static inline Tier TierStackTop(const TierStack *stack) { return Int64ArrayBack(stack); } -/** @brief Returns true if the given STACK is empty, or false otherwise. */ +/** + * @brief Returns whether the given `stack` is empty. + * + * @param[in] stack Stack to check. + * + * @retval true if the stack is empty. + * @retval false otherwise. + */ static inline bool TierStackEmpty(const TierStack *stack) { return Int64ArrayEmpty(stack); } From f0611ee54ac74cc8d4f66868759283a223b6dd0a Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 22:18:28 -0700 Subject: [PATCH 11/12] Remove unused TierPositionArrayContains method and update Doxygen for TierPositionArray --- src/core/types/tier_position_array.c | 14 -------- src/core/types/tier_position_array.h | 49 ++++++++++++++++------------ 2 files changed, 29 insertions(+), 34 deletions(-) diff --git a/src/core/types/tier_position_array.c b/src/core/types/tier_position_array.c index 10c26957..074c0436 100644 --- a/src/core/types/tier_position_array.c +++ b/src/core/types/tier_position_array.c @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Dynamic TierPosition array implementation. - * @version 1.0.1 - * @date 2024-12-10 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -70,15 +68,3 @@ bool TierPositionArrayAppend(TierPositionArray *array, TierPosition TierPositionArrayBack(const TierPositionArray *array) { return array->array[array->size - 1]; } - -bool TierPositionArrayContains(const TierPositionArray *array, - TierPosition target) { - for (int64_t i = 0; i < array->size; ++i) { - if (array->array[i].position == target.position && - array->array[i].tier == target.tier) { - return true; - } - } - - return false; -} diff --git a/src/core/types/tier_position_array.h b/src/core/types/tier_position_array.h index fc1ab3a6..834b113b 100644 --- a/src/core/types/tier_position_array.h +++ b/src/core/types/tier_position_array.h @@ -4,8 +4,6 @@ * @author GamesCrafters Research Group, UC Berkeley * Supervised by Dan Garcia * @brief Dynamic TierPosition array. - * @version 1.0.1 - * @date 2024-12-10 * * @copyright This file is part of GAMESMAN, The Finite, Two-person * Perfect-Information Game Generator released under the GPL: @@ -32,40 +30,51 @@ #include "core/types/base.h" -/** @brief Dynamic TierPosition Array. */ +/** + * @brief Dynamic `TierPosition` array. + */ typedef struct TierPositionArray { - TierPosition *array; /**< Array contents. */ - int64_t size; /**< Size of the array in number of items. */ - int64_t capacity; /**< Capacity of the array in number of items. */ + TierPosition *array; /**< The actual array. */ + int64_t size; /**< Number of items in the array. */ + int64_t capacity; /**< Current capacity of the array. */ } TierPositionArray; -/** @brief Initializes the TierPosition ARRAY to an empty array. */ +/** + * @brief Initializes `array`. + * + * @param[out] array Array to initialize. + */ void TierPositionArrayInit(TierPositionArray *array); -/** @brief Destroyes the TierPosition ARRAY. */ +/** + * @brief Deallocates `array`. + * + * @param[in,out] array Array to deallocate. + */ void TierPositionArrayDestroy(TierPositionArray *array); /** - * @brief Appends TIER_POSITION to the end of ARRAY. + * @brief Appends a new `tier_position` to the back of the `array`. + * + * @param[in,out] array Destination array. + * @param[in] tier_position New item. * - * @param array Destination array. - * @param position Tier position to append. - * @return true on success, - * @return false otherwise. + * @retval true on success. + * @retval false otherwise. */ bool TierPositionArrayAppend(TierPositionArray *array, TierPosition tier_position); /** - * @brief Returns the last TierPosition in ARRAY. + * @brief Returns the item at the back of `array`. * - * @param array Source tier position array. - * @return Last item in ARRAY. + * @details Calling this function on an empty `array` results in undefined + * behavior. + * + * @param[in] array Array to get the item from. + * + * @return Item at the back of `array`. */ TierPosition TierPositionArrayBack(const TierPositionArray *array); -/** @brief Returns whether the given TierPosition ARRAY contains the TARGET. */ -bool TierPositionArrayContains(const TierPositionArray *array, - TierPosition target); - #endif // GAMESMANONE_CORE_TYPES_TIER_POSITION_ARRAY_H_ From 8162f0c41808adf19f1f7fca17d9c00718a39900 Mon Sep 17 00:00:00 2001 From: Robert Shi Date: Fri, 28 Aug 2026 22:32:08 -0700 Subject: [PATCH 12/12] Update comments for Int64HashSet to warn the user not to insert `INT64_MIN` as a key --- src/core/data_structures/int64_hash_set.h | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/core/data_structures/int64_hash_set.h b/src/core/data_structures/int64_hash_set.h index d81cb957..f5a2eea8 100644 --- a/src/core/data_structures/int64_hash_set.h +++ b/src/core/data_structures/int64_hash_set.h @@ -43,7 +43,14 @@ #define INT64_HASH_SET_EMPTY_KEY INT64_MIN /** - * @brief A hash set optimized for storing 64-bit integer keys. + * @brief Highly optimized linear probing hash set for storing 64-bit integer + * keys. + * + * @note `INT64_MIN` (`INT64_HASH_SET_EMPTY_KEY`) is reserved as a sentinel + * value for the hash table to represent an empty slot for optimization + * purposes. Because of this, `Int64HashSet` cannot be used to store + * `INT64_MIN`. The user must make sure that `INT64_MIN` is never inserted as a + * key. */ typedef struct Int64HashSet { int64_t *keys; /**< Array of keys in the hash set. */