| 135 | |
| 136 | template< typename T > |
| 137 | void initializeFaceToSegments( |
| 138 | const IECore::TypedData< std::vector< T > > *primVarData, |
| 139 | const IntVectorData *indicesData, |
| 140 | int &numSegments, |
| 141 | ConstIntVectorDataPtr &faceToSegmentIndexData, |
| 142 | std::vector<int> &remapSegmentIndices, |
| 143 | int &remapSegmentIndexMin, |
| 144 | const IECore::Canceller *canceller |
| 145 | ) |
| 146 | { |
| 147 | const std::vector<T> &data = primVarData->readable(); |
| 148 | numSegments = 0; |
| 149 | remapSegmentIndexMin = 0; |
| 150 | |
| 151 | if( !indicesData ) |
| 152 | { |
| 153 | if constexpr( std::is_same< T, int >::value ) |
| 154 | { |
| 155 | // Special case for integer primVar. An integer primvar is common, because it is produced by |
| 156 | // sources like the Gaffer MeshSegments node, and in this case, we can go much faster using |
| 157 | // a vector than a hash map. This requires us to check the range of the data first though. |
| 158 | |
| 159 | Canceller::check( canceller ); |
| 160 | |
| 161 | int dataMin = data[0]; |
| 162 | int dataMax = data[0]; |
| 163 | for( int i : data ) |
| 164 | { |
| 165 | dataMin = std::min( i, dataMin ); |
| 166 | dataMax = std::max( i, dataMax ); |
| 167 | } |
| 168 | |
| 169 | // This is purely a heuristic - the vector is so much more efficient that we could even go |
| 170 | // larger than data.size() * 4 and still win with the vector, but it seems like a reasonable |
| 171 | // cutoff - once you get up to data.size() * 1000, the hash map will definitely win. The |
| 172 | // important thing is that if the data is already contiguous unique integers ( ie. from |
| 173 | // MeshSegments ) we always hit the fast path. |
| 174 | if( (size_t)( dataMax - dataMin ) < data.size() * 4 ) |
| 175 | { |
| 176 | // Instead of using a uniqueSegmentMap, we can just use the remapSegmentIndices vector for looking up ids |
| 177 | remapSegmentIndexMin = dataMin; |
| 178 | remapSegmentIndices.resize( dataMax + 1 - dataMin, -1 ); |
| 179 | |
| 180 | Canceller::check( canceller ); |
| 181 | |
| 182 | // We initially use the remapSegmentIndices vector just to store a flag for whether each |
| 183 | // index is used, -1 == not used, 0 == used. |
| 184 | // |
| 185 | // This could be an indepedent data structure, but because of how we use it to build |
| 186 | // remapSegmentIndices, it's better for memory use and locality to just use the same memory |
| 187 | for( int d : data ) |
| 188 | { |
| 189 | int &ins = remapSegmentIndices[ d - remapSegmentIndexMin ]; |
| 190 | if( ins == -1 ) |
| 191 | { |
| 192 | ins = 0; |
| 193 | } |
| 194 | } |