#ifndef HEADER_VOXEL_UTILITY_H #define HEADER_VOXEL_UTILITY_H #include #include #include #include #ifdef DEBUG_ENABLED #include #endif // Takes elements starting from a given position and moves them at the beginning, // then shrink the array to fit them. Other elements are discarded. template void shift_up(Vector &v, unsigned int pos) { unsigned int j = 0; for (unsigned int i = pos; i < (unsigned int)v.size(); ++i, ++j) { v.write[j] = v[i]; } int remaining = v.size() - pos; v.resize(remaining); } template void shift_up(std::vector &v, unsigned int pos) { unsigned int j = 0; for (unsigned int i = pos; i < v.size(); ++i, ++j) { v[j] = v[i]; } int remaining = v.size() - pos; v.resize(remaining); } // Pops the last element of the vector and place it at the given position. // (The element that was at this position is the one removed). template void unordered_remove(Vector &v, unsigned int pos) { int last = v.size() - 1; v.write[pos] = v[last]; v.resize(last); } template void unordered_remove(std::vector &v, unsigned int pos) { v[pos] = v.back(); v.pop_back(); } // Removes all items satisfying the given predicate. // This can change the size of the container, and original order of items is not preserved. template inline void unordered_remove_if(std::vector &vec, F predicate) { for (unsigned int i = 0; i < vec.size(); ++i) { if (predicate(vec[i])) { vec[i] = vec.back(); vec.pop_back(); // Note: can underflow, but it should be fine since it's incremented right after. // TODO Use a while()? --i; } } } template inline bool unordered_remove_value(std::vector &vec, T v) { for (size_t i = 0; i < vec.size(); ++i) { if (vec[i] == v) { vec[i] = vec.back(); vec.pop_back(); return true; } } return false; } template inline void append_array(std::vector &dst, const std::vector &src) { dst.insert(dst.end(), src.begin(), src.end()); } // Removes all items satisfying the given predicate. // This can reduce the size of the container. Items are moved to preserve order. //template //inline void remove_if(std::vector &vec, F predicate) { // unsigned int j = 0; // for (unsigned int i = 0; i < vec.size(); ++i) { // if (predicate(vec[i])) { // continue; // } else { // if (i != j) { // vec[j] = vec[i]; // } // ++j; // } // } // vec.resize(j); //} inline String ptr2s(const void *p) { return String::num_uint64((uint64_t)p, 16); } template void raw_copy_to(Vector &to, const std::vector &from) { to.resize(from.size()); // resize can fail in case allocation was not possible ERR_FAIL_COND(from.size() != static_cast(to.size())); memcpy(to.ptrw(), from.data(), from.size() * sizeof(T)); } template inline void sort(T &a, T &b) { if (a > b) { std::swap(a, b); } } template inline void sort(T &a, T &b, T &c, T &d) { sort(a, b); sort(c, d); sort(a, c); sort(b, d); sort(b, c); } // Tests if POD items in an array are all the same. // Better tailored for more than hundred items that have power-of-two size. template inline bool is_uniform(const Item_T *p_data, size_t item_count) { const Item_T v0 = p_data[0]; //typedef size_t Bucket_T; struct Bucket_T { size_t a; size_t b; inline bool operator!=(const Bucket_T &other) const { return a != other.a || b != other.b; } }; if (sizeof(Bucket_T) > sizeof(Item_T) && sizeof(Bucket_T) % sizeof(Item_T) == 0) { static const size_t ITEMS_PER_BUCKET = sizeof(Bucket_T) / sizeof(Item_T); // Make a reference bucket union { Bucket_T packed_items; Item_T items[ITEMS_PER_BUCKET]; } reference_bucket; for (size_t i = 0; i < ITEMS_PER_BUCKET; ++i) { reference_bucket.items[i] = v0; } // Compare using buckets of items rather than individual items const size_t bucket_count = item_count / ITEMS_PER_BUCKET; const Bucket_T *buckets = (const Bucket_T *)p_data; for (size_t i = 0; i < bucket_count; ++i) { if (buckets[i] != reference_bucket.packed_items) { return false; } } // Compare last elements individually if they don't fit in a bucket const size_t remaining_items_start = item_count - (item_count % ITEMS_PER_BUCKET); for (size_t i = remaining_items_start; i < item_count; ++i) { if (p_data[i] != v0) { return false; } } } else { for (size_t i = 1; i < item_count; ++i) { if (p_data[i] != v0) { return false; } } } return true; } #endif // HEADER_VOXEL_UTILITY_H