From 320fe6c3780aabf40d1f3c6ebf736a3a51287c6d Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 3 Jul 2017 17:05:01 +1000 Subject: [PATCH 001/149] job/queue: add trivial job queuing system --- CMakeLists.txt | 3 + job/queue.cpp | 84 +++++++++++++++++++++++++ job/queue.hpp | 153 +++++++++++++++++++++++++++++++++++++++++++++ test/job/queue.cpp | 34 ++++++++++ 4 files changed, 274 insertions(+) create mode 100644 job/queue.cpp create mode 100644 job/queue.hpp create mode 100644 test/job/queue.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index dae941d7..f143c93a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -306,6 +306,8 @@ list ( io.hpp io.ipp iterator.hpp + job/queue.cpp + job/queue.hpp json/fwd.hpp json/except.cpp json/except.hpp @@ -481,6 +483,7 @@ if (TESTS) hton introspection iterator + job/queue json_types maths matrix diff --git a/job/queue.cpp b/job/queue.cpp new file mode 100644 index 00000000..97b0eee0 --- /dev/null +++ b/job/queue.cpp @@ -0,0 +1,84 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2017 Danny Robson + */ + +#include "./queue.hpp" + +#include + +using util::job::queue; + + +/////////////////////////////////////////////////////////////////////////////// +queue::queue (): + queue (std::thread::hardware_concurrency () ?: 1) +{ ; } + + +//----------------------------------------------------------------------------- +queue::queue (unsigned thread_count): + m_loop ([] (store &s) { + args obj; + + while (true) { + // acquire the work lock and see if we need to quit, continue, + // or sleep + std::unique_lock lk (s.mutex); + if (s.pending.empty ()) { + s.cv.wait (lk, [&] () { + return s.stopping.load () || !s.pending.empty (); + }); + } + + if (s.stopping.load ()) + break; + + // extract the arguments and forward them to the functor + obj = std::move (s.pending.front ()); + s.pending.pop_front (); + lk.unlock (); + s.cv.notify_one (); + + obj.function (obj); + } + }), + m_threads (thread_count) +{ + for (auto &t: m_threads) + t = std::thread (m_loop, std::ref (m_store)); +} + + +//----------------------------------------------------------------------------- +queue::~queue () +{ + // tell everyone we want to quit + { + std::lock_guard lk {m_store.mutex}; + m_store.stopping.store (true); + } + m_store.cv.notify_all (); + + // wait for everyone to tidy up. perhaps we'd like to use a timeout, but + // if things deadlock then it's the users fault currently. + std::for_each ( + std::begin (m_threads), + std::end (m_threads), + [] (auto &t) + { + t.join (); + }); +} + diff --git a/job/queue.hpp b/job/queue.hpp new file mode 100644 index 00000000..ad0432e4 --- /dev/null +++ b/job/queue.hpp @@ -0,0 +1,153 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2017 Danny Robson + */ + +#ifndef CRUFT_UTIL_JOB_QUEUE_HPP +#define CRUFT_UTIL_JOB_QUEUE_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +namespace util::job { + class queue { + public: + queue (); + queue (unsigned thread_count); + ~queue (); + + using cookie = int; + + template + cookie + submit (cookie &parent, Function&&, Args&&...); + + /// record a functor and a set of parameters to execute at some point + /// in the future by an arbitrary available thread. + template + cookie + submit (Function &&func, Args &&...params) + { + { + std::unique_lock lk (m_store.mutex); + m_store.pending.emplace_back ( + std::forward (func), + std::forward (params)... + ); + } + + m_store.cv.notify_one (); + + // TODO: return a useful identifier to allow waiting + return 0; + } + + void wait (cookie); + + // HACK: this doesn't actually implement a proper barrier and may not + // even guarantee that all jobs are flushed. it's provided to make + // some amount of testing slightly more convenient by draining most + // of the queue on demand. + void + flush (void) + { + // setup a cv and completion flag. this is a poor man's barrier. + std::mutex m; + std::unique_lock lk (m); + std::condition_variable cv; + std::atomic done = false; + + // submit a job to the back of the queue that sets the done flag + // and wakes us back up again. + submit ([&] (void) { + { + std::lock_guard _{m}; + done.store (true); + } + + cv.notify_one (); + }); + + // wait until the flag is set then exit. + do { + cv.wait (lk, [&] () { return done.load (); }); + } while (!done.load ()); + } + + private: + /// stores a functor and associated arguments in a fixed size buffer + /// for later execution. + /// + /// for ease of implementation the arguments are currently restricted + /// as follows: + /// * trivial types (memcpy'able) + /// * a fixed total maximum size of around one cache line + /// these limitations will be eliminated at some point in the future + /// + /// the user supplied functor is wrapped with our own that unpacks and + /// forwards the arguments from the data buffer. this function must + /// be passed a copy of the current arg object as the only argument. + struct args { + args () = default; + + template + args (Function &&func, Args&&...params) + { + using tuple_t = std::tuple; + static_assert ((std::is_trivial_v && ...)); + static_assert (sizeof (tuple_t) <= sizeof data); + + union { + decltype(data) *byte_ptr; + tuple_t *args_ptr; + }; + byte_ptr = &data; + *args_ptr = std::make_tuple (std::forward (params)...); + + function = [func] (args &base) { + std::apply (func, *reinterpret_cast (&base.data)); + }; + }; + + // GCC: switch to hardware_destructive_interference_size when it + // becomes available in libstdc++. Until then we use a sensible + // guess. + std::array data; + + std::function function; + }; + + struct store { + std::atomic stopping = false; + std::deque pending; + + std::condition_variable cv; + std::mutex mutex; + }; + + store m_store; + std::function m_loop; + std::vector m_threads; + }; +} + +#endif diff --git a/test/job/queue.cpp b/test/job/queue.cpp new file mode 100644 index 00000000..c17b5372 --- /dev/null +++ b/test/job/queue.cpp @@ -0,0 +1,34 @@ +#include "job/queue.hpp" +#include "tap.hpp" + +#include + +int +main (void) +{ + util::TAP::logger tap; + + // dispatch `INNER' simple jobs `OUTTER' times that simply increment an + // atomic variable and quit. this tests that all threads are created, + // executed, and finished. it's not definitive, but executing this many + // items this many times seems reasonably reliable in exposing deadlocks. + bool success = true; + constexpr int OUTTER = 16; + constexpr int INNER = 1024; + + for (auto i = 0; i < OUTTER && success; ++i) { + std::atomic count = 0; + + { + util::job::queue q {}; + for (int j = 0; j < INNER; ++j) + q.submit ([&count] () noexcept { ++count; }); + q.flush (); + } + + success = count == INNER && success; + } + + tap.expect (success, "trivial increment jobs"); + return tap.status (); +} \ No newline at end of file From 21f462d4a0a8623c0465908791c1106869ab8da3 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 4 Jul 2017 14:18:45 +1000 Subject: [PATCH 002/149] job/queue: don't use references for parameters references aren't trivial types. we should support them soon, but this gets us up and running faster. --- job/queue.hpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/job/queue.hpp b/job/queue.hpp index ad0432e4..ceac6986 100644 --- a/job/queue.hpp +++ b/job/queue.hpp @@ -93,6 +93,7 @@ namespace util::job { } while (!done.load ()); } + private: /// stores a functor and associated arguments in a fixed size buffer /// for later execution. @@ -112,8 +113,8 @@ namespace util::job { template args (Function &&func, Args&&...params) { - using tuple_t = std::tuple; - static_assert ((std::is_trivial_v && ...)); + using tuple_t = std::tuple...>; + static_assert ((std::is_trivial_v> && ...)); static_assert (sizeof (tuple_t) <= sizeof data); union { @@ -121,7 +122,7 @@ namespace util::job { tuple_t *args_ptr; }; byte_ptr = &data; - *args_ptr = std::make_tuple (std::forward (params)...); + *args_ptr = std::make_tuple (params...); function = [func] (args &base) { std::apply (func, *reinterpret_cast (&base.data)); From 564d6ab7532aea4c526e7e9a5fe0022760e32204 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 4 Jul 2017 14:20:51 +1000 Subject: [PATCH 003/149] cmake: bump for threading support --- cmake | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmake b/cmake index 06bb32ff..a1d3200f 160000 --- a/cmake +++ b/cmake @@ -1 +1 @@ -Subproject commit 06bb32ff00fc4b6d8581a2e91a17ddab5a1407d4 +Subproject commit a1d3200fde0923ace464ce711fc52d5b183e9e2d From 825102a328b95cbc6c66b5afabfc69504722bc6b Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 4 Jul 2017 16:18:57 +1000 Subject: [PATCH 004/149] extent: add convenience make_range iterator creator --- extent.hpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/extent.hpp b/extent.hpp index eeb804a6..be1c1113 100644 --- a/extent.hpp +++ b/extent.hpp @@ -73,7 +73,7 @@ namespace util { extent m_target; }; - extent_range (extent target); + explicit extent_range (extent target); iterator begin (void) const; iterator end (void) const; @@ -82,6 +82,13 @@ namespace util { extent m_target; }; + template + extent_range + make_range (extent e) + { + return extent_range {e}; + } + // convenience typedefs template using extent2 = extent<2,T>; template using extent3 = extent<3,T>; From af3dcbb41868d6381f63a5ca26596570b649c2b4 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 11 Jul 2017 11:06:59 +1000 Subject: [PATCH 005/149] tuple: make nullary 'ignore' inline works around multiple symbol definition errors at link time. --- tuple.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tuple.hpp b/tuple.hpp index b347e23b..0f05bca3 100644 --- a/tuple.hpp +++ b/tuple.hpp @@ -174,7 +174,7 @@ namespace util::tuple { /// it is guaranteed that this function will never be defined out in /// debug/release/whatever builds. so it is safe to use to guarantee /// parameter evaluation. - void + inline void ignore (void) { ; } From b9ca3f6969543a380705e9c4e9b7f6ad7adcf5b9 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 11 Jul 2017 11:07:48 +1000 Subject: [PATCH 006/149] tuple: add `index' type query for tuple types util::tuple::index finds the first occurence of a type in a tuple and gives the index of this type. --- tuple.hpp | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/tuple.hpp b/tuple.hpp index 0f05bca3..cd6260b4 100644 --- a/tuple.hpp +++ b/tuple.hpp @@ -185,7 +185,31 @@ namespace util::tuple { { ignore (std::forward (args)...); }; -} + + + /////////////////////////////////////////////////////////////////////////// + /// query the index of the first occurrence of type `T' in the tuple type + /// `TupleT'. + /// + /// if the query type does not occur in the tuple type a compiler error + /// should be generated. + template + struct index; + + + //------------------------------------------------------------------------- + template + struct index> { + static constexpr std::size_t value = 0; + }; + + + //------------------------------------------------------------------------- + template + struct index> { + static constexpr std::size_t value = 1 + index>::value; + }; +}; #endif From 3460d5edbe293664bfad2dd8ec977ea5a1effe41 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 11 Jul 2017 16:49:49 +1000 Subject: [PATCH 007/149] crypto/salsa: add initial skeleton for salsa20 --- CMakeLists.txt | 3 + crypto/salsa.cpp | 24 +++++ crypto/salsa.hpp | 86 ++++++++++++++++ test/crypto/salsa.cpp | 229 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 342 insertions(+) create mode 100644 crypto/salsa.cpp create mode 100644 crypto/salsa.hpp create mode 100644 test/crypto/salsa.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index f143c93a..4bad0e2d 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -199,6 +199,8 @@ list ( crypto/arc4.hpp crypto/ice.cpp crypto/ice.hpp + crypto/salsa.cpp + crypto/salsa.hpp crypto/tea.cpp crypto/tea.hpp crypto/xtea.cpp @@ -456,6 +458,7 @@ if (TESTS) coord crypto/arc4 crypto/ice + crypto/salsa crypto/tea crypto/xtea crypto/xxtea diff --git a/crypto/salsa.cpp b/crypto/salsa.cpp new file mode 100644 index 00000000..2cf5590b --- /dev/null +++ b/crypto/salsa.cpp @@ -0,0 +1,24 @@ +#include "./salsa.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +std::array +util::crypto::salsa20 (const std::array bytes) noexcept +{ + auto x = *reinterpret_cast*> (&bytes); + auto y = x; + + for (auto &t: x) + t = util::ltoh (t); + + for (int i = 0; i < 10; ++i) + x = salsa::doubleround (x); + + for (size_t i = 0; i < std::size (y); ++i) + x[i] += y[i]; + + for (auto &t: x) + t = util::htol (t); + + return *reinterpret_cast*> (&x); +} diff --git a/crypto/salsa.hpp b/crypto/salsa.hpp new file mode 100644 index 00000000..c8d81c64 --- /dev/null +++ b/crypto/salsa.hpp @@ -0,0 +1,86 @@ +#include +#include + +#include "../bitwise.hpp" +#include "../endian.hpp" + +namespace util::crypto::salsa { + + /////////////////////////////////////////////////////////////////////////// + constexpr + uint32_t + R (uint32_t a, uint32_t b, uint32_t c, uint32_t k) + { + return b ^ util::rotatel (a + c, k); + } + + + /////////////////////////////////////////////////////////////////////////// + constexpr + std::array + quarter (std::array y) noexcept + { + std::array z {}; + + z[1] = R (y[0], y[1], y[3], 7); + z[2] = R (z[1], y[2], y[0], 9); + z[3] = R (z[2], y[3], z[1], 13); + z[0] = R (z[3], y[0], z[2], 18); + + return z; + } + + + /////////////////////////////////////////////////////////////////////////// + constexpr + std::array + row (const std::array y) noexcept + { + const auto [z00, z01, z02, z03] = quarter ({y[ 0], y[ 1], y[ 2], y[ 3]}); + const auto [z05, z06, z07, z04] = quarter ({y[ 5], y[ 6], y[ 7], y[ 4]}); + const auto [z10, z11, z08, z09] = quarter ({y[10], y[11], y[ 8], y[ 9]}); + const auto [z15, z12, z13, z14] = quarter ({y[15], y[12], y[13], y[14]}); + + return { + z00, z01, z02, z03, + z04, z05, z06, z07, + z08, z09, z10, z11, + z12, z13, z14, z15 + }; + } + + + /////////////////////////////////////////////////////////////////////////// + constexpr + std::array + col (const std::array x) noexcept + { + const auto [y00, y04, y08, y12] = quarter ({x[ 0], x[ 4], x[ 8], x[12]}); + const auto [y05, y09, y13, y01] = quarter ({x[ 5], x[ 9], x[13], x[ 1]}); + const auto [y10, y14, y02, y06] = quarter ({x[10], x[14], x[ 2], x[ 6]}); + const auto [y15, y03, y07, y11] = quarter ({x[15], x[ 3], x[ 7], x[11]}); + + return { + y00, y01, y02, y03, + y04, y05, y06, y07, + y08, y09, y10, y11, + y12, y13, y14, y15, + }; + } + + + /////////////////////////////////////////////////////////////////////////// + constexpr + std::array + doubleround (const std::array x) noexcept + { + return row (col (x)); + } +} + + +namespace util::crypto { + /////////////////////////////////////////////////////////////////////////// + std::array + salsa20 (const std::array) noexcept; +} diff --git a/test/crypto/salsa.cpp b/test/crypto/salsa.cpp new file mode 100644 index 00000000..e3478be9 --- /dev/null +++ b/test/crypto/salsa.cpp @@ -0,0 +1,229 @@ +#include "crypto/salsa.hpp" + +#include "tap.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +void +test_quarter (util::TAP::logger &tap) +{ + static const struct { + std::array a, b; + } TESTS[] = { + { { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }, + { 0x00000000, 0x00000000, 0x00000000, 0x00000000 } }, + { { 0x00000001, 0x00000000, 0x00000000, 0x00000000 }, + { 0x08008145, 0x00000080, 0x00010200, 0x20500000 } }, + { { 0x00000000, 0x00000001, 0x00000000, 0x00000000 }, + { 0x88000100, 0x00000001, 0x00000200, 0x00402000 } }, + { { 0x00000000, 0x00000000, 0x00000001, 0x00000000 }, + { 0x80040000, 0x00000000, 0x00000001, 0x00002000 } }, + { { 0x00000000, 0x00000000, 0x00000000, 0x00000001 }, + { 0x00048044, 0x00000080, 0x00010000, 0x20100001 } }, + { { 0xe7e8c006, 0xc4f9417d, 0x6479b4b2, 0x68c67137 }, + { 0xe876d72b, 0x9361dfd5, 0xf1460244, 0x948541a3 } }, + { { 0xd3917c5b, 0x55f1c407, 0x52a58a7a, 0x8f887a3b }, + { 0x3e2f308c, 0xd90a8f36, 0x6ab2a923, 0x2883524c } }, + }; + + for (size_t i = 0; i < std::size (TESTS); ++i) + tap.expect_eq (util::crypto::salsa::quarter (TESTS[i].a), TESTS[i].b, "quarter %zu", i); +} + + +/////////////////////////////////////////////////////////////////////////////// +void +test_row (util::TAP::logger &tap) +{ + static const struct { + std::array a, b; + } TESTS[] = { + { { 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, }, + { 0x08008145, 0x00000080, 0x00010200, 0x20500000, + 0x20100001, 0x00048044, 0x00000080, 0x00010000, + 0x00000001, 0x00002000, 0x80040000, 0x00000000, + 0x00000001, 0x00000200, 0x00402000, 0x88000100, } + }, + { { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365, + 0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6, + 0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e, + 0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, }, + { 0xa890d39d, 0x65d71596, 0xe9487daa, 0xc8ca6a86, + 0x949d2192, 0x764b7754, 0xe408d9b9, 0x7a41b4d1, + 0x3402e183, 0x3c3af432, 0x50669f96, 0xd89ef0a8, + 0x0040ede5, 0xb545fbce, 0xd257ed4f, 0x1818882d, }, + } + }; + + for (size_t i = 0; i < std::size (TESTS); ++i) + tap.expect_eq (util::crypto::salsa::row (TESTS[i].a), TESTS[i].b, "row %zu", i); +} + + +/////////////////////////////////////////////////////////////////////////////// +void +test_col (util::TAP::logger &tap) +{ + static const struct { + std::array a, b; + } TESTS[] = { + { { 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000001, 0x00000000, 0x00000000, 0x00000000, }, + { 0x10090288, 0x00000000, 0x00000000, 0x00000000, + 0x00000101, 0x00000000, 0x00000000, 0x00000000, + 0x00020401, 0x00000000, 0x00000000, 0x00000000, + 0x40a04001, 0x00000000, 0x00000000, 0x00000000, } }, + { { 0x08521bd6, 0x1fe88837, 0xbb2aa576, 0x3aa26365, + 0xc54c6a5b, 0x2fc74c2f, 0x6dd39cc3, 0xda0a64f6, + 0x90a2f23d, 0x067f95a6, 0x06b35f61, 0x41e4732e, + 0xe859c100, 0xea4d84b7, 0x0f619bff, 0xbc6e965a, }, + { 0x8c9d190a, 0xce8e4c90, 0x1ef8e9d3, 0x1326a71a, + 0x90a20123, 0xead3c4f3, 0x63a091a0, 0xf0708d69, + 0x789b010c, 0xd195a681, 0xeb7d5504, 0xa774135c, + 0x481c2027, 0x53a8e4b5, 0x4c1f89c5, 0x3f78c9c8, } }, + }; + + for (size_t i = 0; i < std::size (TESTS); ++i) + tap.expect_eq (util::crypto::salsa::col (TESTS[i].a), TESTS[i].b, "col %zu", i); +} + + +/////////////////////////////////////////////////////////////////////////////// +void +test_doubleround (util::TAP::logger &tap) +{ + static const struct { + std::array a, b; + } TESTS[] = { + { { 0x00000001, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, + 0x00000000, 0x00000000, 0x00000000, 0x00000000, }, + { 0x8186a22d, 0x0040a284, 0x82479210, 0x06929051, + 0x08000090, 0x02402200, 0x00004000, 0x00800000, + 0x00010200, 0x20400000, 0x08008104, 0x00000000, + 0x20500000, 0xa0000040, 0x0008180a, 0x612a8020, } }, + { { 0xde501066, 0x6f9eb8f7, 0xe4fbbd9b, 0x454e3f57, + 0xb75540d3, 0x43e93a4c, 0x3a6f2aa0, 0x726d6b36, + 0x9243f484, 0x9145d1e8, 0x4fa9d247, 0xdc8dee11, + 0x054bf545, 0x254dd653, 0xd9421b6d, 0x67b276c1, }, + { 0xccaaf672, 0x23d960f7, 0x9153e63a, 0xcd9a60d0, + 0x50440492, 0xf07cad19, 0xae344aa0, 0xdf4cfdfc, + 0xca531c29, 0x8e7943db, 0xac1680cd, 0xd503ca00, + 0xa74b2ad6, 0xbc331c5c, 0x1dda24c7, 0xee928277, } } + }; + + for (size_t i = 0; i < std::size (TESTS); ++i) + tap.expect_eq (util::crypto::salsa::doubleround (TESTS[i].a), TESTS[i].b, "doubleround %zu", i); +} + + +/////////////////////////////////////////////////////////////////////////////// +void +test_salsa20 (util::TAP::logger &tap) +{ + static const struct { + std::array a, b; + } TESTS[] = { + { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, + { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }, + + { { 0xd3, 0x9f, 0x0d, 0x73, 0x4c, 0x37, 0x52, 0xb7, + 0x03, 0x75, 0xde, 0x25, 0xbf, 0xbb, 0xea, 0x88, + 0x31, 0xed, 0xb3, 0x30, 0x01, 0x6a, 0xb2, 0xdb, + 0xaf, 0xc7, 0xa6, 0x30, 0x56, 0x10, 0xb3, 0xcf, + 0x1f, 0xf0, 0x20, 0x3f, 0x0f, 0x53, 0x5d, 0xa1, + 0x74, 0x93, 0x30, 0x71, 0xee, 0x37, 0xcc, 0x24, + 0x4f, 0xc9, 0xeb, 0x4f, 0x03, 0x51, 0x9c, 0x2f, + 0xcb, 0x1a, 0xf4, 0xf3, 0x58, 0x76, 0x68, 0x36 }, + { 0x6d, 0x2a, 0xb2, 0xa8, 0x9c, 0xf0, 0xf8, 0xee, + 0xa8, 0xc4, 0xbe, 0xcb, 0x1a, 0x6e, 0xaa, 0x9a, + 0x1d, 0x1d, 0x96, 0x1a, 0x96, 0x1e, 0xeb, 0xf9, + 0xbe, 0xa3, 0xfb, 0x30, 0x45, 0x90, 0x33, 0x39, + 0x76, 0x28, 0x98, 0x9d, 0xb4, 0x39, 0x1b, 0x5e, + 0x6b, 0x2a, 0xec, 0x23, 0x1b, 0x6f, 0x72, 0x72, + 0xdb, 0xec, 0xe8, 0x87, 0x6f, 0x9b, 0x6e, 0x12, + 0x18, 0xe8, 0x5f, 0x9e, 0xb3, 0x13, 0x30, 0xca } }, + + { { 0x58, 0x76, 0x68, 0x36, 0x4f, 0xc9, 0xeb, 0x4f, + 0x03, 0x51, 0x9c, 0x2f, 0xcb, 0x1a, 0xf4, 0xf3, + 0xbf, 0xbb, 0xea, 0x88, 0xd3, 0x9f, 0x0d, 0x73, + 0x4c, 0x37, 0x52, 0xb7, 0x03, 0x75, 0xde, 0x25, + 0x56, 0x10, 0xb3, 0xcf, 0x31, 0xed, 0xb3, 0x30, + 0x01, 0x6a, 0xb2, 0xdb, 0xaf, 0xc7, 0xa6, 0x30, + 0xee, 0x37, 0xcc, 0x24, 0x1f, 0xf0, 0x20, 0x3f, + 0x0f, 0x53, 0x5d, 0xa1, 0x74, 0x93, 0x30, 0x71 }, + { 0xb3, 0x13, 0x30, 0xca, 0xdb, 0xec, 0xe8, 0x87, + 0x6f, 0x9b, 0x6e, 0x12, 0x18, 0xe8, 0x5f, 0x9e, + 0x1a, 0x6e, 0xaa, 0x9a, 0x6d, 0x2a, 0xb2, 0xa8, + 0x9c, 0xf0, 0xf8, 0xee, 0xa8, 0xc4, 0xbe, 0xcb, + 0x45, 0x90, 0x33, 0x39, 0x1d, 0x1d, 0x96, 0x1a, + 0x96, 0x1e, 0xeb, 0xf9, 0xbe, 0xa3, 0xfb, 0x30, + 0x1b, 0x6f, 0x72, 0x72, 0x76, 0x28, 0x98, 0x9d, + 0xb4, 0x39, 0x1b, 0x5e, 0x6b, 0x2a, 0xec, 0x23 } } + }; + + for (size_t i = 0; i < std::size (TESTS); ++i) + tap.expect_eq (util::crypto::salsa20 (TESTS[i].a), TESTS[i].b, "salsa20 %zu", i); + + struct { + std::array a, b; + } million = { + { 0x06, 0x7c, 0x53, 0x92, 0x26, 0xbf, 0x09, 0x32, + 0x04, 0xa1, 0x2f, 0xde, 0x7a, 0xb6, 0xdf, 0xb9, + 0x4b, 0x1b, 0x00, 0xd8, 0x10, 0x7a, 0x07, 0x59, + 0xa2, 0x68, 0x65, 0x93, 0xd5, 0x15, 0x36, 0x5f, + 0xe1, 0xfd, 0x8b, 0xb0, 0x69, 0x84, 0x17, 0x74, + 0x4c, 0x29, 0xb0, 0xcf, 0xdd, 0x22, 0x9d, 0x6c, + 0x5e, 0x5e, 0x63, 0x34, 0x5a, 0x75, 0x5b, 0xdc, + 0x92, 0xbe, 0xef, 0x8f, 0xc4, 0xb0, 0x82, 0xba }, + { 0x08, 0x12, 0x26, 0xc7, 0x77, 0x4c, 0xd7, 0x43, + 0xad, 0x7f, 0x90, 0xa2, 0x67, 0xd4, 0xb0, 0xd9, + 0xc0, 0x13, 0xe9, 0x21, 0x9f, 0xc5, 0x9a, 0xa0, + 0x80, 0xf3, 0xdb, 0x41, 0xab, 0x88, 0x87, 0xe1, + 0x7b, 0x0b, 0x44, 0x56, 0xed, 0x52, 0x14, 0x9b, + 0x85, 0xbd, 0x09, 0x53, 0xa7, 0x74, 0xc2, 0x4e, + 0x7a, 0x7f, 0xc3, 0xb9, 0xb9, 0xcc, 0xbc, 0x5a, + 0xf5, 0x09, 0xb7, 0xf8, 0xe2, 0x55, 0xf5, 0x68 } + }; + + for (int i = 0; i < 1'000'000; ++i) + million.a = util::crypto::salsa20 (million.a); + + tap.expect_eq (million.a, million.b, "salsa20 million"); +} + + +/////////////////////////////////////////////////////////////////////////////// +int +main (void) +{ + util::TAP::logger tap; + + test_quarter (tap); + test_row (tap); + test_col (tap); + test_doubleround (tap); + test_salsa20 (tap); + + return 0; +} From a27869d1c81f256136c58441134f36395e2d399d Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 19 Jul 2017 17:19:20 +1000 Subject: [PATCH 008/149] region: commenting and style for test cases --- test/region.cpp | 53 +++++++++++++++++++++++++++++++++---------------- 1 file changed, 36 insertions(+), 17 deletions(-) diff --git a/test/region.cpp b/test/region.cpp index 9f4a26d0..eb24e262 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -10,35 +10,54 @@ main (int, char **) { util::TAP::logger tap; + // check that two overlapping regions successfully test for intersection { - util::point2d ap { 32.7, -6.09703 }; - util::extent2d ae { 0.8, 2. }; + const util::point2d ap { 32.7, -6.09703 }; + const util::extent2d ae { 0.8, 2. }; + const util::region2d a (ap, ae); - util::point2d bp {33.5, -4.5}; - util::extent2d be { 0.5, 0.5 }; - - util::region2d a (ap, ae); - util::region2d b (bp, be); + const util::point2d bp {33.5, -4.5}; + const util::extent2d be { 0.5, 0.5 }; + const util::region2d b (bp, be); tap.expect (!a.intersects (b), "simple 2d intersection"); } - tap.expect (util::region2d::max ().intersects (util::region2d::unit ()), "maximal region2d intersection"); - tap.expect (util::region2f::max ().intersects (util::region2f::unit ()), "maximal region2f intersection"); + // check various floating point maximums successfully test for + // intersection. the concern is that infinities are incorrectly handled + // in some comparisons. + tap.expect ( + util::region2d::max ().intersects ( + util::region2d::unit () + ), + "maximal region2d intersection" + ); + tap.expect ( + util::region2f::max ().intersects ( + util::region2f::unit () + ), + "maximal region2f intersection" + ); + + // ensure unit regions are... unit sized... tap.expect_eq (util::region2d::unit ().area (), 1.0, "unit region2d area"); tap.expect_eq (util::region2f::unit ().area (), 1.0f, "unit region2f area"); - util::point2u p0 { 0 }; - util::extent2u e0 { 2 }; + // test boundary cases of includes and contains + { + const util::point2u p0 { 0 }; + const util::extent2u e0 { 2 }; + const util::region2u r {p0, e0}; - tap.expect (util::region2u (p0, e0).includes (util::point2u {1, 1}), "unsigned region centre inclusion"); - tap.expect (util::region2u (p0, e0).includes (util::point2u {0, 0}), "unsigned region base inclusion"); - tap.expect (util::region2u (p0, e0).includes (util::point2u {2, 2}), "unsigned region corner inclusion"); + tap.expect (r.includes (util::point2u {1, 1}), "unsigned region centre inclusion"); + tap.expect (r.includes (util::point2u {0, 0}), "unsigned region base inclusion"); + tap.expect (r.includes (util::point2u {2, 2}), "unsigned region corner inclusion"); - tap.expect ( util::region2u (p0, e0).contains (util::point2u {1, 1}), "unsigned region center contains"); - tap.expect (!util::region2u (p0, e0).contains (util::point2u {0, 0}), "unsigned region base contains"); - tap.expect (!util::region2u (p0, e0).contains (util::point2u {2, 2}), "unsigned region corner contains"); + tap.expect ( r.contains (util::point2u {1, 1}), "unsigned region center contains"); + tap.expect (!r.contains (util::point2u {0, 0}), "unsigned region base contains"); + tap.expect (!r.contains (util::point2u {2, 2}), "unsigned region corner contains"); + } //CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01))); //CHECK (region<2,intmax_t> (0, 0, 10, 10).contains (point2d (0.4, 0.01))); From db5795c25a01ef9f903b223127eb50ca0aa5b41a Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 19 Jul 2017 17:19:37 +1000 Subject: [PATCH 009/149] region: remove array constructor the meaning of the array values weren't particularly clear. are they point-point, point-extent, something else? also the implementation was horribly incorrect for whatever it claimed to be doing. so we remove the function entirely to avoid the aforementioned ambiguity. --- region.cpp | 9 --------- region.hpp | 1 - 2 files changed, 10 deletions(-) diff --git a/region.cpp b/region.cpp index df6b3a5b..3c6c9e6f 100644 --- a/region.cpp +++ b/region.cpp @@ -54,15 +54,6 @@ util::region::region (point_t _a, } -//----------------------------------------------------------------------------- -template -util::region::region (std::array args) -{ - std::copy (&args[0], &args[S], p.data); - std::copy (&args[S], &args[S*2], e.data); -} - - //----------------------------------------------------------------------------- template T diff --git a/region.hpp b/region.hpp index b707a2bd..46c6580d 100644 --- a/region.hpp +++ b/region.hpp @@ -48,7 +48,6 @@ namespace util { explicit region (extent_t); region (point_t, extent_t); region (point_t, point_t); - explicit region (std::array); //--------------------------------------------------------------------- template From fcc78eb103365b68dfdef1fec792ba3e06c41f5a Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 19 Jul 2017 17:20:51 +1000 Subject: [PATCH 010/149] io_posix: style improve the code style for 80 column limitations --- io_posix.cpp | 4 +++- io_posix.hpp | 7 +++++-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/io_posix.cpp b/io_posix.cpp index f4b612d0..c4d8683a 100644 --- a/io_posix.cpp +++ b/io_posix.cpp @@ -27,7 +27,9 @@ using util::detail::posix::mapped_file; ////////////////////////////////////////////////////////////////////////////// -mapped_file::mapped_file (const std::experimental::filesystem::path &path, int fflags, int mflags): +mapped_file::mapped_file (const std::experimental::filesystem::path &path, + int fflags, + int mflags): mapped_file (util::posix::fd (path, fflags), mflags) { ; } diff --git a/io_posix.hpp b/io_posix.hpp index 0eae93eb..338f6b25 100644 --- a/io_posix.hpp +++ b/io_posix.hpp @@ -31,8 +31,11 @@ namespace util { namespace detail::posix { class mapped_file { public: - mapped_file (const std::experimental::filesystem::path&, int fflags = O_RDONLY | O_BINARY, int mflags = PROT_READ); - mapped_file (const util::posix::fd&, int mflags = PROT_READ); + mapped_file (const std::experimental::filesystem::path&, + int fflags = O_RDONLY | O_BINARY, + int mflags = PROT_READ); + mapped_file (const util::posix::fd&, + int mflags = PROT_READ); mapped_file (const mapped_file&) = delete; mapped_file& operator= (const mapped_file&) = delete; From b18feb8bc46e1c7a67a4bbee7104963997027180 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 25 Jul 2017 17:08:52 +1000 Subject: [PATCH 011/149] maths: use bit patterns for tests float values this makes some of the tests more robust in the face of (potentially stanard breaking) optimisations. --- test/maths.cpp | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/test/maths.cpp b/test/maths.cpp index d7572f5d..be27388a 100644 --- a/test/maths.cpp +++ b/test/maths.cpp @@ -161,13 +161,17 @@ main (void) tap.expect_eq (util::pow2 (4u), 16u, "pow2"); - static const double POS_ZERO = 1.0 / numeric_limits::infinity (); - static const double NEG_ZERO = -1.0 / numeric_limits::infinity (); + static const float POS_ZERO = 1.f / numeric_limits::infinity (); + + union { + uint32_t neg_zero_bits = 0x80000000; + float NEG_ZERO; + }; tap.expect_eq (util::sign (-1), -1, "sign(-1)"); tap.expect_eq (util::sign ( 1), 1, "sign( 1)"); - tap.expect_eq (util::sign (POS_ZERO), 1., "sign (POS_ZERO)"); - tap.expect_eq (util::sign (NEG_ZERO), -1., "sign (NEG_ZERO)"); + tap.expect_eq (util::sign (POS_ZERO), 1.f, "sign (POS_ZERO)"); + tap.expect_eq (util::sign (NEG_ZERO), -1.f, "sign (NEG_ZERO)"); tap.expect_eq (util::sign ( numeric_limits::infinity ()), 1., "sign +inf"); tap.expect_eq (util::sign (-numeric_limits::infinity ()), -1., "sign -inf"); From d29276a427ab6323bb1f9e5994b32e4ec2f25785 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 25 Jul 2017 17:10:16 +1000 Subject: [PATCH 012/149] region: add "has" point query --- region.cpp | 9 +++++++++ region.hpp | 1 + test/region.cpp | 4 ++++ 3 files changed, 14 insertions(+) diff --git a/region.cpp b/region.cpp index 3c6c9e6f..1919db23 100644 --- a/region.cpp +++ b/region.cpp @@ -180,6 +180,15 @@ util::region::contains (point_t q) const } +//----------------------------------------------------------------------------- +template +bool +util::region::has (const point_t q) const noexcept +{ + return all (q >= p) && all (q < p + e); +} + + //----------------------------------------------------------------------------- // FIXME: This will fail with an actual infinite range (NaNs will be generated // in the conditionals). diff --git a/region.hpp b/region.hpp index 46c6580d..906a0db5 100644 --- a/region.hpp +++ b/region.hpp @@ -74,6 +74,7 @@ namespace util { bool includes (point_t) const; // inclusive of borders bool contains (point_t) const; // exclusive of borders bool intersects (region) const; // exclusive of borders + bool has (point_t) const noexcept; // inclusive of top and left borders // Move a point to be within the region bounds void constrain (point_t&) const; diff --git a/test/region.cpp b/test/region.cpp index eb24e262..3c54a408 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -57,6 +57,10 @@ main (int, char **) tap.expect ( r.contains (util::point2u {1, 1}), "unsigned region center contains"); tap.expect (!r.contains (util::point2u {0, 0}), "unsigned region base contains"); tap.expect (!r.contains (util::point2u {2, 2}), "unsigned region corner contains"); + + tap.expect ( r.has (util::point2u {1, 1}), "unsigned region centre has"); + tap.expect ( r.has (util::point2u {1, 1}), "unsigned region base has"); + tap.expect (!r.has (util::point2u {2, 2}), "unsigned region corner has"); } //CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01))); From f39f7d73623fdc7dcf4ebf414cf5bf23e6151eac Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 26 Jul 2017 15:25:29 +1000 Subject: [PATCH 013/149] parse: add throwing native type parsers --- CMakeLists.txt | 3 ++ parse.cpp | 86 ++++++++++++++++++++++++++++++++++++++++++++++++++ parse.hpp | 53 +++++++++++++++++++++++++++++++ test/parse.cpp | 18 +++++++++++ 4 files changed, 160 insertions(+) create mode 100644 parse.cpp create mode 100644 parse.hpp create mode 100644 test/parse.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index 4bad0e2d..1e565610 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -334,6 +334,8 @@ list ( memory/deleter.cpp memory/deleter.hpp nocopy.hpp + parse.cpp + parse.hpp pascal.cpp pascal.hpp platform.hpp @@ -491,6 +493,7 @@ if (TESTS) maths matrix memory/deleter + parse point polynomial pool diff --git a/parse.cpp b/parse.cpp new file mode 100644 index 00000000..fcd2036d --- /dev/null +++ b/parse.cpp @@ -0,0 +1,86 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2017 Danny Robson + */ + +#include "./parse.hpp" + +#include +#include + +using util::parse; + +/////////////////////////////////////////////////////////////////////////////// +template struct c_traits; +template <> struct c_traits { static constexpr auto func = strtol; }; +template <> struct c_traits { static constexpr auto func = strtoll; }; +template <> struct c_traits { static constexpr auto func = strtoul; }; +template <> struct c_traits { static constexpr auto func = strtoull; }; + +template <> struct c_traits { static constexpr auto func = strtof; }; +template <> struct c_traits { static constexpr auto func = strtod; }; +template <> struct c_traits { static constexpr auto func = strtold; }; + + +//----------------------------------------------------------------------------- +template +T +c_iparse (const char *first, const char *last) +{ + auto tail = const_cast (last); + auto val = c_traits::func (first, &tail, 0); + + if (tail != last) + throw std::invalid_argument ("unable to parse"); + + return val; +} + + +//----------------------------------------------------------------------------- +template +T +c_fparse (const char *first, const char *last) +{ + auto tail = const_cast (last); + auto val = c_traits::func (first, &tail); + + if (tail != last) + throw std::invalid_argument ("unable to parse"); + + return val; +} + + + + +/////////////////////////////////////////////////////////////////////////////// +#define C_PARSE(T, KLASS) \ +template <> \ +T \ +util::parse (const char *first, const char *last) \ +{ \ + return c_ ## KLASS ## parse (first, last); \ +} + + +//----------------------------------------------------------------------------- +C_PARSE(long, i) +C_PARSE(long long, i) +C_PARSE(unsigned long, i) +C_PARSE(unsigned long long, i) + +C_PARSE(float, f) +C_PARSE(double, f) +C_PARSE(long double, f) diff --git a/parse.hpp b/parse.hpp new file mode 100644 index 00000000..b03b5ee1 --- /dev/null +++ b/parse.hpp @@ -0,0 +1,53 @@ +/* + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + * Copyright 2017 Danny Robson + */ + +#ifndef CRUFT_UTIL_PARSE_HPP +#define CRUFT_UTIL_PARSE_HPP + +#include +#include +#include + + +namespace util { + /////////////////////////////////////////////////////////////////////////// + /// extracts an instance of a native type T from the string [first, last). + /// + /// throws std::invalid_argument when the type cannot be parsed. + template + T + parse (const char *first, const char *last); + + + //------------------------------------------------------------------------- + template + T + parse (const char *str) + { + return parse (str, str + strlen (str)); + } + + + //------------------------------------------------------------------------- + template + T + parse (const std::string &str) + { + return parse (std::cbegin (str), std::cend (str)); + } +} + +#endif diff --git a/test/parse.cpp b/test/parse.cpp new file mode 100644 index 00000000..733e40af --- /dev/null +++ b/test/parse.cpp @@ -0,0 +1,18 @@ +#include "parse.hpp" +#include "tap.hpp" + + +/////////////////////////////////////////////////////////////////////////////// +int +main (void) +{ + util::TAP::logger tap; + + tap.expect_eq (util::parse ("1"), 1L, "parsing long '1'"); + tap.expect_throw ([] () { util::parse ("a"); }, "parsing long 'a'"); + + tap.expect_eq (util::parse ("1"), 1.f, "parsing float '1'"); + tap.expect_throw ([] () { util::parse ("a"); }, "parsing float 'a'"); + + return tap.status (); +} \ No newline at end of file From bdd2e060447bd0e4dba8e5079432d3b334fb1c90 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 28 Jul 2017 14:14:08 +1000 Subject: [PATCH 014/149] extent: add make_extent call we use this until template constructor guides are available in our supported compilers --- extent.hpp | 34 +++++++++++++++++++++++++++++++++- 1 file changed, 33 insertions(+), 1 deletion(-) diff --git a/extent.hpp b/extent.hpp index be1c1113..e972742a 100644 --- a/extent.hpp +++ b/extent.hpp @@ -82,6 +82,32 @@ namespace util { extent m_target; }; + + /// create an extent from supplied arguments, optionally specifying the + /// underlying type. + /// + /// much like experimental::make_array we use a void type to signal we + /// need to deduce the underlying type. + template < + typename _T = void, + typename ...Args + > + auto + make_extent (Args &&...args) + { + using T = std::conditional_t< + std::is_void_v<_T>, + std::common_type_t, + _T + >; + + return extent { + std::forward (args)... + }; + } + + + /////////////////////////////////////////////////////////////////////////// template extent_range make_range (extent e) @@ -89,6 +115,8 @@ namespace util { return extent_range {e}; } + + /////////////////////////////////////////////////////////////////////////// // convenience typedefs template using extent2 = extent<2,T>; template using extent3 = extent<3,T>; @@ -98,20 +126,24 @@ namespace util { template using extentf = extent; template using extentd = extent; + typedef extent2 extent2i; typedef extent2 extent2u; typedef extent2 extent2f; typedef extent2 extent2d; + typedef extent3 extent3u; typedef extent3 extent3f; + + //------------------------------------------------------------------------- template using extent_range2 = extent_range<2,T>; template using extent_range3 = extent_range<3,T>; + using extent_range2u = extent_range2; using extent_range2i = extent_range2; - using extent_range3u = extent_range2; } From 1f337ef964dd8f9480f557f4b69e45fe2888cf54 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 28 Jul 2017 14:22:21 +1000 Subject: [PATCH 015/149] point: add min/max convenience methods these create the smallest/largest expressible coordinates --- point.hpp | 21 ++++++++++++++++++++- 1 file changed, 20 insertions(+), 1 deletion(-) diff --git a/point.hpp b/point.hpp index 3bc78d59..31c65c90 100644 --- a/point.hpp +++ b/point.hpp @@ -37,8 +37,27 @@ namespace util { template point homog (void) const; - static constexpr point origin (void); + /////////////////////////////////////////////////////////////////////// + static constexpr + auto min (void) + { + return point { std::numeric_limits::lowest () }; + } + //------------------------------------------------------------------- + static constexpr + auto max (void) + { + return point { std::numeric_limits::max () }; + } + + + //------------------------------------------------------------------- + static constexpr + point origin (void); + + + /////////////////////////////////////////////////////////////////////// void sanity (void) const; }; From 1248f15e4ff1be78562945654dcf03b040e950d8 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 28 Jul 2017 14:23:20 +1000 Subject: [PATCH 016/149] region: relax assertion to allow zero width/height some degenerate cases create regions of zero area, but non-zero dimensions. eg, vertical linear bezier curves. --- region.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/region.cpp b/region.cpp index 1919db23..2a7cafe0 100644 --- a/region.cpp +++ b/region.cpp @@ -50,6 +50,11 @@ util::region::region (point_t _a, point_t _b): region (_a, extent_t { _b - _a }) { + // This check must allow for zero area (but non-zero dimension) regions. + // Some code paths need to support this degenerate case. It's ugly but + // simplifies generalisation. eg, vertical linear bezier curves. + CHECK (all (_a <= _b)); + debug::sanity (*this); } From e5090ff91617eb9f8d7bec8d0058edbda88d56d1 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 28 Jul 2017 14:26:49 +1000 Subject: [PATCH 017/149] view: add 'data' accessor call added for completeness sake. users can now call std::begin/std::end/std::data --- view.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/view.hpp b/view.hpp index 4072e598..00fa5b83 100644 --- a/view.hpp +++ b/view.hpp @@ -45,6 +45,9 @@ namespace util { constexpr const T& cbegin (void) const noexcept; constexpr const T& cend (void) const noexcept; + auto data (void) { return begin (); } + auto data (void) const { return begin (); } + constexpr T find (const value_type&) const noexcept; constexpr bool empty (void) const noexcept; From 2fad1715cf07fcbe5b2c25a20d7d87f9207f2cdc Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 28 Jul 2017 16:08:59 +1000 Subject: [PATCH 018/149] coord: define make_klass for all coordinate types --- coord/ops.hpp | 32 ++++++++++++++++++++++++++++++++ extent.hpp | 24 ------------------------ 2 files changed, 32 insertions(+), 24 deletions(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index 52cab527..fb2163b2 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -931,6 +931,38 @@ namespace util { static_assert (I < S); return k[I]; }; + + + /// create a coord from supplied arguments, optionally specifying the + /// underlying type. + /// + /// much like experimental::make_array we use a void type to signal we + /// need to deduce the underlying type. +#define MAKE_COORD(KLASS) \ + template < \ + typename _T = void, \ + typename ...Args \ + > \ + auto \ + make_##KLASS (Args &&...args) \ + { \ + using T = std::conditional_t< \ + std::is_void_v<_T>, \ + std::common_type_t, \ + _T \ + >; \ + \ + return KLASS { \ + std::forward (args)... \ + }; \ + } + + MAKE_COORD(extent) + MAKE_COORD(point) + MAKE_COORD(colour) + MAKE_COORD(vector) + +#undef MAKE_COORD } diff --git a/extent.hpp b/extent.hpp index e972742a..cde8c587 100644 --- a/extent.hpp +++ b/extent.hpp @@ -83,30 +83,6 @@ namespace util { }; - /// create an extent from supplied arguments, optionally specifying the - /// underlying type. - /// - /// much like experimental::make_array we use a void type to signal we - /// need to deduce the underlying type. - template < - typename _T = void, - typename ...Args - > - auto - make_extent (Args &&...args) - { - using T = std::conditional_t< - std::is_void_v<_T>, - std::common_type_t, - _T - >; - - return extent { - std::forward (args)... - }; - } - - /////////////////////////////////////////////////////////////////////////// template extent_range From 0016c83dab9b17ccb7cf5ca134672be398cc4700 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 31 Jul 2017 15:41:33 +1000 Subject: [PATCH 019/149] coord: add the select function --- coord/ops.hpp | 24 ++++++++++++++++++++++++ test/coord.cpp | 11 +++++++++++ 2 files changed, 35 insertions(+) diff --git a/coord/ops.hpp b/coord/ops.hpp index fb2163b2..925e8853 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -854,6 +854,30 @@ namespace util { } + ///------------------------------------------------------------------------ + /// returns an instance of K elementwise using a when s is true, and b + /// otherwise. ie, k[i] = s[i] ? a[i] : b[i]; + /// + /// corresponds to the function `select' from OpenCL. + template < + size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr + K + select (vector s, K a, K b) + { + K k {}; + for (size_t i = 0; i < S; ++i) + k[i] = s[i] ? a[i] : b[i]; + return k; + } + /////////////////////////////////////////////////////////////////////////// template < size_t S, diff --git a/test/coord.cpp b/test/coord.cpp index dfdfdb12..c25585ea 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -53,5 +53,16 @@ main (void) ); } + { + const util::point3f a { -1, 2, 0 }; + const util::point3f b { 1, 0, 2 }; + + const util::point3f lo { -1, 0, 0 }; + const util::point3f hi { 1, 2, 2 }; + + tap.expect_eq (select (a < b, a, b), lo, "select with points and min"); + tap.expect_eq (select (a > b, a, b), hi, "select with points and max"); + }; + return tap.status (); } From 01f6e5a1e8a1777bb3ef9c47e549e612f8d55fce Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 31 Jul 2017 15:42:05 +1000 Subject: [PATCH 020/149] region: add make_union function --- region.hpp | 13 +++++++++++++ test/region.cpp | 22 ++++++++++++++++++++++ 2 files changed, 35 insertions(+) diff --git a/region.hpp b/region.hpp index 906a0db5..684e1297 100644 --- a/region.hpp +++ b/region.hpp @@ -111,6 +111,19 @@ namespace util { void sanity (void) const; }; + + /////////////////////////////////////////////////////////////////////////// + /// constructs the minimal region that encompasses a region and a point. + template + region + make_union (region r, point p) + { + const auto p0 = select (r.p < p, r.p, p); + const auto p1 = select (r.away () > p, r.away (), p); + return { p0, p1 }; + } + + template using region2 = region<2,T>; template using region3 = region<3,T>; diff --git a/test/region.cpp b/test/region.cpp index 3c54a408..f15bc2eb 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -63,6 +63,28 @@ main (int, char **) tap.expect (!r.has (util::point2u {2, 2}), "unsigned region corner has"); } + // ensure make_union behaves as expected + { + const util::point2f p { -1 }; + const util::extent2f e { 2 }; + const util::region2f r { p, e }; + + tap.expect_eq (util::make_union (r, util::point2f { 0, 0 }), r, "identity union"); + tap.expect_eq ( + util::make_union (r, util::point2f { 2, 3 }), + util::region2f { p, util::extent2f { 3, 4 } }, + "positive expanding union" + ); + tap.expect_eq ( + util::make_union (r, util::point2f { -3, -2 }), + util::region2f { + util::point2f { -3, -2 }, + util::extent2f { 4, 3 } + }, + "negative expanding union" + ); + }; + //CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01))); //CHECK (region<2,intmax_t> (0, 0, 10, 10).contains (point2d (0.4, 0.01))); From 6c77393a2c49f98dfa42f0fa9c64ab31a87f9dd3 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 31 Jul 2017 16:16:54 +1000 Subject: [PATCH 021/149] coord: make min and max variadic --- coord/ops.hpp | 18 ++++++++++++------ 1 file changed, 12 insertions(+), 6 deletions(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index 925e8853..fe275f51 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -663,15 +663,18 @@ namespace util { template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename ...Args > constexpr K - min (K a, K b) + min (K a, K b, Args &&...args) { + static_assert ((... && std::is_same, std::decay_t>::value)); + K out {}; for (size_t i = 0; i < S; ++i) - out[i] = min (a[i], b[i]); + out[i] = min (a[i], b[i], args[i]...); return out; } @@ -684,15 +687,18 @@ namespace util { template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename ...Args > constexpr K - max (K a, K b) + max (K a, K b, Args &&...args) { + static_assert ((... && std::is_same, std::decay_t>::value)); + K out {}; for (size_t i = 0; i < S; ++i) - out[i] = max (a[i], b[i]); + out[i] = max (a[i], b[i], args[i]...); return out; } From 523c7c7e388ac71c62ce28f41e663f83857e1e54 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 1 Aug 2017 13:31:47 +1000 Subject: [PATCH 022/149] iterator: add the OutputIterator "discard_iterator" --- iterator.hpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/iterator.hpp b/iterator.hpp index c5bbde62..892ef45c 100644 --- a/iterator.hpp +++ b/iterator.hpp @@ -279,6 +279,22 @@ namespace util { data... ); } -} + + + /////////////////////////////////////////////////////////////////////////// + /// an output iterator that always discards any parameters on assignment. + /// + /// sometimes useful to pass to algorithms that generate useful results as + /// a return value, while not caring about the implicit OutputIterator + /// results. + struct discard_iterator : public std::iterator { + template + void operator= (const T&) { ; } + + discard_iterator& operator++ ( ) { return *this; } + discard_iterator operator++ (int) { return *this; } + discard_iterator& operator* ( ) { return *this; } + }; +}; #endif From eabf93bc2af6535d860f8ddeb93bc94fad3fc150 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 1 Aug 2017 14:16:55 +1000 Subject: [PATCH 023/149] view: remove ipp file in preference of inline code --- CMakeLists.txt | 1 - json/flat.cpp.rl | 3 +- json/schema.cpp | 3 +- string.cpp | 4 +- view.cpp | 1 + view.hpp | 130 +++++++++++++++++++----- view.ipp | 256 ----------------------------------------------- 7 files changed, 113 insertions(+), 285 deletions(-) delete mode 100644 view.ipp diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e565610..fbee8d3b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -417,7 +417,6 @@ list ( version.cpp version.hpp view.cpp - view.ipp view.hpp ) diff --git a/json/flat.cpp.rl b/json/flat.cpp.rl index bf577c3d..0ca04ba3 100644 --- a/json/flat.cpp.rl +++ b/json/flat.cpp.rl @@ -14,11 +14,12 @@ * You should have received a copy of the GNU General Public License * along with libgim. If not, see . * - * Copyright 2010-2015 Danny Robson + * Copyright 2010-2017 Danny Robson */ #include "json/flat.hpp" +#include "debug.hpp" #include "json/except.hpp" #include "preprocessor.hpp" diff --git a/json/schema.cpp b/json/schema.cpp index 172c1de6..d135ebb6 100644 --- a/json/schema.cpp +++ b/json/schema.cpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2017 Danny Robson */ #include "./schema.hpp" @@ -19,6 +19,7 @@ #include "./tree.hpp" #include "./except.hpp" +#include "../debug.hpp" #include "../io.hpp" #include "../maths.hpp" diff --git a/string.cpp b/string.cpp index 34423493..55ce664d 100644 --- a/string.cpp +++ b/string.cpp @@ -11,11 +11,13 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011-2016 Danny Robson + * Copyright 2011-2017 Danny Robson */ #include "./string.hpp" +#include "./debug.hpp" + #include #include #include diff --git a/view.cpp b/view.cpp index 40d011dd..11d60ed0 100644 --- a/view.cpp +++ b/view.cpp @@ -16,6 +16,7 @@ #include "./view.hpp" +#include #include diff --git a/view.hpp b/view.hpp index 00fa5b83..3b893c1e 100644 --- a/view.hpp +++ b/view.hpp @@ -23,6 +23,7 @@ #include #include #include +#include namespace util { template @@ -31,32 +32,80 @@ namespace util { using value_type = typename std::iterator_traits>::value_type; constexpr - view (T first, T last) noexcept; + view (T first, T last) noexcept: + m_begin (first), + m_end (last) + { ; } - template constexpr explicit view ( K &klass); - template constexpr explicit view (const K &klass); + template + constexpr explicit + view (K &klass): + m_begin (std::begin (klass)), + m_end (std::end (klass)) + { ; } - constexpr T& begin (void) noexcept; - constexpr T& end (void) noexcept; + template + constexpr explicit + view (const K &klass): + m_begin (std::begin (klass)), + m_end (std::end (klass)) + { ; } - constexpr const T& begin (void) const noexcept; - constexpr const T& end (void) const noexcept; + constexpr T& begin (void) noexcept { return m_begin; } + constexpr T& end (void) noexcept { return m_end; } - constexpr const T& cbegin (void) const noexcept; - constexpr const T& cend (void) const noexcept; + constexpr const T& begin (void) const noexcept { return cbegin (); } + constexpr const T& end (void) const noexcept { return cend (); } + + constexpr const T& cbegin (void) const noexcept { return m_begin; } + constexpr const T& cend (void) const noexcept { return m_end; } auto data (void) { return begin (); } auto data (void) const { return begin (); } - constexpr T find (const value_type&) const noexcept; + constexpr T + find (const value_type &v) const noexcept + { + for (T i = cbegin (); i != cend (); ++i) + if (*i == v) + return i; + return cend (); + } - constexpr bool empty (void) const noexcept; - constexpr size_t size (void) const noexcept; + constexpr bool + empty (void) const noexcept + { + return m_begin == m_end; + } - constexpr value_type& operator[] (size_t) noexcept; - constexpr const value_type& operator[] (size_t) const noexcept; + constexpr auto + size (void) const noexcept + { + return std::distance (m_begin, m_end); + } - bool operator== (view) const noexcept; + constexpr value_type& + operator[] (size_t idx) noexcept + { + auto it = begin (); + std::advance (it, idx); + return *it; + } + + constexpr const value_type& + operator[] (size_t idx) const noexcept + { + auto it = begin (); + std::advance (it, idx); + return *it; + } + + bool + operator== (const view &rhs) const noexcept + { + return rhs.m_begin == m_begin && + rhs.m_end == m_end; + } private: T m_begin; @@ -65,15 +114,24 @@ namespace util { template auto - make_view (const T (&)[N]); + make_view (const T (&arr)[N]) + { + return util::view (arr + 0, arr + N); + } template auto - make_view (T&); + make_view (T &t) + { + return util::view { std::begin (t), std::end (t) }; + } template auto - make_view (const T&); + make_view (const T &t) + { + return util::view { std::cbegin (t), std::cend (t) }; + } template auto @@ -81,7 +139,10 @@ namespace util { template auto - make_cview (const T&); + make_cview (const T &t) + { + return util::view { std::cbegin (t), std::cend (t) }; + } template auto @@ -98,16 +159,37 @@ namespace util { } // string conversions - view make_view (const char *str); - view make_view (char *str); + inline + view make_view (const char *str) + { + return { str, str + strlen (str) }; + } + + inline + view make_view (char *str) + { + return { str, str + strlen (str) }; + } template view - make_view (const std::basic_string&); + make_view (const std::basic_string &str) + { + return { + std::data (str), + std::data (str) + std::size (str) + }; + } template view - make_view (std::basic_string&); + make_view (std::basic_string &str) + { + return { + std::data (str), + std::data (str) + std::size (str) + }; + } template view @@ -136,6 +218,4 @@ namespace util { operator<< (std::ostream&, view); } -#include "./view.ipp" - #endif diff --git a/view.ipp b/view.ipp deleted file mode 100644 index dc42b71b..00000000 --- a/view.ipp +++ /dev/null @@ -1,256 +0,0 @@ -/* - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - * - * Copyright 2015 Danny Robson - */ - - -#ifdef __UTIL_VIEW_IPP -#error -#endif -#define __UTIL_VIEW_IPP - - -#include "./debug.hpp" -#include "./iterator.hpp" - - -/////////////////////////////////////////////////////////////////////////////// -template -constexpr -util::view::view (T _begin, T _end) noexcept: - m_begin (_begin), - m_end (_end) -{ ; } - - -//----------------------------------------------------------------------------- -template -template -constexpr -util::view::view (K &data): - m_begin (std::begin (data)), - m_end (std::end (data)) -{ ; } - - -//----------------------------------------------------------------------------- -template -template -constexpr -util::view::view (const K &data): - m_begin (std::begin (data)), - m_end (std::end (data)) -{ ; } - - -/////////////////////////////////////////////////////////////////////////////// -template -constexpr T& -util::view::begin (void) noexcept -{ - return m_begin; -} - - -//----------------------------------------------------------------------------- -template -constexpr T& -util::view::end (void) noexcept -{ - return m_end; -} - - -//----------------------------------------------------------------------------- -template -constexpr const T& -util::view::begin (void) const noexcept -{ - return cbegin (); -} - - -//----------------------------------------------------------------------------- -template -constexpr const T& -util::view::end (void) const noexcept -{ - return cend (); -} - - -//----------------------------------------------------------------------------- -template -constexpr const T& -util::view::cbegin (void) const noexcept -{ - return m_begin; -} - - -//----------------------------------------------------------------------------- -template -constexpr const T& -util::view::cend (void) const noexcept -{ - return m_end; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -constexpr T -util::view::find (const value_type &v) const noexcept -{ - for (T i = cbegin (); i != cend (); ++i) - if (*i == v) - return i; - return cend (); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -constexpr -bool -util::view::empty (void) const noexcept -{ - return m_begin == m_end; -} - - -//----------------------------------------------------------------------------- -template -constexpr -size_t -util::view::size (void) const noexcept -{ - return m_end - m_begin; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -constexpr -const typename util::view::value_type& -util::view::operator[] (size_t idx) const noexcept -{ - return m_begin[idx]; -} - - -//----------------------------------------------------------------------------- -template -constexpr -typename util::view::value_type& -util::view::operator[] (size_t idx) noexcept -{ - return m_begin[idx]; -} - - -/////////////////////////////////////////////////////////////////////////////// -template -bool -util::view::operator== (const view rhs) const noexcept -{ - return rhs.m_begin == m_begin && - rhs.m_end == m_end; -} - - -//----------------------------------------------------------------------------- -template -bool -util::operator!= (const view a, const view b) -{ - return !(a == b); -} - - -/////////////////////////////////////////////////////////////////////////////// -template -auto -util::make_view (const T (&arr)[N]) -{ - return util::view (arr + 0, arr + N); -} - - -//----------------------------------------------------------------------------- -template -auto -util::make_view (T &t) -{ - return util::view { std::begin (t), std::end (t) }; -} - - -//----------------------------------------------------------------------------- -template -auto -util::make_view (const T &t) -{ - return util::view { std::cbegin (t), std::cend (t) }; -} - - -//----------------------------------------------------------------------------- -template -auto -util::make_cview (const T &t) -{ - return util::view { std::cbegin (t), std::cend (t) }; -} - - -/////////////////////////////////////////////////////////////////////////////// -inline -util::view -util::make_view (const char *str) -{ - return { str, str + strlen (str) }; -} - -//----------------------------------------------------------------------------- -inline -util::view -util::make_view (char *str) -{ - return { str, str + strlen (str) }; -} - - -//----------------------------------------------------------------------------- -template -util::view -util::make_view (const std::basic_string &str) -{ - return { - std::data (str), - std::data (str) + std::size (str) - }; -} - - -//----------------------------------------------------------------------------- -template -util::view -util::make_view (std::basic_string &str) -{ - return { - std::data (str), - std::data (str) + std::size (str) - }; -} From 5634e59dc5d122215aad7aa22aa6042258411a10 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 1 Aug 2017 14:47:44 +1000 Subject: [PATCH 024/149] view: don't return references to iterators we emulate string_view behaviour. modifying our iterators behind our backs isn't a great way to ensure invariants are kept. --- view.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/view.hpp b/view.hpp index 3b893c1e..718a758f 100644 --- a/view.hpp +++ b/view.hpp @@ -51,14 +51,14 @@ namespace util { m_end (std::end (klass)) { ; } - constexpr T& begin (void) noexcept { return m_begin; } - constexpr T& end (void) noexcept { return m_end; } + constexpr T begin (void) noexcept { return m_begin; } + constexpr T end (void) noexcept { return m_end; } - constexpr const T& begin (void) const noexcept { return cbegin (); } - constexpr const T& end (void) const noexcept { return cend (); } + constexpr const T begin (void) const noexcept { return cbegin (); } + constexpr const T end (void) const noexcept { return cend (); } - constexpr const T& cbegin (void) const noexcept { return m_begin; } - constexpr const T& cend (void) const noexcept { return m_end; } + constexpr const T cbegin (void) const noexcept { return m_begin; } + constexpr const T cend (void) const noexcept { return m_end; } auto data (void) { return begin (); } auto data (void) const { return begin (); } From 2b3ef6dbc613a654a5439c5426664fd216edd5b8 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 2 Aug 2017 16:17:24 +1000 Subject: [PATCH 025/149] debug: correct CHECK_NEZ error message --- debug.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/debug.hpp b/debug.hpp index e111ce48..9e400b2d 100644 --- a/debug.hpp +++ b/debug.hpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2010-2015 Danny Robson + * Copyright 2010-2017 Danny Robson */ #ifndef __DEBUG_HPP @@ -222,7 +222,7 @@ DEBUG_ONLY ( \ const auto &__a = (A); \ if (::util::exactly_zero (__a)) \ - _CHECK_PANIC ("expected zero\n" \ + _CHECK_PANIC ("expected non-zero\n" \ "__a: %s is %!", \ #A, __a); \ ); \ From 96d621a4610469ebc769b5bed8e8ef55f50a5388 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 8 Aug 2017 13:54:45 +1000 Subject: [PATCH 026/149] signal: don't forward arguments we may reuse --- signal.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/signal.hpp b/signal.hpp index 17e7dfde..93da480e 100644 --- a/signal.hpp +++ b/signal.hpp @@ -32,7 +32,7 @@ namespace util { R operator() (T first, T last, Args&&... args) { while (first != last) - if (!(*first++)(std::forward (args)...)) + if (!(*first++)(args...)) return false; return true; @@ -47,7 +47,7 @@ namespace util { R operator() (T first, T last, Args&&... args) { while (first != last) - if ((*first++)(std::forward (args)...)) + if ((*first++)(args...)) return true; return false; @@ -62,7 +62,7 @@ namespace util { R operator() (T first, T last, Args&&... args) { while (first != last) { - (*first++)(std::forward (args)...); + (*first++)(args...); } } }; From 6ecab5b6d07929972e816b933c9acc4f6d8ee6aa Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 8 Aug 2017 13:55:06 +1000 Subject: [PATCH 027/149] signal: warn if discarding auto-disconnect cookies --- signal.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/signal.hpp b/signal.hpp index 93da480e..88d1dd5d 100644 --- a/signal.hpp +++ b/signal.hpp @@ -81,8 +81,8 @@ namespace util { ~signal (); /// Add a callback to list. - cookie connect (callback&&); - cookie connect (const callback&); + cookie connect [[gnu::warn_unused_result]] (callback&&); + cookie connect [[gnu::warn_unused_result]] (const callback&); void disconnect (cookie&); From ff5e6945e30cc36b67f2403bca0c70a57e8437a8 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 8 Aug 2017 13:55:20 +1000 Subject: [PATCH 028/149] signal: remove unused code --- signal.ipp | 18 +++++------------- 1 file changed, 5 insertions(+), 13 deletions(-) diff --git a/signal.ipp b/signal.ipp index 56f4e5e5..73cdef12 100644 --- a/signal.ipp +++ b/signal.ipp @@ -165,20 +165,12 @@ namespace util { if (m_children.empty ()) return R(); - //auto i = m_children.cbegin (); - //bool looping; - C combiner; - return combiner (m_children.begin (), m_children.end (), std::forward (tail)...); - - //do { - // // Increment before we execute so that the caller is able to - // // deregister themselves during execution. - // auto current = i++; - // looping = m_children.cend () != i; - - // (*current)(std::forward (tail)...); - //} while (looping); + return combiner ( + m_children.begin (), + m_children.end (), + std::forward (tail)... + ); } From fc41f0991d475d1c5d2a154f6f76b396c507fde6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 9 Aug 2017 17:17:55 +1000 Subject: [PATCH 029/149] region: add overload of inset for vectors --- region.cpp | 19 ++++++++++++++----- region.hpp | 3 ++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/region.cpp b/region.cpp index 2a7cafe0..13986dcd 100644 --- a/region.cpp +++ b/region.cpp @@ -262,14 +262,23 @@ util::region::resize (extent _e) //----------------------------------------------------------------------------- template util::region -util::region::inset (T mag) +util::region::inset (T mag) const { - // ensure we have enough space to inset - CHECK (min (e) >= 2 * mag); + return inset (util::vector {mag}); +} + + +//----------------------------------------------------------------------------- +template +util::region +util::region::inset (vector mag) const +{ + // ensure we have enough space to trim off our total extent + CHECK (all (e >= 2 * mag)); return { - p + mag, - e - static_cast (2 * mag) + p + mag, + e - T{2} * mag }; } diff --git a/region.hpp b/region.hpp index 684e1297..d5048f60 100644 --- a/region.hpp +++ b/region.hpp @@ -87,7 +87,8 @@ namespace util { region& resize (extent); // Compute a region `mag` units into the region - region inset (T mag); + region inset (T mag) const; + region inset (vector mag) const; region expanded (T mag) const; region expanded (vector) const; From b6edf25cd8401265a7ac77aa09de2095454d3d09 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 9 Aug 2017 17:27:28 +1000 Subject: [PATCH 030/149] region: remove the resize method we're moving away from mutating operators so this is somewhat out-of-place. it's not a huge functional change though as there are enough locations where the internal representation of point/extent are assumed that we just do it through the members. --- region.cpp | 9 --------- region.hpp | 2 -- 2 files changed, 11 deletions(-) diff --git a/region.cpp b/region.cpp index 13986dcd..9138dbe0 100644 --- a/region.cpp +++ b/region.cpp @@ -250,15 +250,6 @@ util::region::intersection (region rhs) const } -//----------------------------------------------------------------------------- -template -util::region& -util::region::resize (extent _e) -{ - e = _e; - return *this; -} - //----------------------------------------------------------------------------- template util::region diff --git a/region.hpp b/region.hpp index d5048f60..81ef39cc 100644 --- a/region.hpp +++ b/region.hpp @@ -84,8 +84,6 @@ namespace util { region intersection (region) const; //--------------------------------------------------------------------- - region& resize (extent); - // Compute a region `mag` units into the region region inset (T mag) const; region inset (vector mag) const; From 72f631ab4be17128fa94e40d61a3141ea916a7ae Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 9 Aug 2017 17:28:53 +1000 Subject: [PATCH 031/149] region: remove `expanded' function we're trying to move away from mutating operators. also, we do the bad thing of just renaming the non-mutating operator given it appears no one is using the mutating operator in our code bases anyway... --- region.cpp | 27 +++------------------------ region.hpp | 7 ++----- 2 files changed, 5 insertions(+), 29 deletions(-) diff --git a/region.cpp b/region.cpp index 9138dbe0..a39d49d9 100644 --- a/region.cpp +++ b/region.cpp @@ -274,31 +274,10 @@ util::region::inset (vector mag) const } -//----------------------------------------------------------------------------- -template -util::region& -util::region::expand (vector v) -{ - p -= v; - e += v * T{2}; - - return *this; -} - - -//----------------------------------------------------------------------------- -template -util::region& -util::region::expand (T mag) -{ - return expand (vector {mag}); -} - - //----------------------------------------------------------------------------- template util::region -util::region::expanded (vector v) const +util::region::expand (vector v) const { return { p - v, @@ -310,9 +289,9 @@ util::region::expanded (vector v) const //----------------------------------------------------------------------------- template util::region -util::region::expanded (T mag) const +util::region::expand (T mag) const { - return expanded (vector {mag}); + return expand (vector {mag}); } diff --git a/region.hpp b/region.hpp index 81ef39cc..379eefcc 100644 --- a/region.hpp +++ b/region.hpp @@ -88,11 +88,8 @@ namespace util { region inset (T mag) const; region inset (vector mag) const; - region expanded (T mag) const; - region expanded (vector) const; - - region& expand (T mag); - region& expand (vector); + region expand (T mag) const; + region expand (vector) const; // arithmetic operators region operator+ (vector) const; From f36a14973a259c9dd4e3a7f748b2779f2412a577 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 11 Aug 2017 14:39:46 +1000 Subject: [PATCH 032/149] region: add `encloses' test for subregions --- region.cpp | 9 +++++++++ region.hpp | 3 +++ 2 files changed, 12 insertions(+) diff --git a/region.cpp b/region.cpp index a39d49d9..164ddf14 100644 --- a/region.cpp +++ b/region.cpp @@ -252,6 +252,15 @@ util::region::intersection (region rhs) const //----------------------------------------------------------------------------- template +bool +util::region::encloses (const region r) const noexcept +{ + return all (p <= r.p) && all (p + e >= r.p + r.e); +} + + +/////////////////////////////////////////////////////////////////////////////// +template util::region util::region::inset (T mag) const { diff --git a/region.hpp b/region.hpp index 379eefcc..e052bc4b 100644 --- a/region.hpp +++ b/region.hpp @@ -83,6 +83,9 @@ namespace util { // Compute binary region combinations region intersection (region) const; + // Test if a region lies completely within our space + bool encloses (region) const noexcept; + //--------------------------------------------------------------------- // Compute a region `mag` units into the region region inset (T mag) const; From 31d2e6bfd8313505b26d1168942ee91d956381cb Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 11 Aug 2017 15:15:44 +1000 Subject: [PATCH 033/149] region: remove duplicate point/region coverage tests --- region.cpp | 52 +++++++++++++------------------------------------ region.hpp | 20 +++++++++---------- test/region.cpp | 21 ++++++++------------ 3 files changed, 31 insertions(+), 62 deletions(-) diff --git a/region.cpp b/region.cpp index 164ddf14..b71f3b59 100644 --- a/region.cpp +++ b/region.cpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2010-2016 Danny Robson + * Copyright 2010-2017 Danny Robson */ @@ -23,6 +23,8 @@ #include +using util::region; + //----------------------------------------------------------------------------- template @@ -159,41 +161,6 @@ util::region::closest (point_t q) const } -//----------------------------------------------------------------------------- -template -bool -util::region::includes (point_t q) const -{ - for (size_t i = 0; i < S; ++i) - if (q[i] < p[i] || q[i] > p[i] + e[i]) - return false; - - return true; -} - - -//----------------------------------------------------------------------------- -template -bool -util::region::contains (point_t q) const -{ - for (size_t i = 0; i < S; ++i) - if (q[i] <= p[i] || q[i] >= p[i] + e[i]) - return false; - - return true; -} - - -//----------------------------------------------------------------------------- -template -bool -util::region::has (const point_t q) const noexcept -{ - return all (q >= p) && all (q < p + e); -} - - //----------------------------------------------------------------------------- // FIXME: This will fail with an actual infinite range (NaNs will be generated // in the conditionals). @@ -202,7 +169,7 @@ bool util::region::intersects (region rhs) const { for (size_t i = 0; i < S; ++i) - if (p[i] >= rhs.p[i] + rhs.e[i] || + if ( p[i] >= rhs.p[i] + rhs.e[i] || rhs.p[i] >= p[i] + e[i]) { return false; } @@ -253,12 +220,21 @@ util::region::intersection (region rhs) const //----------------------------------------------------------------------------- template bool -util::region::encloses (const region r) const noexcept +util::region::covers (region r) const noexcept { return all (p <= r.p) && all (p + e >= r.p + r.e); } +//----------------------------------------------------------------------------- +template +bool +region::covers (const point q) const noexcept +{ + return all (p <= q) && all (p + e >= q); +} + + /////////////////////////////////////////////////////////////////////////////// template util::region diff --git a/region.hpp b/region.hpp index e052bc4b..7ab9a848 100644 --- a/region.hpp +++ b/region.hpp @@ -70,21 +70,19 @@ namespace util { point_t closest (point_t) const; //--------------------------------------------------------------------- - // Point and region relation queries - bool includes (point_t) const; // inclusive of borders - bool contains (point_t) const; // exclusive of borders - bool intersects (region) const; // exclusive of borders - bool has (point_t) const noexcept; // inclusive of top and left borders - - // Move a point to be within the region bounds - void constrain (point_t&) const; - point_t constrained (point_t) const; - + // exclusive of borders + bool intersects (region) const; // Compute binary region combinations region intersection (region) const; // Test if a region lies completely within our space - bool encloses (region) const noexcept; + bool covers (region) const noexcept; + // Test if a point lies within out space. Inclusive of borders + bool covers (point) const noexcept; + + // Move a point to be within the region bounds + void constrain (point_t&) const; + point_t constrained (point_t) const; //--------------------------------------------------------------------- // Compute a region `mag` units into the region diff --git a/test/region.cpp b/test/region.cpp index f15bc2eb..ca7ff390 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -46,21 +46,16 @@ main (int, char **) // test boundary cases of includes and contains { - const util::point2u p0 { 0 }; - const util::extent2u e0 { 2 }; - const util::region2u r {p0, e0}; + const util::point2f p0 { 0 }; + const util::extent2f e0 { 2 }; + const util::region2f r {p0, e0}; - tap.expect (r.includes (util::point2u {1, 1}), "unsigned region centre inclusion"); - tap.expect (r.includes (util::point2u {0, 0}), "unsigned region base inclusion"); - tap.expect (r.includes (util::point2u {2, 2}), "unsigned region corner inclusion"); + tap.expect (!r.covers (util::point2f {-1, 1}), "region/point covers, invalid x"); + tap.expect (!r.covers (util::point2f { 1, 3}), "region/point covers, invalid y "); - tap.expect ( r.contains (util::point2u {1, 1}), "unsigned region center contains"); - tap.expect (!r.contains (util::point2u {0, 0}), "unsigned region base contains"); - tap.expect (!r.contains (util::point2u {2, 2}), "unsigned region corner contains"); - - tap.expect ( r.has (util::point2u {1, 1}), "unsigned region centre has"); - tap.expect ( r.has (util::point2u {1, 1}), "unsigned region base has"); - tap.expect (!r.has (util::point2u {2, 2}), "unsigned region corner has"); + tap.expect (r.covers (util::point2f {1, 1}), "region/point covers, centre"); + tap.expect (r.covers (util::point2f {0, 0}), "region/point covers, base"); + tap.expect (r.covers (util::point2f {2, 2}), "region/point covers, corner"); } // ensure make_union behaves as expected From 9abfef2769aee11f528518ac12dbdd4b5ef1348f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 11 Aug 2017 15:19:14 +1000 Subject: [PATCH 034/149] region: remove mutating point constrain function --- region.cpp | 13 ++----------- region.hpp | 3 +-- 2 files changed, 3 insertions(+), 13 deletions(-) diff --git a/region.cpp b/region.cpp index b71f3b59..9cbb4dff 100644 --- a/region.cpp +++ b/region.cpp @@ -179,20 +179,11 @@ util::region::intersects (region rhs) const //----------------------------------------------------------------------------- template -void -util::region::constrain (point_t &q) const +typename region::point_t +region::constrain (point_t q) const noexcept { for (size_t i = 0; i < S; ++i) q[i] = limit (q[i], p[i], p[i] + e[i]); -} - - -//----------------------------------------------------------------------------- -template -typename util::region::point_t -util::region::constrained (point_t q) const -{ - constrain (q); return q; } diff --git a/region.hpp b/region.hpp index 7ab9a848..db88f01d 100644 --- a/region.hpp +++ b/region.hpp @@ -81,8 +81,7 @@ namespace util { bool covers (point) const noexcept; // Move a point to be within the region bounds - void constrain (point_t&) const; - point_t constrained (point_t) const; + point_t constrain (point_t) const noexcept; //--------------------------------------------------------------------- // Compute a region `mag` units into the region From ec0cb7d2c1660f33c149f3a118c5e8a067b70a3c Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 11 Aug 2017 15:20:48 +1000 Subject: [PATCH 035/149] region: remove scale operation it's not immediately apparent how scale operates on both of point and extent components. rather than complicate matters we remove them in preference of letting the user construct it directly. --- region.cpp | 11 ----------- region.hpp | 2 -- 2 files changed, 13 deletions(-) diff --git a/region.cpp b/region.cpp index 9cbb4dff..b25079d5 100644 --- a/region.cpp +++ b/region.cpp @@ -98,17 +98,6 @@ util::region::magnitude (extent_t _e) } -//----------------------------------------------------------------------------- -template -void -util::region::scale (T factor) -{ - auto o = (e * factor - e) / T(2); - p -= o; - e *= factor; -} - - //----------------------------------------------------------------------------- template bool diff --git a/region.hpp b/region.hpp index db88f01d..f38bf813 100644 --- a/region.hpp +++ b/region.hpp @@ -59,8 +59,6 @@ namespace util { extent_t magnitude (void) const; extent_t magnitude (extent_t); - void scale (T factor); - bool empty (void) const; //--------------------------------------------------------------------- From 959bc85987cd63d166ef5edb4643713c408f3fee Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 15 Aug 2017 16:44:54 +1000 Subject: [PATCH 036/149] range: add signed integer instantiations --- range.cpp | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/range.cpp b/range.cpp index d376b3bb..1246ac54 100644 --- a/range.cpp +++ b/range.cpp @@ -204,14 +204,16 @@ namespace util { //----------------------------------------------------------------------------- -namespace util { - template struct range; - template struct range; - template struct range; - template struct range; - template struct range; - template struct range; -} +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; +template struct util::range; //----------------------------------------------------------------------------- From 651324d6f941964bb1326cfe5b2bc9db37a721e0 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 16 Aug 2017 17:25:29 +1000 Subject: [PATCH 037/149] tuple: clarify warn_unused_arg usage for ignore(...) --- tuple.hpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tuple.hpp b/tuple.hpp index cd6260b4..ad15b6c2 100644 --- a/tuple.hpp +++ b/tuple.hpp @@ -169,7 +169,8 @@ namespace util::tuple { /// do nothing with a set of parameters. /// /// useful for temporarily silencing unused argument warnings in parameter - /// packs. + /// packs, or for avoiding assignment of [[gnu::warn_unused_result]] to a + /// temporary value we'd just cast to void anyway (GCC#66425). /// /// it is guaranteed that this function will never be defined out in /// debug/release/whatever builds. so it is safe to use to guarantee From d6b77f879f404c5db6ff5b8b43d024e0af8e11c2 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 16 Aug 2017 17:25:56 +1000 Subject: [PATCH 038/149] region: add convenience zero() constructor --- region.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/region.hpp b/region.hpp index f38bf813..92f527af 100644 --- a/region.hpp +++ b/region.hpp @@ -102,6 +102,9 @@ namespace util { static constexpr region max (void); static constexpr region unit (void); + static constexpr region zero (void) + { return { point_t {0}, extent_t {0} }; } + void sanity (void) const; }; From c49738e7a398ecb2364fe8af846c50d9a06999d5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Wed, 16 Aug 2017 17:26:16 +1000 Subject: [PATCH 039/149] coord/ops: add elementwise limit operation --- coord/ops.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/coord/ops.hpp b/coord/ops.hpp index fe275f51..ba70e257 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -703,6 +703,25 @@ namespace util { } + //------------------------------------------------------------------------- + + template < + size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr + K + limit (K k, K lo, K hi) + { + assert (all (lo <= hi)); + return max (min (k, hi), lo); + } + + ///------------------------------------------------------------------------ template < size_t S, From 46d28ba7be9be2e018ca83f6fcd8133ed8090c7f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 18 Aug 2017 11:15:00 +1000 Subject: [PATCH 040/149] debug: add variable escape and memory clobber functions --- debug.hpp | 66 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 66 insertions(+) diff --git a/debug.hpp b/debug.hpp index 9e400b2d..a5e58220 100644 --- a/debug.hpp +++ b/debug.hpp @@ -221,6 +221,7 @@ #define CHECK_NEZ(A) do { \ DEBUG_ONLY ( \ const auto &__a = (A); \ + \ if (::util::exactly_zero (__a)) \ _CHECK_PANIC ("expected non-zero\n" \ "__a: %s is %!", \ @@ -234,6 +235,7 @@ DEBUG_ONLY ( \ const auto &__check_mod_v = (V); \ const auto &__check_mod_m = (M); \ + \ if (!::util::exactly_zero (__check_mod_v % __check_mod_m)) \ _CHECK_PANIC ("expected zero modulus\n" \ "__v: %s is %!\n" \ @@ -296,6 +298,70 @@ } while (0) +/////////////////////////////////////////////////////////////////////////////// +/// make the compiler think a particular variable may now be aliased somewhere. +/// +/// useful for preventing optimisations eliding a variable. +/// +/// stolen from Chandler Carruth's 2015 talk: "Tuning C++". +namespace util::debug { + template + inline T* + escape (T *t) + { + asm volatile ("": : "g"(t): "memory"); + return t; + } + + + template + inline const T* + escape (const T *t) + { + asm volatile ("": : "g"(t): "memory"); + return t; + } + + + template + inline const T& + escape (const T &t) + { + return *escape (&t); + } + + + template + inline T& + escape (T &t) + { + return *escape (&t); + } + + + template + inline void + escape (T t, Args ...args) + { + escape (t); + escape (args...); + } +} + + +/////////////////////////////////////////////////////////////////////////////// +/// force the compiler to conceptually dirty the global memory space. +/// +/// stolen from Chandler Carruth's 2015 talk: "Tuning C++". +namespace util::debug { + inline void + clobber (void) + { + asm volatile ("": : : "memory"); + } +} + + /////////////////////////////////////////////////////////////////////////////// constexpr void panic [[noreturn]] (const char*); From dcdfa339d7795a1a8fda4a5294eedbe40f302ff6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 21 Aug 2017 16:50:46 +1000 Subject: [PATCH 041/149] adapter: actually perform the reverse in reverse adapter --- adapter.hpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/adapter.hpp b/adapter.hpp index a5b87a05..c258a685 100644 --- a/adapter.hpp +++ b/adapter.hpp @@ -30,14 +30,14 @@ namespace util::adapter { m_target (_target) { ; } - auto begin (void) { return m_target.begin (); } - auto end (void) { return m_target.end (); } + auto begin (void) & { return m_target.rbegin (); } + auto end (void) & { return m_target.rend (); } - auto begin (void) const { return m_target.begin (); } - auto end (void) const { return m_target.end (); } + auto begin (void) const& { return m_target.rbegin (); } + auto end (void) const& { return m_target.rend (); } - auto cbegin (void) { return m_target.cbegin (); } - auto cend (void) { return m_target.cend (); } + auto cbegin (void) const& { return m_target.crbegin (); } + auto cend (void) const& { return m_target.crend (); } private: T &m_target; From 439809ca655509bda22bd601069e78fbf84461eb Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 21 Aug 2017 16:51:03 +1000 Subject: [PATCH 042/149] adapter: add make_reverse for reverse adapter --- adapter.hpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/adapter.hpp b/adapter.hpp index c258a685..c7d1ec7c 100644 --- a/adapter.hpp +++ b/adapter.hpp @@ -44,6 +44,14 @@ namespace util::adapter { }; + template + auto + make_reverse (Container &c) + { + return reverse { c }; + }; + + // adapt a container's range methods to return indices rather than iterators template struct indices { From a016e98b12254392263b27821c1ece6b1acf6fc6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 21 Aug 2017 18:48:52 +1000 Subject: [PATCH 043/149] region: add make_range for regions introduces an object that provides iterators suitable for row-major scanning of points covering a region object. mostly a wrapper for the equivalent extent_range. --- region.hpp | 97 +++++++++++++++++++++++++++++++++++++++++++++---- test/region.cpp | 24 ++++++++++++ 2 files changed, 114 insertions(+), 7 deletions(-) diff --git a/region.hpp b/region.hpp index 92f527af..a22ffd3c 100644 --- a/region.hpp +++ b/region.hpp @@ -11,17 +11,17 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2010-2015 Danny Robson + * Copyright 2010-2017 Danny Robson */ -#ifndef __UTIL_REGION_HPP -#define __UTIL_REGION_HPP +#ifndef CRUFT_UTIL_REGION_HPP +#define CRUFT_UTIL_REGION_HPP -#include "extent.hpp" -#include "point.hpp" -#include "vector.hpp" -#include "types/traits.hpp" +#include "./extent.hpp" +#include "./point.hpp" +#include "./vector.hpp" +#include "./types/traits.hpp" #include @@ -121,6 +121,89 @@ namespace util { } + /////////////////////////////////////////////////////////////////////////// + /// construct a point iterator across a given region, generating each + /// valid point in row-major sequence. + /// + /// this is only defined for integral types as it's not clear how to + /// handle floats; it's _super_ unlikely anyone actually wants to visit + /// every single floating point value for a region (and if so they can + /// damn well code that monstrosity themselves). + template < + typename T, + std::size_t S, + typename = std::enable_if_t< + std::is_integral_v, void + > + > + auto + make_range (region r) + { + using region_t = region; + using point_t = typename region_t::point_t; + using vector_t = util::vector; + + // this range object is mostly a wrapper around the existing + // extent_range object with a constant offset. it's not going to be as + // performant, but when we discover this is an issue we can do write a + // better version of this object & iterator. + class region_range { + public: + class iterator : public std::iterator { + public: + iterator (typename extent_range::iterator _inner, vector_t _offset): + m_inner (_inner), + m_offset (_offset) + { ; } + + + point_t operator* (void) const { return *m_inner + m_offset; } + + iterator& + operator++ (void) + { + ++m_inner; + return *this; + } + + + bool operator== (const iterator &rhs) const + { + assert (m_offset == rhs.m_offset); + return m_inner == rhs.m_inner; + } + + + bool operator!= (const iterator &rhs) const + { return !(*this == rhs); } + + + private: + typename extent_range::iterator m_inner; + vector_t m_offset; + }; + + region_range (region_t _r): + m_range { _r.e + T{1} }, + m_offset { _r.p.template as () } + { ; } + + iterator begin (void) const { return { m_range.begin (), m_offset }; } + iterator end (void) const { return { m_range.end (), m_offset }; } + + iterator cbegin (void) const { return begin (); } + iterator cend (void) const { return end (); } + + private: + const extent_range m_range; + const vector_t m_offset; + }; + + + return region_range { r }; + }; + + template using region2 = region<2,T>; template using region3 = region<3,T>; diff --git a/test/region.cpp b/test/region.cpp index ca7ff390..4d41729f 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -3,6 +3,7 @@ #include "point.hpp" #include "tap.hpp" +#include //----------------------------------------------------------------------------- int @@ -80,6 +81,29 @@ main (int, char **) ); }; + // ensure make_region covers the expected values + { + const util::region2i REGION { + util::point2i { -1, 1 }, + util::point2i { 1, 3 } + }; + + const util::point2i EXPECTED[] = { + { -1, 1 }, { 0, 1 }, { 1, 1 }, + { -1, 2 }, { 0, 2 }, { 1, 2 }, + { -1, 3 }, { 0, 3 }, { 1, 3 }, + }; + + std::vector values; + auto sequence = util::make_range (REGION); + std::copy (std::cbegin (sequence), std::cend (sequence), std::back_inserter (values)); + + bool success = values.size () == std::size (EXPECTED) + && std::equal (std::cbegin (values), std::cend (values), + std::cbegin (EXPECTED), std::cend (EXPECTED)); + tap.expect (success, "make_range(region2i)"); + }; + //CHECK (region<2,intmax_t> (0, 0, 10, 10).includes (point2d (0.4, 0.01))); //CHECK (region<2,intmax_t> (0, 0, 10, 10).contains (point2d (0.4, 0.01))); From 10f777c380a0009331c7d823c47b141c07ddb13c Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 22 Aug 2017 15:05:58 +1000 Subject: [PATCH 044/149] matrix: remove mutating operations --- matrix.cpp | 9 --------- matrix.hpp | 2 -- 2 files changed, 11 deletions(-) diff --git a/matrix.cpp b/matrix.cpp index dea7a429..3915c06c 100644 --- a/matrix.cpp +++ b/matrix.cpp @@ -27,15 +27,6 @@ using util::matrix; /////////////////////////////////////////////////////////////////////////////// -template -matrix& -matrix::invert (void) -{ - return *this = inverse (); -} - - -//----------------------------------------------------------------------------- //template //matrix& //matrix::invert_affine (void) diff --git a/matrix.hpp b/matrix.hpp index e66cf5a7..3443f754 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -50,9 +50,7 @@ namespace util { T determinant (void) const; matrix inverse (void) const; - matrix& invert (void); matrix inverse_affine (void) const; - matrix& invert_affine (void); vector operator* (const vector&) const; point operator* (const point &) const; From 8b089d412c3b1a68a8182aed913199a2216b9b19 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 22 Aug 2017 15:06:16 +1000 Subject: [PATCH 045/149] matrix: add fallback implementation for inverse_affine --- matrix.hpp | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/matrix.hpp b/matrix.hpp index 3443f754..417ecb59 100644 --- a/matrix.hpp +++ b/matrix.hpp @@ -49,8 +49,14 @@ namespace util { T determinant (void) const; - matrix inverse (void) const; - matrix inverse_affine (void) const; + matrix inverse (void) const; + + matrix + inverse_affine (void) const + { + // TODO: ensure we have specialisations for typical dimensions + return inverse (); + } vector operator* (const vector&) const; point operator* (const point &) const; From 2576061b262c4b609cad22caac5bc340300db9a2 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 22 Aug 2017 15:46:49 +1000 Subject: [PATCH 046/149] ray: extract make member function as free function for consistency with other make_foo functions. to be replaced with deduction guides in the future. --- geom/ray.cpp | 24 ------------------------ geom/ray.hpp | 28 +++++++++++++++++++++++----- test/geom/ray.cpp | 18 +++++++++--------- 3 files changed, 32 insertions(+), 38 deletions(-) diff --git a/geom/ray.cpp b/geom/ray.cpp index 41fa0d76..3650ad3f 100644 --- a/geom/ray.cpp +++ b/geom/ray.cpp @@ -24,30 +24,6 @@ using util::geom::ray; -/////////////////////////////////////////////////////////////////////////////// -template -ray::ray (util::point _origin, - util::vector _direction): - origin (_origin), - direction (_direction) -{ - CHECK (is_normalised (direction)); -} - - -//----------------------------------------------------------------------------- -template -ray -ray::make (util::point origin, - util::point target) -{ - return { - origin, - normalised (target - origin) - }; -} - - /////////////////////////////////////////////////////////////////////////////// /// returns the distance along the ray in a ray-plane intersection /// diff --git a/geom/ray.hpp b/geom/ray.hpp index 2f63abed..b3381281 100644 --- a/geom/ray.hpp +++ b/geom/ray.hpp @@ -28,13 +28,17 @@ namespace util::geom { template struct ray { - ray (point origin, - vector direction); + constexpr ray (point _origin, vector _direction) noexcept: + origin (_origin), + direction (_direction) + { ; } - static - ray make (point origin, - point target); + constexpr ray (point _origin, point _distant) noexcept: + ray (_origin, _origin.to (_distant )) + { ; } + + //--------------------------------------------------------------------- // intersection tests T intersect (plane) const; T intersect (AABB) const; @@ -50,6 +54,20 @@ namespace util::geom { vector direction; }; + template + constexpr auto + make_ray (point p, vector d) noexcept + { + return ray { p, d }; + } + + template + constexpr auto + make_ray (point p, point q) + { + return ray { p, q }; + }; + typedef ray<2,float> ray2f; typedef ray<3,float> ray3f; } diff --git a/test/geom/ray.cpp b/test/geom/ray.cpp index 45d989e4..2cef97e1 100644 --- a/test/geom/ray.cpp +++ b/test/geom/ray.cpp @@ -12,8 +12,8 @@ void test_intersect_plane (util::TAP::logger &tap) { // trivial case: origin ray facing z, plane at unit z facing -z. - const util::geom::ray3f l ({0,0,0}, {0,0, 1}); - const util::geom::plane3f p ({0,0,1}, {0,0,-1}); + const util::geom::ray3f l (util::point3f {0,0,0}, util::vector3f {0,0, 1}); + const util::geom::plane3f p (util::point3f {0,0,1}, util::vector3f {0,0,-1}); tap.expect_eq (l.intersect (p), 1.f, "ray-plane intersect"); } @@ -32,15 +32,15 @@ test_intersect_aabb (util::TAP::logger &tap) }; const ray2f forward { - { 0.5f, -0.5f }, - { 0.f, 1.f } + util::point2f { 0.5f, -0.5f }, + util::vector2f { 0.f, 1.f } }; tap.expect_eq (forward.intersect (box), 0.5f, "ray-aabb intersect"); const ray2f behind { - { 0.5f, 2.f }, - { 0.f, 1.f } + util::point2f { 0.5f, 2.f }, + util::vector2f { 0.f, 1.f } }; tap.expect_nan (behind.intersect (box), "ray-aabb intersect behind"); @@ -55,13 +55,13 @@ test_intersect_sphere (util::TAP::logger &tap) const sphere3f s = {{0.f, 0.f, 0.f}, 1.f}; - const ray3f r0 {{0.f, 2.f, 0.f}, {0.f, -1.f, 0.f}}; + const ray3f r0 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, -1.f, 0.f}}; tap.expect_eq (r0.intersect (s), 1.f, "ray-sphere simple"); - const ray3f r1 {{0.f, 1.f, 0.f}, {0.f, 1.f, 0.f}}; + const ray3f r1 {util::point3f {0.f, 1.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}}; tap.expect_eq (r1.intersect (s), 0.f, "ray-sphere adjacent"); - const ray3f r2 {{0.f, 2.f, 0.f}, {0.f, 1.f, 0.f}}; + const ray3f r2 {util::point3f {0.f, 2.f, 0.f}, util::vector3f {0.f, 1.f, 0.f}}; tap.expect_nan (r2.intersect (s), "ray-sphere no-intersect"); } From 1d988608c183b95814547077f37823d827d17fd1 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Tue, 22 Aug 2017 17:23:36 +1000 Subject: [PATCH 047/149] geom/ray: add an (explicitly) default constructor --- geom/ray.hpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/geom/ray.hpp b/geom/ray.hpp index b3381281..12f8aa13 100644 --- a/geom/ray.hpp +++ b/geom/ray.hpp @@ -28,6 +28,8 @@ namespace util::geom { template struct ray { + constexpr ray () = default; + constexpr ray (point _origin, vector _direction) noexcept: origin (_origin), direction (_direction) From d8e4354f228661ec4dbc3f46627553c6f941309f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 12:26:36 +1000 Subject: [PATCH 048/149] maths: only enable util::limit for scalar types this reduces conflicts with the coord limit operation. --- maths.hpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/maths.hpp b/maths.hpp index 9e8e9f35..475666ea 100644 --- a/maths.hpp +++ b/maths.hpp @@ -628,7 +628,10 @@ namespace util { // min/max clamping template constexpr - T + std::enable_if_t< + std::is_scalar_v && std::is_scalar_v && std::is_scalar_v, + std::common_type_t + > limit (const T val, const U lo, const V hi) { assert (lo <= hi); From e134d911e6f8b2bd521dd5ba66a9de6e0deec08f Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 12:27:18 +1000 Subject: [PATCH 049/149] geom/ray: reinsert is_normalised check for direction param --- geom/ray.hpp | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/geom/ray.hpp b/geom/ray.hpp index 12f8aa13..5b2d13f6 100644 --- a/geom/ray.hpp +++ b/geom/ray.hpp @@ -33,11 +33,15 @@ namespace util::geom { constexpr ray (point _origin, vector _direction) noexcept: origin (_origin), direction (_direction) - { ; } + { + CHECK (is_normalised (direction)); + } constexpr ray (point _origin, point _distant) noexcept: ray (_origin, _origin.to (_distant )) - { ; } + { + CHECK (is_normalised (direction)); + } //--------------------------------------------------------------------- From ac19e165ba3d2cb94a8c839e7a35ec9b4c9b48c4 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 12:49:59 +1000 Subject: [PATCH 050/149] coord/ops: add comment for util::limit --- coord/ops.hpp | 57 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 56 insertions(+), 1 deletion(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index ba70e257..c02a8700 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -704,7 +704,12 @@ namespace util { //------------------------------------------------------------------------- - + /// returns a coordinate type where each element has been clamped to the + /// range [lo,hi]. + /// + /// we specifically do not allow different coordinate types for val, lo, + /// and hi because the min and max calls are ill definied for varying + /// types (not because varying types would not be useful). template < size_t S, typename T, @@ -722,6 +727,56 @@ namespace util { } + //------------------------------------------------------------------------- + template < + size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr + K + limit (K k, T lo, K hi) + { + return limit (k, K {lo}, hi); + } + + + //------------------------------------------------------------------------- + template < + size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr + K + limit (K k, K lo, T hi) + { + return limit (k, lo, K {hi}); + } + + + //------------------------------------------------------------------------- + template < + size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr K + limit (K k, T lo, T hi) + { + return limit (k, K {lo}, K {hi}); + } + + ///------------------------------------------------------------------------ template < size_t S, From 14718594c9e609783be864a8e604adb5986d1ff5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 12:50:17 +1000 Subject: [PATCH 051/149] coord: add tests for vec/num/num overload of util::limit --- test/coord.cpp | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/test/coord.cpp b/test/coord.cpp index c25585ea..c2b9f183 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -42,6 +42,7 @@ main (void) tap.expect (x == p.x && y == p.y, "structured bindings extract correct data"); } + // ensure the distance function behaves correctly with non-normal numbers. { util::point3f a { 103, 0, 14 }; util::point3f b { 104, INFINITY, 15 }; @@ -53,6 +54,7 @@ main (void) ); } + // ensure the util::select function behaves as expected { const util::point3f a { -1, 2, 0 }; const util::point3f b { 1, 0, 2 }; @@ -64,5 +66,18 @@ main (void) tap.expect_eq (select (a > b, a, b), hi, "select with points and max"); }; + // ensure that util::limit resolves to the coord overload. the exact + // values are less useful than exercising the compiler/linker. + { + const util::vector3f val { 0, -1, 2 }; + const util::vector3f lo { -1, 1, -2 }; + const util::vector3f hi { 1, 2, 0 }; + + tap.expect_eq (limit (val, lo, hi), util::vector3f { 0, 1, 0 }, "limit with vec/vec/vec"); + tap.expect_eq (limit (val, 0.f, hi), util::vector3f { 0, 0, 0 }, "limit with vec/num/vec"); + tap.expect_eq (limit (val, lo, 2.f), util::vector3f { 0, 1, 2 }, "limit with vec/vec/num"); + tap.expect_eq (limit (val, 0.f, 2.f), util::vector3f { 0, 0, 2 }, "limit with vec/num/num"); + } + return tap.status (); } From 84963aacf80c27a606bf4cbcf503c2af1d3348c5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:32:58 +1000 Subject: [PATCH 052/149] coord/ops: make 'all' and 'any' constexpr --- coord/ops.hpp | 70 +++++++++++++++++++++++++++++++++++++++++++------- test/coord.cpp | 12 +++++++++ 2 files changed, 73 insertions(+), 9 deletions(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index c02a8700..2e488311 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -899,38 +899,90 @@ namespace util { #undef SCALAR_OP - //------------------------------------------------------------------------- + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template < + std::size_t S, + template class K, + std::size_t ...I, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr bool + any (const K k, std::index_sequence) + { + return (k[I] || ...); + } + }; + + + ///--------------------------------------------------------------------------- + /// returns true if any element is true. + /// + /// this function must be suitable for use in static_assert, so it must remain + /// constexpr. + /// + /// we would ideally use std::any_of, but it is not constexpr. + /// we would ideally use range-for, but cbegin is not constexpr. + /// so... moar templates. template < size_t S, template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename Indices = std::make_index_sequence > constexpr bool any (const K k) { - return std::any_of (std::cbegin (k), - std::cend (k), - identity); + return detail::any (k, Indices{}); + } + + + /////////////////////////////////////////////////////////////////////////// + namespace detail { + template < + std::size_t S, + template class K, + std::size_t ...I, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr bool + all (const K k, std::index_sequence) + { + return (k[I] && ...); + } } //------------------------------------------------------------------------- + /// returns true if all elements are true. + /// + /// this function must be suitable for use in static_assert, so it must be + /// constexpr. + /// + /// we would ideally use std::all_of, but it is not constexpr. + /// we would ideally use range-for, but cbegin is not constexpr. + /// so... moar templates. template < size_t S, template class K, typename = std::enable_if_t< is_coord_v>, void - > + >, + typename Indices = std::make_index_sequence > constexpr bool all (const K k) { - return std::all_of (std::cbegin (k), - std::cend (k), - identity); + return detail::all (k, Indices {}); } diff --git a/test/coord.cpp b/test/coord.cpp index c2b9f183..593cc0ec 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -54,6 +54,18 @@ main (void) ); } + // test expected outputs for various logical operations + { + constexpr util::point3i a { 0, -1, 2 }; + constexpr util::point3i b { 0, 1, -2 }; + constexpr util::point3i c { -9, -9, -9 }; + + tap.expect (!all (a <= b), "all, expected failure"); + tap.expect ( all (a <= a), "all, expected success"); + tap.expect (!any (a <= c), "any, expected failure"); + tap.expect ( any (a <= b), "any, expected success"); + }; + // ensure the util::select function behaves as expected { const util::point3f a { -1, 2, 0 }; From 0b52ef47be0d30e415605c2fe48ff7491eb6a978 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:33:20 +1000 Subject: [PATCH 053/149] coord/ops: make make_foo functions constexpr --- coord/ops.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index 2e488311..d8b47903 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -1099,7 +1099,7 @@ namespace util { typename _T = void, \ typename ...Args \ > \ - auto \ + constexpr auto \ make_##KLASS (Args &&...args) \ { \ using T = std::conditional_t< \ From a14847bb59d57bbe347f8d16ee8363233818fd92 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:33:41 +1000 Subject: [PATCH 054/149] vector: add and correct 4-dimension types --- vector.hpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/vector.hpp b/vector.hpp index bfeb6398..f274a650 100644 --- a/vector.hpp +++ b/vector.hpp @@ -61,7 +61,6 @@ namespace util { const json::tree::node& operator>> (const json::tree::node&, vector&); - // convenience typedefs template using vector2 = vector<2,T>; template using vector3 = vector<3,T>; template using vector4 = vector<4,T>; @@ -72,9 +71,11 @@ namespace util { typedef vector2 vector2u; typedef vector3 vector3u; + typedef vector4 vector4u; typedef vector2 vector2i; typedef vector3 vector3i; + typedef vector4 vector4i; typedef vector2 vector2f; typedef vector3 vector3f; @@ -82,7 +83,7 @@ namespace util { typedef vector2 vector2d; typedef vector3 vector3d; - typedef vector3 vector4d; + typedef vector4 vector4d; } #include "vector.ipp" From 1d4992e3e4c5ec379e795fbfa76c431ad36dc488 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:34:22 +1000 Subject: [PATCH 055/149] coord/base: add comments for constructors --- coord/base.hpp | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index bc3c0d65..0b519ee7 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -40,13 +40,22 @@ namespace util::coord { static constexpr size_t dimension = S; static constexpr size_t elements = S; + /// returns the number of elements we contain static constexpr size_t size (void) { return S; } - // constructors + // inherit the fancy elementwise constructors from `init'. using init::init; + + /// constructs, but does not initialise, the data. + /// + /// used to avoid unnecessary initialisation in many situations where + /// we have arrays of these types that are about to be overwritten. it + /// is a very important performance optimisation. base () = default; - constexpr explicit base (T val) + /// constructs an instance where all elements are initialised to `val'. + constexpr explicit + base (T val) { std::fill (begin (), end (), val); } constexpr base (const base &rhs) = default; From ad345f19d5226763e524e9af36e7f362e465e72e Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:34:46 +1000 Subject: [PATCH 056/149] coord/base: add restrictions to redim with/out params redim to lower dimensionality should not allow a parameter, and redim to higher dimensions should require a fill parameter. --- coord/base.hpp | 60 +++++++++++++++++++++++++++++--------------------- 1 file changed, 35 insertions(+), 25 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index 0b519ee7..8a6dbc03 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -18,6 +18,8 @@ #define __UTIL_COORD_BASE_HPP #include "init.hpp" + +#include "./ops.hpp" #include "../maths.hpp" #include @@ -103,51 +105,59 @@ namespace util::coord { } /////////////////////////////////////////////////////////////////////// - // redimension - template - KLASS + /// returns an instance with the same data, but truncated to `D' + /// elements + /// + /// explicitly does not allow a fill parameter given it can't be used + /// when reducing dimensions. + template + std::enable_if_t< + D <= S, KLASS + > redim (void) const { KLASS out; - std::copy_n (std::cbegin (this->data), - min (S, D), - std::begin (out.data)); + std::copy_n (cbegin (), D, std::begin (out.data)); return out; } //--------------------------------------------------------------------- - template - KLASS + /// returns an instance with the same data, but more elements, where + /// the new elements are initialised with values with the same index + /// in the coordinate `fill'. + /// + /// explicitly requires a fill parameter so that we avoid undefined + /// values. + template + std::enable_if_t< + (D > S), KLASS + > redim (const KLASS fill) const { KLASS out; - static constexpr auto L1 = min (S, D); - static constexpr auto L2 = D - L1; - - std::copy_n (std::cbegin (this->data), - L1, - std::begin (out.data)); - - std::copy_n (fill.data + L1, - L2, - out.data + L1); + auto next = std::copy (cbegin (), cend (), std::begin (out)); + std::copy (std::cbegin (fill) + S, std::cend (fill), next); return out; } //--------------------------------------------------------------------- - template - KLASS + /// returns an instance with the same data, but more elements, where + /// all the new elemenst are initialised with the scalar `fill'. + /// + /// explicitly requires a fill parameter so that we avoid undefined + /// values. + template + std::enable_if_t< + (D > S), KLASS + > redim (T fill) const { KLASS out; - auto cursor = std::copy_n (std::cbegin (this->data), - min (S, D), - std::begin (out.data)); - std::fill (cursor, std::end (out.data), fill); - + auto next = std::copy (cbegin (), cend (), std::begin (out)); + std::fill (next, std::end (out), fill); return out; } }; From efb719b8224254f7432679d3b74fae2c1286acc1 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 14:39:06 +1000 Subject: [PATCH 057/149] coord/base: add indices method --- coord/base.hpp | 15 +++++++++++++++ test/coord.cpp | 8 ++++++++ 2 files changed, 23 insertions(+) diff --git a/coord/base.hpp b/coord/base.hpp index 8a6dbc03..8a32ade2 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -160,6 +160,21 @@ namespace util::coord { std::fill (next, std::end (out), fill); return out; } + + + /////////////////////////////////////////////////////////////////////// + /// returns an instance with elements specified by the Indices + /// parameter. eg, point2f p{}.indices<0,2> would return {p.x, p.z}. + /// + /// it's ugly as sin, but simplifies some situations where we don't + /// want a temporary. + template + KLASS + indices (void) const + { + static_assert (all (make_vector ((Indices < S)...))); + return KLASS { this->data[Indices]... }; + } }; } diff --git a/test/coord.cpp b/test/coord.cpp index 593cc0ec..8de918aa 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -91,5 +91,13 @@ main (void) tap.expect_eq (limit (val, 0.f, 2.f), util::vector3f { 0, 0, 2 }, "limit with vec/num/num"); } + // ensure that klass::indices appears to link correctly + { + const util::vector3i seq { 0, 1, 2 }; + const util::vector4i res { 2, 0, 0, 1 }; + + tap.expect_eq (seq.indices<2,0,0,1> (), res, "coord::indices expansion"); + }; + return tap.status (); } From 6e32ad84a7ce7ada36f8f72a02060daf17817ab3 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 15:54:51 +1000 Subject: [PATCH 058/149] coord: use consistent naming for point coverage tests use inclusive for tests that include all borders, and exclusive for tests that do not accept the bottom right borders. --- extent.hpp | 25 ++++++++++++++++++++++--- extent.ipp | 15 +-------------- region.cpp | 9 --------- region.hpp | 19 +++++++++++++++++-- test/region.cpp | 10 +++++----- 5 files changed, 45 insertions(+), 33 deletions(-) diff --git a/extent.hpp b/extent.hpp index cde8c587..5c456803 100644 --- a/extent.hpp +++ b/extent.hpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2010-2015 Danny Robson + * Copyright 2010-2017 Danny Robson */ #ifndef __UTIL_EXTENT_HPP @@ -41,8 +41,27 @@ namespace util { constexpr U aspect (void) const; - template - bool includes (util::point) const; + + /// tests whether a point would lie within: + /// region { origin, *this }, inclusive of borders. + /// + /// included for parity with util::region. + constexpr bool + inclusive (util::point p) const + { + return all (p >= T{0} && p <= *this); + } + + + /// tests whether a point would like within: + /// region { origin, *this }, exclusive of the bottom-right border + /// included for parity with util::region + constexpr bool + exclusive (point p) const + { + return all (p >= T{0} && p < *this); + } + extent expanded (vector) const; extent expanded (T) const; diff --git a/extent.ipp b/extent.ipp index 2f732d56..8c725523 100644 --- a/extent.ipp +++ b/extent.ipp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2017 Danny Robson */ @@ -66,19 +66,6 @@ util::extent::aspect (void) const } -/////////////////////////////////////////////////////////////////////////////// -template -template -bool -util::extent::includes (point p) const -{ - for (size_t i = 0; i < S; ++i) - if (p[i] < 0 || static_cast (p[i]) >= this->data[i]) - return false; - return true; -} - - /////////////////////////////////////////////////////////////////////////////// template constexpr diff --git a/region.cpp b/region.cpp index b25079d5..65f62462 100644 --- a/region.cpp +++ b/region.cpp @@ -206,15 +206,6 @@ util::region::covers (region r) const noexcept } -//----------------------------------------------------------------------------- -template -bool -region::covers (const point q) const noexcept -{ - return all (p <= q) && all (p + e >= q); -} - - /////////////////////////////////////////////////////////////////////////////// template util::region diff --git a/region.hpp b/region.hpp index a22ffd3c..7299b726 100644 --- a/region.hpp +++ b/region.hpp @@ -70,13 +70,28 @@ namespace util { //--------------------------------------------------------------------- // exclusive of borders bool intersects (region) const; + // Compute binary region combinations region intersection (region) const; // Test if a region lies completely within our space bool covers (region) const noexcept; - // Test if a point lies within out space. Inclusive of borders - bool covers (point) const noexcept; + + /// Test if a point lies within our space. Inclusive of borders + constexpr + bool + inclusive (point q) const noexcept + { + return all (p <= q && p + e >= q); + } + + /// test if a point lies within our space, exclusive of the + /// bottom-right border + constexpr bool + exclusive (point q) const noexcept + { + return all (p <= q && p + e > q); + } // Move a point to be within the region bounds point_t constrain (point_t) const noexcept; diff --git a/test/region.cpp b/test/region.cpp index 4d41729f..dceb0ceb 100644 --- a/test/region.cpp +++ b/test/region.cpp @@ -51,12 +51,12 @@ main (int, char **) const util::extent2f e0 { 2 }; const util::region2f r {p0, e0}; - tap.expect (!r.covers (util::point2f {-1, 1}), "region/point covers, invalid x"); - tap.expect (!r.covers (util::point2f { 1, 3}), "region/point covers, invalid y "); + tap.expect (!r.inclusive (util::point2f {-1, 1}), "region/point inclusive, invalid x"); + tap.expect (!r.inclusive (util::point2f { 1, 3}), "region/point inclusive, invalid y "); - tap.expect (r.covers (util::point2f {1, 1}), "region/point covers, centre"); - tap.expect (r.covers (util::point2f {0, 0}), "region/point covers, base"); - tap.expect (r.covers (util::point2f {2, 2}), "region/point covers, corner"); + tap.expect (r.inclusive (util::point2f {1, 1}), "region/point inclusive, centre"); + tap.expect (r.inclusive (util::point2f {0, 0}), "region/point inclusive, base"); + tap.expect (r.inclusive (util::point2f {2, 2}), "region/point inclusive, corner"); } // ensure make_union behaves as expected From dba4e673ca6b2923893b3880a1e81ea0e6607aa8 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 16:25:27 +1000 Subject: [PATCH 059/149] coord/ops: add scalar/vector relational operators --- coord/ops.hpp | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/coord/ops.hpp b/coord/ops.hpp index d8b47903..c996b8d4 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -887,6 +887,25 @@ namespace util { for (size_t i = 0; i < S; ++i) \ out[i] = k[i] OP u; \ return out; \ + } \ + \ + template < \ + size_t S, \ + typename T, \ + typename U, \ + template class K, \ + typename = std::enable_if_t< \ + is_coord_v>, void \ + > \ + > \ + constexpr \ + vector \ + operator OP (const U u, const K k) \ + { \ + vector out {}; \ + for (size_t i = 0; i < S; ++i) \ + out[i] = u OP k[i]; \ + return out; \ } SCALAR_OP(<) From 359702fb8664e71e51395b70b012ff446610be61 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 16:25:57 +1000 Subject: [PATCH 060/149] geom/aabb: remove mutating operators --- geom/aabb.cpp | 90 +++++++++++++++++----------------------------- geom/aabb.hpp | 12 +++---- test/geom/aabb.cpp | 33 ++++------------- 3 files changed, 42 insertions(+), 93 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index b2601671..81901265 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -85,91 +85,65 @@ AABB::closest (point q) const /////////////////////////////////////////////////////////////////////////////// template -AABB& -AABB::expand (util::vector mag) +AABB +AABB::expanded (vector mag) const noexcept { - p0 -= mag / T{2}; - p1 += mag / T{2}; + CHECK (all (mag >= T{0})); + CHECK (all (mag < p1 - p0)); - return *this; -} - - -//----------------------------------------------------------------------------- -template -AABB& -AABB::expand (T t) -{ - return expand (vector {t}); + return { + p0 - mag / T{2}, + p1 + mag / T{2} + }; } //----------------------------------------------------------------------------- template AABB -AABB::expanded (vector mag) +AABB::expanded (T t) const noexcept { - auto ret = *this; - ret.expand (mag); - return ret; -} + CHECK_GE (t, T{0}); + CHECK (all (t < p1 - p0)); - -//----------------------------------------------------------------------------- -template -AABB -AABB::expanded (T t) -{ - return expanded (vector {t}); + return { + p0 - t / T{2}, + p1 + t / T{2} + }; } /////////////////////////////////////////////////////////////////////////////// template -AABB& -AABB::contract (util::vector mag) +AABB +AABB::contracted (util::vector mag) const noexcept { - // Avoid contracting magnitudes larger than our extent - auto diff = p1 - p0; - auto delta = min (diff, mag); + CHECK (all (mag > T{0})); + CHECK (all (mag <= p1 - p0)); - p0 += delta / T{2}; - p1 -= delta / T{2}; - - return *this; -} - - -//----------------------------------------------------------------------------- -template -AABB& -AABB::contract (T mag) -{ - return contract (util::vector {mag}); + return { + p0 + mag / T{2}, + p1 - mag / T{2} + }; } //----------------------------------------------------------------------------- template AABB -AABB::contracted (util::vector mag) const +AABB::contracted (T mag) const noexcept { - AABB res = *this; - res.contract (mag); - return res; + CHECK_GE (mag, T{0}); + CHECK (all (mag <= p1 - p0)); + + return { + p0 + mag / T{2}, + p1 - mag / T{2} + }; } -//----------------------------------------------------------------------------- -template -AABB -AABB::contracted (T mag) const -{ - return contracted (vector {mag}); -} - - -//----------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////////////// template void AABB::cover (point p) diff --git a/geom/aabb.hpp b/geom/aabb.hpp index 2c169d25..aaafb61a 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -36,15 +36,11 @@ namespace util::geom { point closest (point) const; - AABB& expand (util::vector); - AABB& expand (T); - AABB expanded (util::vector); - AABB expanded (T); + AABB expanded (util::vector) const noexcept; + AABB expanded (T) const noexcept; - AABB& contract (util::vector); - AABB& contract (T); - AABB contracted (util::vector) const; - AABB contracted (T) const; + AABB contracted (util::vector) const noexcept; + AABB contracted (T) const noexcept; void cover (point); diff --git a/test/geom/aabb.cpp b/test/geom/aabb.cpp index cbd5c43b..696254a4 100644 --- a/test/geom/aabb.cpp +++ b/test/geom/aabb.cpp @@ -14,39 +14,18 @@ main (int, char**) { // Test contraction - AABB2f box { - { 2, 2 }, - { 8, 8 } - }; + const AABB2f val { { 2, 2 }, { 8, 8 } }; + const AABB2f res { { 3, 3 }, { 7, 7 } }; - box.contract (2.f); - - tap.expect_eq (box, { { 3, 3 }, { 7, 7 }}, "over contraction"); + tap.expect_eq (val.contracted (2.f), res, "over contraction"); } { // Test expansion - AABB2f box { - { 2, 2 }, - { 8, 8 } - }; + const AABB2f val { { 2, 2 }, { 8, 8 } }; + const AABB2f res { { 1, 1 }, { 9, 9 } }; - box.expand (2.f); - - tap.expect_eq (box, { { 1, 1 }, { 9, 9 }}, "expansion"); - } - - - { - // Ensure we don't wrap-around on unsigned position types when contracting - AABB2f small { - { 0, 0 }, - { 1, 1 } - }; - - small.contract (10); - - tap.expect_eq (small, { { 0.5f, 0.5f }, { 0.5f, 0.5f }}, "unsigned over-contract"); + tap.expect_eq (val.expanded (2.f), res, "expansion"); } return tap.status (); From cd1bb730f29cb287654fe2e2649400ec060f7a94 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 16:43:54 +1000 Subject: [PATCH 061/149] geom/aabb: rename AABB to aabb --- geom/aabb.cpp | 54 +++++++++++++++++++++++----------------------- geom/aabb.hpp | 32 +++++++++++++-------------- geom/aabb.ipp | 4 ++-- geom/ellipse.cpp | 8 +++---- geom/fwd.hpp | 2 +- geom/iostream.hpp | 2 +- geom/ops.hpp | 2 +- geom/ray.cpp | 2 +- geom/ray.hpp | 2 +- test/geom/aabb.cpp | 10 ++++----- test/geom/ray.cpp | 4 ++-- 11 files changed, 61 insertions(+), 61 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 81901265..ad122a4b 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -21,11 +21,11 @@ #include "../coord/iostream.hpp" #include "../debug.hpp" -using util::geom::AABB; +using util::geom::aabb; //----------------------------------------------------------------------------- template -AABB::AABB (point _p0, point _p1): +aabb::aabb (point _p0, point _p1): p0 (_p0), p1 (_p1) { @@ -36,7 +36,7 @@ AABB::AABB (point _p0, point _p1): //----------------------------------------------------------------------------- template T -AABB::diameter (void) const +aabb::diameter (void) const { return magnitude ().diameter (); } @@ -45,7 +45,7 @@ AABB::diameter (void) const //----------------------------------------------------------------------------- template util::extent -AABB::magnitude (void) const +aabb::magnitude (void) const { extent out; for (size_t i = 0; i < S; ++i) @@ -57,7 +57,7 @@ AABB::magnitude (void) const //----------------------------------------------------------------------------- template bool -AABB::overlaps (point p) const +aabb::overlaps (point p) const { for (size_t i = 0; i < S; ++i) if (p0[i] > p[i] || p1[i] < p[i]) @@ -70,7 +70,7 @@ AABB::overlaps (point p) const //----------------------------------------------------------------------------- template util::point -AABB::closest (point q) const +aabb::closest (point q) const { point res; @@ -85,8 +85,8 @@ AABB::closest (point q) const /////////////////////////////////////////////////////////////////////////////// template -AABB -AABB::expanded (vector mag) const noexcept +aabb +aabb::expanded (vector mag) const noexcept { CHECK (all (mag >= T{0})); CHECK (all (mag < p1 - p0)); @@ -100,8 +100,8 @@ AABB::expanded (vector mag) const noexcept //----------------------------------------------------------------------------- template -AABB -AABB::expanded (T t) const noexcept +aabb +aabb::expanded (T t) const noexcept { CHECK_GE (t, T{0}); CHECK (all (t < p1 - p0)); @@ -115,8 +115,8 @@ AABB::expanded (T t) const noexcept /////////////////////////////////////////////////////////////////////////////// template -AABB -AABB::contracted (util::vector mag) const noexcept +aabb +aabb::contracted (util::vector mag) const noexcept { CHECK (all (mag > T{0})); CHECK (all (mag <= p1 - p0)); @@ -130,8 +130,8 @@ AABB::contracted (util::vector mag) const noexcept //----------------------------------------------------------------------------- template -AABB -AABB::contracted (T mag) const noexcept +aabb +aabb::contracted (T mag) const noexcept { CHECK_GE (mag, T{0}); CHECK (all (mag <= p1 - p0)); @@ -146,7 +146,7 @@ AABB::contracted (T mag) const noexcept /////////////////////////////////////////////////////////////////////////////// template void -AABB::cover (point p) +aabb::cover (point p) { p0 = min (p, p0); p1 = max (p, p1); @@ -155,8 +155,8 @@ AABB::cover (point p) /////////////////////////////////////////////////////////////////////////////// template -AABB -AABB::operator+ (vector v) const +aabb +aabb::operator+ (vector v) const { return { p0 + v, p1 + v }; } @@ -164,8 +164,8 @@ AABB::operator+ (vector v) const //----------------------------------------------------------------------------- template -AABB -AABB::operator- (vector v) const +aabb +aabb::operator- (vector v) const { return { p0 - v, p1 - v }; } @@ -174,7 +174,7 @@ AABB::operator- (vector v) const /////////////////////////////////////////////////////////////////////////////// template bool -AABB::operator== (const AABB rhs) const +aabb::operator== (const aabb rhs) const { return rhs.p0 == p0 && rhs.p1 == p1; } @@ -184,8 +184,8 @@ AABB::operator== (const AABB rhs) const //----------------------------------------------------------------------------- namespace util::debug { template - struct validator> { - static bool is_valid (const AABB &b) + struct validator> { + static bool is_valid (const aabb &b) { for (size_t i = 0; i < S; ++i) if (b.p1[i] < b.p0[i]) @@ -200,18 +200,18 @@ namespace util::debug { //----------------------------------------------------------------------------- template std::ostream& -util::geom::operator<< (std::ostream &os, util::geom::AABB b) +util::geom::operator<< (std::ostream &os, util::geom::aabb b) { - os << "AABB(" << b.p0 << ", " << b.p1 << ")"; + os << "aabb(" << b.p0 << ", " << b.p1 << ")"; return os; } //----------------------------------------------------------------------------- #define INSTANTIATE_S_T(S,T) \ -namespace util::geom { template struct AABB; } \ -template bool util::debug::is_valid (const AABB&); \ -template std::ostream& util::geom::operator<< (std::ostream&, AABB); +namespace util::geom { template struct aabb; } \ +template bool util::debug::is_valid (const aabb&); \ +template std::ostream& util::geom::operator<< (std::ostream&, aabb); #define INSTANTIATE(T) \ INSTANTIATE_S_T(2,T) \ diff --git a/geom/aabb.hpp b/geom/aabb.hpp index aaafb61a..62793d7d 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -25,9 +25,9 @@ namespace util::geom { template - struct AABB { - AABB () = default; - AABB (point, point); + struct aabb { + aabb () = default; + aabb (point, point); T diameter (void) const; extent magnitude (void) const; @@ -36,30 +36,30 @@ namespace util::geom { point closest (point) const; - AABB expanded (util::vector) const noexcept; - AABB expanded (T) const noexcept; + aabb expanded (util::vector) const noexcept; + aabb expanded (T) const noexcept; - AABB contracted (util::vector) const noexcept; - AABB contracted (T) const noexcept; + aabb contracted (util::vector) const noexcept; + aabb contracted (T) const noexcept; void cover (point); - AABB operator+ (vector) const; - AABB operator- (vector) const; + aabb operator+ (vector) const; + aabb operator- (vector) const; - bool operator== (AABB) const; + bool operator== (aabb) const; point p0; point p1; }; - typedef AABB<2,float> AABB2f; - typedef AABB<2,unsigned> AABB2u; - typedef AABB<2,int> AABB2i; + typedef aabb<2,float> aabb2f; + typedef aabb<2,unsigned> aabb2u; + typedef aabb<2,int> aabb2i; - typedef AABB<3,float> AABB3f; - typedef AABB<3,unsigned> AABB3u; - typedef AABB<3,int> AABB3i; + typedef aabb<3,float> aabb3f; + typedef aabb<3,unsigned> aabb3u; + typedef aabb<3,int> aabb3i; } #include "aabb.ipp" diff --git a/geom/aabb.ipp b/geom/aabb.ipp index 78017b34..6e13332e 100644 --- a/geom/aabb.ipp +++ b/geom/aabb.ipp @@ -28,9 +28,9 @@ /////////////////////////////////////////////////////////////////////////////// namespace util::geom { template - struct sampler { + struct sampler { static point - fn (AABB b, G &g) + fn (aabb b, G &g) { std::uniform_real_distribution d; diff --git a/geom/ellipse.cpp b/geom/ellipse.cpp index 5d59698b..e0516b19 100644 --- a/geom/ellipse.cpp +++ b/geom/ellipse.cpp @@ -47,7 +47,7 @@ template bool util::geom::intersects (ellipse<3,float>, util::point<3,float>); /////////////////////////////////////////////////////////////////////////////// template -static util::geom::AABB +static util::geom::aabb bounds (ellipse e) { return { @@ -59,7 +59,7 @@ bounds (ellipse e) //----------------------------------------------------------------------------- template class K> -util::geom::AABB +util::geom::aabb util::geom::bounds (K k) { return ::bounds (k); @@ -67,5 +67,5 @@ util::geom::bounds (K k) //----------------------------------------------------------------------------- -template util::geom::AABB<2,float> util::geom::bounds (ellipse<2,float>); -template util::geom::AABB<3,float> util::geom::bounds (ellipse<3,float>); +template util::geom::aabb<2,float> util::geom::bounds (ellipse<2,float>); +template util::geom::aabb<3,float> util::geom::bounds (ellipse<3,float>); diff --git a/geom/fwd.hpp b/geom/fwd.hpp index 78772ffb..611a89a9 100644 --- a/geom/fwd.hpp +++ b/geom/fwd.hpp @@ -22,7 +22,7 @@ namespace util::geom { template struct ray; template struct plane; - template struct AABB; + template struct aabb; template struct sphere; template struct ellipse; template struct rect; diff --git a/geom/iostream.hpp b/geom/iostream.hpp index 507aecab..66af161c 100644 --- a/geom/iostream.hpp +++ b/geom/iostream.hpp @@ -26,7 +26,7 @@ namespace util::geom { template std::ostream& - operator<< (std::ostream&, AABB); + operator<< (std::ostream&, aabb); template std::ostream& diff --git a/geom/ops.hpp b/geom/ops.hpp index 504d584d..e0f5f979 100644 --- a/geom/ops.hpp +++ b/geom/ops.hpp @@ -55,7 +55,7 @@ namespace util::geom { typename T, template class K > - AABB + aabb bounds (K); template < diff --git a/geom/ray.cpp b/geom/ray.cpp index 3650ad3f..84802215 100644 --- a/geom/ray.cpp +++ b/geom/ray.cpp @@ -44,7 +44,7 @@ ray::intersect (plane q) const /// returns NaN if behind template T -ray::intersect (AABB r) const +ray::intersect (aabb r) const { auto t1 = (r.p0 - origin) / direction; auto t2 = (r.p1 - origin) / direction; diff --git a/geom/ray.hpp b/geom/ray.hpp index 5b2d13f6..3f506e86 100644 --- a/geom/ray.hpp +++ b/geom/ray.hpp @@ -47,7 +47,7 @@ namespace util::geom { //--------------------------------------------------------------------- // intersection tests T intersect (plane) const; - T intersect (AABB) const; + T intersect (aabb) const; T intersect (sphere) const; // queries diff --git a/test/geom/aabb.cpp b/test/geom/aabb.cpp index 696254a4..8e1cf651 100644 --- a/test/geom/aabb.cpp +++ b/test/geom/aabb.cpp @@ -4,7 +4,7 @@ #include -using util::geom::AABB2f; +using util::geom::aabb2f; int @@ -14,16 +14,16 @@ main (int, char**) { // Test contraction - const AABB2f val { { 2, 2 }, { 8, 8 } }; - const AABB2f res { { 3, 3 }, { 7, 7 } }; + const aabb2f val { { 2, 2 }, { 8, 8 } }; + const aabb2f res { { 3, 3 }, { 7, 7 } }; tap.expect_eq (val.contracted (2.f), res, "over contraction"); } { // Test expansion - const AABB2f val { { 2, 2 }, { 8, 8 } }; - const AABB2f res { { 1, 1 }, { 9, 9 } }; + const aabb2f val { { 2, 2 }, { 8, 8 } }; + const aabb2f res { { 1, 1 }, { 9, 9 } }; tap.expect_eq (val.expanded (2.f), res, "expansion"); } diff --git a/test/geom/ray.cpp b/test/geom/ray.cpp index 2cef97e1..7d5a3dc1 100644 --- a/test/geom/ray.cpp +++ b/test/geom/ray.cpp @@ -23,10 +23,10 @@ test_intersect_plane (util::TAP::logger &tap) void test_intersect_aabb (util::TAP::logger &tap) { - using util::geom::AABB2f; + using util::geom::aabb2f; // trivial case: unit aabb at origin, ray from (0.5,-0.5) upwards - const AABB2f box { + const aabb2f box { { 0.f, 0.f }, { 1.f, 1.f } }; From f77cdabaee0ba43400bc4e60e26019fb2779e533 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 16:47:02 +1000 Subject: [PATCH 062/149] geom/aabb: dont use mutating function naming convention --- geom/aabb.cpp | 8 ++++---- geom/aabb.hpp | 8 ++++---- test/geom/aabb.cpp | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index ad122a4b..50aa3d21 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -86,7 +86,7 @@ aabb::closest (point q) const /////////////////////////////////////////////////////////////////////////////// template aabb -aabb::expanded (vector mag) const noexcept +aabb::expand (vector mag) const noexcept { CHECK (all (mag >= T{0})); CHECK (all (mag < p1 - p0)); @@ -101,7 +101,7 @@ aabb::expanded (vector mag) const noexcept //----------------------------------------------------------------------------- template aabb -aabb::expanded (T t) const noexcept +aabb::expand (T t) const noexcept { CHECK_GE (t, T{0}); CHECK (all (t < p1 - p0)); @@ -116,7 +116,7 @@ aabb::expanded (T t) const noexcept /////////////////////////////////////////////////////////////////////////////// template aabb -aabb::contracted (util::vector mag) const noexcept +aabb::contract (util::vector mag) const noexcept { CHECK (all (mag > T{0})); CHECK (all (mag <= p1 - p0)); @@ -131,7 +131,7 @@ aabb::contracted (util::vector mag) const noexcept //----------------------------------------------------------------------------- template aabb -aabb::contracted (T mag) const noexcept +aabb::contract (T mag) const noexcept { CHECK_GE (mag, T{0}); CHECK (all (mag <= p1 - p0)); diff --git a/geom/aabb.hpp b/geom/aabb.hpp index 62793d7d..6f11b6aa 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -36,11 +36,11 @@ namespace util::geom { point closest (point) const; - aabb expanded (util::vector) const noexcept; - aabb expanded (T) const noexcept; + aabb expand (util::vector) const noexcept; + aabb expand (T) const noexcept; - aabb contracted (util::vector) const noexcept; - aabb contracted (T) const noexcept; + aabb contract (util::vector) const noexcept; + aabb contract (T) const noexcept; void cover (point); diff --git a/test/geom/aabb.cpp b/test/geom/aabb.cpp index 8e1cf651..f9346f44 100644 --- a/test/geom/aabb.cpp +++ b/test/geom/aabb.cpp @@ -17,7 +17,7 @@ main (int, char**) const aabb2f val { { 2, 2 }, { 8, 8 } }; const aabb2f res { { 3, 3 }, { 7, 7 } }; - tap.expect_eq (val.contracted (2.f), res, "over contraction"); + tap.expect_eq (val.contract (2.f), res, "over contraction"); } { @@ -25,7 +25,7 @@ main (int, char**) const aabb2f val { { 2, 2 }, { 8, 8 } }; const aabb2f res { { 1, 1 }, { 9, 9 } }; - tap.expect_eq (val.expanded (2.f), res, "expansion"); + tap.expect_eq (val.expand (2.f), res, "expansion"); } return tap.status (); From 1cea1600d3cfc0f7a67a1ce19753baa1ea4fcaba Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 16:54:48 +1000 Subject: [PATCH 063/149] geom/aabb: change contract/expand semantics to mirror region --- geom/aabb.cpp | 32 +++++++++----------------------- test/geom/aabb.cpp | 4 ++-- 2 files changed, 11 insertions(+), 25 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 50aa3d21..c491885e 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -89,27 +89,19 @@ aabb aabb::expand (vector mag) const noexcept { CHECK (all (mag >= T{0})); - CHECK (all (mag < p1 - p0)); - return { - p0 - mag / T{2}, - p1 + mag / T{2} - }; + return { p0 - mag, p1 + mag }; } //----------------------------------------------------------------------------- template aabb -aabb::expand (T t) const noexcept +aabb::expand (T mag) const noexcept { - CHECK_GE (t, T{0}); - CHECK (all (t < p1 - p0)); + CHECK_GE (mag, T{0}); - return { - p0 - t / T{2}, - p1 + t / T{2} - }; + return { p0 - mag, p1 + mag }; } @@ -118,13 +110,10 @@ template aabb aabb::contract (util::vector mag) const noexcept { - CHECK (all (mag > T{0})); - CHECK (all (mag <= p1 - p0)); + CHECK (all (mag >= T{0})); + CHECK (all (2 * mag <= p1 - p0)); - return { - p0 + mag / T{2}, - p1 - mag / T{2} - }; + return { p0 + mag, p1 - mag }; } @@ -134,12 +123,9 @@ aabb aabb::contract (T mag) const noexcept { CHECK_GE (mag, T{0}); - CHECK (all (mag <= p1 - p0)); + CHECK (all (2 * mag <= p1 - p0)); - return { - p0 + mag / T{2}, - p1 - mag / T{2} - }; + return { p0 + mag, p1 - mag }; } diff --git a/test/geom/aabb.cpp b/test/geom/aabb.cpp index f9346f44..35583bd4 100644 --- a/test/geom/aabb.cpp +++ b/test/geom/aabb.cpp @@ -17,7 +17,7 @@ main (int, char**) const aabb2f val { { 2, 2 }, { 8, 8 } }; const aabb2f res { { 3, 3 }, { 7, 7 } }; - tap.expect_eq (val.contract (2.f), res, "over contraction"); + tap.expect_eq (val.contract (1.f), res, "over contraction"); } { @@ -25,7 +25,7 @@ main (int, char**) const aabb2f val { { 2, 2 }, { 8, 8 } }; const aabb2f res { { 1, 1 }, { 9, 9 } }; - tap.expect_eq (val.expand (2.f), res, "expansion"); + tap.expect_eq (val.expand (1.f), res, "expansion"); } return tap.status (); From 56444b4a50ab925b15ed2246c17c0fb45797a1e6 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:02:18 +1000 Subject: [PATCH 064/149] geom/aabb: add (minimally) more thorough test data --- test/geom/aabb.cpp | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/test/geom/aabb.cpp b/test/geom/aabb.cpp index 35583bd4..1925e822 100644 --- a/test/geom/aabb.cpp +++ b/test/geom/aabb.cpp @@ -13,19 +13,17 @@ main (int, char**) util::TAP::logger tap; { - // Test contraction - const aabb2f val { { 2, 2 }, { 8, 8 } }; - const aabb2f res { { 3, 3 }, { 7, 7 } }; + const aabb2f val { { 1, 2 }, { 8, 5 } }; + const aabb2f res { { 3, 3 }, { 6, 4 } }; - tap.expect_eq (val.contract (1.f), res, "over contraction"); + tap.expect_eq (val.contract ({2.f, 1.f}), res, "aabb::contract"); } { - // Test expansion - const aabb2f val { { 2, 2 }, { 8, 8 } }; - const aabb2f res { { 1, 1 }, { 9, 9 } }; + const aabb2f val { { 2, 1 }, { 3, 6 } }; + const aabb2f res { { 1, -1 }, { 4, 8 } }; - tap.expect_eq (val.expand (1.f), res, "expansion"); + tap.expect_eq (val.expand ({1.f, 2.f}), res, "aabb::expand"); } return tap.status (); From 94e02fced4adf4426d4413d9a07bac125aea32c5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:08:37 +1000 Subject: [PATCH 065/149] geom/aabb: make the equality operator a free function --- geom/aabb.cpp | 13 ++----------- geom/aabb.hpp | 20 +++++++++++++++----- 2 files changed, 17 insertions(+), 16 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index c491885e..029ea30e 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -11,7 +11,7 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015 Danny Robson + * Copyright 2015-2017 Danny Robson */ @@ -23,6 +23,7 @@ using util::geom::aabb; + //----------------------------------------------------------------------------- template aabb::aabb (point _p0, point _p1): @@ -158,16 +159,6 @@ aabb::operator- (vector v) const /////////////////////////////////////////////////////////////////////////////// -template -bool -aabb::operator== (const aabb rhs) const -{ - return rhs.p0 == p0 && rhs.p1 == p1; -} - - - -//----------------------------------------------------------------------------- namespace util::debug { template struct validator> { diff --git a/geom/aabb.hpp b/geom/aabb.hpp index 6f11b6aa..ab943799 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -11,12 +11,12 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2015-2016 Danny Robson + * Copyright 2015-2017 Danny Robson */ -#ifndef __UTIL_GEOM_AABB_HPP -#define __UTIL_GEOM_AABB_HPP +#ifndef CRUFT_UTIL_GEOM_AABB_HPP +#define CRUFT_UTIL_GEOM_AABB_HPP #include "../point.hpp" #include "../extent.hpp" @@ -24,6 +24,7 @@ #include namespace util::geom { + /////////////////////////////////////////////////////////////////////////// template struct aabb { aabb () = default; @@ -47,12 +48,21 @@ namespace util::geom { aabb operator+ (vector) const; aabb operator- (vector) const; - bool operator== (aabb) const; - point p0; point p1; }; + + /////////////////////////////////////////////////////////////////////////// + template + constexpr bool + operator== (const aabb &a, const aabb &b) noexcept + { + return a.p0 == b.p0 && a.p1 == b.p1; + } + + + /////////////////////////////////////////////////////////////////////////// typedef aabb<2,float> aabb2f; typedef aabb<2,unsigned> aabb2u; typedef aabb<2,int> aabb2i; From 9fe89984765c9ca31818f38f8e78d9f8fe803f91 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:11:48 +1000 Subject: [PATCH 066/149] geom/aabb: rename overlaps as inclusive for consistency --- geom/aabb.cpp | 2 +- geom/aabb.hpp | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 029ea30e..4b1acb05 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -58,7 +58,7 @@ aabb::magnitude (void) const //----------------------------------------------------------------------------- template bool -aabb::overlaps (point p) const +aabb::inclusive (point p) const { for (size_t i = 0; i < S; ++i) if (p0[i] > p[i] || p1[i] < p[i]) diff --git a/geom/aabb.hpp b/geom/aabb.hpp index ab943799..461ac8fb 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -33,7 +33,8 @@ namespace util::geom { T diameter (void) const; extent magnitude (void) const; - bool overlaps (point) const; + /// tests whether a point lies within the region, inclusive of borders + bool inclusive (point) const; point closest (point) const; From d47f52b63f0391eac2acfcd5cd8541c3cc81cf4c Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:12:17 +1000 Subject: [PATCH 067/149] geom/aabb: use vector operations for inclusive test --- geom/aabb.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 4b1acb05..dd44c6e8 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -60,11 +60,7 @@ template bool aabb::inclusive (point p) const { - for (size_t i = 0; i < S; ++i) - if (p0[i] > p[i] || p1[i] < p[i]) - return false; - - return true; + return all (p0 <= p && p1 >= p); } From e82d770d2b3146ac7006defeb767a8918f64dee2 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:21:23 +1000 Subject: [PATCH 068/149] geom/aabb: move inclusive point query into header --- geom/aabb.cpp | 14 +------------- geom/aabb.hpp | 6 ++++-- 2 files changed, 5 insertions(+), 15 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index dd44c6e8..03d1608a 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -48,19 +48,7 @@ template util::extent aabb::magnitude (void) const { - extent out; - for (size_t i = 0; i < S; ++i) - out[i] = p1[i] - p0[i]; - return out; -} - - -//----------------------------------------------------------------------------- -template -bool -aabb::inclusive (point p) const -{ - return all (p0 <= p && p1 >= p); + return (p1 - p0).template as (); } diff --git a/geom/aabb.hpp b/geom/aabb.hpp index 461ac8fb..31ca00ce 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -30,11 +30,13 @@ namespace util::geom { aabb () = default; aabb (point, point); - T diameter (void) const; extent magnitude (void) const; + T diameter (void) const; /// tests whether a point lies within the region, inclusive of borders - bool inclusive (point) const; + constexpr bool + inclusive (point p) const noexcept + { return all (p0 <= p && p1 >= p); } point closest (point) const; From f53b547a40ae196c6663c0d1ec12d803e0934311 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:27:31 +1000 Subject: [PATCH 069/149] geom/aabb: prefer to use vector operations over loops --- geom/aabb.cpp | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 03d1608a..a5258ba7 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -57,14 +57,7 @@ template util::point aabb::closest (point q) const { - point res; - - for (size_t i = 0; i < S; ++i) - res[i] = q[i] < p0[i] ? p0[i] : - q[i] > p1[i] ? p1[i] : - q[i]; - - return res; + return limit (q, p0, p1); } @@ -148,11 +141,7 @@ namespace util::debug { struct validator> { static bool is_valid (const aabb &b) { - for (size_t i = 0; i < S; ++i) - if (b.p1[i] < b.p0[i]) - return false; - - return true; + return all (b.p0 <= b.p1); } }; } From 1277975708128a073f966242e90f72962b55ec9c Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:27:46 +1000 Subject: [PATCH 070/149] geom/aabb: add brief class description --- geom/aabb.hpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/geom/aabb.hpp b/geom/aabb.hpp index 31ca00ce..a471136c 100644 --- a/geom/aabb.hpp +++ b/geom/aabb.hpp @@ -25,6 +25,10 @@ namespace util::geom { /////////////////////////////////////////////////////////////////////////// + /// represents an axis-aligned bounding-box through two opposing corners. + /// + /// p0 must be less-than-or-equal to p1. equality is allowed so that we + /// can represent zero sized bounding-boxes. template struct aabb { aabb () = default; From 8b2c1d3fd29b4238b38fe34aa97b6dda08d43524 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:52:06 +1000 Subject: [PATCH 071/149] coord/init: make 1-dimension constructor explicit --- coord/init.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/coord/init.hpp b/coord/init.hpp index 5423e75b..cef7dd30 100644 --- a/coord/init.hpp +++ b/coord/init.hpp @@ -31,7 +31,7 @@ namespace util::coord { { using store<1,T,tags...>::store; constexpr init () = default; - constexpr init (T v0): + constexpr explicit init (T v0): store<1,T,tags...> ({v0}) { ; } }; From e573c0bcc6b906c9398cf880741c9b9cb39b6348 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:52:46 +1000 Subject: [PATCH 072/149] geom/aabb: style and headers --- geom/aabb.cpp | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index a5258ba7..74b75a1f 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -24,9 +24,9 @@ using util::geom::aabb; -//----------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////////////// template -aabb::aabb (point _p0, point _p1): +aabb::aabb (const point _p0, const point _p1): p0 (_p0), p1 (_p1) { @@ -34,7 +34,7 @@ aabb::aabb (point _p0, point _p1): } -//----------------------------------------------------------------------------- +/////////////////////////////////////////////////////////////////////////////// template T aabb::diameter (void) const @@ -55,7 +55,7 @@ aabb::magnitude (void) const //----------------------------------------------------------------------------- template util::point -aabb::closest (point q) const +aabb::closest (const point q) const { return limit (q, p0, p1); } @@ -64,7 +64,7 @@ aabb::closest (point q) const /////////////////////////////////////////////////////////////////////////////// template aabb -aabb::expand (vector mag) const noexcept +aabb::expand (const vector mag) const noexcept { CHECK (all (mag >= T{0})); @@ -75,7 +75,7 @@ aabb::expand (vector mag) const noexcept //----------------------------------------------------------------------------- template aabb -aabb::expand (T mag) const noexcept +aabb::expand (const T mag) const noexcept { CHECK_GE (mag, T{0}); @@ -83,10 +83,10 @@ aabb::expand (T mag) const noexcept } -/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- template aabb -aabb::contract (util::vector mag) const noexcept +aabb::contract (const util::vector mag) const noexcept { CHECK (all (mag >= T{0})); CHECK (all (2 * mag <= p1 - p0)); @@ -98,7 +98,7 @@ aabb::contract (util::vector mag) const noexcept //----------------------------------------------------------------------------- template aabb -aabb::contract (T mag) const noexcept +aabb::contract (const T mag) const noexcept { CHECK_GE (mag, T{0}); CHECK (all (2 * mag <= p1 - p0)); @@ -107,10 +107,10 @@ aabb::contract (T mag) const noexcept } -/////////////////////////////////////////////////////////////////////////////// +//----------------------------------------------------------------------------- template void -aabb::cover (point p) +aabb::cover (const point p) { p0 = min (p, p0); p1 = max (p, p1); @@ -120,7 +120,7 @@ aabb::cover (point p) /////////////////////////////////////////////////////////////////////////////// template aabb -aabb::operator+ (vector v) const +aabb::operator+ (const vector v) const { return { p0 + v, p1 + v }; } @@ -129,7 +129,7 @@ aabb::operator+ (vector v) const //----------------------------------------------------------------------------- template aabb -aabb::operator- (vector v) const +aabb::operator- (const vector v) const { return { p0 - v, p1 - v }; } From 07d74187c597ca71a73a966eb87d9f05442e35bd Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:52:59 +1000 Subject: [PATCH 073/149] geom/aabb: don't write the class name with ostream operators --- geom/aabb.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/geom/aabb.cpp b/geom/aabb.cpp index 74b75a1f..8a826025 100644 --- a/geom/aabb.cpp +++ b/geom/aabb.cpp @@ -152,8 +152,7 @@ template std::ostream& util::geom::operator<< (std::ostream &os, util::geom::aabb b) { - os << "aabb(" << b.p0 << ", " << b.p1 << ")"; - return os; + return os << "[ " << b.p0 << ", " << b.p1 << " ]"; } From 8f6af0f837d98e4758f73c91640ee64b7f8ddfd5 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:53:27 +1000 Subject: [PATCH 074/149] job/queue: make single argument constructor explicit --- job/queue.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/job/queue.hpp b/job/queue.hpp index ceac6986..ddc3194e 100644 --- a/job/queue.hpp +++ b/job/queue.hpp @@ -32,7 +32,7 @@ namespace util::job { class queue { public: queue (); - queue (unsigned thread_count); + explicit queue (unsigned thread_count); ~queue (); using cookie = int; From e9ef2ae316e1b41eb98a1110463d2d09e8870cdd Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Thu, 24 Aug 2017 17:53:46 +1000 Subject: [PATCH 075/149] sarray: add assignment operator for completeness in test --- test/sarray.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/test/sarray.cpp b/test/sarray.cpp index e44d5c28..70370de8 100644 --- a/test/sarray.cpp +++ b/test/sarray.cpp @@ -19,6 +19,12 @@ struct counter { counter (rhs.var) { ; } + counter& operator= (const counter &rhs) + { + var = rhs.var; + return *this; + } + ~counter () { --var; } From 3c9dcba2fb54e29509fe5e2f40f083f020e78dac Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Fri, 25 Aug 2017 13:03:21 +1000 Subject: [PATCH 076/149] coord/ops: add rshift coord operation shifts each element to the right `num' places and fills the left space with a constant or elements from another vector. --- coord/ops.hpp | 47 +++++++++++++++++++++++++++++++++++++++++++++++ test/coord.cpp | 12 ++++++++++++ 2 files changed, 59 insertions(+) diff --git a/coord/ops.hpp b/coord/ops.hpp index c996b8d4..70dadb81 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -1052,6 +1052,53 @@ namespace util { return out; } + + /////////////////////////////////////////////////////////////////////////// + /// shifts all elements `num' indices to the right, setting the left-most + /// `num' indices to the value `fill'. + /// + /// num must be between 0 and S. when 0 it is equivalent to an ordinary + /// fill, when S it is equivalent to a noop. + template< + std::size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr + K + rshift (const K k, const int num, const K fill) + { + CHECK_LIMIT (num, 0, int (S)); + + K res {}; + + std::copy_n (std::cbegin (k), S - num, std::begin (res) + num); + std::copy_n (std::cbegin (fill), num, std::begin (res)); + + return res; + } + + + //------------------------------------------------------------------------- + template< + std::size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, void + > + > + constexpr + K + rshift (const K k, const int num, T fill) + { + return rshift (k, num, K {fill}); + } + + /// returns the data at a templated index in a coordinate. /// /// specifically required for structured bindings support. diff --git a/test/coord.cpp b/test/coord.cpp index 8de918aa..7f606db9 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -99,5 +99,17 @@ main (void) tap.expect_eq (seq.indices<2,0,0,1> (), res, "coord::indices expansion"); }; + // ensure that util::shift operations appear to operate correctly + { + const util::vector3i seq { 0, 1, 2 }; + tap.expect_eq (rshift (seq, 1, 0), util::make_vector (0, 0, 1), "rshift, scalar fill"); + + tap.expect_eq ( + rshift (seq, 2, util::make_vector (3, 4, 5 )), + util::make_vector (3, 4, 0), + "rshift, coord fill" + ); + }; + return tap.status (); } From 8f216a0a27982b3fca916761077c191ac83fc152 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 11:37:18 +1000 Subject: [PATCH 077/149] coord/base: don't use std::fill in constexpr constructor --- coord/base.hpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index 8a32ade2..6e38df40 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -57,8 +57,11 @@ namespace util::coord { /// constructs an instance where all elements are initialised to `val'. constexpr explicit - base (T val) - { std::fill (begin (), end (), val); } + base (T fill) + { + for (decltype(S) i = 0; i < S; ++i) + this->data[i] = fill; + } constexpr base (const base &rhs) = default; base& operator= (const base &rhs) = default; From 31652ed3a360243be76ebff3572c4670d1a76fe7 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 11:37:52 +1000 Subject: [PATCH 078/149] coord/base: add clarifying comment to index assertion --- coord/base.hpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/coord/base.hpp b/coord/base.hpp index 6e38df40..22bf4601 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -175,7 +175,11 @@ namespace util::coord { KLASS indices (void) const { - static_assert (all (make_vector ((Indices < S)...))); + static_assert ( + all (make_vector ((Indices < S)...)), + "indices must fall within the defined range for the type" + ); + return KLASS { this->data[Indices]... }; } }; From 677a0aa4a9fba7e55212217375ae990b97578fcb Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 12:27:26 +1000 Subject: [PATCH 079/149] coord/ops: use vector ops for point difference --- coord/ops.hpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/coord/ops.hpp b/coord/ops.hpp index 70dadb81..b86b0fc4 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -367,10 +367,7 @@ namespace util { vector> operator- (point a, point b) { - vector> out {}; - for (size_t i = 0; i < S; ++i) - out[i] = a[i] - b[i]; - return out; + return a.template as () - b.template as (); } From cde0fe882e9a7cf83a26ec34edf110b0b2218a99 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 12:28:00 +1000 Subject: [PATCH 080/149] vector: add more convenience typedefs for bools --- vector.hpp | 29 +++++++++++++++++------------ 1 file changed, 17 insertions(+), 12 deletions(-) diff --git a/vector.hpp b/vector.hpp index f274a650..2d58c1bc 100644 --- a/vector.hpp +++ b/vector.hpp @@ -68,22 +68,27 @@ namespace util { template using vectoru = vector; template using vectori = vector; template using vectorf = vector; + template using vectorb = vector; - typedef vector2 vector2u; - typedef vector3 vector3u; - typedef vector4 vector4u; + using vector2u = vector2; + using vector3u = vector3; + using vector4u = vector4; - typedef vector2 vector2i; - typedef vector3 vector3i; - typedef vector4 vector4i; + using vector2i = vector2; + using vector3i = vector3; + using vector4i = vector4; - typedef vector2 vector2f; - typedef vector3 vector3f; - typedef vector4 vector4f; + using vector2f = vector2; + using vector3f = vector3; + using vector4f = vector4; - typedef vector2 vector2d; - typedef vector3 vector3d; - typedef vector4 vector4d; + using vector2d = vector2; + using vector3d = vector3; + using vector4d = vector4; + + using vector2b = vector2; + using vector3b = vector3; + using vector4b = vector4; } #include "vector.ipp" From 9aa0ba8f5569a7e028efcc2eb2a4bfbaa3d1ef33 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 12:28:56 +1000 Subject: [PATCH 081/149] test: use constexpr for test data where possible --- test/coord.cpp | 2 +- test/extent.cpp | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/test/coord.cpp b/test/coord.cpp index 7f606db9..4836918c 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -54,7 +54,7 @@ main (void) ); } - // test expected outputs for various logical operations + // test expected outputs for various vector-logical operations { constexpr util::point3i a { 0, -1, 2 }; constexpr util::point3i b { 0, 1, -2 }; diff --git a/test/extent.cpp b/test/extent.cpp index cedd6301..624d897e 100644 --- a/test/extent.cpp +++ b/test/extent.cpp @@ -8,13 +8,13 @@ main (void) util::TAP::logger tap; { - util::extent2u hi { 8, 4 }; - util::extent2u lo { 6, 2 }; + constexpr const util::extent2u hi { 8, 4 }; + constexpr const util::extent2u lo { 6, 2 }; tap.expect_eq (lo, hi.contracted (2), "extent scalar contraction by value"); } { - static const util::point2u EXPECTED[] = { + static constexpr util::point2u EXPECTED[] = { { 0, 0 }, { 1, 0 }, { 2, 0 }, { 0, 1 }, { 1, 1 }, { 2, 1 }, { 0, 2 }, { 1, 2 }, { 2, 2 }, From e7fe5d044abf2851db752770b175ab84317edda2 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 12:30:09 +1000 Subject: [PATCH 082/149] extent: prefer to use brace initialisation --- extent.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/extent.cpp b/extent.cpp index 03b4becb..3c1bc38e 100644 --- a/extent.cpp +++ b/extent.cpp @@ -98,7 +98,7 @@ template typename extent_range::iterator extent_range::begin (void) const { - return iterator (m_target, util::point (0)); + return { m_target, util::point (0) }; } @@ -110,7 +110,7 @@ extent_range::end (void) const util::point cursor (0); cursor[S-1] = m_target[S-1]; - return iterator (m_target, cursor); + return { m_target, cursor }; } From 3799135236484b767d9bbc05d61280480c4c5f01 Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Sun, 27 Aug 2017 12:32:00 +1000 Subject: [PATCH 083/149] coord: add general vector comparison function --- coord/base.hpp | 1 + coord/ops.hpp | 83 ++++++++++++++++++++++++++++++++++++++++--------- test/coord.cpp | 7 ----- test/matrix.cpp | 9 +++++- vector.hpp | 14 ++++++--- 5 files changed, 87 insertions(+), 27 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index 22bf4601..e63e4a52 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -185,5 +185,6 @@ namespace util::coord { }; } +#include "../vector.hpp" #endif diff --git a/coord/ops.hpp b/coord/ops.hpp index b86b0fc4..7ed7183e 100644 --- a/coord/ops.hpp +++ b/coord/ops.hpp @@ -11,11 +11,11 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2012-2016 Danny Robson + * Copyright 2012-2017 Danny Robson */ -#ifndef __UTIL_COORDS_OPS -#define __UTIL_COORDS_OPS +#ifndef CRUFT_UTIL_COORDS_OPS +#define CRUFT_UTIL_COORDS_OPS #include "./fwd.hpp" @@ -28,6 +28,7 @@ #include #include #include +#include namespace util { /////////////////////////////////////////////////////////////////////// @@ -293,6 +294,63 @@ namespace util { /////////////////////////////////////////////////////////////////////////// // logic operators + namespace detail { + template < + std::size_t S, + typename T, + template class K, + typename FuncT, + typename = std::enable_if_t< + is_coord_v>, + void + >, + std::size_t ...Indices + > + constexpr auto + compare (FuncT &&func, std::index_sequence, const K a, const K b) + { + return vector { + std::invoke (func, a[Indices], b[Indices])... + }; + } + } + + + //------------------------------------------------------------------------- + template < + std::size_t S, + typename T, + template class K, + typename FuncT, + typename = std::enable_if_t< + is_coord_v>, + void + >, + typename Indices = std::make_index_sequence + > + constexpr auto + compare (const K a, const K b, FuncT &&func) + { + return detail::compare (std::forward (func), Indices{}, a, b); + } + + + //------------------------------------------------------------------------- + template < + std::size_t S, + typename T, + template class K, + typename = std::enable_if_t< + is_coord_v>, + void + > + > + constexpr auto + compare (const K a, const K b) + { + return compare (a, b, std::equal_to {}); + } + /// elementwise equality operator template < @@ -303,16 +361,10 @@ namespace util { is_coord_v>, void > > - constexpr - bool + constexpr bool operator== (const K a, const K b) { - bool (*predicate)(const T&, const T&) = almost_equal; - - return std::equal (std::cbegin (a), - std::cend (a), - std::cbegin (b), - predicate); + return all (compare (a, b, std::equal_to {})); } ///------------------------------------------------------------------------ @@ -325,11 +377,10 @@ namespace util { is_coord_v>, void > > - constexpr - bool - operator!= (K a, K b) + constexpr bool + operator!= (const K a, const K b) { - return !(a == b); + return any (compare (a, b, std::not_equal_to {})); } @@ -909,6 +960,7 @@ namespace util { SCALAR_OP(>) SCALAR_OP(<=) SCALAR_OP(>=) + SCALAR_OP(==) SCALAR_OP(&&) SCALAR_OP(||) @@ -1026,6 +1078,7 @@ namespace util { return k; } + /////////////////////////////////////////////////////////////////////////// template < size_t S, diff --git a/test/coord.cpp b/test/coord.cpp index 4836918c..a11aede1 100644 --- a/test/coord.cpp +++ b/test/coord.cpp @@ -23,13 +23,6 @@ main (void) tap.expect_eq (-p, util::point2i { 1, -2 }, "unary point negation"); tap.expect_eq ( p, p, "unary point addition"); - tap.expect ( - std::is_same< - bool, - decltype(!p)::value_type - >::value, - "unary point boolean negation has type bool" - ); auto vec = util::vector4f (0.5f); tap.expect_eq (vec, util::normalised (vec), "normalisation of normalised vector"); diff --git a/test/matrix.cpp b/test/matrix.cpp index 844a8ef8..0e077098 100644 --- a/test/matrix.cpp +++ b/test/matrix.cpp @@ -203,7 +203,14 @@ main (void) euler = mod (euler + 4 * PI2, PI2); truth = mod (truth + 4 * PI2, PI2); - tap.expect_eq (truth, euler, "matrix-to-euler, %s", t.msg); + tap.expect ( + all (compare ( + truth, euler, + [] (auto a, auto b) { return util::almost_equal (a, b); } + )), + "matrix-to-euler, %s", + t.msg + ); } } diff --git a/vector.hpp b/vector.hpp index 2d58c1bc..fcf5e9e4 100644 --- a/vector.hpp +++ b/vector.hpp @@ -11,15 +11,21 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2011-2016 Danny Robson + * Copyright 2011-2017 Danny Robson */ -#ifndef __UTIL_VECTOR_HPP -#define __UTIL_VECTOR_HPP +#ifndef CRUFT_UTIL_VECTOR_HPP +#define CRUFT_UTIL_VECTOR_HPP + +#include "./coord/fwd.hpp" +#include "./coord.hpp" -#include "coord.hpp" #include "json/fwd.hpp" +#include + + +/////////////////////////////////////////////////////////////////////////////// namespace util { template struct vector : public coord::base From c4e367e648c90a5170a6f306cd4d5522a3330bbe Mon Sep 17 00:00:00 2001 From: Danny Robson Date: Mon, 28 Aug 2017 12:25:23 +1000 Subject: [PATCH 084/149] coord: use std::size_t over size_t --- coord/base.hpp | 22 +-- coord/fwd.hpp | 16 ++- coord/init.hpp | 8 +- coord/iostream.hpp | 12 +- coord/names.hpp | 4 +- coord/ops.hpp | 324 ++++++++++++++++++++++----------------------- coord/store.hpp | 12 +- 7 files changed, 200 insertions(+), 198 deletions(-) diff --git a/coord/base.hpp b/coord/base.hpp index e63e4a52..2afb74bd 100644 --- a/coord/base.hpp +++ b/coord/base.hpp @@ -11,11 +11,11 @@ * See the License for the specific language governing permissions and * limitations under the License. * - * Copyright 2012-2016 Danny Robson + * Copyright 2012-2017 Danny Robson */ -#ifndef __UTIL_COORD_BASE_HPP -#define __UTIL_COORD_BASE_HPP +#ifndef CRUFT_UTIL_COORD_BASE_HPP +#define CRUFT_UTIL_COORD_BASE_HPP #include "init.hpp" @@ -29,9 +29,9 @@ namespace util::coord { ///////////////////////////////////////////////////////////////////////// template < - size_t S, + std::size_t S, typename T, - template class KLASS, + template class KLASS, typename ...tags > struct base : public init { @@ -39,11 +39,11 @@ namespace util::coord { static_assert (std::is_arithmetic::value); using value_type = T; - static constexpr size_t dimension = S; - static constexpr size_t elements = S; + static constexpr std::size_t dimension = S; + static constexpr std::size_t elements = S; /// returns the number of elements we contain - static constexpr size_t size (void) { return S; } + static constexpr std::size_t size (void) { return S; } // inherit the fancy elementwise constructors from `init'. using init::init; @@ -67,8 +67,8 @@ namespace util::coord { base& operator= (const base &rhs) = default; // element accessors - T& operator[] (size_t i) { return this->data[i]; } - constexpr const T& operator[] (size_t i) const { return this->data[i]; } + T& operator[] (std::size_t i) { return this->data[i]; } + constexpr const T& operator[] (std::size_t i) const { return this->data[i]; } auto cbegin (void) const { return std::cbegin (this->data); } auto cend (void) const { return std::cend (this->data); } @@ -87,7 +87,7 @@ namespace util::coord { /////////////////////////////////////////////////////////////////////// // conversions - template