allow to reserve space in OAHashMap explicitly and also in AStar.
* also handle overflow occurring in _get_probe_length
This commit is contained in:
parent
6d6d437146
commit
1031833fb0
6 changed files with 132 additions and 9 deletions
|
@ -243,6 +243,20 @@ void AStar::clear() {
|
|||
points.clear();
|
||||
}
|
||||
|
||||
int AStar::get_point_count() const {
|
||||
return points.get_num_elements();
|
||||
}
|
||||
|
||||
int AStar::get_point_capacity() const {
|
||||
return points.get_capacity();
|
||||
}
|
||||
|
||||
void AStar::reserve_space(int p_num_nodes) {
|
||||
ERR_FAIL_COND_MSG(p_num_nodes <= 0, "New capacity must be greater than 0, was: " + itos(p_num_nodes) + ".");
|
||||
ERR_FAIL_COND_MSG((uint32_t)p_num_nodes < points.get_capacity(), "New capacity must be greater than current capacity: " + itos(points.get_capacity()) + ", new was: " + itos(p_num_nodes) + ".");
|
||||
points.reserve(p_num_nodes);
|
||||
}
|
||||
|
||||
int AStar::get_closest_point(const Vector3 &p_point) const {
|
||||
|
||||
int closest_id = -1;
|
||||
|
@ -521,6 +535,9 @@ void AStar::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar::disconnect_points);
|
||||
ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar::are_points_connected);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_point_count"), &AStar::get_point_count);
|
||||
ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar::get_point_capacity);
|
||||
ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar::reserve_space);
|
||||
ClassDB::bind_method(D_METHOD("clear"), &AStar::clear);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position"), &AStar::get_closest_point);
|
||||
|
@ -605,10 +622,22 @@ bool AStar2D::are_points_connected(int p_id, int p_with_id) const {
|
|||
return astar.are_points_connected(p_id, p_with_id);
|
||||
}
|
||||
|
||||
int AStar2D::get_point_count() const {
|
||||
return astar.get_point_count();
|
||||
}
|
||||
|
||||
int AStar2D::get_point_capacity() const {
|
||||
return astar.get_point_capacity();
|
||||
}
|
||||
|
||||
void AStar2D::clear() {
|
||||
astar.clear();
|
||||
}
|
||||
|
||||
void AStar2D::reserve_space(int p_num_nodes) {
|
||||
astar.reserve_space(p_num_nodes);
|
||||
}
|
||||
|
||||
int AStar2D::get_closest_point(const Vector2 &p_point) const {
|
||||
return astar.get_closest_point(Vector3(p_point.x, p_point.y, 0));
|
||||
}
|
||||
|
@ -659,6 +688,9 @@ void AStar2D::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("disconnect_points", "id", "to_id"), &AStar2D::disconnect_points);
|
||||
ClassDB::bind_method(D_METHOD("are_points_connected", "id", "to_id"), &AStar2D::are_points_connected);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_point_count"), &AStar2D::get_point_count);
|
||||
ClassDB::bind_method(D_METHOD("get_point_capacity"), &AStar2D::get_point_capacity);
|
||||
ClassDB::bind_method(D_METHOD("reserve_space", "num_nodes"), &AStar2D::reserve_space);
|
||||
ClassDB::bind_method(D_METHOD("clear"), &AStar2D::clear);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_closest_point", "to_position"), &AStar2D::get_closest_point);
|
||||
|
|
|
@ -46,6 +46,10 @@ class AStar : public Reference {
|
|||
|
||||
struct Point {
|
||||
|
||||
Point() :
|
||||
neighbours(4u),
|
||||
unlinked_neighbours(4u) {}
|
||||
|
||||
int id;
|
||||
Vector3 pos;
|
||||
real_t weight_scale;
|
||||
|
@ -132,6 +136,9 @@ public:
|
|||
void disconnect_points(int p_id, int p_with_id);
|
||||
bool are_points_connected(int p_id, int p_with_id) const;
|
||||
|
||||
int get_point_count() const;
|
||||
int get_point_capacity() const;
|
||||
void reserve_space(int p_num_nodes);
|
||||
void clear();
|
||||
|
||||
int get_closest_point(const Vector3 &p_point) const;
|
||||
|
@ -171,6 +178,9 @@ public:
|
|||
void disconnect_points(int p_id, int p_with_id);
|
||||
bool are_points_connected(int p_id, int p_with_id) const;
|
||||
|
||||
int get_point_count() const;
|
||||
int get_point_capacity() const;
|
||||
void reserve_space(int p_num_nodes);
|
||||
void clear();
|
||||
|
||||
int get_closest_point(const Vector2 &p_point) const;
|
||||
|
|
|
@ -78,8 +78,7 @@ private:
|
|||
p_hash = p_hash & ~DELETED_HASH_BIT; // we don't care if it was deleted or not
|
||||
|
||||
uint32_t original_pos = p_hash % capacity;
|
||||
|
||||
return p_pos - original_pos;
|
||||
return (p_pos - original_pos) % capacity;
|
||||
}
|
||||
|
||||
_FORCE_INLINE_ void _construct(uint32_t p_pos, uint32_t p_hash, const TKey &p_key, const TValue &p_value) {
|
||||
|
@ -152,17 +151,16 @@ private:
|
|||
}
|
||||
}
|
||||
|
||||
void _resize_and_rehash() {
|
||||
void _resize_and_rehash(uint32_t p_new_capacity) {
|
||||
|
||||
uint32_t old_capacity = capacity;
|
||||
capacity = p_new_capacity;
|
||||
|
||||
TKey *old_keys = keys;
|
||||
TValue *old_values = values;
|
||||
uint32_t *old_hashes = hashes;
|
||||
|
||||
uint32_t old_capacity = capacity;
|
||||
|
||||
capacity = old_capacity * 2;
|
||||
num_elements = 0;
|
||||
|
||||
keys = memnew_arr(TKey, capacity);
|
||||
values = memnew_arr(TValue, capacity);
|
||||
hashes = memnew_arr(uint32_t, capacity);
|
||||
|
@ -187,6 +185,10 @@ private:
|
|||
memdelete_arr(old_hashes);
|
||||
}
|
||||
|
||||
void _resize_and_rehash() {
|
||||
_resize_and_rehash(capacity * 2);
|
||||
}
|
||||
|
||||
public:
|
||||
_FORCE_INLINE_ uint32_t get_capacity() const { return capacity; }
|
||||
_FORCE_INLINE_ uint32_t get_num_elements() const { return num_elements; }
|
||||
|
@ -199,11 +201,15 @@ public:
|
|||
|
||||
for (uint32_t i = 0; i < capacity; i++) {
|
||||
|
||||
if (hashes[i] == EMPTY_HASH) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (hashes[i] & DELETED_HASH_BIT) {
|
||||
continue;
|
||||
}
|
||||
|
||||
hashes[i] |= DELETED_HASH_BIT;
|
||||
hashes[i] = EMPTY_HASH;
|
||||
values[i].~TValue();
|
||||
keys[i].~TKey();
|
||||
}
|
||||
|
@ -272,6 +278,16 @@ public:
|
|||
num_elements--;
|
||||
}
|
||||
|
||||
/**
|
||||
* reserves space for a number of elements, useful to avoid many resizes and rehashes
|
||||
* if adding a known (possibly large) number of elements at once, must be larger than old
|
||||
* capacity.
|
||||
**/
|
||||
void reserve(uint32_t p_new_capacity) {
|
||||
ERR_FAIL_COND(p_new_capacity < capacity);
|
||||
_resize_and_rehash(p_new_capacity);
|
||||
}
|
||||
|
||||
struct Iterator {
|
||||
bool valid;
|
||||
|
||||
|
@ -336,7 +352,7 @@ public:
|
|||
hashes = memnew_arr(uint32_t, p_initial_capacity);
|
||||
|
||||
for (uint32_t i = 0; i < p_initial_capacity; i++) {
|
||||
hashes[i] = 0;
|
||||
hashes[i] = EMPTY_HASH;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -157,6 +157,13 @@
|
|||
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_capacity" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the capacity of the structure backing the points, useful in conjunction with [code]reserve_space[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_connections">
|
||||
<return type="PoolIntArray">
|
||||
</return>
|
||||
|
@ -178,6 +185,13 @@
|
|||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_count" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the number of points currently in the points pool.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_path">
|
||||
<return type="PoolVector3Array">
|
||||
</return>
|
||||
|
@ -241,6 +255,15 @@
|
|||
Removes the point associated with the given [code]id[/code] from the points pool.
|
||||
</description>
|
||||
</method>
|
||||
<method name="reserve_space">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="num_nodes" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
Reserves space internally for [code]num_nodes[/code] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_point_disabled">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -134,6 +134,13 @@
|
|||
If you change the 2nd point's weight to 3, then the result will be [code][1, 4, 3][/code] instead, because now even though the distance is longer, it's "easier" to get through point 4 than through point 2.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_capacity" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the capacity of the structure backing the points, useful in conjunction with [code]reserve_space[/code].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_connections">
|
||||
<return type="PoolIntArray">
|
||||
</return>
|
||||
|
@ -155,6 +162,13 @@
|
|||
[/codeblock]
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_count" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
Returns the number of points currently in the points pool.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_point_path">
|
||||
<return type="PoolVector2Array">
|
||||
</return>
|
||||
|
@ -218,6 +232,15 @@
|
|||
Removes the point associated with the given [code]id[/code] from the points pool.
|
||||
</description>
|
||||
</method>
|
||||
<method name="reserve_space">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="num_nodes" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
Reserves space internally for [code]num_nodes[/code] points, useful if you're adding a known large number of points at once, for a grid for instance. New capacity must be greater or equals to old capacity.
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_point_disabled">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -121,6 +121,25 @@ MainLoop *test() {
|
|||
delete[] keys;
|
||||
}
|
||||
|
||||
// regression test / test for issue related to #31402
|
||||
{
|
||||
|
||||
OS::get_singleton()->print("test for issue #31402 started...\n");
|
||||
|
||||
const int num_test_values = 12;
|
||||
int test_values[num_test_values] = { 0, 24, 48, 72, 96, 120, 144, 168, 192, 216, 240, 264 };
|
||||
|
||||
int dummy = 0;
|
||||
OAHashMap<int, int> map;
|
||||
map.clear();
|
||||
|
||||
for (int i = 0; i < num_test_values; ++i) {
|
||||
map.set(test_values[i], dummy);
|
||||
}
|
||||
|
||||
OS::get_singleton()->print("test for issue #31402 passed.\n");
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
} // namespace TestOAHashMap
|
||||
|
|
Loading…
Reference in a new issue