Sun, 23 Nov 2025 13:15:19 +0100
optimize sorted insertion by using the infimum instead of the supremum
The reason is that the supremum returns the equal element with the smallest index, and we want the largest.
Therefore, we use the infimum, which already gives us the largest index when there are equal elements, and increase the index by one. The infimum is also guaranteed to exist in that case.
/* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * * Copyright 2021 Mike Becker, Olaf Wintermann All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ /** * @file iterator.h * @brief Interface for iterator implementations. * @author Mike Becker * @author Olaf Wintermann * @copyright 2-Clause BSD License */ #ifndef UCX_ITERATOR_H #define UCX_ITERATOR_H #include "common.h" #ifdef __cplusplus extern "C" { #endif /** * Common data for all iterators. */ struct cx_iterator_base_s { /** * True if the iterator points to valid data. */ bool (*valid)(const void *); /** * Original implementation in case the function needs to be wrapped. */ bool (*valid_impl)(const void *); /** * Returns a pointer to the current element. * * When valid returns false, the behavior of this function is undefined. */ void *(*current)(const void *); /** * Original implementation in case the function needs to be wrapped. */ void *(*current_impl)(const void *); /** * Advances the iterator. * * When valid returns false, the behavior of this function is undefined. */ void (*next)(void *); /** * Original implementation in case the function needs to be wrapped. */ void (*next_impl)(void *); /** * Indicates whether this iterator may remove elements. */ bool allow_remove; /** * Internal flag for removing the current element when advancing. */ bool remove; }; /** * Convenience type definition for the base structure of an iterator. * @see #CX_ITERATOR_BASE */ typedef struct cx_iterator_base_s CxIteratorBase; /** * Declares base attributes for an iterator. * Must be the first member of an iterator structure. */ #define CX_ITERATOR_BASE struct cx_iterator_base_s base /** * Internal iterator struct - use CxIterator. */ struct cx_iterator_s { /** * Inherited common data for all iterators. */ CX_ITERATOR_BASE; /** * Handle for the current element. */ void *elem_handle; /** * Handle for the source collection, if any. */ void *src_handle; /** * If the iterator is position-aware, contains the index of the element in the underlying collection. * Otherwise, this field is usually uninitialized. */ size_t index; /** * The size of an individual element. */ size_t elem_size; /** * May contain the total number of elements, if known. * Shall be set to @c SIZE_MAX when the total number is unknown during iteration. */ size_t elem_count; }; /** * Iterator type. * * An iterator points to a certain element in a (possibly unbounded) chain of elements. * Iterators that are based on collections (which have a defined "first" element) are supposed * to be "position-aware", which means that they keep track of the current index within the collection. * * @note Objects that are pointed to by an iterator are always mutable through that iterator. However, * any concurrent mutation of the collection other than by this iterator makes this iterator obsolete, * and it must not be used anymore. */ typedef struct cx_iterator_s CxIterator; /** * Checks if the iterator points to valid data. * * @param iter the iterator * @retval true if the iterator points to valid data * @retval false if the iterator already moved past the end */ #define cxIteratorValid(iter) (iter).base.valid(&(iter)) /** * Returns a pointer to the current element. * * The behavior is undefined if this iterator is invalid. * * @param iter the iterator * @return a pointer to the current element * @see cxIteratorValid() */ #define cxIteratorCurrent(iter) (iter).base.current(&iter) /** * Advances the iterator to the next element. * * @param iter the iterator */ #define cxIteratorNext(iter) (iter).base.next(&iter) /** * Flags the current element for removal if the iterator allows it. * * @param iter the iterator * @return @c true if removal is allowed, @c false otherwise */ #define cxIteratorFlagRemoval(iter) ((iter).base.remove = (iter).base.allow_remove) /** * Obtains a reference to an arbitrary iterator. * * This is useful for APIs that expect some iterator as an argument. * * @param iter the iterator * @return (@c struct @c cx_iterator_base_s*) a pointer to the iterator */ #define cxIteratorRef(iter) &((iter).base) /** * Loops over an iterator. * * @param type the type of the elements * @param elem the name of the iteration variable * @param iter the iterator */ #define cx_foreach(type, elem, iter) \ for (type elem; cxIteratorValid(iter) && (elem = (type)cxIteratorCurrent(iter)) != NULL ; cxIteratorNext(iter)) /** * Creates an iterator for the specified plain array. * * The @p array can be @c NULL, in which case the iterator will be immediately * initialized such that #cxIteratorValid() returns @c false. * * This iterator yields the addresses of the array elements. * If you want to iterator over an array of pointers, you can * use cxIteratorPtr() to create an iterator which directly * yields the stored pointers. * * While the iterator is in use, the array may only be altered by removing * elements through #cxIteratorFlagRemoval(). Every other change to the array * will bring this iterator to an undefined state. * * When @p remove_keeps_order is set to @c false, removing an element will only * move the last element to the position of the removed element, instead of * moving all subsequent elements by one. Usually, when the order of elements is * not important, this parameter should be set to @c false. * * @param array a pointer to the array (can be @c NULL) * @param elem_size the size of one array element * @param elem_count the number of elements in the array * @param remove_keeps_order @c true if the order of elements must be preserved * when removing an element * @return an iterator for the specified array * @see cxIteratorPtr() */ cx_attr_nodiscard CX_EXPORT CxIterator cxIterator(const void *array, size_t elem_size, size_t elem_count, bool remove_keeps_order); /** * Creates an iterator for the specified plain pointer array. * * This iterator assumes that every element in the array is a pointer * and yields exactly those pointers during iteration (on the other * hand, an iterator created with cxIterator() would return the * addresses of those pointers within the array). * * While the iterator is in use, the array may only be altered by removing * elements through #cxIteratorFlagRemoval(). Every other change to the array * will bring this iterator to an undefined state. * * When @p remove_keeps_order is set to @c false, removing an element will only * move the last element to the position of the removed element, instead of * moving all subsequent elements by one. Usually, when the order of elements is * not important, this parameter should be set to @c false. * * @param array a pointer to the array (can be @c NULL) * @param elem_count the number of elements in the array * @param remove_keeps_order @c true if the order of elements must be preserved * when removing an element * @return an iterator for the specified array * @see cxIterator() */ cx_attr_nodiscard CX_EXPORT CxIterator cxIteratorPtr(const void *array, size_t elem_count, bool remove_keeps_order); #ifdef __cplusplus } // extern "C" #endif #endif // UCX_ITERATOR_H