Move bisect to Span and deduplicate code.

Co-authored-by: Lukas Tenbrink <lukas.tenbrink@gmail.com>
This commit is contained in:
Yufeng Ying
2025-05-13 22:49:20 +08:00
parent 09fcbb8645
commit 3bf400ffae
9 changed files with 113 additions and 108 deletions

View File

@@ -1,64 +0,0 @@
/**************************************************************************/
/* search_array.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/**************************************************************************/
/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
/* */
/* 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. */
/**************************************************************************/
#pragma once
#include "core/typedefs.h"
template <typename T, typename Comparator = Comparator<T>>
class SearchArray {
public:
Comparator compare;
inline int64_t bisect(const T *p_array, int64_t p_len, const T &p_value, bool p_before) const {
int64_t lo = 0;
int64_t hi = p_len;
if (p_before) {
while (lo < hi) {
const int64_t mid = (lo + hi) / 2;
if (compare(p_array[mid], p_value)) {
lo = mid + 1;
} else {
hi = mid;
}
}
} else {
while (lo < hi) {
const int64_t mid = (lo + hi) / 2;
if (compare(p_value, p_array[mid])) {
hi = mid;
} else {
lo = mid + 1;
}
}
}
return lo;
}
};

View File

@@ -86,6 +86,10 @@ public:
constexpr int64_t rfind(const T &p_val, uint64_t p_from) const;
_FORCE_INLINE_ constexpr int64_t rfind(const T &p_val) const { return rfind(p_val, size() - 1); }
constexpr uint64_t count(const T &p_val) const;
/// Find the index of the given value using binary search.
/// Note: Assumes that elements in the span are sorted. Otherwise, use find() instead.
template <typename Comparator = Comparator<T>>
constexpr uint64_t bisect(const T &p_value, bool p_before, Comparator compare = Comparator()) const;
};
template <typename T>
@@ -119,6 +123,33 @@ constexpr uint64_t Span<T>::count(const T &p_val) const {
return amount;
}
template <typename T>
template <typename Comparator>
constexpr uint64_t Span<T>::bisect(const T &p_value, bool p_before, Comparator compare) const {
uint64_t lo = 0;
uint64_t hi = size();
if (p_before) {
while (lo < hi) {
const uint64_t mid = (lo + hi) / 2;
if (compare(ptr()[mid], p_value)) {
lo = mid + 1;
} else {
hi = mid;
}
}
} else {
while (lo < hi) {
const uint64_t mid = (lo + hi) / 2;
if (compare(p_value, ptr()[mid])) {
hi = mid;
} else {
lo = mid + 1;
}
}
}
return lo;
}
// Zero-constructing Span initializes _ptr and _len to 0 (and thus empty).
template <typename T>
struct is_zero_constructible<Span<T>> : std::true_type {};

View File

@@ -40,7 +40,6 @@
#include "core/error/error_macros.h"
#include "core/templates/cowdata.h"
#include "core/templates/search_array.h"
#include "core/templates/sort_array.h"
#include <initializer_list>
@@ -152,8 +151,7 @@ public:
template <typename Comparator, typename Value, typename... Args>
Size bsearch_custom(const Value &p_value, bool p_before, Args &&...args) {
SearchArray<T, Comparator> search{ args... };
return search.bisect(ptrw(), size(), p_value, p_before);
return span().bisect(p_value, p_before, Comparator{ args... });
}
Vector<T> duplicate() {

View File

@@ -37,41 +37,19 @@ template <typename T>
class VSet {
Vector<T> _data;
protected:
_FORCE_INLINE_ int _find(const T &p_val, bool &r_exact) const {
r_exact = false;
if (_data.is_empty()) {
return 0;
}
int low = 0;
int high = _data.size() - 1;
const T *a = &_data[0];
int middle = 0;
int64_t pos = _data.span().bisect(p_val, true);
#ifdef DEBUG_ENABLED
if (low > high) {
ERR_PRINT("low > high, this may be a bug");
if (pos < _data.size() && !(p_val < _data[pos]) && !(_data[pos] < p_val)) {
r_exact = true;
}
#endif
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; //search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; //search high end of array
} else {
r_exact = true;
return middle;
}
}
//return the position where this would be inserted
if (a[middle] < p_val) {
middle++;
}
return middle;
return pos;
}
_FORCE_INLINE_ int _find_exact(const T &p_val) const {
@@ -79,23 +57,11 @@ class VSet {
return -1;
}
int low = 0;
int high = _data.size() - 1;
int middle;
const T *a = &_data[0];
int64_t pos = _data.span().bisect(p_val, true);
while (low <= high) {
middle = (low + high) / 2;
if (p_val < a[middle]) {
high = middle - 1; //search low end of array
} else if (a[middle] < p_val) {
low = middle + 1; //search high end of array
} else {
return middle;
}
if (pos < _data.size() && !(p_val < _data[pos]) && !(_data[pos] < p_val)) {
return pos;
}
return -1;
}