1111
1212namespace delaunator {
1313
14+ // @see https://stackoverflow.com/questions/33333363/built-in-mod-vs-custom-mod-function-improve-the-performance-of-modulus-op/33333636#33333636
15+ inline size_t fast_mod (const size_t i, const size_t c) {
16+ return i >= c ? i % c : i;
17+ };
18+
19+ inline size_t fast_mod_3 (const size_t i) {
20+ return i % 3 ;
21+ };
22+
1423// Kahan and Babuska summation, Neumaier variant; accumulates less FP error
1524inline double sum (const std::vector<double >& x) {
1625 double sum = x[0 ];
@@ -151,7 +160,7 @@ inline bool check_pts_equal(double x1, double y1, double x2, double y2) {
151160}
152161
153162// monotonically increases with real angle, but doesn't need expensive trigonometry
154- inline double pseudo_angle (double dx, double dy) {
163+ inline double pseudo_angle (const double dx, const double dy) {
155164 const double p = dx / (std::abs (dx) + std::abs (dy));
156165 return (dy > 0.0 ? 3.0 - p : 1.0 + p) / 4.0 ; // [0..1)
157166}
@@ -189,7 +198,7 @@ class Delaunator {
189198 std::size_t m_legalize_stack[LEGALIZE_STACK_SIZE];
190199
191200 std::size_t legalize (std::size_t a);
192- std::size_t hash_key (double x, double y);
201+ std::size_t hash_key (double x, double y) const ;
193202 std::size_t add_triangle (
194203 std::size_t i0,
195204 std::size_t i1,
@@ -354,7 +363,7 @@ Delaunator::Delaunator(std::vector<double> const& in_coords)
354363
355364 size_t key = hash_key (x, y);
356365 for (size_t j = 0 ; j < m_hash_size; j++) {
357- start = m_hash[(key + j) % m_hash_size];
366+ start = m_hash[fast_mod (key + j, m_hash_size) ];
358367 if (start != INVALID_INDEX && start != hull_next[start]) break ;
359368 }
360369
@@ -441,10 +450,10 @@ std::size_t Delaunator::legalize(std::size_t ia) {
441450 std::size_t ar;
442451 std::size_t bl;
443452
444- size_t i = 0 ;
453+ unsigned int i = 0 ;
445454 m_legalize_stack[i] = ia;
446455 size_t size = 1 ;
447- while (i < size) {
456+ while (i < size) {
448457
449458 if (i >= LEGALIZE_STACK_SIZE) {
450459 throw std::runtime_error (" Legalize stack overflow" );
@@ -471,12 +480,13 @@ std::size_t Delaunator::legalize(std::size_t ia) {
471480
472481 b = halfedges[a];
473482
474- a0 = a - a % 3 ;
475- b0 = b - b % 3 ;
483+ // @see https://embeddedgurus.com/stack-overflow/2011/02/efficient-c-tip-13-use-the-modulus-operator-with-caution/
484+ a0 = 3 * (a / 3 ); // a - a % 3;
485+ b0 = 3 * (b / 3 ); // b - b % 3;
476486
477- al = a0 + (a + 1 ) % 3 ;
478- ar = a0 + (a + 2 ) % 3 ;
479- bl = b0 + (b + 2 ) % 3 ;
487+ al = a0 + fast_mod_3 (a + 1 );
488+ ar = a0 + fast_mod_3 (a + 2 );
489+ bl = b0 + fast_mod_3 (b + 2 );
480490
481491 const std::size_t p0 = triangles[ar];
482492 const std::size_t pr = triangles[a];
@@ -518,29 +528,29 @@ std::size_t Delaunator::legalize(std::size_t ia) {
518528 link (b, halfedges[ar]);
519529 link (ar, bl);
520530
521- std::size_t br = b0 + (b + 1 ) % 3 ;
531+ std::size_t br = b0 + fast_mod_3 (b + 1 );
522532
523533 if (i < size) {
524534 // move elements down the stack
525- for (auto mi = size - 1 ; mi >= i; mi--) {
535+ for (auto mi = size - 1 ; mi >= i; mi--) {
526536 m_legalize_stack[mi + 2 ] = m_legalize_stack[mi];
527537 }
528538 }
529539
530540 m_legalize_stack[i] = a;
531541 m_legalize_stack[i + 1 ] = br;
532- size+= 2 ;
542+ size += 2 ;
533543 }
534544 }
535545 return ar;
536546}
537547
538- std::size_t Delaunator::hash_key (double x, double y) {
548+ inline std::size_t Delaunator::hash_key (const double x, const double y) const {
539549 const double dx = x - m_center_x;
540550 const double dy = y - m_center_y;
541- return static_cast <std:: size_t >( std::llround (
542- std::floor (pseudo_angle (dx, dy) * static_cast <double >(m_hash_size)))) %
543- m_hash_size;
551+ return fast_mod (
552+ static_cast < std::size_t >( std::llround ( std:: floor (pseudo_angle (dx, dy) * static_cast <double >(m_hash_size)))),
553+ m_hash_size) ;
544554}
545555
546556std::size_t Delaunator::add_triangle (
0 commit comments