From 1d8ce1aa7c300eeb9c2b59577b81cf64834baf30 Mon Sep 17 00:00:00 2001 From: Patrick Brosi Date: Fri, 6 Oct 2023 12:39:49 +0200 Subject: [PATCH] use util submodule --- .gitmodules | 3 + src/util | 1 + src/util/3rdparty/MurmurHash3.cpp | 436 ---- src/util/3rdparty/MurmurHash3.h | 37 - src/util/3rdparty/RTree.h | 1700 -------------- src/util/3rdparty/dtoa_milo.h | 454 ---- src/util/CMakeLists.txt | 29 - src/util/Misc.h | 706 ------ src/util/Nullable.h | 116 - src/util/PriorityQueue.h | 39 - src/util/PriorityQueue.tpp | 36 - src/util/String.h | 458 ---- src/util/geo/BezierCurve.h | 55 - src/util/geo/BezierCurve.tpp | 70 - src/util/geo/Box.h | 94 - src/util/geo/CircularSegment.h | 41 - src/util/geo/CircularSegment.tpp | 51 - src/util/geo/Geo.h | 2339 -------------------- src/util/geo/GeoGraph.h | 32 - src/util/geo/Grid.h | 138 -- src/util/geo/Grid.tpp | 246 -- src/util/geo/Line.h | 28 - src/util/geo/Point.h | 58 - src/util/geo/PolyLine.h | 156 -- src/util/geo/PolyLine.tpp | 690 ------ src/util/geo/Polygon.h | 46 - src/util/geo/QuadTree.h | 94 - src/util/geo/QuadTree.tpp | 117 - src/util/geo/RTree.h | 82 - src/util/geo/RTree.tpp | 134 -- src/util/geo/output/GeoGraphJsonOutput.h | 69 - src/util/geo/output/GeoGraphJsonOutput.tpp | 123 - src/util/geo/output/GeoJsonOutput.cpp | 39 - src/util/geo/output/GeoJsonOutput.h | 73 - src/util/geo/output/GeoJsonOutput.tpp | 174 -- src/util/graph/Algorithm.h | 46 - src/util/graph/Algorithm.tpp | 40 - src/util/graph/BiDijkstra.cpp | 7 - src/util/graph/BiDijkstra.h | 129 -- src/util/graph/BiDijkstra.tpp | 293 --- src/util/graph/Dijkstra.cpp | 7 - src/util/graph/Dijkstra.h | 116 - src/util/graph/Dijkstra.tpp | 195 -- src/util/graph/DirGraph.h | 40 - src/util/graph/DirGraph.tpp | 67 - src/util/graph/DirNode.h | 58 - src/util/graph/DirNode.tpp | 157 -- src/util/graph/EDijkstra.cpp | 7 - src/util/graph/EDijkstra.h | 240 -- src/util/graph/EDijkstra.tpp | 564 ----- src/util/graph/Edge.h | 40 - src/util/graph/Edge.tpp | 46 - src/util/graph/Graph.h | 55 - src/util/graph/Graph.tpp | 80 - src/util/graph/Node.h | 49 - src/util/graph/ShortestPath.h | 548 ----- src/util/graph/ShortestPath.tpp | 1 - src/util/graph/UndirGraph.h | 42 - src/util/graph/UndirGraph.tpp | 74 - src/util/graph/UndirNode.h | 54 - src/util/graph/UndirNode.tpp | 130 -- src/util/graph/radix_heap.h | 226 -- src/util/graph/robin/robin_growth_policy.h | 348 --- src/util/graph/robin/robin_hash.h | 1451 ------------ src/util/graph/robin/robin_map.h | 715 ------ src/util/graph/robin/robin_set.h | 582 ----- src/util/http/Server.cpp | 360 --- src/util/http/Server.h | 141 -- src/util/json/Writer.cpp | 189 -- src/util/json/Writer.h | 112 - src/util/log/Log.h | 58 - src/util/tests/CMakeLists.txt | 6 - src/util/tests/QuadTreeTest.cpp | 38 - src/util/tests/QuadTreeTest.h | 12 - src/util/tests/TestMain.cpp | 1949 ---------------- src/util/xml/XmlWriter.cpp | 291 --- src/util/xml/XmlWriter.h | 135 -- 77 files changed, 4 insertions(+), 18658 deletions(-) create mode 160000 src/util delete mode 100644 src/util/3rdparty/MurmurHash3.cpp delete mode 100644 src/util/3rdparty/MurmurHash3.h delete mode 100644 src/util/3rdparty/RTree.h delete mode 100644 src/util/3rdparty/dtoa_milo.h delete mode 100644 src/util/CMakeLists.txt delete mode 100644 src/util/Misc.h delete mode 100644 src/util/Nullable.h delete mode 100644 src/util/PriorityQueue.h delete mode 100644 src/util/PriorityQueue.tpp delete mode 100644 src/util/String.h delete mode 100644 src/util/geo/BezierCurve.h delete mode 100644 src/util/geo/BezierCurve.tpp delete mode 100644 src/util/geo/Box.h delete mode 100644 src/util/geo/CircularSegment.h delete mode 100644 src/util/geo/CircularSegment.tpp delete mode 100644 src/util/geo/Geo.h delete mode 100644 src/util/geo/GeoGraph.h delete mode 100644 src/util/geo/Grid.h delete mode 100644 src/util/geo/Grid.tpp delete mode 100644 src/util/geo/Line.h delete mode 100644 src/util/geo/Point.h delete mode 100644 src/util/geo/PolyLine.h delete mode 100644 src/util/geo/PolyLine.tpp delete mode 100644 src/util/geo/Polygon.h delete mode 100644 src/util/geo/QuadTree.h delete mode 100644 src/util/geo/QuadTree.tpp delete mode 100644 src/util/geo/RTree.h delete mode 100644 src/util/geo/RTree.tpp delete mode 100644 src/util/geo/output/GeoGraphJsonOutput.h delete mode 100644 src/util/geo/output/GeoGraphJsonOutput.tpp delete mode 100644 src/util/geo/output/GeoJsonOutput.cpp delete mode 100644 src/util/geo/output/GeoJsonOutput.h delete mode 100644 src/util/geo/output/GeoJsonOutput.tpp delete mode 100644 src/util/graph/Algorithm.h delete mode 100644 src/util/graph/Algorithm.tpp delete mode 100644 src/util/graph/BiDijkstra.cpp delete mode 100644 src/util/graph/BiDijkstra.h delete mode 100644 src/util/graph/BiDijkstra.tpp delete mode 100644 src/util/graph/Dijkstra.cpp delete mode 100644 src/util/graph/Dijkstra.h delete mode 100644 src/util/graph/Dijkstra.tpp delete mode 100644 src/util/graph/DirGraph.h delete mode 100644 src/util/graph/DirGraph.tpp delete mode 100644 src/util/graph/DirNode.h delete mode 100644 src/util/graph/DirNode.tpp delete mode 100644 src/util/graph/EDijkstra.cpp delete mode 100644 src/util/graph/EDijkstra.h delete mode 100644 src/util/graph/EDijkstra.tpp delete mode 100644 src/util/graph/Edge.h delete mode 100644 src/util/graph/Edge.tpp delete mode 100644 src/util/graph/Graph.h delete mode 100644 src/util/graph/Graph.tpp delete mode 100644 src/util/graph/Node.h delete mode 100644 src/util/graph/ShortestPath.h delete mode 100644 src/util/graph/ShortestPath.tpp delete mode 100644 src/util/graph/UndirGraph.h delete mode 100644 src/util/graph/UndirGraph.tpp delete mode 100644 src/util/graph/UndirNode.h delete mode 100644 src/util/graph/UndirNode.tpp delete mode 100644 src/util/graph/radix_heap.h delete mode 100644 src/util/graph/robin/robin_growth_policy.h delete mode 100644 src/util/graph/robin/robin_hash.h delete mode 100644 src/util/graph/robin/robin_map.h delete mode 100644 src/util/graph/robin/robin_set.h delete mode 100644 src/util/http/Server.cpp delete mode 100644 src/util/http/Server.h delete mode 100644 src/util/json/Writer.cpp delete mode 100644 src/util/json/Writer.h delete mode 100644 src/util/log/Log.h delete mode 100644 src/util/tests/CMakeLists.txt delete mode 100644 src/util/tests/QuadTreeTest.cpp delete mode 100644 src/util/tests/QuadTreeTest.h delete mode 100644 src/util/tests/TestMain.cpp delete mode 100644 src/util/xml/XmlWriter.cpp delete mode 100644 src/util/xml/XmlWriter.h diff --git a/.gitmodules b/.gitmodules index 0b9e413..5790aa1 100644 --- a/.gitmodules +++ b/.gitmodules @@ -7,3 +7,6 @@ [submodule "src/configparser"] path = src/configparser url = https://git.patrickbrosi.de/patrick/configparser +[submodule "src/util"] + path = src/util + url = https://github.com/ad-freiburg/util diff --git a/src/util b/src/util new file mode 160000 index 0000000..dc9d4a6 --- /dev/null +++ b/src/util @@ -0,0 +1 @@ +Subproject commit dc9d4a6c701bd2b88c09683a4f901d743dc8999e diff --git a/src/util/3rdparty/MurmurHash3.cpp b/src/util/3rdparty/MurmurHash3.cpp deleted file mode 100644 index 23ac4fb..0000000 --- a/src/util/3rdparty/MurmurHash3.cpp +++ /dev/null @@ -1,436 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -// Note - The x86 and x64 versions do _not_ produce the same results, as the -// algorithms are optimized for their respective platforms. You can still -// compile and run any of them on any platform, but your performance with the -// non-native version will be less than optimal. - -#include "MurmurHash3.h" - -//----------------------------------------------------------------------------- -// Platform-specific functions and macros - -// Microsoft Visual Studio - -#if defined(_MSC_VER) - -#define FORCE_INLINE __forceinline - -#include - -#define ROTL32(x, y) _rotl(x, y) -#define ROTL64(x, y) _rotl64(x, y) - -#define BIG_CONSTANT(x) (x) - -// Other compilers - -#else // defined(_MSC_VER) - -#define FORCE_INLINE inline __attribute__((always_inline)) - -inline uint32_t rotl32(uint32_t x, int8_t r) { - return (x << r) | (x >> (32 - r)); -} - -inline uint64_t rotl64(uint64_t x, int8_t r) { - return (x << r) | (x >> (64 - r)); -} - -#define ROTL32(x, y) rotl32(x, y) -#define ROTL64(x, y) rotl64(x, y) - -#define BIG_CONSTANT(x) (x##LLU) - -#endif // !defined(_MSC_VER) - -//----------------------------------------------------------------------------- -// Block read - if your platform needs to do endian-swapping or can only -// handle aligned reads, do the conversion here - -FORCE_INLINE uint32_t getblock32(const uint32_t *p, int i) { return p[i]; } - -FORCE_INLINE uint64_t getblock64(const uint64_t *p, int i) { return p[i]; } - -//----------------------------------------------------------------------------- -// Finalization mix - force all bits of a hash block to avalanche - -FORCE_INLINE uint32_t fmix32(uint32_t h) { - h ^= h >> 16; - h *= 0x85ebca6b; - h ^= h >> 13; - h *= 0xc2b2ae35; - h ^= h >> 16; - - return h; -} - -//---------- - -FORCE_INLINE uint64_t fmix64(uint64_t k) { - k ^= k >> 33; - k *= BIG_CONSTANT(0xff51afd7ed558ccd); - k ^= k >> 33; - k *= BIG_CONSTANT(0xc4ceb9fe1a85ec53); - k ^= k >> 33; - - return k; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x86_32(const void *key, int len, uint32_t seed, void *out) { - const uint8_t *data = (const uint8_t *)key; - const int nblocks = len / 4; - - uint32_t h1 = seed; - - const uint32_t c1 = 0xcc9e2d51; - const uint32_t c2 = 0x1b873593; - - //---------- - // body - - const uint32_t *blocks = (const uint32_t *)(data + nblocks * 4); - - for (int i = -nblocks; i; i++) { - uint32_t k1 = getblock32(blocks, i); - - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - - h1 ^= k1; - h1 = ROTL32(h1, 13); - h1 = h1 * 5 + 0xe6546b64; - } - - //---------- - // tail - - const uint8_t *tail = (const uint8_t *)(data + nblocks * 4); - - uint32_t k1 = 0; - - switch (len & 3) { - case 3: - k1 ^= tail[2] << 16; - // fall through - case 2: - k1 ^= tail[1] << 8; - // fall through - case 1: - k1 ^= tail[0]; - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - - h1 = fmix32(h1); - - *(uint32_t *)out = h1; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x86_128(const void *key, const int len, uint32_t seed, - void *out) { - const uint8_t *data = (const uint8_t *)key; - const int nblocks = len / 16; - - uint32_t h1 = seed; - uint32_t h2 = seed; - uint32_t h3 = seed; - uint32_t h4 = seed; - - const uint32_t c1 = 0x239b961b; - const uint32_t c2 = 0xab0e9789; - const uint32_t c3 = 0x38b34ae5; - const uint32_t c4 = 0xa1e38b93; - - //---------- - // body - - const uint32_t *blocks = (const uint32_t *)(data + nblocks * 16); - - for (int i = -nblocks; i; i++) { - uint32_t k1 = getblock32(blocks, i * 4 + 0); - uint32_t k2 = getblock32(blocks, i * 4 + 1); - uint32_t k3 = getblock32(blocks, i * 4 + 2); - uint32_t k4 = getblock32(blocks, i * 4 + 3); - - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - - h1 = ROTL32(h1, 19); - h1 += h2; - h1 = h1 * 5 + 0x561ccd1b; - - k2 *= c2; - k2 = ROTL32(k2, 16); - k2 *= c3; - h2 ^= k2; - - h2 = ROTL32(h2, 17); - h2 += h3; - h2 = h2 * 5 + 0x0bcaa747; - - k3 *= c3; - k3 = ROTL32(k3, 17); - k3 *= c4; - h3 ^= k3; - - h3 = ROTL32(h3, 15); - h3 += h4; - h3 = h3 * 5 + 0x96cd1c35; - - k4 *= c4; - k4 = ROTL32(k4, 18); - k4 *= c1; - h4 ^= k4; - - h4 = ROTL32(h4, 13); - h4 += h1; - h4 = h4 * 5 + 0x32ac3b17; - } - - //---------- - // tail - - const uint8_t *tail = (const uint8_t *)(data + nblocks * 16); - - uint32_t k1 = 0; - uint32_t k2 = 0; - uint32_t k3 = 0; - uint32_t k4 = 0; - - switch (len & 15) { - case 15: - k4 ^= tail[14] << 16; - // fall through - case 14: - k4 ^= tail[13] << 8; - // fall through - case 13: - k4 ^= tail[12] << 0; - k4 *= c4; - k4 = ROTL32(k4, 18); - k4 *= c1; - h4 ^= k4; - // fall through - case 12: - k3 ^= tail[11] << 24; - // fall through - case 11: - k3 ^= tail[10] << 16; - // fall through - case 10: - k3 ^= tail[9] << 8; - // fall through - case 9: - k3 ^= tail[8] << 0; - k3 *= c3; - k3 = ROTL32(k3, 17); - k3 *= c4; - h3 ^= k3; - // fall through - case 8: - k2 ^= tail[7] << 24; - // fall through - case 7: - k2 ^= tail[6] << 16; - // fall through - case 6: - k2 ^= tail[5] << 8; - // fall through - case 5: - k2 ^= tail[4] << 0; - k2 *= c2; - k2 = ROTL32(k2, 16); - k2 *= c3; - h2 ^= k2; - // fall through - case 4: - k1 ^= tail[3] << 24; - // fall through - case 3: - k1 ^= tail[2] << 16; - // fall through - case 2: - k1 ^= tail[1] << 8; - // fall through - case 1: - k1 ^= tail[0] << 0; - k1 *= c1; - k1 = ROTL32(k1, 15); - k1 *= c2; - h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - h2 ^= len; - h3 ^= len; - h4 ^= len; - - h1 += h2; - h1 += h3; - h1 += h4; - h2 += h1; - h3 += h1; - h4 += h1; - - h1 = fmix32(h1); - h2 = fmix32(h2); - h3 = fmix32(h3); - h4 = fmix32(h4); - - h1 += h2; - h1 += h3; - h1 += h4; - h2 += h1; - h3 += h1; - h4 += h1; - - ((uint32_t *)out)[0] = h1; - ((uint32_t *)out)[1] = h2; - ((uint32_t *)out)[2] = h3; - ((uint32_t *)out)[3] = h4; -} - -//----------------------------------------------------------------------------- - -void MurmurHash3_x64_128(const void *key, const int len, const uint32_t seed, - void *out) { - const uint8_t *data = (const uint8_t *)key; - const int nblocks = len / 16; - - uint64_t h1 = seed; - uint64_t h2 = seed; - - const uint64_t c1 = BIG_CONSTANT(0x87c37b91114253d5); - const uint64_t c2 = BIG_CONSTANT(0x4cf5ad432745937f); - - //---------- - // body - - const uint64_t *blocks = (const uint64_t *)(data); - - for (int i = 0; i < nblocks; i++) { - uint64_t k1 = getblock64(blocks, i * 2 + 0); - uint64_t k2 = getblock64(blocks, i * 2 + 1); - - k1 *= c1; - k1 = ROTL64(k1, 31); - k1 *= c2; - h1 ^= k1; - - h1 = ROTL64(h1, 27); - h1 += h2; - h1 = h1 * 5 + 0x52dce729; - - k2 *= c2; - k2 = ROTL64(k2, 33); - k2 *= c1; - h2 ^= k2; - - h2 = ROTL64(h2, 31); - h2 += h1; - h2 = h2 * 5 + 0x38495ab5; - } - - //---------- - // tail - - const uint8_t *tail = (const uint8_t *)(data + nblocks * 16); - - uint64_t k1 = 0; - uint64_t k2 = 0; - - switch (len & 15) { - case 15: - k2 ^= ((uint64_t)tail[14]) << 48; - // fall through - case 14: - k2 ^= ((uint64_t)tail[13]) << 40; - // fall through - case 13: - k2 ^= ((uint64_t)tail[12]) << 32; - // fall through - case 12: - k2 ^= ((uint64_t)tail[11]) << 24; - // fall through - case 11: - k2 ^= ((uint64_t)tail[10]) << 16; - // fall through - case 10: - k2 ^= ((uint64_t)tail[9]) << 8; - // fall through - case 9: - k2 ^= ((uint64_t)tail[8]) << 0; - k2 *= c2; - k2 = ROTL64(k2, 33); - k2 *= c1; - h2 ^= k2; - // fall through - case 8: - k1 ^= ((uint64_t)tail[7]) << 56; - // fall through - case 7: - k1 ^= ((uint64_t)tail[6]) << 48; - // fall through - case 6: - k1 ^= ((uint64_t)tail[5]) << 40; - // fall through - case 5: - k1 ^= ((uint64_t)tail[4]) << 32; - // fall through - case 4: - k1 ^= ((uint64_t)tail[3]) << 24; - // fall through - case 3: - k1 ^= ((uint64_t)tail[2]) << 16; - // fall through - case 2: - k1 ^= ((uint64_t)tail[1]) << 8; - // fall through - case 1: - k1 ^= ((uint64_t)tail[0]) << 0; - k1 *= c1; - k1 = ROTL64(k1, 31); - k1 *= c2; - h1 ^= k1; - }; - - //---------- - // finalization - - h1 ^= len; - h2 ^= len; - - h1 += h2; - h2 += h1; - - h1 = fmix64(h1); - h2 = fmix64(h2); - - h1 += h2; - h2 += h1; - - ((uint64_t *)out)[0] = h1; - ((uint64_t *)out)[1] = h2; -} - -//----------------------------------------------------------------------------- diff --git a/src/util/3rdparty/MurmurHash3.h b/src/util/3rdparty/MurmurHash3.h deleted file mode 100644 index e1c6d34..0000000 --- a/src/util/3rdparty/MurmurHash3.h +++ /dev/null @@ -1,37 +0,0 @@ -//----------------------------------------------------------------------------- -// MurmurHash3 was written by Austin Appleby, and is placed in the public -// domain. The author hereby disclaims copyright to this source code. - -#ifndef _MURMURHASH3_H_ -#define _MURMURHASH3_H_ - -//----------------------------------------------------------------------------- -// Platform-specific functions and macros - -// Microsoft Visual Studio - -#if defined(_MSC_VER) && (_MSC_VER < 1600) - -typedef unsigned char uint8_t; -typedef unsigned int uint32_t; -typedef unsigned __int64 uint64_t; - -// Other compilers - -#else // defined(_MSC_VER) - -#include - -#endif // !defined(_MSC_VER) - -//----------------------------------------------------------------------------- - -void MurmurHash3_x86_32 ( const void * key, int len, uint32_t seed, void * out ); - -void MurmurHash3_x86_128 ( const void * key, int len, uint32_t seed, void * out ); - -void MurmurHash3_x64_128 ( const void * key, int len, uint32_t seed, void * out ); - -//----------------------------------------------------------------------------- - -#endif // _MURMURHASH3_H_ diff --git a/src/util/3rdparty/RTree.h b/src/util/3rdparty/RTree.h deleted file mode 100644 index 28d4691..0000000 --- a/src/util/3rdparty/RTree.h +++ /dev/null @@ -1,1700 +0,0 @@ -#ifndef RTREE_H -#define RTREE_H - -// NOTE This file compiles under MSVC 6 SP5 and MSVC .Net 2003 it may not work on other compilers without modification. - -// NOTE These next few lines may be win32 specific, you may need to modify them to compile on other platform -#include -#include -#include -#include - -#include -#include -#include - -namespace DA { - -#define ASSERT assert // RTree uses ASSERT( condition ) -#ifndef Min - #define Min std::min -#endif //Min -#ifndef Max - #define Max std::max -#endif //Max - -// -// RTree.h -// - -#define RTREE_TEMPLATE template -#define RTREE_QUAL RTree - -#define RTREE_DONT_USE_MEMPOOLS // This version does not contain a fixed memory allocator, fill in lines with EXAMPLE to implement one. -#define RTREE_USE_SPHERICAL_VOLUME // Better split classification, may be slower on some systems - -// Fwd decl -class RTFileStream; // File I/O helper class, look below for implementation and notes. - - -/// \class RTree -/// Implementation of RTree, a multidimensional bounding rectangle tree. -/// Example usage: For a 3-dimensional tree use RTree myTree; -/// -/// This modified, templated C++ version by Greg Douglas at Auran (http://www.auran.com) -/// -/// DATATYPE Referenced data, should be int, void*, obj* etc. no larger than sizeof and simple type -/// ELEMTYPE Type of element such as int or float -/// NUMDIMS Number of dimensions such as 2 or 3 -/// ELEMTYPEREAL Type of element that allows fractional and large values such as float or double, for use in volume calcs -/// -/// NOTES: Inserting and removing data requires the knowledge of its constant Minimal Bounding Rectangle. -/// This version uses new/delete for nodes, I recommend using a fixed size allocator for efficiency. -/// Instead of using a callback function for returned results, I recommend and efficient pre-sized, grow-only memory -/// array similar to MFC CArray or STL Vector for returning search query result. -/// -template -class RTree -{ - static_assert(std::numeric_limits::is_iec559, "'ELEMTYPEREAL' accepts floating-point types only"); - -protected: - - struct Node; // Fwd decl. Used by other internal structs and iterator - -public: - - // These constant must be declared after Branch and before Node struct - // Stuck up here for MSVC 6 compiler. NSVC .NET 2003 is much happier. - enum - { - MAXNODES = TMAXNODES, ///< Max elements in node - MINNODES = TMINNODES, ///< Min elements in node - }; - -public: - - RTree(); - RTree(const RTree& other); - virtual ~RTree(); - - /// Insert entry - /// \param a_min Min of bounding rect - /// \param a_max Max of bounding rect - /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. - void Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); - - /// Remove entry - /// \param a_min Min of bounding rect - /// \param a_max Max of bounding rect - /// \param a_dataId Positive Id of data. Maybe zero, but negative numbers not allowed. - bool Remove(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId); - - /// Find all within search rectangle - /// \param a_min Min of search bounding rect - /// \param a_max Max of search bounding rect - /// \param a_searchResult Search result array. Caller should set grow size. Function will reset, not append to array. - /// \param a_resultCallback Callback function to return result. Callback should return 'true' to continue searching - /// \param a_context User context to pass as parameter to a_resultCallback - /// \return Returns the number of entries found - int Search(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], std::function callback) const; - - /// Remove all entries from tree - void RemoveAll(); - - /// Count the data elements in this container. This is slow as no internal counter is maintained. - int Count(); - - /// Load tree contents from file - bool Load(const char* a_fileName); - /// Load tree contents from stream - bool Load(RTFileStream& a_stream); - - - /// Save tree contents to file - bool Save(const char* a_fileName); - /// Save tree contents to stream - bool Save(RTFileStream& a_stream); - - /// Iterator is not remove safe. - class Iterator - { - private: - - enum { MAX_STACK = 32 }; // Max stack size. Allows almost n^32 where n is number of branches in node - - struct StackElement - { - Node* m_node; - int m_branchIndex; - }; - - public: - - Iterator() { Init(); } - - ~Iterator() { } - - /// Is iterator invalid - bool IsNull() { return (m_tos <= 0); } - - /// Is iterator pointing to valid data - bool IsNotNull() { return (m_tos > 0); } - - /// Access the current data element. Caller must be sure iterator is not NULL first. - DATATYPE& operator*() - { - ASSERT(IsNotNull()); - StackElement& curTos = m_stack[m_tos - 1]; - return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; - } - - /// Access the current data element. Caller must be sure iterator is not NULL first. - const DATATYPE& operator*() const - { - ASSERT(IsNotNull()); - StackElement& curTos = m_stack[m_tos - 1]; - return curTos.m_node->m_branch[curTos.m_branchIndex].m_data; - } - - /// Find the next data element - bool operator++() { return FindNextData(); } - - /// Get the bounds for this node - void GetBounds(ELEMTYPE a_min[NUMDIMS], ELEMTYPE a_max[NUMDIMS]) - { - ASSERT(IsNotNull()); - StackElement& curTos = m_stack[m_tos - 1]; - Branch& curBranch = curTos.m_node->m_branch[curTos.m_branchIndex]; - - for(int index = 0; index < NUMDIMS; ++index) - { - a_min[index] = curBranch.m_rect.m_min[index]; - a_max[index] = curBranch.m_rect.m_max[index]; - } - } - - private: - - /// Reset iterator - void Init() { m_tos = 0; } - - /// Find the next data element in the tree (For internal use only) - bool FindNextData() - { - for(;;) - { - if(m_tos <= 0) - { - return false; - } - StackElement curTos = Pop(); // Copy stack top cause it may change as we use it - - if(curTos.m_node->IsLeaf()) - { - // Keep walking through data while we can - if(curTos.m_branchIndex+1 < curTos.m_node->m_count) - { - // There is more data, just point to the next one - Push(curTos.m_node, curTos.m_branchIndex + 1); - return true; - } - // No more data, so it will fall back to previous level - } - else - { - if(curTos.m_branchIndex+1 < curTos.m_node->m_count) - { - // Push sibling on for future tree walk - // This is the 'fall back' node when we finish with the current level - Push(curTos.m_node, curTos.m_branchIndex + 1); - } - // Since cur node is not a leaf, push first of next level to get deeper into the tree - Node* nextLevelnode = curTos.m_node->m_branch[curTos.m_branchIndex].m_child; - Push(nextLevelnode, 0); - - // If we pushed on a new leaf, exit as the data is ready at TOS - if(nextLevelnode->IsLeaf()) - { - return true; - } - } - } - } - - /// Push node and branch onto iteration stack (For internal use only) - void Push(Node* a_node, int a_branchIndex) - { - m_stack[m_tos].m_node = a_node; - m_stack[m_tos].m_branchIndex = a_branchIndex; - ++m_tos; - ASSERT(m_tos <= MAX_STACK); - } - - /// Pop element off iteration stack (For internal use only) - StackElement& Pop() - { - ASSERT(m_tos > 0); - --m_tos; - return m_stack[m_tos]; - } - - StackElement m_stack[MAX_STACK]; ///< Stack as we are doing iteration instead of recursion - int m_tos; ///< Top Of Stack index - - friend class RTree; // Allow hiding of non-public functions while allowing manipulation by logical owner - }; - - /// Get 'first' for iteration - void GetFirst(Iterator& a_it) - { - a_it.Init(); - Node* first = m_root; - while(first) - { - if(first->IsInternalNode() && first->m_count > 1) - { - a_it.Push(first, 1); // Descend sibling branch later - } - else if(first->IsLeaf()) - { - if(first->m_count) - { - a_it.Push(first, 0); - } - break; - } - first = first->m_branch[0].m_child; - } - } - - /// Get Next for iteration - void GetNext(Iterator& a_it) { ++a_it; } - - /// Is iterator NULL, or at end? - bool IsNull(Iterator& a_it) { return a_it.IsNull(); } - - /// Get object at iterator position - DATATYPE& GetAt(Iterator& a_it) { return *a_it; } - -protected: - - /// Minimal bounding rectangle (n-dimensional) - struct Rect - { - ELEMTYPE m_min[NUMDIMS]; ///< Min dimensions of bounding box - ELEMTYPE m_max[NUMDIMS]; ///< Max dimensions of bounding box - }; - - /// May be data or may be another subtree - /// The parents level determines this. - /// If the parents level is 0, then this is data - struct Branch - { - Rect m_rect; ///< Bounds - Node* m_child; ///< Child node - DATATYPE m_data; ///< Data Id - }; - - /// Node for each branch level - struct Node - { - bool IsInternalNode() { return (m_level > 0); } // Not a leaf, but a internal node - bool IsLeaf() { return (m_level == 0); } // A leaf, contains data - - int m_count; ///< Count - int m_level; ///< Leaf is zero, others positive - Branch m_branch[MAXNODES]; ///< Branch - }; - - /// A link list of nodes for reinsertion after a delete operation - struct ListNode - { - ListNode* m_next; ///< Next in list - Node* m_node; ///< Node - }; - - /// Variables for finding a split partition - struct PartitionVars - { - enum { NOT_TAKEN = -1 }; // indicates that position - - int m_partition[MAXNODES+1]; - int m_total; - int m_minFill; - int m_count[2]; - Rect m_cover[2]; - ELEMTYPEREAL m_area[2]; - - Branch m_branchBuf[MAXNODES+1]; - int m_branchCount; - Rect m_coverSplit; - ELEMTYPEREAL m_coverSplitArea; - }; - - Node* AllocNode(); - void FreeNode(Node* a_node); - void InitNode(Node* a_node); - void InitRect(Rect* a_rect); - bool InsertRectRec(const Branch& a_branch, Node* a_node, Node** a_newNode, int a_level); - bool InsertRect(const Branch& a_branch, Node** a_root, int a_level); - Rect NodeCover(Node* a_node); - bool AddBranch(const Branch* a_branch, Node* a_node, Node** a_newNode); - void DisconnectBranch(Node* a_node, int a_index); - int PickBranch(const Rect* a_rect, Node* a_node); - Rect CombineRect(const Rect* a_rectA, const Rect* a_rectB); - void SplitNode(Node* a_node, const Branch* a_branch, Node** a_newNode); - ELEMTYPEREAL RectSphericalVolume(Rect* a_rect); - ELEMTYPEREAL RectVolume(Rect* a_rect); - ELEMTYPEREAL CalcRectVolume(Rect* a_rect); - void GetBranches(Node* a_node, const Branch* a_branch, PartitionVars* a_parVars); - void ChoosePartition(PartitionVars* a_parVars, int a_minFill); - void LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars); - void InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill); - void PickSeeds(PartitionVars* a_parVars); - void Classify(int a_index, int a_group, PartitionVars* a_parVars); - bool RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root); - bool RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode); - ListNode* AllocListNode(); - void FreeListNode(ListNode* a_listNode); - bool Overlap(Rect* a_rectA, Rect* a_rectB) const; - void ReInsert(Node* a_node, ListNode** a_listNode); - bool Search(Node* a_node, Rect* a_rect, int& a_foundCount, std::function callback) const; - void RemoveAllRec(Node* a_node); - void Reset(); - void CountRec(Node* a_node, int& a_count); - - bool SaveRec(Node* a_node, RTFileStream& a_stream); - bool LoadRec(Node* a_node, RTFileStream& a_stream); - void CopyRec(Node* current, Node* other); - - Node* m_root; ///< Root of tree - ELEMTYPEREAL m_unitSphereVolume; ///< Unit sphere constant for required number of dimensions - -public: - // return all the AABBs that form the RTree - std::vector ListTree() const; -}; - - -// Because there is not stream support, this is a quick and dirty file I/O helper. -// Users will likely replace its usage with a Stream implementation from their favorite API. -class RTFileStream -{ - FILE* m_file; - -public: - - - RTFileStream() - { - m_file = NULL; - } - - ~RTFileStream() - { - Close(); - } - - bool Open(const char* a_fileName, const char* mode) - { -#if defined(_WIN32) && defined(__STDC_WANT_SECURE_LIB__) - return fopen_s(&m_file, a_fileName, mode) == 0; -#else - m_file = fopen(a_fileName, mode); - return m_file != nullptr; -#endif - } - - bool OpenRead(const char* a_fileName) - { - return this->Open(a_fileName, "rb"); - } - - bool OpenWrite(const char* a_fileName) - { - return this->Open(a_fileName, "wb"); - } - - void Close() - { - if(m_file) - { - fclose(m_file); - m_file = NULL; - } - } - - template< typename TYPE > - size_t Write(const TYPE& a_value) - { - ASSERT(m_file); - return fwrite((void*)&a_value, sizeof(a_value), 1, m_file); - } - - template< typename TYPE > - size_t WriteArray(const TYPE* a_array, int a_count) - { - ASSERT(m_file); - return fwrite((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); - } - - template< typename TYPE > - size_t Read(TYPE& a_value) - { - ASSERT(m_file); - return fread((void*)&a_value, sizeof(a_value), 1, m_file); - } - - template< typename TYPE > - size_t ReadArray(TYPE* a_array, int a_count) - { - ASSERT(m_file); - return fread((void*)a_array, sizeof(TYPE) * a_count, 1, m_file); - } -}; - - -RTREE_TEMPLATE -RTREE_QUAL::RTree() -{ - ASSERT(MAXNODES > MINNODES); - ASSERT(MINNODES > 0); - - // Precomputed volumes of the unit spheres for the first few dimensions - const float UNIT_SPHERE_VOLUMES[] = { - 0.000000f, 2.000000f, 3.141593f, // Dimension 0,1,2 - 4.188790f, 4.934802f, 5.263789f, // Dimension 3,4,5 - 5.167713f, 4.724766f, 4.058712f, // Dimension 6,7,8 - 3.298509f, 2.550164f, 1.884104f, // Dimension 9,10,11 - 1.335263f, 0.910629f, 0.599265f, // Dimension 12,13,14 - 0.381443f, 0.235331f, 0.140981f, // Dimension 15,16,17 - 0.082146f, 0.046622f, 0.025807f, // Dimension 18,19,20 - }; - - m_root = AllocNode(); - m_root->m_level = 0; - m_unitSphereVolume = (ELEMTYPEREAL)UNIT_SPHERE_VOLUMES[NUMDIMS]; -} - - -RTREE_TEMPLATE -RTREE_QUAL::RTree(const RTree& other) : RTree() -{ - CopyRec(m_root, other.m_root); -} - - -RTREE_TEMPLATE -RTREE_QUAL::~RTree() -{ - Reset(); // Free, or reset node memory -} - - -RTREE_TEMPLATE -void RTREE_QUAL::Insert(const ELEMTYPE a_min[NUMDIMS], const ELEMTYPE a_max[NUMDIMS], const DATATYPE& a_dataId) -{ -#ifdef _DEBUG - for(int index=0; index callback) const -{ -#ifdef _DEBUG - for(int index=0; indexIsInternalNode()) // not a leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - CountRec(a_node->m_branch[index].m_child, a_count); - } - } - else // A leaf node - { - a_count += a_node->m_count; - } -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Load(const char* a_fileName) -{ - RemoveAll(); // Clear existing tree - - RTFileStream stream; - if(!stream.OpenRead(a_fileName)) - { - return false; - } - - bool result = Load(stream); - - stream.Close(); - - return result; -} - - - -RTREE_TEMPLATE -bool RTREE_QUAL::Load(RTFileStream& a_stream) -{ - // Write some kind of header - int _dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); - int _dataSize = sizeof(DATATYPE); - int _dataNumDims = NUMDIMS; - int _dataElemSize = sizeof(ELEMTYPE); - int _dataElemRealSize = sizeof(ELEMTYPEREAL); - int _dataMaxNodes = TMAXNODES; - int _dataMinNodes = TMINNODES; - - int dataFileId = 0; - int dataSize = 0; - int dataNumDims = 0; - int dataElemSize = 0; - int dataElemRealSize = 0; - int dataMaxNodes = 0; - int dataMinNodes = 0; - - a_stream.Read(dataFileId); - a_stream.Read(dataSize); - a_stream.Read(dataNumDims); - a_stream.Read(dataElemSize); - a_stream.Read(dataElemRealSize); - a_stream.Read(dataMaxNodes); - a_stream.Read(dataMinNodes); - - bool result = false; - - // Test if header was valid and compatible - if( (dataFileId == _dataFileId) - && (dataSize == _dataSize) - && (dataNumDims == _dataNumDims) - && (dataElemSize == _dataElemSize) - && (dataElemRealSize == _dataElemRealSize) - && (dataMaxNodes == _dataMaxNodes) - && (dataMinNodes == _dataMinNodes) - ) - { - // Recursively load tree - result = LoadRec(m_root, a_stream); - } - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::LoadRec(Node* a_node, RTFileStream& a_stream) -{ - a_stream.Read(a_node->m_level); - a_stream.Read(a_node->m_count); - - if(a_node->IsInternalNode()) // not a leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); - a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); - - curBranch->m_child = AllocNode(); - LoadRec(curBranch->m_child, a_stream); - } - } - else // A leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.ReadArray(curBranch->m_rect.m_min, NUMDIMS); - a_stream.ReadArray(curBranch->m_rect.m_max, NUMDIMS); - - a_stream.Read(curBranch->m_data); - } - } - - return true; // Should do more error checking on I/O operations -} - - -RTREE_TEMPLATE -void RTREE_QUAL::CopyRec(Node* current, Node* other) -{ - current->m_level = other->m_level; - current->m_count = other->m_count; - - if(current->IsInternalNode()) // not a leaf node - { - for(int index = 0; index < current->m_count; ++index) - { - Branch* currentBranch = ¤t->m_branch[index]; - Branch* otherBranch = &other->m_branch[index]; - - std::copy(otherBranch->m_rect.m_min, - otherBranch->m_rect.m_min + NUMDIMS, - currentBranch->m_rect.m_min); - - std::copy(otherBranch->m_rect.m_max, - otherBranch->m_rect.m_max + NUMDIMS, - currentBranch->m_rect.m_max); - - currentBranch->m_child = AllocNode(); - CopyRec(currentBranch->m_child, otherBranch->m_child); - } - } - else // A leaf node - { - for(int index = 0; index < current->m_count; ++index) - { - Branch* currentBranch = ¤t->m_branch[index]; - Branch* otherBranch = &other->m_branch[index]; - - std::copy(otherBranch->m_rect.m_min, - otherBranch->m_rect.m_min + NUMDIMS, - currentBranch->m_rect.m_min); - - std::copy(otherBranch->m_rect.m_max, - otherBranch->m_rect.m_max + NUMDIMS, - currentBranch->m_rect.m_max); - - currentBranch->m_data = otherBranch->m_data; - } - } -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Save(const char* a_fileName) -{ - RTFileStream stream; - if(!stream.OpenWrite(a_fileName)) - { - return false; - } - - bool result = Save(stream); - - stream.Close(); - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::Save(RTFileStream& a_stream) -{ - // Write some kind of header - int dataFileId = ('R'<<0)|('T'<<8)|('R'<<16)|('E'<<24); - int dataSize = sizeof(DATATYPE); - int dataNumDims = NUMDIMS; - int dataElemSize = sizeof(ELEMTYPE); - int dataElemRealSize = sizeof(ELEMTYPEREAL); - int dataMaxNodes = TMAXNODES; - int dataMinNodes = TMINNODES; - - a_stream.Write(dataFileId); - a_stream.Write(dataSize); - a_stream.Write(dataNumDims); - a_stream.Write(dataElemSize); - a_stream.Write(dataElemRealSize); - a_stream.Write(dataMaxNodes); - a_stream.Write(dataMinNodes); - - // Recursively save tree - bool result = SaveRec(m_root, a_stream); - - return result; -} - - -RTREE_TEMPLATE -bool RTREE_QUAL::SaveRec(Node* a_node, RTFileStream& a_stream) -{ - a_stream.Write(a_node->m_level); - a_stream.Write(a_node->m_count); - - if(a_node->IsInternalNode()) // not a leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); - a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); - - SaveRec(curBranch->m_child, a_stream); - } - } - else // A leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - Branch* curBranch = &a_node->m_branch[index]; - - a_stream.WriteArray(curBranch->m_rect.m_min, NUMDIMS); - a_stream.WriteArray(curBranch->m_rect.m_max, NUMDIMS); - - a_stream.Write(curBranch->m_data); - } - } - - return true; // Should do more error checking on I/O operations -} - - -RTREE_TEMPLATE -void RTREE_QUAL::RemoveAll() -{ - // Delete all existing nodes - Reset(); - - m_root = AllocNode(); - m_root->m_level = 0; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::Reset() -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - // Delete all existing nodes - RemoveAllRec(m_root); -#else // RTREE_DONT_USE_MEMPOOLS - // Just reset memory pools. We are not using complex types - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::RemoveAllRec(Node* a_node) -{ - ASSERT(a_node); - ASSERT(a_node->m_level >= 0); - - if(a_node->IsInternalNode()) // This is an internal node in the tree - { - for(int index=0; index < a_node->m_count; ++index) - { - RemoveAllRec(a_node->m_branch[index].m_child); - } - } - FreeNode(a_node); -} - - -RTREE_TEMPLATE -typename RTREE_QUAL::Node* RTREE_QUAL::AllocNode() -{ - Node* newNode; -#ifdef RTREE_DONT_USE_MEMPOOLS - newNode = new Node; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS - InitNode(newNode); - return newNode; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::FreeNode(Node* a_node) -{ - ASSERT(a_node); - -#ifdef RTREE_DONT_USE_MEMPOOLS - delete a_node; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -// Allocate space for a node in the list used in DeletRect to -// store Nodes that are too empty. -RTREE_TEMPLATE -typename RTREE_QUAL::ListNode* RTREE_QUAL::AllocListNode() -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - return new ListNode; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::FreeListNode(ListNode* a_listNode) -{ -#ifdef RTREE_DONT_USE_MEMPOOLS - delete a_listNode; -#else // RTREE_DONT_USE_MEMPOOLS - // EXAMPLE -#endif // RTREE_DONT_USE_MEMPOOLS -} - - -RTREE_TEMPLATE -void RTREE_QUAL::InitNode(Node* a_node) -{ - a_node->m_count = 0; - a_node->m_level = -1; -} - - -RTREE_TEMPLATE -void RTREE_QUAL::InitRect(Rect* a_rect) -{ - for(int index = 0; index < NUMDIMS; ++index) - { - a_rect->m_min[index] = (ELEMTYPE)0; - a_rect->m_max[index] = (ELEMTYPE)0; - } -} - - -// Inserts a new data rectangle into the index structure. -// Recursively descends tree, propagates splits back up. -// Returns 0 if node was not split. Old node updated. -// If node was split, returns 1 and sets the pointer pointed to by -// new_node to point to the new node. Old node updated to become one of two. -// The level argument specifies the number of steps up from the leaf -// level to insert; e.g. a data rectangle goes in at level = 0. -RTREE_TEMPLATE -bool RTREE_QUAL::InsertRectRec(const Branch& a_branch, Node* a_node, Node** a_newNode, int a_level) -{ - ASSERT(a_node && a_newNode); - ASSERT(a_level >= 0 && a_level <= a_node->m_level); - - // recurse until we reach the correct level for the new record. data records - // will always be called with a_level == 0 (leaf) - if(a_node->m_level > a_level) - { - // Still above level for insertion, go down tree recursively - Node* otherNode; - - // find the optimal branch for this record - int index = PickBranch(&a_branch.m_rect, a_node); - - // recursively insert this record into the picked branch - bool childWasSplit = InsertRectRec(a_branch, a_node->m_branch[index].m_child, &otherNode, a_level); - - if (!childWasSplit) - { - // Child was not split. Merge the bounding box of the new record with the - // existing bounding box - a_node->m_branch[index].m_rect = CombineRect(&a_branch.m_rect, &(a_node->m_branch[index].m_rect)); - return false; - } - else - { - // Child was split. The old branches are now re-partitioned to two nodes - // so we have to re-calculate the bounding boxes of each node - a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); - Branch branch; - branch.m_child = otherNode; - branch.m_rect = NodeCover(otherNode); - - // The old node is already a child of a_node. Now add the newly-created - // node to a_node as well. a_node might be split because of that. - return AddBranch(&branch, a_node, a_newNode); - } - } - else if(a_node->m_level == a_level) - { - // We have reached level for insertion. Add rect, split if necessary - return AddBranch(&a_branch, a_node, a_newNode); - } - else - { - // Should never occur - ASSERT(0); - return false; - } -} - - -// Insert a data rectangle into an index structure. -// InsertRect provides for splitting the root; -// returns 1 if root was split, 0 if it was not. -// The level argument specifies the number of steps up from the leaf -// level to insert; e.g. a data rectangle goes in at level = 0. -// InsertRect2 does the recursion. -// -RTREE_TEMPLATE -bool RTREE_QUAL::InsertRect(const Branch& a_branch, Node** a_root, int a_level) -{ - ASSERT(a_root); - ASSERT(a_level >= 0 && a_level <= (*a_root)->m_level); -#ifdef _DEBUG - for(int index=0; index < NUMDIMS; ++index) - { - ASSERT(a_branch.m_rect.m_min[index] <= a_branch.m_rect.m_max[index]); - } -#endif //_DEBUG - - Node* newNode; - - if(InsertRectRec(a_branch, *a_root, &newNode, a_level)) // Root split - { - // Grow tree taller and new root - Node* newRoot = AllocNode(); - newRoot->m_level = (*a_root)->m_level + 1; - - Branch branch; - - // add old root node as a child of the new root - branch.m_rect = NodeCover(*a_root); - branch.m_child = *a_root; - AddBranch(&branch, newRoot, NULL); - - // add the split node as a child of the new root - branch.m_rect = NodeCover(newNode); - branch.m_child = newNode; - AddBranch(&branch, newRoot, NULL); - - // set the new root as the root node - *a_root = newRoot; - - return true; - } - - return false; -} - - -// Find the smallest rectangle that includes all rectangles in branches of a node. -RTREE_TEMPLATE -typename RTREE_QUAL::Rect RTREE_QUAL::NodeCover(Node* a_node) -{ - ASSERT(a_node); - - Rect rect = a_node->m_branch[0].m_rect; - for(int index = 1; index < a_node->m_count; ++index) - { - rect = CombineRect(&rect, &(a_node->m_branch[index].m_rect)); - } - - return rect; -} - - -// Add a branch to a node. Split the node if necessary. -// Returns 0 if node not split. Old node updated. -// Returns 1 if node split, sets *new_node to address of new node. -// Old node updated, becomes one of two. -RTREE_TEMPLATE -bool RTREE_QUAL::AddBranch(const Branch* a_branch, Node* a_node, Node** a_newNode) -{ - ASSERT(a_branch); - ASSERT(a_node); - - if(a_node->m_count < MAXNODES) // Split won't be necessary - { - a_node->m_branch[a_node->m_count] = *a_branch; - ++a_node->m_count; - - return false; - } - else - { - ASSERT(a_newNode); - - SplitNode(a_node, a_branch, a_newNode); - return true; - } -} - - -// Disconnect a dependent node. -// Caller must return (or stop using iteration index) after this as count has changed -RTREE_TEMPLATE -void RTREE_QUAL::DisconnectBranch(Node* a_node, int a_index) -{ - ASSERT(a_node && (a_index >= 0) && (a_index < MAXNODES)); - ASSERT(a_node->m_count > 0); - - // Remove element by swapping with the last element to prevent gaps in array - a_node->m_branch[a_index] = a_node->m_branch[a_node->m_count - 1]; - - --a_node->m_count; -} - - -// Pick a branch. Pick the one that will need the smallest increase -// in area to accomodate the new rectangle. This will result in the -// least total area for the covering rectangles in the current node. -// In case of a tie, pick the one which was smaller before, to get -// the best resolution when searching. -RTREE_TEMPLATE -int RTREE_QUAL::PickBranch(const Rect* a_rect, Node* a_node) -{ - ASSERT(a_rect && a_node); - - bool firstTime = true; - ELEMTYPEREAL increase; - ELEMTYPEREAL bestIncr = (ELEMTYPEREAL)-1; - ELEMTYPEREAL area; - ELEMTYPEREAL bestArea; - int best = 0; - Rect tempRect; - - for(int index=0; index < a_node->m_count; ++index) - { - Rect* curRect = &a_node->m_branch[index].m_rect; - area = CalcRectVolume(curRect); - tempRect = CombineRect(a_rect, curRect); - increase = CalcRectVolume(&tempRect) - area; - if((increase < bestIncr) || firstTime) - { - best = index; - bestArea = area; - bestIncr = increase; - firstTime = false; - } - else if((increase == bestIncr) && (area < bestArea)) - { - best = index; - bestArea = area; - bestIncr = increase; - } - } - return best; -} - - -// Combine two rectangles into larger one containing both -RTREE_TEMPLATE -typename RTREE_QUAL::Rect RTREE_QUAL::CombineRect(const Rect* a_rectA, const Rect* a_rectB) -{ - ASSERT(a_rectA && a_rectB); - - Rect newRect; - - for(int index = 0; index < NUMDIMS; ++index) - { - newRect.m_min[index] = Min(a_rectA->m_min[index], a_rectB->m_min[index]); - newRect.m_max[index] = Max(a_rectA->m_max[index], a_rectB->m_max[index]); - } - - return newRect; -} - - - -// Split a node. -// Divides the nodes branches and the extra one between two nodes. -// Old node is one of the new ones, and one really new one is created. -// Tries more than one method for choosing a partition, uses best result. -RTREE_TEMPLATE -void RTREE_QUAL::SplitNode(Node* a_node, const Branch* a_branch, Node** a_newNode) -{ - ASSERT(a_node); - ASSERT(a_branch); - - // Could just use local here, but member or external is faster since it is reused - PartitionVars localVars; - PartitionVars* parVars = &localVars; - - // Load all the branches into a buffer, initialize old node - GetBranches(a_node, a_branch, parVars); - - // Find partition - ChoosePartition(parVars, MINNODES); - - // Create a new node to hold (about) half of the branches - *a_newNode = AllocNode(); - (*a_newNode)->m_level = a_node->m_level; - - // Put branches from buffer into 2 nodes according to the chosen partition - a_node->m_count = 0; - LoadNodes(a_node, *a_newNode, parVars); - - ASSERT((a_node->m_count + (*a_newNode)->m_count) == parVars->m_total); -} - - -// Calculate the n-dimensional volume of a rectangle -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::RectVolume(Rect* a_rect) -{ - ASSERT(a_rect); - - ELEMTYPEREAL volume = (ELEMTYPEREAL)1; - - for(int index=0; indexm_max[index] - a_rect->m_min[index]; - } - - ASSERT(volume >= (ELEMTYPEREAL)0); - - return volume; -} - - -// The exact volume of the bounding sphere for the given Rect -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::RectSphericalVolume(Rect* a_rect) -{ - ASSERT(a_rect); - - ELEMTYPEREAL sumOfSquares = (ELEMTYPEREAL)0; - ELEMTYPEREAL radius; - - for(int index=0; index < NUMDIMS; ++index) - { - ELEMTYPEREAL halfExtent = ((ELEMTYPEREAL)a_rect->m_max[index] - (ELEMTYPEREAL)a_rect->m_min[index]) * (ELEMTYPEREAL)0.5; - sumOfSquares += halfExtent * halfExtent; - } - - radius = (ELEMTYPEREAL)sqrt(sumOfSquares); - - // Pow maybe slow, so test for common dims like 2,3 and just use x*x, x*x*x. - if(NUMDIMS == 3) - { - return (radius * radius * radius * m_unitSphereVolume); - } - else if(NUMDIMS == 2) - { - return (radius * radius * m_unitSphereVolume); - } - else - { - return (ELEMTYPEREAL)(pow(radius, NUMDIMS) * m_unitSphereVolume); - } -} - - -// Use one of the methods to calculate retangle volume -RTREE_TEMPLATE -ELEMTYPEREAL RTREE_QUAL::CalcRectVolume(Rect* a_rect) -{ -#ifdef RTREE_USE_SPHERICAL_VOLUME - return RectSphericalVolume(a_rect); // Slower but helps certain merge cases -#else // RTREE_USE_SPHERICAL_VOLUME - return RectVolume(a_rect); // Faster but can cause poor merges -#endif // RTREE_USE_SPHERICAL_VOLUME -} - - -// Load branch buffer with branches from full node plus the extra branch. -RTREE_TEMPLATE -void RTREE_QUAL::GetBranches(Node* a_node, const Branch* a_branch, PartitionVars* a_parVars) -{ - ASSERT(a_node); - ASSERT(a_branch); - - ASSERT(a_node->m_count == MAXNODES); - - // Load the branch buffer - for(int index=0; index < MAXNODES; ++index) - { - a_parVars->m_branchBuf[index] = a_node->m_branch[index]; - } - a_parVars->m_branchBuf[MAXNODES] = *a_branch; - a_parVars->m_branchCount = MAXNODES + 1; - - // Calculate rect containing all in the set - a_parVars->m_coverSplit = a_parVars->m_branchBuf[0].m_rect; - for(int index=1; index < MAXNODES+1; ++index) - { - a_parVars->m_coverSplit = CombineRect(&a_parVars->m_coverSplit, &a_parVars->m_branchBuf[index].m_rect); - } - a_parVars->m_coverSplitArea = CalcRectVolume(&a_parVars->m_coverSplit); -} - - -// Method #0 for choosing a partition: -// As the seeds for the two groups, pick the two rects that would waste the -// most area if covered by a single rectangle, i.e. evidently the worst pair -// to have in the same group. -// Of the remaining, one at a time is chosen to be put in one of the two groups. -// The one chosen is the one with the greatest difference in area expansion -// depending on which group - the rect most strongly attracted to one group -// and repelled from the other. -// If one group gets too full (more would force other group to violate min -// fill requirement) then other group gets the rest. -// These last are the ones that can go in either group most easily. -RTREE_TEMPLATE -void RTREE_QUAL::ChoosePartition(PartitionVars* a_parVars, int a_minFill) -{ - ASSERT(a_parVars); - - ELEMTYPEREAL biggestDiff; - int group, chosen = 0, betterGroup = 0; - - InitParVars(a_parVars, a_parVars->m_branchCount, a_minFill); - PickSeeds(a_parVars); - - while (((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) - && (a_parVars->m_count[0] < (a_parVars->m_total - a_parVars->m_minFill)) - && (a_parVars->m_count[1] < (a_parVars->m_total - a_parVars->m_minFill))) - { - biggestDiff = (ELEMTYPEREAL) -1; - for(int index=0; indexm_total; ++index) - { - if(PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) - { - Rect* curRect = &a_parVars->m_branchBuf[index].m_rect; - Rect rect0 = CombineRect(curRect, &a_parVars->m_cover[0]); - Rect rect1 = CombineRect(curRect, &a_parVars->m_cover[1]); - ELEMTYPEREAL growth0 = CalcRectVolume(&rect0) - a_parVars->m_area[0]; - ELEMTYPEREAL growth1 = CalcRectVolume(&rect1) - a_parVars->m_area[1]; - ELEMTYPEREAL diff = growth1 - growth0; - if(diff >= 0) - { - group = 0; - } - else - { - group = 1; - diff = -diff; - } - - if(diff > biggestDiff) - { - biggestDiff = diff; - chosen = index; - betterGroup = group; - } - else if((diff == biggestDiff) && (a_parVars->m_count[group] < a_parVars->m_count[betterGroup])) - { - chosen = index; - betterGroup = group; - } - } - } - Classify(chosen, betterGroup, a_parVars); - } - - // If one group too full, put remaining rects in the other - if((a_parVars->m_count[0] + a_parVars->m_count[1]) < a_parVars->m_total) - { - if(a_parVars->m_count[0] >= a_parVars->m_total - a_parVars->m_minFill) - { - group = 1; - } - else - { - group = 0; - } - for(int index=0; indexm_total; ++index) - { - if(PartitionVars::NOT_TAKEN == a_parVars->m_partition[index]) - { - Classify(index, group, a_parVars); - } - } - } - - ASSERT((a_parVars->m_count[0] + a_parVars->m_count[1]) == a_parVars->m_total); - ASSERT((a_parVars->m_count[0] >= a_parVars->m_minFill) && - (a_parVars->m_count[1] >= a_parVars->m_minFill)); -} - - -// Copy branches from the buffer into two nodes according to the partition. -RTREE_TEMPLATE -void RTREE_QUAL::LoadNodes(Node* a_nodeA, Node* a_nodeB, PartitionVars* a_parVars) -{ - ASSERT(a_nodeA); - ASSERT(a_nodeB); - ASSERT(a_parVars); - - for(int index=0; index < a_parVars->m_total; ++index) - { - ASSERT(a_parVars->m_partition[index] == 0 || a_parVars->m_partition[index] == 1); - - int targetNodeIndex = a_parVars->m_partition[index]; - Node* targetNodes[] = {a_nodeA, a_nodeB}; - - // It is assured that AddBranch here will not cause a node split. - bool nodeWasSplit = AddBranch(&a_parVars->m_branchBuf[index], targetNodes[targetNodeIndex], NULL); - ASSERT(!nodeWasSplit); - } -} - - -// Initialize a PartitionVars structure. -RTREE_TEMPLATE -void RTREE_QUAL::InitParVars(PartitionVars* a_parVars, int a_maxRects, int a_minFill) -{ - ASSERT(a_parVars); - - a_parVars->m_count[0] = a_parVars->m_count[1] = 0; - a_parVars->m_area[0] = a_parVars->m_area[1] = (ELEMTYPEREAL)0; - a_parVars->m_total = a_maxRects; - a_parVars->m_minFill = a_minFill; - for(int index=0; index < a_maxRects; ++index) - { - a_parVars->m_partition[index] = PartitionVars::NOT_TAKEN; - } -} - - -RTREE_TEMPLATE -void RTREE_QUAL::PickSeeds(PartitionVars* a_parVars) -{ - int seed0 = 0, seed1 = 0; - ELEMTYPEREAL worst, waste; - ELEMTYPEREAL area[MAXNODES+1]; - - for(int index=0; indexm_total; ++index) - { - area[index] = CalcRectVolume(&a_parVars->m_branchBuf[index].m_rect); - } - - worst = -a_parVars->m_coverSplitArea - 1; - for(int indexA=0; indexA < a_parVars->m_total-1; ++indexA) - { - for(int indexB = indexA+1; indexB < a_parVars->m_total; ++indexB) - { - Rect oneRect = CombineRect(&a_parVars->m_branchBuf[indexA].m_rect, &a_parVars->m_branchBuf[indexB].m_rect); - waste = CalcRectVolume(&oneRect) - area[indexA] - area[indexB]; - if(waste > worst) - { - worst = waste; - seed0 = indexA; - seed1 = indexB; - } - } - } - - Classify(seed0, 0, a_parVars); - Classify(seed1, 1, a_parVars); -} - - -// Put a branch in one of the groups. -RTREE_TEMPLATE -void RTREE_QUAL::Classify(int a_index, int a_group, PartitionVars* a_parVars) -{ - ASSERT(a_parVars); - ASSERT(PartitionVars::NOT_TAKEN == a_parVars->m_partition[a_index]); - - a_parVars->m_partition[a_index] = a_group; - - // Calculate combined rect - if (a_parVars->m_count[a_group] == 0) - { - a_parVars->m_cover[a_group] = a_parVars->m_branchBuf[a_index].m_rect; - } - else - { - a_parVars->m_cover[a_group] = CombineRect(&a_parVars->m_branchBuf[a_index].m_rect, &a_parVars->m_cover[a_group]); - } - - // Calculate volume of combined rect - a_parVars->m_area[a_group] = CalcRectVolume(&a_parVars->m_cover[a_group]); - - ++a_parVars->m_count[a_group]; -} - - -// Delete a data rectangle from an index structure. -// Pass in a pointer to a Rect, the tid of the record, ptr to ptr to root node. -// Returns 1 if record not found, 0 if success. -// RemoveRect provides for eliminating the root. -RTREE_TEMPLATE -bool RTREE_QUAL::RemoveRect(Rect* a_rect, const DATATYPE& a_id, Node** a_root) -{ - ASSERT(a_rect && a_root); - ASSERT(*a_root); - - ListNode* reInsertList = NULL; - - if(!RemoveRectRec(a_rect, a_id, *a_root, &reInsertList)) - { - // Found and deleted a data item - // Reinsert any branches from eliminated nodes - while(reInsertList) - { - Node* tempNode = reInsertList->m_node; - - for(int index = 0; index < tempNode->m_count; ++index) - { - // TODO go over this code. should I use (tempNode->m_level - 1)? - InsertRect(tempNode->m_branch[index], - a_root, - tempNode->m_level); - } - - ListNode* remLNode = reInsertList; - reInsertList = reInsertList->m_next; - - FreeNode(remLNode->m_node); - FreeListNode(remLNode); - } - - // Check for redundant root (not leaf, 1 child) and eliminate TODO replace - // if with while? In case there is a whole branch of redundant roots... - if((*a_root)->m_count == 1 && (*a_root)->IsInternalNode()) - { - Node* tempNode = (*a_root)->m_branch[0].m_child; - - ASSERT(tempNode); - FreeNode(*a_root); - *a_root = tempNode; - } - return false; - } - else - { - return true; - } -} - - -// Delete a rectangle from non-root part of an index structure. -// Called by RemoveRect. Descends tree recursively, -// merges branches on the way back up. -// Returns 1 if record not found, 0 if success. -RTREE_TEMPLATE -bool RTREE_QUAL::RemoveRectRec(Rect* a_rect, const DATATYPE& a_id, Node* a_node, ListNode** a_listNode) -{ - ASSERT(a_rect && a_node && a_listNode); - ASSERT(a_node->m_level >= 0); - - if(a_node->IsInternalNode()) // not a leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - if(Overlap(a_rect, &(a_node->m_branch[index].m_rect))) - { - if(!RemoveRectRec(a_rect, a_id, a_node->m_branch[index].m_child, a_listNode)) - { - if(a_node->m_branch[index].m_child->m_count >= MINNODES) - { - // child removed, just resize parent rect - a_node->m_branch[index].m_rect = NodeCover(a_node->m_branch[index].m_child); - } - else - { - // child removed, not enough entries in node, eliminate node - ReInsert(a_node->m_branch[index].m_child, a_listNode); - DisconnectBranch(a_node, index); // Must return after this call as count has changed - } - return false; - } - } - } - return true; - } - else // A leaf node - { - for(int index = 0; index < a_node->m_count; ++index) - { - if(a_node->m_branch[index].m_data == a_id) - { - DisconnectBranch(a_node, index); // Must return after this call as count has changed - return false; - } - } - return true; - } -} - - -// Decide whether two rectangles overlap. -RTREE_TEMPLATE -bool RTREE_QUAL::Overlap(Rect* a_rectA, Rect* a_rectB) const -{ - ASSERT(a_rectA && a_rectB); - - for(int index=0; index < NUMDIMS; ++index) - { - if (a_rectA->m_min[index] > a_rectB->m_max[index] || - a_rectB->m_min[index] > a_rectA->m_max[index]) - { - return false; - } - } - return true; -} - - -// Add a node to the reinsertion list. All its branches will later -// be reinserted into the index structure. -RTREE_TEMPLATE -void RTREE_QUAL::ReInsert(Node* a_node, ListNode** a_listNode) -{ - ListNode* newListNode; - - newListNode = AllocListNode(); - newListNode->m_node = a_node; - newListNode->m_next = *a_listNode; - *a_listNode = newListNode; -} - - -// Search in an index tree or subtree for all data retangles that overlap the argument rectangle. -RTREE_TEMPLATE -bool RTREE_QUAL::Search(Node* a_node, Rect* a_rect, int& a_foundCount, std::function callback) const -{ - ASSERT(a_node); - ASSERT(a_node->m_level >= 0); - ASSERT(a_rect); - - if(a_node->IsInternalNode()) - { - // This is an internal node in the tree - for(int index=0; index < a_node->m_count; ++index) - { - if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) - { - if(!Search(a_node->m_branch[index].m_child, a_rect, a_foundCount, callback)) - { - // The callback indicated to stop searching - return false; - } - } - } - } - else - { - // This is a leaf node - for(int index=0; index < a_node->m_count; ++index) - { - if(Overlap(a_rect, &a_node->m_branch[index].m_rect)) - { - DATATYPE& id = a_node->m_branch[index].m_data; - ++a_foundCount; - - if(callback && !callback(id)) - { - return false; // Don't continue searching - } - } - } - } - - return true; // Continue searching -} - - -RTREE_TEMPLATE -std::vector RTREE_QUAL::ListTree() const -{ - ASSERT(m_root); - ASSERT(m_root->m_level >= 0); - - std::vector treeList; - - std::vector toVisit; - toVisit.push_back(m_root); - - while (!toVisit.empty()) { - Node* a_node = toVisit.back(); - toVisit.pop_back(); - if(a_node->IsInternalNode()) - { - // This is an internal node in the tree - for(int index=0; index < a_node->m_count; ++index) - { - treeList.push_back(a_node->m_branch[index].m_rect); - toVisit.push_back(a_node->m_branch[index].m_child); - } - } - else - { - // This is a leaf node - for(int index=0; index < a_node->m_count; ++index) - { - treeList.push_back(a_node->m_branch[index].m_rect); - } - } - } - - return treeList; -} - - -#undef RTREE_TEMPLATE -#undef RTREE_QUAL - -} - -#endif //RTREE_H - diff --git a/src/util/3rdparty/dtoa_milo.h b/src/util/3rdparty/dtoa_milo.h deleted file mode 100644 index 1ed2670..0000000 --- a/src/util/3rdparty/dtoa_milo.h +++ /dev/null @@ -1,454 +0,0 @@ -// based on -// https://github.com/miloyip/dtoa-benchmark/blob/master/src/milo/dtoa_milo.h - -#pragma once -#include -#include -#include - -#if defined(_MSC_VER) -#include -#include "msinttypes/stdint.h" -#else -#include -#endif - -namespace gcc_ints { -__extension__ typedef __int128 int128; -__extension__ typedef unsigned __int128 uint128; -} // namespace gcc_ints - -#define UINT64_C2(h, l) \ - ((static_cast(h) << 32) | static_cast(l)) - -namespace util { - -struct DiyFp { - DiyFp() {} - - DiyFp(uint64_t f, int e) : f(f), e(e) {} - - DiyFp(double d) { - union { - double d; - uint64_t u64; - } u = {d}; - - int biased_e = (u.u64 & kDpExponentMask) >> kDpSignificandSize; - uint64_t significand = (u.u64 & kDpSignificandMask); - if (biased_e != 0) { - f = significand + kDpHiddenBit; - e = biased_e - kDpExponentBias; - } else { - f = significand; - e = kDpMinExponent + 1; - } - } - - DiyFp operator-(const DiyFp& rhs) const { - assert(e == rhs.e); - assert(f >= rhs.f); - return DiyFp(f - rhs.f, e); - } - - DiyFp operator*(const DiyFp& rhs) const { -#if defined(_MSC_VER) && defined(_M_AMD64) - uint64_t h; - uint64_t l = _umul128(f, rhs.f, &h); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#elif (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) && \ - defined(__x86_64__) - gcc_ints::uint128 p = static_cast(f) * - static_cast(rhs.f); - uint64_t h = p >> 64; - uint64_t l = static_cast(p); - if (l & (uint64_t(1) << 63)) // rounding - h++; - return DiyFp(h, e + rhs.e + 64); -#else - const uint64_t M32 = 0xFFFFFFFF; - const uint64_t a = f >> 32; - const uint64_t b = f & M32; - const uint64_t c = rhs.f >> 32; - const uint64_t d = rhs.f & M32; - const uint64_t ac = a * c; - const uint64_t bc = b * c; - const uint64_t ad = a * d; - const uint64_t bd = b * d; - uint64_t tmp = (bd >> 32) + (ad & M32) + (bc & M32); - tmp += 1U << 31; /// mult_round - return DiyFp(ac + (ad >> 32) + (bc >> 32) + (tmp >> 32), e + rhs.e + 64); -#endif - } - - DiyFp Normalize() const { -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#elif defined(__GNUC__) - int s = __builtin_clzll(f); - return DiyFp(f << s, e - s); -#else - DiyFp res = *this; - while (!(res.f & kDpHiddenBit)) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 1); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 1); - return res; -#endif - } - - DiyFp NormalizeBoundary() const { -#if defined(_MSC_VER) && defined(_M_AMD64) - unsigned long index; - _BitScanReverse64(&index, f); - return DiyFp(f << (63 - index), e - (63 - index)); -#else - DiyFp res = *this; - while (!(res.f & (kDpHiddenBit << 1))) { - res.f <<= 1; - res.e--; - } - res.f <<= (kDiySignificandSize - kDpSignificandSize - 2); - res.e = res.e - (kDiySignificandSize - kDpSignificandSize - 2); - return res; -#endif - } - - void NormalizedBoundaries(DiyFp* minus, DiyFp* plus) const { - DiyFp pl = DiyFp((f << 1) + 1, e - 1).NormalizeBoundary(); - DiyFp mi = (f == kDpHiddenBit) ? DiyFp((f << 2) - 1, e - 2) - : DiyFp((f << 1) - 1, e - 1); - mi.f <<= mi.e - pl.e; - mi.e = pl.e; - *plus = pl; - *minus = mi; - } - - static const int kDiySignificandSize = 64; - static const int kDpSignificandSize = 52; - static const int kDpExponentBias = 0x3FF + kDpSignificandSize; - static const int kDpMinExponent = -kDpExponentBias; - static const uint64_t kDpExponentMask = UINT64_C2(0x7FF00000, 0x00000000); - static const uint64_t kDpSignificandMask = UINT64_C2(0x000FFFFF, 0xFFFFFFFF); - static const uint64_t kDpHiddenBit = UINT64_C2(0x00100000, 0x00000000); - - uint64_t f; - int e; -}; - -inline DiyFp GetCachedPower(int e, int* K) { - // 10^-348, 10^-340, ..., 10^340 - static const uint64_t kCachedPowers_F[] = { - UINT64_C2(0xfa8fd5a0, 0x081c0288), UINT64_C2(0xbaaee17f, 0xa23ebf76), - UINT64_C2(0x8b16fb20, 0x3055ac76), UINT64_C2(0xcf42894a, 0x5dce35ea), - UINT64_C2(0x9a6bb0aa, 0x55653b2d), UINT64_C2(0xe61acf03, 0x3d1a45df), - UINT64_C2(0xab70fe17, 0xc79ac6ca), UINT64_C2(0xff77b1fc, 0xbebcdc4f), - UINT64_C2(0xbe5691ef, 0x416bd60c), UINT64_C2(0x8dd01fad, 0x907ffc3c), - UINT64_C2(0xd3515c28, 0x31559a83), UINT64_C2(0x9d71ac8f, 0xada6c9b5), - UINT64_C2(0xea9c2277, 0x23ee8bcb), UINT64_C2(0xaecc4991, 0x4078536d), - UINT64_C2(0x823c1279, 0x5db6ce57), UINT64_C2(0xc2109436, 0x4dfb5637), - UINT64_C2(0x9096ea6f, 0x3848984f), UINT64_C2(0xd77485cb, 0x25823ac7), - UINT64_C2(0xa086cfcd, 0x97bf97f4), UINT64_C2(0xef340a98, 0x172aace5), - UINT64_C2(0xb23867fb, 0x2a35b28e), UINT64_C2(0x84c8d4df, 0xd2c63f3b), - UINT64_C2(0xc5dd4427, 0x1ad3cdba), UINT64_C2(0x936b9fce, 0xbb25c996), - UINT64_C2(0xdbac6c24, 0x7d62a584), UINT64_C2(0xa3ab6658, 0x0d5fdaf6), - UINT64_C2(0xf3e2f893, 0xdec3f126), UINT64_C2(0xb5b5ada8, 0xaaff80b8), - UINT64_C2(0x87625f05, 0x6c7c4a8b), UINT64_C2(0xc9bcff60, 0x34c13053), - UINT64_C2(0x964e858c, 0x91ba2655), UINT64_C2(0xdff97724, 0x70297ebd), - UINT64_C2(0xa6dfbd9f, 0xb8e5b88f), UINT64_C2(0xf8a95fcf, 0x88747d94), - UINT64_C2(0xb9447093, 0x8fa89bcf), UINT64_C2(0x8a08f0f8, 0xbf0f156b), - UINT64_C2(0xcdb02555, 0x653131b6), UINT64_C2(0x993fe2c6, 0xd07b7fac), - UINT64_C2(0xe45c10c4, 0x2a2b3b06), UINT64_C2(0xaa242499, 0x697392d3), - UINT64_C2(0xfd87b5f2, 0x8300ca0e), UINT64_C2(0xbce50864, 0x92111aeb), - UINT64_C2(0x8cbccc09, 0x6f5088cc), UINT64_C2(0xd1b71758, 0xe219652c), - UINT64_C2(0x9c400000, 0x00000000), UINT64_C2(0xe8d4a510, 0x00000000), - UINT64_C2(0xad78ebc5, 0xac620000), UINT64_C2(0x813f3978, 0xf8940984), - UINT64_C2(0xc097ce7b, 0xc90715b3), UINT64_C2(0x8f7e32ce, 0x7bea5c70), - UINT64_C2(0xd5d238a4, 0xabe98068), UINT64_C2(0x9f4f2726, 0x179a2245), - UINT64_C2(0xed63a231, 0xd4c4fb27), UINT64_C2(0xb0de6538, 0x8cc8ada8), - UINT64_C2(0x83c7088e, 0x1aab65db), UINT64_C2(0xc45d1df9, 0x42711d9a), - UINT64_C2(0x924d692c, 0xa61be758), UINT64_C2(0xda01ee64, 0x1a708dea), - UINT64_C2(0xa26da399, 0x9aef774a), UINT64_C2(0xf209787b, 0xb47d6b85), - UINT64_C2(0xb454e4a1, 0x79dd1877), UINT64_C2(0x865b8692, 0x5b9bc5c2), - UINT64_C2(0xc83553c5, 0xc8965d3d), UINT64_C2(0x952ab45c, 0xfa97a0b3), - UINT64_C2(0xde469fbd, 0x99a05fe3), UINT64_C2(0xa59bc234, 0xdb398c25), - UINT64_C2(0xf6c69a72, 0xa3989f5c), UINT64_C2(0xb7dcbf53, 0x54e9bece), - UINT64_C2(0x88fcf317, 0xf22241e2), UINT64_C2(0xcc20ce9b, 0xd35c78a5), - UINT64_C2(0x98165af3, 0x7b2153df), UINT64_C2(0xe2a0b5dc, 0x971f303a), - UINT64_C2(0xa8d9d153, 0x5ce3b396), UINT64_C2(0xfb9b7cd9, 0xa4a7443c), - UINT64_C2(0xbb764c4c, 0xa7a44410), UINT64_C2(0x8bab8eef, 0xb6409c1a), - UINT64_C2(0xd01fef10, 0xa657842c), UINT64_C2(0x9b10a4e5, 0xe9913129), - UINT64_C2(0xe7109bfb, 0xa19c0c9d), UINT64_C2(0xac2820d9, 0x623bf429), - UINT64_C2(0x80444b5e, 0x7aa7cf85), UINT64_C2(0xbf21e440, 0x03acdd2d), - UINT64_C2(0x8e679c2f, 0x5e44ff8f), UINT64_C2(0xd433179d, 0x9c8cb841), - UINT64_C2(0x9e19db92, 0xb4e31ba9), UINT64_C2(0xeb96bf6e, 0xbadf77d9), - UINT64_C2(0xaf87023b, 0x9bf0ee6b)}; - static const int16_t kCachedPowers_E[] = { - -1220, -1193, -1166, -1140, -1113, -1087, -1060, -1034, -1007, -980, -954, - -927, -901, -874, -847, -821, -794, -768, -741, -715, -688, -661, - -635, -608, -582, -555, -529, -502, -475, -449, -422, -396, -369, - -343, -316, -289, -263, -236, -210, -183, -157, -130, -103, -77, - -50, -24, 3, 30, 56, 83, 109, 136, 162, 189, 216, - 242, 269, 295, 322, 348, 375, 402, 428, 455, 481, 508, - 534, 561, 588, 614, 641, 667, 694, 720, 747, 774, 800, - 827, 853, 880, 907, 933, 960, 986, 1013, 1039, 1066}; - - // int k = static_cast(ceil((-61 - e) * 0.30102999566398114)) + 374; - double dk = (-61 - e) * 0.30102999566398114 + - 347; // dk must be positive, so can do ceiling in positive - int k = static_cast(dk); - if (dk - k > 0.0) k++; - - unsigned index = static_cast((k >> 3) + 1); - *K = -(-348 + static_cast( - index << 3)); // decimal exponent no need lookup table - - assert(index < sizeof(kCachedPowers_F) / sizeof(kCachedPowers_F[0])); - return DiyFp(kCachedPowers_F[index], kCachedPowers_E[index]); -} - -inline void GrisuRound(char* buffer, int len, uint64_t delta, uint64_t rest, - uint64_t ten_kappa, uint64_t wp_w) { - while (rest < wp_w && delta - rest >= ten_kappa && - (rest + ten_kappa < wp_w || /// closer - wp_w - rest > rest + ten_kappa - wp_w)) { - buffer[len - 1]--; - rest += ten_kappa; - } -} - -inline unsigned CountDecimalDigit32(uint32_t n) { - // Simple pure C++ implementation was faster than __builtin_clz version in - // this situation. - if (n < 10) return 1; - if (n < 100) return 2; - if (n < 1000) return 3; - if (n < 10000) return 4; - if (n < 100000) return 5; - if (n < 1000000) return 6; - if (n < 10000000) return 7; - if (n < 100000000) return 8; - if (n < 1000000000) return 9; - return 10; -} - -inline void DigitGen(const DiyFp& W, const DiyFp& Mp, uint64_t delta, - char* buffer, int* len, int* K) { - static const uint64_t kPow10[] = {1, - 10, - 100, - 1000, - 10000, - 100000, - 1000000, - 10000000, - 100000000, - 1000000000, - 10000000000, - 100000000000, - 1000000000000, - 10000000000000, - 100000000000000}; - const DiyFp one(uint64_t(1) << -Mp.e, Mp.e); - const DiyFp wp_w = Mp - W; - uint32_t p1 = static_cast(Mp.f >> -one.e); - uint64_t p2 = Mp.f & (one.f - 1); - int kappa = static_cast(CountDecimalDigit32(p1)); - *len = 0; - - while (kappa > 0) { - uint32_t d; - switch (kappa) { - case 10: - d = p1 / 1000000000; - p1 %= 1000000000; - break; - case 9: - d = p1 / 100000000; - p1 %= 100000000; - break; - case 8: - d = p1 / 10000000; - p1 %= 10000000; - break; - case 7: - d = p1 / 1000000; - p1 %= 1000000; - break; - case 6: - d = p1 / 100000; - p1 %= 100000; - break; - case 5: - d = p1 / 10000; - p1 %= 10000; - break; - case 4: - d = p1 / 1000; - p1 %= 1000; - break; - case 3: - d = p1 / 100; - p1 %= 100; - break; - case 2: - d = p1 / 10; - p1 %= 10; - break; - case 1: - d = p1; - p1 = 0; - break; - default: -#if defined(_MSC_VER) - __assume(0); -#elif __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5) - __builtin_unreachable(); -#else - d = 0; -#endif - } - if (d || *len) buffer[(*len)++] = '0' + static_cast(d); - kappa--; - uint64_t tmp = (static_cast(p1) << -one.e) + p2; - if (tmp <= delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, tmp, - static_cast(kPow10[kappa]) << -one.e, wp_w.f); - return; - } - } - - // kappa = 0 - for (;;) { - p2 *= 10; - delta *= 10; - char d = static_cast(p2 >> -one.e); - if (d || *len) buffer[(*len)++] = '0' + d; - p2 &= one.f - 1; - kappa--; - if (p2 < delta) { - *K += kappa; - GrisuRound(buffer, *len, delta, p2, one.f, wp_w.f * kPow10[-kappa]); - return; - } - } -} - -inline void Grisu2(double value, char* buffer, int* length, int* K) { - const DiyFp v(value); - DiyFp w_m, w_p; - v.NormalizedBoundaries(&w_m, &w_p); - - const DiyFp c_mk = GetCachedPower(w_p.e, K); - const DiyFp W = v.Normalize() * c_mk; - DiyFp Wp = w_p * c_mk; - DiyFp Wm = w_m * c_mk; - Wm.f++; - Wp.f--; - DigitGen(W, Wp, Wp.f - Wm.f, buffer, length, K); -} - -inline const char* GetDigitsLut() { - static const char cDigitsLut[200] = { - '0', '0', '0', '1', '0', '2', '0', '3', '0', '4', '0', '5', '0', '6', '0', - '7', '0', '8', '0', '9', '1', '0', '1', '1', '1', '2', '1', '3', '1', '4', - '1', '5', '1', '6', '1', '7', '1', '8', '1', '9', '2', '0', '2', '1', '2', - '2', '2', '3', '2', '4', '2', '5', '2', '6', '2', '7', '2', '8', '2', '9', - '3', '0', '3', '1', '3', '2', '3', '3', '3', '4', '3', '5', '3', '6', '3', - '7', '3', '8', '3', '9', '4', '0', '4', '1', '4', '2', '4', '3', '4', '4', - '4', '5', '4', '6', '4', '7', '4', '8', '4', '9', '5', '0', '5', '1', '5', - '2', '5', '3', '5', '4', '5', '5', '5', '6', '5', '7', '5', '8', '5', '9', - '6', '0', '6', '1', '6', '2', '6', '3', '6', '4', '6', '5', '6', '6', '6', - '7', '6', '8', '6', '9', '7', '0', '7', '1', '7', '2', '7', '3', '7', '4', - '7', '5', '7', '6', '7', '7', '7', '8', '7', '9', '8', '0', '8', '1', '8', - '2', '8', '3', '8', '4', '8', '5', '8', '6', '8', '7', '8', '8', '8', '9', - '9', '0', '9', '1', '9', '2', '9', '3', '9', '4', '9', '5', '9', '6', '9', - '7', '9', '8', '9', '9'}; - return cDigitsLut; -} - -inline void WriteExponent(int K, char* buffer) { - if (K < 0) { - *buffer++ = '-'; - K = -K; - } - - if (K >= 100) { - *buffer++ = '0' + static_cast(K / 100); - K %= 100; - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } else if (K >= 10) { - const char* d = GetDigitsLut() + K * 2; - *buffer++ = d[0]; - *buffer++ = d[1]; - } else - *buffer++ = '0' + static_cast(K); - - *buffer = '\0'; -} - -inline void Prettify(char* buffer, int length, int k) { - const int kk = length + k; // 10^(kk-1) <= v < 10^kk - - if (length <= kk && kk <= 21) { - // 1234e7 -> 12340000000 - for (int i = length; i < kk; i++) buffer[i] = '0'; - buffer[kk] = '.'; - buffer[kk + 1] = '0'; - buffer[kk + 2] = '\0'; - } else if (0 < kk && kk <= 21) { - // 1234e-2 -> 12.34 - memmove(&buffer[kk + 1], &buffer[kk], length - kk); - buffer[kk] = '.'; - buffer[length + 1] = '\0'; - } else if (-6 < kk && kk <= 0) { - // 1234e-6 -> 0.001234 - const int offset = 2 - kk; - memmove(&buffer[offset], &buffer[0], length); - buffer[0] = '0'; - buffer[1] = '.'; - for (int i = 2; i < offset; i++) buffer[i] = '0'; - buffer[length + offset] = '\0'; - } else if (length == 1) { - // 1e30 - buffer[1] = 'e'; - WriteExponent(kk - 1, &buffer[2]); - } else { - // 1234e30 -> 1.234e33 - memmove(&buffer[2], &buffer[1], length - 1); - buffer[1] = '.'; - buffer[length + 1] = 'e'; - WriteExponent(kk - 1, &buffer[0 + length + 2]); - } -} - -inline void dtoa_milo(double value, char* buffer) { - // Not handling NaN and inf - assert(!std::isnan(value)); - assert(!std::isinf(value)); - - if (value == 0) { - buffer[0] = '0'; - buffer[1] = '.'; - buffer[2] = '0'; - buffer[3] = '\0'; - } else { - if (value < 0) { - *buffer++ = '-'; - value = -value; - } - int length, K; - Grisu2(value, buffer, &length, &K); - Prettify(buffer, length, K); - } -} -} // namespace util diff --git a/src/util/CMakeLists.txt b/src/util/CMakeLists.txt deleted file mode 100644 index fef7557..0000000 --- a/src/util/CMakeLists.txt +++ /dev/null @@ -1,29 +0,0 @@ -file(GLOB_RECURSE util_SRC *.cpp) -list(REMOVE_ITEM util_SRC TestMain.cpp) -add_library(util ${util_SRC}) - -if (!BZIP2_FOUND) - find_package(BZip2) - if (ZLIB_FOUND) - add_definitions( -DBZLIB_FOUND=${BZIP2_FOUND} ) - endif() -endif() - -if (BZIP2_FOUND) - include_directories( ${BZIP2_INCLUDE_DIR} ) - target_link_libraries( util ${BZIP2_LIBRARIES} ) -endif(BZIP2_FOUND) - -if (!ZLIB_FOUND) - find_package(ZLIB) - if (ZLIB_FOUND) - add_definitions( -DZLIB_FOUND=${ZLIB_FOUND} ) - endif() -endif() - -if (ZLIB_FOUND) - include_directories( ${ZLIB_INCLUDE_DIRS} ) - target_link_libraries( util ${ZLIB_LIBRARIES} ) -endif(ZLIB_FOUND) - -add_subdirectory(tests) diff --git a/src/util/Misc.h b/src/util/Misc.h deleted file mode 100644 index 1aad2e9..0000000 --- a/src/util/Misc.h +++ /dev/null @@ -1,706 +0,0 @@ -// Copyright 2017, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_MISC_H_ -#define UTIL_MISC_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "3rdparty/dtoa_milo.h" -#include "util/String.h" - -#define UNUSED(expr) do { (void)(expr); } while (0) -#define TIME() std::chrono::high_resolution_clock::now() -#define TOOK(t1, t2) (std::chrono::duration_cast(t2 - t1).count() / 1000.0) -#define T_START(n) auto _tstart_##n = std::chrono::high_resolution_clock::now() -#define T_STOP(n) (std::chrono::duration_cast(std::chrono::high_resolution_clock::now() - _tstart_##n).count() / 1000.0) - -#define _TEST3(s, o, e) if (!(s o e)) { std::cerr << "\n" << __FILE__ << ":" << __LINE__ << ": Test failed!\n Expected " << #s << " " << #o " " << (e) << ", got " << (s) << std::endl; exit(1);} -#define _TEST2(s, e) _TEST3(s, ==, e) -#define _TEST1(s) _TEST3(static_cast(s), ==, true) - -#define _GET_TEST_MACRO(_1,_2,_3,NAME,...) NAME -#define TEST(...) _GET_TEST_MACRO(__VA_ARGS__, _TEST3, _TEST2, _TEST1, UNUSED)(__VA_ARGS__) - -#define TODO(msg) std::cerr << "\n" __FILE__ << ":" << __LINE__ << ": TODO: " << #msg << std::endl; - -#if defined(_WIN32) -#include -#include -#elif defined(__unix__) || defined(__unix) || defined(unix) || (defined(__APPLE__) && defined(__MACH__)) -#include -#include -#if defined(__APPLE__) && defined(__MACH__) -#include -#elif (defined(_AIX) || defined(__TOS__AIX__)) || (defined(__sun__) || defined(__sun) || defined(sun) && (defined(__SVR4) || defined(__svr4__))) -#include -#include -#elif defined(__linux__) || defined(__linux) || defined(linux) || defined(__gnu_linux__) -#include -#endif -#else -#error "Cannot define getPeakRSS( ) or getCurrentRSS( ) for an unknown OS." -#endif - -namespace util { - -const static std::map HTML_COLOR_NAMES = { - {"aliceblue","F0F8FF"}, - {"antiquewhite","FAEBD7"}, - {"aqua","00FFFF"}, - {"aquamarine","7FFFD4"}, - {"azure","F0FFFF"}, - {"beige","F5F5DC"}, - {"bisque","FFE4C4"}, - {"black","000000"}, - {"blanchedalmond","FFEBCD"}, - {"blue","0000FF"}, - {"blueviolet","8A2BE2"}, - {"brown","A52A2A"}, - {"burlywood","DEB887"}, - {"cadetblue","5F9EA0"}, - {"chartreuse","7FFF00"}, - {"chocolate","D2691E"}, - {"coral","FF7F50"}, - {"cornflowerblue","6495ED"}, - {"cornsilk","FFF8DC"}, - {"crimson","DC143C"}, - {"cyan","00FFFF"}, - {"darkblue","00008B"}, - {"darkcyan","008B8B"}, - {"darkgoldenrod","B8860B"}, - {"darkgray","A9A9A9"}, - {"darkgreen","006400"}, - {"darkgrey","A9A9A9"}, - {"darkkhaki","BDB76B"}, - {"darkmagenta","8B008B"}, - {"darkolivegreen","556B2F"}, - {"darkorange","FF8C00"}, - {"darkorchid","9932CC"}, - {"darkred","8B0000"}, - {"darksalmon","E9967A"}, - {"darkseagreen","8FBC8F"}, - {"darkslateblue","483D8B"}, - {"darkslategray","2F4F4F"}, - {"darkslategrey","2F4F4F"}, - {"darkturquoise","00CED1"}, - {"darkviolet","9400D3"}, - {"deeppink","FF1493"}, - {"deepskyblue","00BFFF"}, - {"dimgray","696969"}, - {"dimgrey","696969"}, - {"dodgerblue","1E90FF"}, - {"firebrick","B22222"}, - {"floralwhite","FFFAF0"}, - {"forestgreen","228B22"}, - {"fuchsia","FF00FF"}, - {"gainsboro","DCDCDC"}, - {"ghostwhite","F8F8FF"}, - {"gold","FFD700"}, - {"goldenrod","DAA520"}, - {"gray","808080"}, - {"green","008000"}, - {"greenyellow","ADFF2F"}, - {"grey","808080"}, - {"honeydew","F0FFF0"}, - {"hotpink","FF69B4"}, - {"indianred","CD5C5C"}, - {"indigo","4B0082"}, - {"ivory","FFFFF0"}, - {"khaki","F0E68C"}, - {"lavender","E6E6FA"}, - {"lavenderblush","FFF0F5"}, - {"lawngreen","7CFC00"}, - {"lemonchiffon","FFFACD"}, - {"lightblue","ADD8E6"}, - {"lightcoral","F08080"}, - {"lightcyan","E0FFFF"}, - {"lightgoldenrodyellow","FAFAD2"}, - {"lightgray","D3D3D3"}, - {"lightgreen","90EE90"}, - {"lightgrey","D3D3D3"}, - {"lightpink","FFB6C1"}, - {"lightsalmon","FFA07A"}, - {"lightseagreen","20B2AA"}, - {"lightskyblue","87CEFA"}, - {"lightslategray","778899"}, - {"lightslategrey","778899"}, - {"lightsteelblue","B0C4DE"}, - {"lightyellow","FFFFE0"}, - {"lime","00FF00"}, - {"limegreen","32CD32"}, - {"linen","FAF0E6"}, - {"magenta","FF00FF"}, - {"maroon","800000"}, - {"mediumaquamarine","66CDAA"}, - {"mediumblue","0000CD"}, - {"mediumorchid","BA55D3"}, - {"mediumpurple","9370DB"}, - {"mediumseagreen","3CB371"}, - {"mediumslateblue","7B68EE"}, - {"mediumspringgreen","00FA9A"}, - {"mediumturquoise","48D1CC"}, - {"mediumvioletred","C71585"}, - {"midnightblue","191970"}, - {"mintcream","F5FFFA"}, - {"mistyrose","FFE4E1"}, - {"moccasin","FFE4B5"}, - {"navajowhite","FFDEAD"}, - {"navy","000080"}, - {"oldlace","FDF5E6"}, - {"olive","808000"}, - {"olivedrab","6B8E23"}, - {"orange","FFA500"}, - {"orangered","FF4500"}, - {"orchid","DA70D6"}, - {"palegoldenrod","EEE8AA"}, - {"palegreen","98FB98"}, - {"paleturquoise","AFEEEE"}, - {"palevioletred","DB7093"}, - {"papayawhip","FFEFD5"}, - {"peachpuff","FFDAB9"}, - {"peru","CD853F"}, - {"pink","FFC0CB"}, - {"plum","DDA0DD"}, - {"powderblue","B0E0E6"}, - {"purple","800080"}, - {"red","FF0000"}, - {"rosybrown","BC8F8F"}, - {"royalblue","4169E1"}, - {"saddlebrown","8B4513"}, - {"salmon","FA8072"}, - {"sandybrown","F4A460"}, - {"seagreen","2E8B57"}, - {"seashell","FFF5EE"}, - {"sienna","A0522D"}, - {"silver","C0C0C0"}, - {"skyblue","87CEEB"}, - {"slateblue","6A5ACD"}, - {"slategray","708090"}, - {"slategrey","708090"}, - {"snow","FFFAFA"}, - {"springgreen","00FF7F"}, - {"steelblue","4682B4"}, - {"tan","D2B48C"}, - {"teal","008080"}, - {"thistle","D8BFD8"}, - {"tomato","FF6347"}, - {"turquoise","40E0D0"}, - {"violet","EE82EE"}, - {"wheat","F5DEB3"}, - {"white","FFFFFF"}, - {"whitesmoke","F5F5F5"}, - {"yellow","FFFF00"}, - {"yellowgreen","9ACD32"} -}; - -struct hashPair { - template - size_t operator()(const std::pair& p) const { - auto h1 = std::hash{}(p.first); - auto h2 = std::hash{}(p.second); - return h1 ^ h2; - } -}; - -template -class SparseMatrix { - public: - Val get(const Key& x, const Key& y) const { - auto a = _m.find(std::pair(x, y)); - if (a == _m.end()) return Def; - return a->second; - } - - void set(Key x, Key y, Val v) { - _m[std::pair(x, y)] = v; - } - - const std::map, Val>& vals() const { - return _m; - } - - private: - std::map, Val> _m; -}; - -// cached first 10 powers of 10 -static int pow10[10] = { - 1, 10, 100, 1000, 10000, - 100000, 1000000, 10000000, 100000000, 1000000000}; - -// _____________________________________________________________________________ -inline uint64_t factorial(uint64_t n) { - if (n < 2) return 1; - return n * factorial(n - 1); -} - -// _____________________________________________________________________________ -inline uint64_t atoul(const char* p) { - uint64_t ret = 0; - - while (*p) { - ret = ret * 10 + (*p++ - '0'); - } - - return ret; -} - -// _____________________________________________________________________________ -inline bool isFloatingPoint(const std::string& str) { - std::stringstream ss(str); - double f; - ss >> std::noskipws >> f; - return ss.eof() && ! ss.fail(); -} - -// _____________________________________________________________________________ -inline std::string formatFloat(double f, size_t digits) { - std::stringstream ss; - ss << std::fixed << std::setprecision(digits) << f; - std::string ret = ss.str(); - - if (ret.find('.') != std::string::npos) { - auto p = ret.find_last_not_of('0'); - if (ret[p] == '.') return ret.substr(0, p); - return ret.substr(0, p + 1); - } - - return ret; -} - -// _____________________________________________________________________________ -inline double atof(const char* p, uint8_t mn) { - // this atof implementation works only on "normal" float strings like - // 56.445 or -345.00, but should be faster than std::atof - double ret = 0.0; - bool neg = false; - if (*p == '-') { - neg = true; - p++; - } - - while (*p >= '0' && *p <= '9') { - ret = ret * 10.0 + (*p - '0'); - p++; - } - - if (*p == '.') { - p++; - double f = 0; - uint8_t n = 0; - - for (; n < mn && *p >= '0' && *p <= '9'; n++, p++) { - f = f * 10.0 + (*p - '0'); - } - - if (n < 10) - ret += f / pow10[n]; - else - ret += f / std::pow(10, n); - } - - if (neg) return -ret; - return ret; -} - -// _____________________________________________________________________________ -inline double atof(const char* p) { return atof(p, 38); } - -// _____________________________________________________________________________ -template -int merge(V* lst, V* tmpLst, size_t l, size_t m, size_t r) { - size_t ret = 0; - - size_t lp = l; - size_t rp = m; - size_t outp = l; - - while (lp < m && rp < r + 1) { - if (lst[lp] <= lst[rp]) { - // if left element is smaller or equal, add it to return list, - // increase left pointer - tmpLst[outp] = lst[lp]; - lp++; - } else { - // if left element is bigger, add the right element, add it to ret, - // increase right pointer - tmpLst[outp] = lst[rp]; - rp++; - - // if the left element was bigger, everything to the right in the - // left list is also bigger, and all these m - i elements were - // initially in the wrong order! Count these inversions. - ret += m - lp; - } - - outp++; - } - - // fill in remaining values - if (lp < m) std::memcpy(tmpLst + outp, lst + lp, (m - lp) * sizeof(V)); - if (rp <= r) std::memcpy(tmpLst + outp, lst + rp, ((r + 1) - rp) * sizeof(V)); - - // copy to output - std::memcpy(lst + l, tmpLst + l, ((r + 1) - l) * sizeof(V)); - - return ret; -} - -// _____________________________________________________________________________ -template -size_t mergeInvCount(V* lst, V* tmpLst, size_t l, size_t r) { - size_t ret = 0; - if (l < r) { - size_t m = (r + l) / 2; - - ret += mergeInvCount(lst, tmpLst, l, m); - ret += mergeInvCount(lst, tmpLst, m + 1, r); - - ret += merge(lst, tmpLst, l, m + 1, r); - } - return ret; -} - -// _____________________________________________________________________________ -template -size_t inversions(const std::vector& v) { - if (v.size() < 2) return 0; // no inversions possible - - // unroll some simple cases - if (v.size() == 2) return v[1] < v[0]; - if (v.size() == 3) return (v[0] > v[1]) + (v[0] > v[2]) + (v[1] > v[2]); - - auto tmpLst = new V[v.size()]; - auto lst = new V[v.size()]; - - for (size_t i = 0; i < v.size(); i++) lst[i] = v[i]; - - size_t ret = mergeInvCount(lst, tmpLst, 0, v.size() - 1); - delete[] tmpLst; - delete[] lst; - return ret; -} - - -// _____________________________________________________________________________ -inline std::string getHomeDir() { - // parse implicit paths - const char* homedir = 0; - char* buf = 0; - - if ((homedir = getenv("HOME")) == 0) { - homedir = ""; - struct passwd pwd; - struct passwd* result; - size_t bufsize; - bufsize = sysconf(_SC_GETPW_R_SIZE_MAX); - if (bufsize == static_cast(-1)) bufsize = 0x4000; - buf = static_cast(malloc(bufsize)); - if (buf != 0) { - getpwuid_r(getuid(), &pwd, buf, bufsize, &result); - if (result != NULL) homedir = result->pw_dir; - } - } - - std::string ret(homedir); - if (buf) free(buf); - - return ret; -} - -// _____________________________________________________________________________ -inline std::string getTmpDir() { - // first, check if an env variable is set - const char* tmpdir = getenv("TMPDIR"); - if (tmpdir && std::strlen(tmpdir)) return std::string(tmpdir); - - // second, check if /tmp is writable - if (access("/tmp/", W_OK) == 0) return "/tmp"; - - // third, check if the cwd is writable - if (access(".", W_OK) == 0) return "."; - - // lastly, return the users home directory as a fallback - return getHomeDir(); -} - -// _____________________________________________________________________________ -inline std::string getTmpFName(std::string dir, std::string name, - std::string postf) { - if (postf.size()) postf = "-" + postf; - if (dir == "") dir = util::getTmpDir(); - if (dir.size() && dir.back() != '/') dir = dir + "/"; - - std::string f = dir + name + postf; - - size_t c = 0; - - while (access(f.c_str(), F_OK) != -1) { - c++; - if (c > 10000) { - // giving up... - std::cerr << "Could not find temporary file name!" << std::endl; - exit(1); - } - std::stringstream ss; - ss << dir << name << postf << "-" << std::rand(); - f = ss.str().c_str(); - } - - return f; -} - -// ___________________________________________________________________________ -inline std::string rgbToHex(int r, int g, int b) { - char hexcol[16]; - snprintf(hexcol, sizeof hexcol, "%02x%02x%02x", r, g, b); - return hexcol; -} - -// ___________________________________________________________________________ -inline void hsvToRgb(float* r, float* g, float* b, float h, float s, float v) { - int i; - float f, p, q, t; - - if (s == 0) { - *r = *g = *b = v; - return; - } - - h /= 60; - i = floor(h); - f = h - i; - p = v * (1 - s); - q = v * (1 - s * f); - t = v * (1 - s * (1 - f)); - - switch (i) { - case 0: - *r = v; - *g = t; - *b = p; - break; - case 1: - *r = q; - *g = v; - *b = p; - break; - case 2: - *r = p; - *g = v; - *b = t; - break; - case 3: - *r = p; - *g = q; - *b = v; - break; - case 4: - *r = t; - *g = p; - *b = v; - break; - default: - *r = v; - *g = p; - *b = q; - break; - } -} - -// ___________________________________________________________________________ -inline std::string normHtmlColor(const std::string& col) { - auto i = HTML_COLOR_NAMES.find(toLower(col)); - if (i != HTML_COLOR_NAMES.end()) return i->second; - return col; -} - -// ___________________________________________________________________________ -inline std::string randomHtmlColor() { - double goldenRatio = 0.618033988749895; - double h = static_cast(rand()) / static_cast(RAND_MAX); - h += goldenRatio; - h = fmod(h, 1.0); - float r, g, b; - hsvToRgb(&r, &g, &b, h * 360, 0.95, 0.95); - return rgbToHex(r * 256, g * 256, b * 256); -} - -// _____________________________________________________________________________ -inline char* readableSize(double size, size_t n, char* buf) { - int i = 0; - const char* units[] = {"B", "kB", "MB", "GB", "TB", "PB"}; - while (size > 1024 && i < 5) { - size /= 1024; - i++; - } - snprintf(buf, n, "%.*f %s", i, size, units[i]); - return buf; -} - -// _____________________________________________________________________________ -inline std::string readableSize(double size) { - char buffer[30]; - return readableSize(size, 30, buffer); -} - -// _____________________________________________________________________________ -class approx { - public: - explicit approx(double magnitude) - : _epsilon{std::numeric_limits::epsilon() * 100}, - _magnitude{magnitude} {} - - friend bool operator==(double lhs, approx const& rhs) { - return std::abs(lhs - rhs._magnitude) < rhs._epsilon; - } - - friend bool operator==(approx const& lhs, double rhs) { - return operator==(rhs, lhs); - } - - friend bool operator!=(double lhs, approx const& rhs) { - return !operator==(lhs, rhs); - } - - friend bool operator!=(approx const& lhs, double rhs) { - return !operator==(rhs, lhs); - } - - friend bool operator<=(double lhs, approx const& rhs) { - return lhs < rhs._magnitude || lhs == rhs; - } - - friend bool operator<=(approx const& lhs, double rhs) { - return lhs._magnitude < rhs || lhs == rhs; - } - - friend bool operator>=(double lhs, approx const& rhs) { - return lhs > rhs._magnitude || lhs == rhs; - } - - friend bool operator>=(approx const& lhs, double rhs) { - return lhs._magnitude > rhs || lhs == rhs; - } - - friend std::ostream& operator<< (std::ostream &out, const approx &a) { - out << "~" << a._magnitude; - return out; - } - - private: - double _epsilon; - double _magnitude; -}; - -/* - * Author: David Robert Nadeau - * Site: http://NadeauSoftware.com/ - * License: Creative Commons Attribution 3.0 Unported License - * http://creativecommons.org/licenses/by/3.0/deed.en_US - */ - -/** - * Returns the peak (maximum so far) resident set size (physical - * memory use) measured in bytes, or zero if the value cannot be - * determined on this OS. - */ - -// _____________________________________________________________________________ -inline size_t getPeakRSS() { -#if defined(_WIN32) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); - return (size_t)info.PeakWorkingSetSize; - -#elif (defined(_AIX) || defined(__TOS__AIX__)) || \ - (defined(__sun__) || defined(__sun) || \ - defined(sun) && (defined(__SVR4) || defined(__svr4__))) - /* AIX and Solaris ------------------------------------------ */ - struct psinfo psinfo; - int fd = -1; - if ((fd = open("/proc/self/psinfo", O_RDONLY)) == -1) - return (size_t)0L; /* Can't open? */ - if (read(fd, &psinfo, sizeof(psinfo)) != sizeof(psinfo)) { - close(fd); - return (size_t)0L; /* Can't read? */ - } - close(fd); - return (size_t)(psinfo.pr_rssize * 1024L); - -#elif defined(__unix__) || defined(__unix) || defined(unix) || \ - (defined(__APPLE__) && defined(__MACH__)) - /* BSD, Linux, and OSX -------------------------------------- */ - struct rusage rusage; - getrusage(RUSAGE_SELF, &rusage); -#if defined(__APPLE__) && defined(__MACH__) - return (size_t)rusage.ru_maxrss; -#else - return (size_t)(rusage.ru_maxrss * 1024L); -#endif - -#else - /* Unknown OS ----------------------------------------------- */ - return (size_t)0L; /* Unsupported. */ -#endif -} - -/* - * Returns the current resident set size (physical memory use) measured - * in bytes, or zero if the value cannot be determined on this OS. - */ - -// _____________________________________________________________________________ -inline size_t getCurrentRSS() { -#if defined(_WIN32) - /* Windows -------------------------------------------------- */ - PROCESS_MEMORY_COUNTERS info; - GetProcessMemoryInfo(GetCurrentProcess(), &info, sizeof(info)); - return (size_t)info.WorkingSetSize; - -#elif defined(__APPLE__) && defined(__MACH__) - /* OSX ------------------------------------------------------ */ - struct mach_task_basic_info info; - mach_msg_type_number_t infoCount = MACH_TASK_BASIC_INFO_COUNT; - if (task_info(mach_task_self(), MACH_TASK_BASIC_INFO, (task_info_t)&info, - &infoCount) != KERN_SUCCESS) - return (size_t)0L; /* Can't access? */ - return (size_t)info.resident_size; - -#elif defined(__linux__) || defined(__linux) || defined(linux) || \ - defined(__gnu_linux__) - /* Linux ---------------------------------------------------- */ - long rss = 0L; - FILE* fp = NULL; - if ((fp = fopen("/proc/self/statm", "r")) == NULL) - return (size_t)0L; /* Can't open? */ - if (fscanf(fp, "%*s%ld", &rss) != 1) { - fclose(fp); - return (size_t)0L; /* Can't read? */ - } - fclose(fp); - return (size_t)rss * (size_t)sysconf(_SC_PAGESIZE); - -#else - /* AIX, BSD, Solaris, and Unknown OS ------------------------ */ - return (size_t)0L; /* Unsupported. */ -#endif -} - -} // namespace util - -#endif // UTIL_MISC_H_ diff --git a/src/util/Nullable.h b/src/util/Nullable.h deleted file mode 100644 index 069426f..0000000 --- a/src/util/Nullable.h +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2017, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#include - -#ifndef UTIL_NULLABLE_H_ -#define UTIL_NULLABLE_H_ - -namespace util { - -template -class Nullable { - public: - Nullable() - : val(), null(true) {} - Nullable(T* valPointer) - : val(), null(true) { - if (valPointer) { - assign(*valPointer); - } - } - Nullable(const T& value) - : val(value), null(false) {} - Nullable(const Nullable& other) - : val(other.val), null(other.isNull()) {} - - Nullable& operator=(const Nullable& other) { - if (!other.isNull()) val = other.get(); - null = other.isNull(); - return *this; - } - - T operator=(const T& other) { - assign(other); - return val; - } - - /** - * Passing through comparision operators - */ - - bool operator==(const Nullable& other) const { - return (other.isNull() && isNull()) || other.get() == get(); - } - - bool operator!=(const Nullable& other) const { - return !(*this == other); - } - - bool operator<(const Nullable& other) const { - return !other.isNull() && !isNull() && get() < other.get(); - } - - bool operator>(const Nullable& other) const { - return !(*this < other || *this == other); - } - - bool operator<=(const Nullable& other) const { - return *this < other || *this == other; - } - - bool operator>=(const Nullable& other) const { - return *this > other || *this == other; - } - - bool operator==(const T& other) const { - return !isNull() && other == get(); - } - - bool operator!=(const T& other) const { - return !(*this == other); - } - - bool operator<(const T& other) const { - return !isNull() && get() < other; - } - - bool operator>(const T& other) const { - return !(*this < other || *this == other); - } - - bool operator<=(const T& other) const { - return *this < other || *this == other; - } - - bool operator>=(const T& other) const { - return *this > other || *this == other; - } - - operator T() const { - return get(); - } - - bool isNull() const { - return null; - } - - T get() const { - if (!isNull()) return val; - else throw std::runtime_error("Trying to retrieve value of NULL object."); - } - -private: - void assign(T v) { - val = v; - null = false; - } - - T val; - bool null; -}; - -} - -#endif // UTIL_NULLABLE_H_ diff --git a/src/util/PriorityQueue.h b/src/util/PriorityQueue.h deleted file mode 100644 index 13bd973..0000000 --- a/src/util/PriorityQueue.h +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright 2019, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_PRIORITYQUEUE_H_ -#define UTIL_PRIORITYQUEUE_H_ - -#include -#include -#include - -namespace util { -template -class PriorityQueue { - struct _ByFirst { - bool operator()(const std::pair& a, const std::pair& b) { - return a.first > b.first; - } - }; - - - public: - PriorityQueue() : _last(std::numeric_limits::lowest()) {} - void push(K k, const V& v); - const K topKey() ; - const V& topVal() ; - void pop(); - - bool empty() const; - - private: - K _last; - std::priority_queue, std::vector>, _ByFirst> - _pq; -}; -#include "util/PriorityQueue.tpp" -} // namespace util - -#endif diff --git a/src/util/PriorityQueue.tpp b/src/util/PriorityQueue.tpp deleted file mode 100644 index 611b5c2..0000000 --- a/src/util/PriorityQueue.tpp +++ /dev/null @@ -1,36 +0,0 @@ -// Copyright 2019, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -// _____________________________________________________________________________ -template -void PriorityQueue::push(K key, const V& val) { - if (key < _last) key = _last; - _pq.emplace(std::pair(key, val)); -} - -// _____________________________________________________________________________ -template -const K PriorityQueue::topKey() { - _last = _pq.top().first; - return _pq.top().first; -} - -// _____________________________________________________________________________ -template -const V& PriorityQueue::topVal() { - _last = _pq.top().first; - return _pq.top().second; -} - -// _____________________________________________________________________________ -template -bool PriorityQueue::empty() const { - return _pq.empty(); -} - -// _____________________________________________________________________________ -template -void PriorityQueue::pop() { - _pq.pop(); -} diff --git a/src/util/String.h b/src/util/String.h deleted file mode 100644 index 8b20303..0000000 --- a/src/util/String.h +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2017, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_STRING_H_ -#define UTIL_STRING_H_ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -namespace util { - -// _____________________________________________________________________________ -inline bool endsWith(const std::string& a, const std::string& suff) { - if (suff.size() > a.size()) return false; - return a.compare(a.length() - suff.length(), suff.length(), suff) == 0; -} - -// _____________________________________________________________________________ -inline std::string urlDecode(const std::string& encoded) { - std::string decoded; - for (size_t i = 0; i < encoded.size(); ++i) { - char c = encoded[i]; - if (c == '%') { - std::string ah = encoded.substr(i + 1, 2); - char* nonProced = 0; - char hexVal = strtol(ah.c_str(), &nonProced, 16); - - if (ah.find_first_of("+-") > 1 && ah.size() - strlen(nonProced) == 2) { - c = hexVal; - i += 2; - } - } else if (c == '+') { - c = ' '; - } - decoded += c; - } - return decoded; -} - -// _____________________________________________________________________________ -inline std::string jsonStringEscape(const std::string& unesc) { - // modified code from - // http://stackoverflow.com/questions/7724448/simple-json-string-escape-for-c - std::ostringstream o; - for (auto c = unesc.cbegin(); c != unesc.cend(); c++) { - switch (*c) { - case '"': - o << "\\\""; - break; - case '\\': - o << "\\\\"; - break; - case '\b': - o << "\\b"; - break; - case '\f': - o << "\\f"; - break; - case '\n': - o << "\\n"; - break; - case '\r': - o << "\\r"; - break; - case '\t': - o << "\\t"; - break; - default: - if ('\x00' <= *c && *c <= '\x1f') { - o << "\\u" << std::hex << std::setw(4) << std::setfill('0') - << static_cast(*c); - } else { - o << *c; - } - } - } - return o.str(); -} - -// _____________________________________________________________________________ -inline bool replace(std::string& subj, const std::string& from, - const std::string& to) { - if (from.empty()) return false; - size_t start_pos = subj.find(from); - if (start_pos != std::string::npos) { - subj.replace(start_pos, from.length(), to); - return true; - } - - return false; -} - -// _____________________________________________________________________________ -inline bool replaceAll(std::string& subj, const std::string& from, - const std::string& to) { - if (from.empty()) return false; - bool found = false; - size_t s = subj.find(from, 0); - for (; s != std::string::npos; s = subj.find(from, s + to.length())) { - found = true; - subj.replace(s, from.length(), to); - } - - return found; -} - -// _____________________________________________________________________________ -inline std::string unixBasename(const std::string& pathname) { - return {std::find_if(pathname.rbegin(), pathname.rend(), - [](char c) { return c == '/'; }) - .base(), - pathname.end()}; -} - -// _____________________________________________________________________________ -template -inline std::string toString(T obj) { - std::stringstream ss; - ss << obj; - return ss.str(); -} - -// _____________________________________________________________________________ -inline std::vector split(std::string in, char sep) { - std::stringstream ss(in); - std::vector ret(1); - while (std::getline(ss, ret.back(), sep)) { - ret.push_back(""); - } - ret.pop_back(); - return ret; -} - -// _____________________________________________________________________________ -inline std::string ltrim(std::string str, std::string c) { - str.erase(0, str.find_first_not_of(c)); - return str; -} - -// _____________________________________________________________________________ -inline std::string rtrim(std::string str, std::string c) { - str.erase(str.find_last_not_of(c) + 1); - return str; -} - -// _____________________________________________________________________________ -inline std::string trim(std::string str, std::string c) { - return ltrim(rtrim(str, c), c); -} - -// _____________________________________________________________________________ -inline std::string ltrim(std::string str) { return ltrim(str, " \t\n\v\f\r"); } - -// _____________________________________________________________________________ -inline std::string rtrim(std::string str) { return rtrim(str, " \t\n\v\f\r"); } - -// _____________________________________________________________________________ -inline std::string trim(std::string str) { return trim(str, " \t\n\v\f\r"); } - -// _____________________________________________________________________________ -inline size_t editDist(const std::string& s1, const std::string& s2) { - // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++ - size_t len1 = s1.size(); - size_t len2 = s2.size(); - std::vector cur(len2 + 1); - std::vector prev(len2 + 1); - - for (size_t i = 0; i < prev.size(); i++) prev[i] = i; - - for (size_t i = 0; i < len1; i++) { - cur[0] = i + 1; - for (size_t j = 0; j < len2; j++) { - cur[j + 1] = - std::min(prev[1 + j] + 1, - std::min(cur[j] + 1, prev[j] + (s1[i] == s2[j] ? 0 : 1))); - } - std::swap(cur, prev); - } - - return prev[len2]; -} - -// _____________________________________________________________________________ -template -inline size_t prefixEditDist(const String& prefix, const String& s, - size_t deltaMax) { - // https://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#C++ - size_t len1 = prefix.size(); - size_t len2 = std::min(s.size(), prefix.size() + deltaMax + 1); - std::vector d((len1 + 1) * (len2 + 1)); - - d[0] = 0; - for (size_t i = 1; i <= len1; ++i) d[i * (len2 + 1)] = i; - for (size_t i = 1; i <= len2; ++i) d[i] = i; - - for (size_t i = 1; i <= len1; i++) { - for (size_t j = 1; j <= len2; j++) { - d[i * (len2 + 1) + j] = std::min(std::min(d[(i - 1) * (len2 + 1) + j] + 1, - d[i * (len2 + 1) + j - 1] + 1), - d[(i - 1) * (len2 + 1) + j - 1] + - (prefix[i - 1] == s[j - 1] ? 0 : 1)); - } - } - - // take min of last row - size_t deltaMin = std::max(std::max(deltaMax + 1, prefix.size()), s.size()); - for (size_t i = 0; i <= len2; i++) { - if (d[len1 * (len2 + 1) + i] < deltaMin) - deltaMin = d[len1 * (len2 + 1) + i]; - } - - return deltaMin; -} - -// _____________________________________________________________________________ -template -inline size_t prefixEditDist(const String& prefix, const String& s) { - return prefixEditDist(prefix, s, s.size()); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const char* prefix, const char* s) { - return prefixEditDist(std::string(prefix), std::string(s)); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const char* prefix, const char* s, - size_t deltaMax) { - return prefixEditDist(std::string(prefix), std::string(s), - deltaMax); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const char* prefix, const std::string& s) { - return prefixEditDist(std::string(prefix), s); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const char* prefix, const std::string& s, - size_t deltaMax) { - return prefixEditDist(std::string(prefix), s, deltaMax); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const std::string& prefix, const char* s) { - return prefixEditDist(prefix, std::string(s)); -} - -// _____________________________________________________________________________ -inline size_t prefixEditDist(const std::string& prefix, const char* s, - size_t deltaMax) { - return prefixEditDist(prefix, std::string(s), deltaMax); -} - -// _____________________________________________________________________________ -inline std::string toUpper(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), toupper); - return str; -} - -// _____________________________________________________________________________ -inline std::string toLower(std::string str) { - std::transform(str.begin(), str.end(), str.begin(), tolower); - return str; -} - -// _____________________________________________________________________________ -template -inline std::string implode(Iter begin, const Iter& end, const char* del) { - std::stringstream ss; - size_t i = 0; - while (begin != end) { - if (i != 0) ss << del; - ss << *begin; - begin++; - i++; - } - - return ss.str(); -} - -// _____________________________________________________________________________ -template -inline std::string implode(const std::vector& vec, const char* del) { - return implode(vec.begin(), vec.end(), del); -} - -// _____________________________________________________________________________ -inline std::string normalizeWhiteSpace(const std::string& input) { - std::string ret; - bool ws = false; - for (size_t i = 0; i < input.size(); i++) { - if (std::isspace(input[i])) { - if (!ws) { - ret += " "; - ws = true; - } - continue; - } else { - ws = false; - ret += input[i]; - } - } - return ret; -} - -// _____________________________________________________________________________ -inline std::wstring toWStr(const std::string& str) { - std::wstring_convert> converter; - return converter.from_bytes(str); -} - -// _____________________________________________________________________________ -inline std::string toNStr(const std::wstring& wstr) { - std::wstring_convert> converter; - return converter.to_bytes(wstr); -} - -// _____________________________________________________________________________ -inline std::vector tokenize(const std::string& str) { - std::vector ret; - std::wstring wStr = toWStr(str); - - std::wstring cur; - for (size_t i = 0; i < wStr.size(); ++i) { - if (!std::iswalnum(wStr[i])) { - if (cur.size()) ret.push_back(toNStr(cur)); - cur = L""; - continue; - } - cur += wStr[i]; - } - if (cur.size()) ret.push_back(toNStr(cur)); - - return ret; -} - -// _____________________________________________________________________________ -inline double jaccardSimi(const std::string& a, const std::string& b) { - if (a == b) return 1; - - std::set sa, sb; - - auto toksA = tokenize(a); - auto toksB = tokenize(b); - - // 0 if both are empty - if (toksA.size() == 0 && toksB.size() == 0) return 0; - - sa.insert(toksA.begin(), toksA.end()); - sb.insert(toksB.begin(), toksB.end()); - - std::set isect; - - std::set_intersection(sa.begin(), sa.end(), sb.begin(), sb.end(), - std::inserter(isect, isect.begin())); - - double sInter = isect.size(); - double s1 = sa.size(); - double s2 = sb.size(); - return sInter / (s1 + s2 - sInter); -} - -// _____________________________________________________________________________ -inline double btsSimiInner(const std::vector& toks, - const std::string& b, double best) { - std::set toksSet; - toksSet.insert(toks.begin(), toks.end()); - std::vector toksUniqSorted; - toksUniqSorted.insert(toksUniqSorted.begin(), toksSet.begin(), toksSet.end()); - - assert(toksUniqSorted.size() <= 8); - - for (uint8_t v = 1; v <= pow(2, toksUniqSorted.size()); v++) { - std::bitset<8> bs(v); - std::vector cur(bs.count()); - - size_t i = 0; - for (size_t j = 0; j < toksUniqSorted.size(); j++) { - if (bs[j]) { - cur[i] = toksUniqSorted[j]; - i++; - } - } - - double tmp = util::implode(cur, " ").size(); - - // ed between the two string will always be at least their length - // difference - if this is already too big, skip it right now - double dt = 1 - (fabs(tmp - b.size()) * 1.0) / (fmax(tmp, b.size()) * 1.0); - - if (dt <= best) continue; - - // cur is guaranteed to be sorted now - do { - const auto& comb = util::implode(cur, " "); - - double d = - 1 - ((editDist(comb, b) * 1.0) / (fmax(comb.size(), b.size()) * 1.0)); - - if (fabs(d - 1) < 0.0001) return 1; - - if (d > best) best = d; - } while (std::next_permutation(cur.begin(), cur.end())); - } - - return best; -} - -// _____________________________________________________________________________ -inline double btsSimi(std::string a, std::string b) { - // this follows the implementation for the station similarity paper in - // https://github.com/ad-freiburg/statsimi/ - if (a == b) return 1; - - std::set sa, sb; - - auto toksA = tokenize(a); - auto toksB = tokenize(b); - - // fallback to jaccard if the token set is too large - if (toksA.size() > 6 || toksB.size() > 6) { - return jaccardSimi(a, b); - } - - if (toksA.size() > toksB.size()) { - std::swap(a, b); - std::swap(toksA, toksB); - } - - // this is already our best known value - simply the edit - // distance similarity between the strings - double best = 1 - (editDist(a, b) * 1.0) / std::fmax(a.size(), b.size()); - - if (fabs(best) < 0.0001) return 0; - - best = btsSimiInner(toksA, b, best); - - if (fabs(best - 1) < 0.0001) return 1; - - return btsSimiInner(toksB, a, best); -} -} // namespace util - -#endif // UTIL_STRING_H_ diff --git a/src/util/geo/BezierCurve.h b/src/util/geo/BezierCurve.h deleted file mode 100644 index 23f3263..0000000 --- a/src/util/geo/BezierCurve.h +++ /dev/null @@ -1,55 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_GEO_BEZIERCURVE_H_ -#define UTIL_GEO_BEZIERCURVE_H_ - -#include -#include "util/geo/Geo.h" -#include "util/geo/PolyLine.h" - -namespace util { -namespace geo { - -struct CubicPolynom { - CubicPolynom(double a, double b, double c, double d, double x) - : a(a), b(b), c(c), d(d), x(x) {} - CubicPolynom() : a(0), b(0), c(0), d(0), x(0) {} - double a, b, c, d, x; - - double valueAt(double x) const; -}; - -/** - * Bezier curve - */ -template -class BezierCurve { - public: - BezierCurve(const Point& a, const Point& b, const Point& c, - const Point& d); - - const PolyLine& render(double d); - - private: - double _d; - - // the x and y polynoms for this spline - CubicPolynom _xp, _yp; - - // store the rendered polyline for quicker access - PolyLine _rendered; - bool _didRender; - - void recalcPolynoms(const Point& x, const Point& b, const Point& c, - const Point& d); - - Point valueAt(double t) const; -}; - -#include "util/geo/BezierCurve.tpp" -} -} - -#endif // UTIL_GEO_BEZIERCURVE_H_ diff --git a/src/util/geo/BezierCurve.tpp b/src/util/geo/BezierCurve.tpp deleted file mode 100644 index 4f08a31..0000000 --- a/src/util/geo/BezierCurve.tpp +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -// _____________________________________________________________________________ -template -BezierCurve::BezierCurve(const Point& a, const Point& b, - const Point& c, const Point& d) - : _d(dist(a, d)) { - assert(_d > 0); - recalcPolynoms(a, b, c, d); -} - -// _____________________________________________________________________________ -template -void BezierCurve::recalcPolynoms(const Point& a, const Point& b, - const Point& c, const Point& d) { - _xp.a = a.getX(); - _xp.b = 3.0 * (b.getX() - a.getX()); - _xp.c = 3.0 * (c.getX() - b.getX()) - _xp.b; - _xp.d = d.getX() - a.getX() - _xp.c - _xp.b; - - _yp.a = a.getY(); - _yp.b = 3.0 * (b.getY() - a.getY()); - _yp.c = 3.0 * (c.getY() - b.getY()) - _yp.b; - _yp.d = d.getY() - a.getY() - _yp.c - _yp.b; - - _didRender = false; -} - -// _____________________________________________________________________________ -template -Point BezierCurve::valueAt(double t) const { - return Point(_xp.valueAt(t), _yp.valueAt(t)); -} - -// _____________________________________________________________________________ -template -const PolyLine& BezierCurve::render(double d) { - assert(d > 0); - if (_didRender) return _rendered; - - if (_d == 0) { - _rendered << Point(_xp.a, _yp.a) << Point(_xp.a, _yp.a); - return _rendered; - } - - _rendered.empty(); - double n = _d / d, dt = 1 / n, t = 0; - - bool cancel = false; - while (true) { - _rendered << valueAt(t); - t += dt; - if (cancel) break; - if (t > 1) { - t = 1; - cancel = true; - } - } - - _didRender = true; - return _rendered; -} - -// _____________________________________________________________________________ -inline double CubicPolynom::valueAt(double atx) const { - double dx = atx - x; - return a + b * dx + c * dx * dx + d * dx * dx * dx; -} diff --git a/src/util/geo/Box.h b/src/util/geo/Box.h deleted file mode 100644 index 1415937..0000000 --- a/src/util/geo/Box.h +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Author: Patrick Brosi - -#ifndef UTIL_GEO_BOX_H_ -#define UTIL_GEO_BOX_H_ - -#include "./Point.h" - -namespace util { -namespace geo { - -template -class Box { - public: - // maximum inverse box as default value of box - Box() - : _ll(std::numeric_limits::max(), std::numeric_limits::max()), - _ur(std::numeric_limits::lowest(), std::numeric_limits::lowest()) {} - Box(const Point& ll, const Point& ur) : _ll(ll), _ur(ur) {} - const Point& getLowerLeft() const { return _ll; } - const Point& getUpperRight() const { return _ur; } - - Point& getLowerLeft() { return _ll; } - Point& getUpperRight() { return _ur; } - - Point getUpperLeft() { return {_ll.getX(), _ur.getY()}; } - Point getLowerRight() { return {_ur.getX(), _ll.getY()}; } - - void setLowerLeft(const Point& ll) { _ll = ll; } - void setUpperRight(const Point& ur) { _ur = ur; } - - bool operator==(const Box& b) const { - return getLowerLeft() == b.getLowerLeft() && - getUpperRight() == b.getUpperRight(); - } - - bool operator!=(const Box& p) const { return !(*this == p); } - - private: - Point _ll, _ur; -}; - -template -class RotatedBox { - public: - RotatedBox() : _box(), _deg(0), _center() {} - RotatedBox(const Box& box) - : _box(box), - _deg(0), - _center(Point( - (box.getUpperRight().getX() - box.getLowerLeft().getX()) / T(2), - (box.getUpperRight().getY() - box.getLowerLeft().getY()) / T(2))) {} - RotatedBox(const Point& ll, const Point& ur) - : _box(ll, ur), - _deg(0), - _center(Point((ur.getX() - ll.getX()) / T(2), - (ur.getY() - ll.getY()) / T(2))) {} - RotatedBox(const Box& box, double deg) - : _box(box), - _deg(deg), - _center(Point( - (box.getUpperRight().getX() - box.getLowerLeft().getX()) / T(2), - (box.getUpperRight().getY() - box.getLowerLeft().getY()) / T(2))) {} - RotatedBox(const Point& ll, const Point& ur, double deg) - : _box(ll, ur), - _deg(deg), - _center(Point((ur.getX() - ll.getX()) / T(2), - (ur.getY() - ll.getY()) / T(2))) {} - RotatedBox(const Box& box, double deg, const Point& center) - : _box(box), _deg(deg), _center(center) {} - RotatedBox(const Point& ll, const Point& ur, double deg, - const Point& center) - : _box(ll, ur), _deg(deg), _center(center) {} - - const Box& getBox() const { return _box; } - Box& getBox() { return _box; } - - double getDegree() const { return _deg; } - const Point& getCenter() const { return _center; } - Point& getCenter() { return _center; } - - void setDegree(double deg) { _deg = deg; } - - private: - Box _box; - double _deg; - Point _center; -}; - -} // namespace geo -} // namespace util - -#endif // UTIL_GEO_BOX_H_ diff --git a/src/util/geo/CircularSegment.h b/src/util/geo/CircularSegment.h deleted file mode 100644 index b80e60d..0000000 --- a/src/util/geo/CircularSegment.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_GEO_CIRCULARSEGMENT_H_ -#define UTIL_GEO_CIRCULARSEGMENT_H_ - -#include -#include "util/geo/Geo.h" -#include "util/geo/PolyLine.h" - -namespace util { -namespace geo { - -/** - * Circular segment - */ -template -class CircularSegment { - public: - CircularSegment(const Point& a, double ang, const Point& c); - - const PolyLine& render(double d); - - private: - // store the rendered polyline for quicker access - PolyLine _rendered; - - const Point& _a, _c; - double _renderD; - - double _ang, _rad, _s, _initAng; - - Point valueAt(double t) const; -}; - -#include "util/geo/CircularSegment.tpp" -} -} - -#endif // UTIL_GEO_BEZIERCURVE_H_ diff --git a/src/util/geo/CircularSegment.tpp b/src/util/geo/CircularSegment.tpp deleted file mode 100644 index 6058c68..0000000 --- a/src/util/geo/CircularSegment.tpp +++ /dev/null @@ -1,51 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -// _____________________________________________________________________________ -template -CircularSegment::CircularSegment(const Point& a, double ang, - const Point& c) : _a(a), _c(c), _renderD(0), _ang(ang) - { - - _rad = dist(a, c); - _s = fabs(_ang * _rad); - _initAng = angBetween(c, a); -} - -// _____________________________________________________________________________ -template -Point CircularSegment::valueAt(double ang) const { - double xPos = _c.getX() + _rad * cos(ang); - double yPos = _c.getY() + _rad * sin(ang); - return Point(xPos, yPos); -} - -// _____________________________________________________________________________ -template -const PolyLine& CircularSegment::render(double d) { - assert(d > 0); - if (fabs(d - _renderD) < 0.001) return _rendered; - _renderD = d; - - if (_s == 0) { - _rendered << _a << _a; - return _rendered; - } - - _rendered.empty(); - double n = _s / d, dt = 1 / n, t = 0; - - bool cancel = false; - while (true) { - _rendered << valueAt(_initAng + t * _ang); - t += dt; - if (cancel) break; - if (t > 1) { - t = 1; - cancel = true; - } - } - - return _rendered; -} diff --git a/src/util/geo/Geo.h b/src/util/geo/Geo.h deleted file mode 100644 index f431b8e..0000000 --- a/src/util/geo/Geo.h +++ /dev/null @@ -1,2339 +0,0 @@ -// Copyright 2016, University of Freiburg, -// Chair of Algorithms and Data Structures. -// Authors: Patrick Brosi - -#ifndef UTIL_GEO_GEO_H_ -#define UTIL_GEO_GEO_H_ - -#define _USE_MATH_DEFINES - -#include -#include -#include -#include -#include -#include -#include -#include "util/Misc.h" -#include "util/String.h" -#include "util/geo/Box.h" -#include "util/geo/Line.h" -#include "util/geo/Point.h" -#include "util/geo/Polygon.h" - -// ------------------- -// Geometry stuff -// ------------------ - -namespace util { -namespace geo { - -// convenience aliases - -typedef Point DPoint; -typedef Point FPoint; -typedef Point IPoint; - -typedef LineSegment DLineSegment; -typedef LineSegment FLineSegment; -typedef LineSegment ILineSegment; - -typedef Line DLine; -typedef Line FLine; -typedef Line ILine; - -typedef Box DBox; -typedef Box FBox; -typedef Box IBox; - -typedef Polygon DPolygon; -typedef Polygon FPolygon; -typedef Polygon IPolygon; - -const static double EPSILON = 0.00001; -const static double RAD = 0.017453292519943295; // PI/180 -const static double IRAD = 180.0 / M_PI; // 180 / PI -const static double AVERAGING_STEP = 20; - -const static double M_PER_DEG = 111319.4; - -// _____________________________________________________________________________ -template -inline Box pad(const Box& box, double padding) { - return Box(Point(box.getLowerLeft().getX() - padding, - box.getLowerLeft().getY() - padding), - Point(box.getUpperRight().getX() + padding, - box.getUpperRight().getY() + padding)); -} - -// _____________________________________________________________________________ -template -inline Point centroid(const Point p) { - return p; -} - -// _____________________________________________________________________________ -template -inline Point centroid(const LineSegment ls) { - return Point((ls.first.getX() + ls.second.getX()) / T(2), - (ls.first.getY() + ls.second.getY()) / T(2)); -} - -// _____________________________________________________________________________ -template -inline Point centroid(const Line ls) { - double x = 0, y = 0; - for (const auto& p : ls) { - x += p.getX(); - y += p.getY(); - } - return Point(x / T(ls.size()), y / T(ls.size())); -} - -// _____________________________________________________________________________ -template -inline Point centroid(const Polygon ls) { - return centroid(ls.getOuter()); -} - -// _____________________________________________________________________________ -template -inline Point centroid(const Box box) { - return centroid(LineSegment(box.getLowerLeft(), box.getUpperRight())); -} - -// _____________________________________________________________________________ -template class Geometry> -inline Point centroid(std::vector> multigeo) { - Line a; - for (const auto& g : multigeo) a.push_back(centroid(g)); - return centroid(a); -} - -// _____________________________________________________________________________ -template -inline Point rotate(const Point& p, double deg) { - UNUSED(deg); - return p; -} - -// _____________________________________________________________________________ -template -inline Point rotate(Point p, double deg, const Point& c) { - deg *= -RAD; - double si = sin(deg); - double co = cos(deg); - p = p - c; - - return Point(p.getX() * co - p.getY() * si, - p.getX() * si + p.getY() * co) + - c; -} - -// _____________________________________________________________________________ -template -inline LineSegment rotate(LineSegment geo, double deg, - const Point& c) { - geo.first = rotate(geo.first, deg, c); - geo.second = rotate(geo.second, deg, c); - return geo; -} - -// _____________________________________________________________________________ -template -inline LineSegment rotate(LineSegment geo, double deg) { - return (geo, deg, centroid(geo)); -} - -// _____________________________________________________________________________ -template -inline Line rotate(Line geo, double deg, const Point& c) { - for (size_t i = 0; i < geo.size(); i++) geo[i] = rotate(geo[i], deg, c); - return geo; -} - -// _____________________________________________________________________________ -template -inline Polygon rotate(Polygon geo, double deg, const Point& c) { - for (size_t i = 0; i < geo.getOuter().size(); i++) - geo.getOuter()[i] = rotate(geo.getOuter()[i], deg, c); - return geo; -} - -// _____________________________________________________________________________ -template