KiCad PCB EDA Suite
Loading...
Searching...
No Matches
fracture_edge_index_utils.h
Go to the documentation of this file.
1/*
2 * This program source code file is part of KiCad, a free EDA CAD application.
3 *
4 * Copyright The KiCad Developers, see AUTHORS.txt for contributors.
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <https://www.gnu.org/licenses/>.
18 */
19
20#ifndef FRACTURE_EDGE_INDEX_UTILS_H
21#define FRACTURE_EDGE_INDEX_UTILS_H
22
23#include <algorithm>
24#include <cmath>
25#include <cstddef>
26#include <cstdint>
27#include <limits>
28#include <utility>
29
31{
32constexpr uint32_t MAX_STRIPES = 65536;
33constexpr uint32_t MAX_BUCKET_SPAN = 8;
34// The index is at most ~1.6x the edge set it serves, so a budget proportional to the edge set
35// bounds the footprint without dropping the index on the large planes that need it most
36constexpr size_t EDGE_SET_BUDGET_MULTIPLE = 2;
37constexpr uint64_t MIN_EDGE_VISITS = 32768;
38constexpr size_t MIN_HOLE_COUNT = 8;
39
40inline uint32_t StripeCountFor( size_t aEdgeCount )
41{
42 const double count = std::clamp( std::sqrt( static_cast<double>( aEdgeCount ) ), 1.0,
43 static_cast<double>( MAX_STRIPES ) );
44 return static_cast<uint32_t>( count );
45}
46
47inline uint32_t MapYToStripe( int aY, int aMinY, int aMaxY, uint32_t aStripeCount )
48{
49 // An inverted extent would divide by a non-positive range and violate the clamp bounds
50 if( aMaxY < aMinY )
51 return 0;
52
53 const int64_t range = int64_t( aMaxY ) - int64_t( aMinY ) + 1;
54 const int64_t offset = std::clamp<int64_t>( int64_t( aY ) - int64_t( aMinY ), 0, range - 1 );
55 const uint64_t mapped = uint64_t( offset ) * aStripeCount / uint64_t( range );
56 return std::min<uint32_t>( static_cast<uint32_t>( mapped ), aStripeCount - 1 );
57}
58
59inline std::pair<uint32_t, uint32_t> StripeSpan( int aY1, int aY2, int aMinY, int aMaxY, uint32_t aStripeCount )
60{
61 return { MapYToStripe( std::min( aY1, aY2 ), aMinY, aMaxY, aStripeCount ),
62 MapYToStripe( std::max( aY1, aY2 ), aMinY, aMaxY, aStripeCount ) };
63}
64
65inline bool CheckedAdd( size_t& aTotal, size_t aCount, size_t aElementSize )
66{
67 if( aElementSize == 0 )
68 return true;
69
70 if( aCount > ( std::numeric_limits<size_t>::max() - aTotal ) / aElementSize )
71 return false;
72
73 aTotal += aCount * aElementSize;
74 return true;
75}
76
77inline size_t CapacityBudget( size_t aEdgeCount, size_t aEdgeSize )
78{
79 size_t budget = 0;
80
81 for( size_t ii = 0; ii < EDGE_SET_BUDGET_MULTIPLE; ++ii )
82 {
83 if( !CheckedAdd( budget, aEdgeCount, aEdgeSize ) )
84 return std::numeric_limits<size_t>::max();
85 }
86
87 return budget;
88}
89
90inline bool CapacityFits( size_t aBucketIds, size_t aLongIds, size_t aStripeCount, size_t aHoleCount, size_t aNodeSize,
91 size_t aBudget )
92{
93 size_t bytes = 0;
94
95 return CheckedAdd( bytes, aBucketIds, sizeof( uint32_t ) ) && CheckedAdd( bytes, aLongIds, sizeof( uint32_t ) )
96 && CheckedAdd( bytes, aStripeCount + 1, sizeof( uint32_t ) )
97 && CheckedAdd( bytes, aStripeCount, sizeof( uint32_t ) )
98 && CheckedAdd( bytes, aStripeCount + 1, sizeof( uint32_t ) )
99 && CheckedAdd( bytes, ( MAX_BUCKET_SPAN + 2 ) * aHoleCount, aNodeSize ) && bytes <= aBudget;
100}
101
102inline bool ActualCapacityFits( size_t aBucketIds, size_t aLongIds, size_t aOffsets, size_t aScratch, size_t aHeads,
103 size_t aNodes, size_t aNodeSize, size_t aBudget, size_t* aBytes = nullptr )
104{
105 size_t bytes = 0;
106
107 const bool valid = CheckedAdd( bytes, aBucketIds, sizeof( uint32_t ) )
108 && CheckedAdd( bytes, aLongIds, sizeof( uint32_t ) )
109 && CheckedAdd( bytes, aOffsets, sizeof( uint32_t ) )
110 && CheckedAdd( bytes, aScratch, sizeof( uint32_t ) )
111 && CheckedAdd( bytes, aHeads, sizeof( uint32_t ) ) && CheckedAdd( bytes, aNodes, aNodeSize );
112
113 if( aBytes )
114 *aBytes = valid ? bytes : 0;
115
116 return valid && bytes <= aBudget;
117}
118
119inline bool ShouldIndex( uint64_t aEstimatedVisits, size_t aHoleCount )
120{
121 return aHoleCount >= MIN_HOLE_COUNT && aEstimatedVisits >= MIN_EDGE_VISITS;
122}
123} // namespace KIGEOM::FRACTURE_INDEX
124
125#endif
std::pair< uint32_t, uint32_t > StripeSpan(int aY1, int aY2, int aMinY, int aMaxY, uint32_t aStripeCount)
constexpr size_t EDGE_SET_BUDGET_MULTIPLE
size_t CapacityBudget(size_t aEdgeCount, size_t aEdgeSize)
bool ActualCapacityFits(size_t aBucketIds, size_t aLongIds, size_t aOffsets, size_t aScratch, size_t aHeads, size_t aNodes, size_t aNodeSize, size_t aBudget, size_t *aBytes=nullptr)
bool ShouldIndex(uint64_t aEstimatedVisits, size_t aHoleCount)
bool CapacityFits(size_t aBucketIds, size_t aLongIds, size_t aStripeCount, size_t aHoleCount, size_t aNodeSize, size_t aBudget)
bool CheckedAdd(size_t &aTotal, size_t aCount, size_t aElementSize)
uint32_t MapYToStripe(int aY, int aMinY, int aMaxY, uint32_t aStripeCount)
uint32_t StripeCountFor(size_t aEdgeCount)