/* MIT License * * Copyright (c) 2025 Tyge Løvset * * 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. */ // IWYU pragma: private #ifdef _i_is_list #define i_at(self, idx) (&((_m_value *)(self)->last)[idx]) #define i_at_mut i_at #elif !defined i_at #define i_at(self, idx) _c_MEMB(_at)(self, idx) #define i_at_mut(self, idx) _c_MEMB(_at_mut)(self, idx) #endif STC_API void _c_MEMB(_sort_lowhigh)(Self* self, isize lo, isize hi); #ifdef _i_is_array STC_API isize _c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end); STC_API isize _c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end); static inline void _c_MEMB(_sort)(Self* arr, isize n) { _c_MEMB(_sort_lowhigh)(arr, 0, n - 1); } static inline isize // c_NPOS = not found _c_MEMB(_lower_bound)(const Self* arr, const _m_raw raw, isize n) { return _c_MEMB(_lower_bound_range)(arr, raw, 0, n); } static inline isize // c_NPOS = not found _c_MEMB(_binary_search)(const Self* arr, const _m_raw raw, isize n) { return _c_MEMB(_binary_search_range)(arr, raw, 0, n); } #elif !defined _i_is_list STC_API isize _c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end); STC_API isize _c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end); static inline void _c_MEMB(_sort)(Self* self) { _c_MEMB(_sort_lowhigh)(self, 0, _c_MEMB(_size)(self) - 1); } static inline isize // c_NPOS = not found _c_MEMB(_lower_bound)(const Self* self, const _m_raw raw) { return _c_MEMB(_lower_bound_range)(self, raw, 0, _c_MEMB(_size)(self)); } static inline isize // c_NPOS = not found _c_MEMB(_binary_search)(const Self* self, const _m_raw raw) { return _c_MEMB(_binary_search_range)(self, raw, 0, _c_MEMB(_size)(self)); } #endif /* -------------------------- IMPLEMENTATION ------------------------- */ #if defined i_implement static void _c_MEMB(_insertsort_lowhigh)(Self* self, isize lo, isize hi) { for (isize j = lo, i = lo + 1; i <= hi; j = i, ++i) { _m_value x = *i_at(self, i); _m_raw rx = i_keytoraw((&x)); while (j >= 0) { _m_raw ry = i_keytoraw(i_at(self, j)); if (!(i_less((&rx), (&ry)))) break; *i_at_mut(self, j + 1) = *i_at(self, j); --j; } *i_at_mut(self, j + 1) = x; } } STC_DEF void _c_MEMB(_sort_lowhigh)(Self* self, isize lo, isize hi) { isize i = lo, j; while (lo < hi) { _m_raw pivot = i_keytoraw(i_at(self, (isize)(lo + (hi - lo)*7LL/16))), rx; j = hi; do { do { rx = i_keytoraw(i_at(self, i)); } while ((i_less((&rx), (&pivot))) && ++i); do { rx = i_keytoraw(i_at(self, j)); } while ((i_less((&pivot), (&rx))) && --j); if (i > j) break; c_swap(i_at_mut(self, i), i_at_mut(self, j)); ++i; --j; } while (i <= j); if (j - lo > hi - i) { c_swap(&lo, &i); c_swap(&hi, &j); } if (j - lo > 64) _c_MEMB(_sort_lowhigh)(self, lo, j); else if (j > lo) _c_MEMB(_insertsort_lowhigh)(self, lo, j); lo = i; } } #ifndef _i_is_list STC_DEF isize // c_NPOS = not found _c_MEMB(_lower_bound_range)(const Self* self, const _m_raw raw, isize start, isize end) { isize count = end - start, step = count/2; while (count > 0) { const _m_raw rx = i_keytoraw(i_at(self, start + step)); if (i_less((&rx), (&raw))) { start += step + 1; count -= step + 1; step = count*7/8; } else { count = step; step = count/8; } } return start >= end ? c_NPOS : start; } STC_DEF isize // c_NPOS = not found _c_MEMB(_binary_search_range)(const Self* self, const _m_raw raw, isize start, isize end) { isize res = _c_MEMB(_lower_bound_range)(self, raw, start, end); if (res != c_NPOS) { const _m_raw rx = i_keytoraw(i_at(self, res)); if (i_less((&raw), (&rx))) res = c_NPOS; } return res; } #endif // !_i_is_list #endif // IMPLEMENTATION #undef i_at #undef i_at_mut