| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | /* | ||
| 2 | * Copyright (c) 2000-2022 Inria | ||
| 3 | * All rights reserved. | ||
| 4 | * | ||
| 5 | * Redistribution and use in source and binary forms, with or without | ||
| 6 | * modification, are permitted provided that the following conditions are met: | ||
| 7 | * | ||
| 8 | * * Redistributions of source code must retain the above copyright notice, | ||
| 9 | * this list of conditions and the following disclaimer. | ||
| 10 | * * Redistributions in binary form must reproduce the above copyright notice, | ||
| 11 | * this list of conditions and the following disclaimer in the documentation | ||
| 12 | * and/or other materials provided with the distribution. | ||
| 13 | * * Neither the name of the ALICE Project-Team nor the names of its | ||
| 14 | * contributors may be used to endorse or promote products derived from this | ||
| 15 | * software without specific prior written permission. | ||
| 16 | * | ||
| 17 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" | ||
| 18 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE | ||
| 19 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE | ||
| 20 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE | ||
| 21 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR | ||
| 22 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF | ||
| 23 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||
| 24 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||
| 25 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | ||
| 26 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||
| 27 | * POSSIBILITY OF SUCH DAMAGE. | ||
| 28 | * | ||
| 29 | * Contact: Bruno Levy | ||
| 30 | * | ||
| 31 | * https://www.inria.fr/fr/bruno-levy | ||
| 32 | * | ||
| 33 | * Inria, | ||
| 34 | * Domaine de Voluceau, | ||
| 35 | * 78150 Le Chesnay - Rocquencourt | ||
| 36 | * FRANCE | ||
| 37 | * | ||
| 38 | */ | ||
| 39 | |||
| 40 | #include <geogram/basic/attributes.h> | ||
| 41 | #include <geogram/basic/permutation.h> | ||
| 42 | #include <geogram/basic/string.h> | ||
| 43 | #include <geogram/basic/geometry.h> | ||
| 44 | #include <algorithm> | ||
| 45 | |||
| 46 | namespace GEO { | ||
| 47 | |||
| 48 | 3627 | void AttributeStoreObserver::register_me(AttributeStore* store) { | |
| 49 | 3627 | store->register_observer(this); | |
| 50 | 3627 | } | |
| 51 | |||
| 52 | 3627 | void AttributeStoreObserver::unregister_me(AttributeStore* store) { | |
| 53 | 3627 | store->unregister_observer(this); | |
| 54 | 3627 | } | |
| 55 | |||
| 56 | /******************************************************************/ | ||
| 57 | |||
| 58 | 5526 | AttributeStoreCreator::~AttributeStoreCreator() { | |
| 59 | 5526 | } | |
| 60 | |||
| 61 | /******************************************************************/ | ||
| 62 | |||
| 63 | std::map<std::string, AttributeStoreCreator_var> | ||
| 64 | AttributeStore::type_name_to_creator_; | ||
| 65 | |||
| 66 | std::map<std::string, std::string> | ||
| 67 | AttributeStore::typeid_name_to_type_name_; | ||
| 68 | |||
| 69 | std::map<std::string, std::string> | ||
| 70 | AttributeStore::type_name_to_typeid_name_; | ||
| 71 | |||
| 72 | 2078 | AttributeStore::AttributeStore(size_t elemsize, index_t dim) : | |
| 73 | 2078 | element_size_(elemsize), | |
| 74 | 2078 | dimension_(dim), | |
| 75 | 2078 | cached_base_addr_(nullptr), | |
| 76 | 2078 | cached_size_(0), | |
| 77 | 2078 | cached_capacity_(0), | |
| 78 | 2078 | lock_(GEOGRAM_SPINLOCK_INIT) | |
| 79 | { | ||
| 80 | 2078 | } | |
| 81 | |||
| 82 | 2116625 | void AttributeStore::notify( | |
| 83 | Memory::pointer base_addr, index_t size, index_t dim | ||
| 84 | ) { | ||
| 85 | 2116625 | Process::acquire_spinlock(lock_); | |
| 86 | 2116625 | if( | |
| 87 |
2/2✓ Branch 0 taken 6695 times.
✓ Branch 1 taken 2109930 times.
|
2116625 | size != cached_size_ || |
| 88 |
2/2✓ Branch 0 taken 3669 times.
✓ Branch 1 taken 3026 times.
|
6695 | base_addr != cached_base_addr_ || |
| 89 |
2/2✓ Branch 0 taken 229 times.
✓ Branch 1 taken 3440 times.
|
3669 | dim != dimension_ |
| 90 | ) { | ||
| 91 | 2113185 | cached_base_addr_ = base_addr; | |
| 92 | 2113185 | cached_size_ = size; | |
| 93 | 2113185 | dimension_ = dim; | |
| 94 |
2/2✓ Branch 5 taken 1970725 times.
✓ Branch 6 taken 2113185 times.
|
4083910 | for(auto cur : observers_) { |
| 95 | 1970725 | cur->notify(cached_base_addr_, cached_size_, dim); | |
| 96 | } | ||
| 97 | } | ||
| 98 | 2116625 | Process::release_spinlock(lock_); | |
| 99 | 2116625 | } | |
| 100 | |||
| 101 | 4156 | AttributeStore::~AttributeStore() { | |
| 102 | // Disconnect all the attributes, for the special case where | ||
| 103 | // the AttributeStore is destroyed before the Attributes, can | ||
| 104 | // occur for instance when using Lua scripting with Attribute wrapper | ||
| 105 | // objects. | ||
| 106 |
1/2✗ Branch 5 not taken.
✓ Branch 6 taken 2078 times.
|
4156 | for(auto cur : observers_) { |
| 107 | ✗ | cur->disconnect(); | |
| 108 | } | ||
| 109 | 4156 | } | |
| 110 | |||
| 111 | 3627 | void AttributeStore::register_observer(AttributeStoreObserver* observer) { | |
| 112 | 3627 | Process::acquire_spinlock(lock_); | |
| 113 |
2/8✓ Branch 2 taken 3627 times.
✗ Branch 3 not taken.
✗ Branch 5 not taken.
✓ Branch 6 taken 3627 times.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
✗ Branch 11 not taken.
✗ Branch 12 not taken.
|
3627 | geo_assert(observers_.find(observer) == observers_.end()); |
| 114 | 3627 | observers_.insert(observer); | |
| 115 | 3627 | observer->notify(cached_base_addr_, cached_size_, dimension_); | |
| 116 | 3627 | Process::release_spinlock(lock_); | |
| 117 | 3627 | } | |
| 118 | |||
| 119 | 3627 | void AttributeStore::unregister_observer(AttributeStoreObserver* observer) { | |
| 120 | 3627 | Process::acquire_spinlock(lock_); | |
| 121 |
1/2✓ Branch 1 taken 3627 times.
✗ Branch 2 not taken.
|
3627 | auto it = observers_.find(observer); |
| 122 |
1/6✗ Branch 2 not taken.
✓ Branch 3 taken 3627 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✗ Branch 8 not taken.
✗ Branch 9 not taken.
|
3627 | geo_assert(it != observers_.end()); |
| 123 |
1/2✓ Branch 1 taken 3627 times.
✗ Branch 2 not taken.
|
3627 | observers_.erase(it); |
| 124 | 3627 | Process::release_spinlock(lock_); | |
| 125 | 3627 | } | |
| 126 | |||
| 127 | ✗ | void AttributeStore::apply_permutation_with_lifecycle( | |
| 128 | const vector<index_t>& permutation_in | ||
| 129 | ) { | ||
| 130 | ✗ | Memory::pointer pdata = cached_base_addr_; | |
| 131 | ✗ | vector<index_t>& perm = const_cast<vector<index_t>&>(permutation_in); | |
| 132 | ✗ | geo_debug_assert(Permutation::is_valid(perm)); | |
| 133 | ✗ | size_t item_size = element_size_ * dimension_; | |
| 134 | ✗ | Memory::pointer temp = static_cast<Memory::pointer>(alloca(item_size)); | |
| 135 | ✗ | for(index_t k = 0; k < perm.size(); ++k) { | |
| 136 | ✗ | if(Permutation::is_marked(perm, k)) { | |
| 137 | ✗ | continue; | |
| 138 | } | ||
| 139 | ✗ | index_t i = k; | |
| 140 | ✗ | index_t j = perm[k]; | |
| 141 | |||
| 142 | ✗ | lifecycle_->copy_construct_array( | |
| 143 | ✗ | temp, pdata + i * item_size, dimension_ | |
| 144 | ); | ||
| 145 | |||
| 146 | ✗ | Permutation::mark(perm, k); | |
| 147 | ✗ | while(j != k) { | |
| 148 | ✗ | lifecycle_->assign_array( | |
| 149 | ✗ | pdata + i * item_size, pdata + j * item_size, dimension_ | |
| 150 | ); | ||
| 151 | ✗ | index_t nj = perm[j]; | |
| 152 | ✗ | Permutation::mark(perm, j); | |
| 153 | ✗ | i = j; | |
| 154 | ✗ | j = nj; | |
| 155 | } | ||
| 156 | ✗ | lifecycle_->assign_array(pdata + i * item_size, temp, dimension_); | |
| 157 | ✗ | lifecycle_->destroy_array(temp, dimension_); | |
| 158 | } | ||
| 159 | ✗ | for(index_t k = 0; k < perm.size(); ++k) { | |
| 160 | ✗ | Permutation::unmark(perm, k); | |
| 161 | } | ||
| 162 | ✗ | } | |
| 163 | |||
| 164 | 14 | void AttributeStore::apply_permutation(const vector<index_t>& permutation) { | |
| 165 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 14 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
14 | geo_debug_assert(permutation.size() <= cached_size_); |
| 166 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | if(lifecycle_.is_null()) { |
| 167 | 14 | Permutation::apply( | |
| 168 | 14 | cached_base_addr_, permutation, element_size_ * dimension_ | |
| 169 | ); | ||
| 170 | } else { | ||
| 171 | ✗ | apply_permutation_with_lifecycle(permutation); | |
| 172 | } | ||
| 173 | 14 | } | |
| 174 | |||
| 175 | 1398 | void AttributeStore::compress(const vector<index_t>& old2new) { | |
| 176 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 1398 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
1398 | geo_debug_assert(old2new.size() <= cached_size_); |
| 177 | 1398 | size_t item_size = size_t(element_size_) * dimension_; | |
| 178 |
2/2✓ Branch 1 taken 7981104 times.
✓ Branch 2 taken 1398 times.
|
7982502 | for(index_t i=0; i<old2new.size(); ++i) { |
| 179 | 7981104 | index_t j = old2new[i]; | |
| 180 |
4/4✓ Branch 0 taken 3799855 times.
✓ Branch 1 taken 4181249 times.
✓ Branch 2 taken 850927 times.
✓ Branch 3 taken 2948928 times.
|
7981104 | if(j == NO_INDEX || j == i) { |
| 181 | 5032176 | continue; | |
| 182 | } | ||
| 183 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 2948928 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
2948928 | geo_debug_assert(j <= i); |
| 184 |
1/2✓ Branch 1 taken 2948928 times.
✗ Branch 2 not taken.
|
2948928 | if(lifecycle_.is_null()) { |
| 185 | 2948928 | Memory::copy( | |
| 186 | 2948928 | cached_base_addr_+size_t(j)*item_size, | |
| 187 | 2948928 | cached_base_addr_+size_t(i)*item_size, | |
| 188 | item_size | ||
| 189 | ); | ||
| 190 | } else { | ||
| 191 | ✗ | lifecycle_->assign_array( | |
| 192 | ✗ | cached_base_addr_+size_t(j)*item_size, | |
| 193 | ✗ | cached_base_addr_+size_t(i)*item_size, | |
| 194 | dimension_ | ||
| 195 | ); | ||
| 196 | } | ||
| 197 | } | ||
| 198 | 1398 | } | |
| 199 | |||
| 200 | 18 | void AttributeStore::zero() { | |
| 201 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | if(lifecycle_.is_null()) { |
| 202 | 18 | Memory::clear( | |
| 203 | 18 | cached_base_addr_, element_size_ * dimension_ * cached_size_ | |
| 204 | ); | ||
| 205 | } else { | ||
| 206 | ✗ | index_t nb_elements = cached_size_ * dimension_; | |
| 207 | ✗ | for(index_t i=0; i<nb_elements; ++i) { | |
| 208 | ✗ | lifecycle_->reset(cached_base_addr_ + i * element_size_); | |
| 209 | } | ||
| 210 | } | ||
| 211 | 18 | } | |
| 212 | |||
| 213 | 429538 | void AttributeStore::swap_items(index_t i, index_t j) { | |
| 214 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 429538 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
429538 | geo_debug_assert(i < cached_size_); |
| 215 |
1/6✗ Branch 0 not taken.
✓ Branch 1 taken 429538 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 6 not taken.
✗ Branch 7 not taken.
|
429538 | geo_debug_assert(j < cached_size_); |
| 216 | 429538 | size_t item_size = element_size_ * dimension_; | |
| 217 |
1/2✓ Branch 1 taken 429538 times.
✗ Branch 2 not taken.
|
429538 | if(lifecycle_.is_null()) { |
| 218 | 429538 | void* temp = alloca(item_size); | |
| 219 | 429538 | Memory::copy( | |
| 220 | temp, | ||
| 221 | 429538 | cached_base_addr_+i*item_size, | |
| 222 | item_size | ||
| 223 | ); | ||
| 224 | 429538 | Memory::copy( | |
| 225 | 429538 | cached_base_addr_+i*item_size, | |
| 226 | 429538 | cached_base_addr_+j*item_size, | |
| 227 | item_size | ||
| 228 | ); | ||
| 229 | 429538 | Memory::copy( | |
| 230 | 429538 | cached_base_addr_+j*item_size, | |
| 231 | temp, | ||
| 232 | item_size | ||
| 233 | ); | ||
| 234 | } else { | ||
| 235 | ✗ | for(index_t c=0; c<dimension_; ++c) { | |
| 236 | ✗ | lifecycle_->swap( | |
| 237 | ✗ | cached_base_addr_+i*item_size+c*element_size(), | |
| 238 | ✗ | cached_base_addr_+j*item_size+c*element_size() | |
| 239 | ); | ||
| 240 | } | ||
| 241 | } | ||
| 242 | 429538 | } | |
| 243 | |||
| 244 | ✗ | void AttributeStore::scale_item(index_t to, double s) { | |
| 245 | ✗ | geo_argused(to); | |
| 246 | ✗ | geo_argused(s); | |
| 247 | ✗ | } | |
| 248 | |||
| 249 | ✗ | void AttributeStore::madd_item(index_t to, double s, index_t from) { | |
| 250 | ✗ | geo_argused(to); | |
| 251 | ✗ | geo_argused(s); | |
| 252 | ✗ | geo_argused(from); | |
| 253 | ✗ | } | |
| 254 | |||
| 255 | 2763 | void AttributeStore::register_attribute_creator( | |
| 256 | AttributeStoreCreator* creator, | ||
| 257 | const std::string& element_type_name, | ||
| 258 | const std::string& element_typeid_name | ||
| 259 | ) { | ||
| 260 |
1/2✗ Branch 1 not taken.
✓ Branch 2 taken 2763 times.
|
2763 | if(element_type_name_is_known(element_type_name)) { |
| 261 | ✗ | Logger::warn("Attributes") << element_type_name | |
| 262 | ✗ | << " already registered" | |
| 263 | ✗ | << std::endl; | |
| 264 | ✗ | if(element_typeid_name_is_known(element_typeid_name)) { | |
| 265 | bool already_registered_attribute_has_same_type = ( | ||
| 266 | ✗ | type_name_to_typeid_name_[element_type_name] == | |
| 267 | element_typeid_name | ||
| 268 | ); | ||
| 269 | ✗ | geo_assert(already_registered_attribute_has_same_type); | |
| 270 | } | ||
| 271 | } | ||
| 272 | 2763 | type_name_to_creator_[element_type_name] = creator; | |
| 273 | 2763 | typeid_name_to_type_name_[element_typeid_name] = element_type_name; | |
| 274 | 2763 | type_name_to_typeid_name_[element_type_name] = element_typeid_name; | |
| 275 | 2763 | } | |
| 276 | |||
| 277 | /*************************************************************************/ | ||
| 278 | |||
| 279 | 5761 | AttributesManager::AttributesManager() : size_(0), capacity_(0) { | |
| 280 | 5761 | } | |
| 281 | |||
| 282 | 5761 | AttributesManager::~AttributesManager() { | |
| 283 | 5761 | clear(false,false); | |
| 284 | 5761 | } | |
| 285 | |||
| 286 | 6192668 | void AttributesManager::resize(index_t new_size) { | |
| 287 |
2/2✓ Branch 0 taken 309 times.
✓ Branch 1 taken 6192359 times.
|
6192668 | if(new_size == size_) { |
| 288 | 309 | return; | |
| 289 | } | ||
| 290 |
2/2✓ Branch 5 taken 2108740 times.
✓ Branch 6 taken 6192359 times.
|
8301099 | for(auto& cur : attributes_) { |
| 291 |
1/2✓ Branch 1 taken 2108740 times.
✗ Branch 2 not taken.
|
2108740 | cur.second->resize(new_size); |
| 292 | } | ||
| 293 | 6192359 | size_ = new_size; | |
| 294 | } | ||
| 295 | |||
| 296 | 8524 | void AttributesManager::reserve(index_t new_capacity) { | |
| 297 |
2/2✓ Branch 0 taken 484 times.
✓ Branch 1 taken 8040 times.
|
8524 | if(new_capacity <= capacity_) { |
| 298 | 484 | return; | |
| 299 | } | ||
| 300 |
2/2✓ Branch 5 taken 3532 times.
✓ Branch 6 taken 8040 times.
|
11572 | for(auto& cur : attributes_) { |
| 301 |
1/2✓ Branch 1 taken 3532 times.
✗ Branch 2 not taken.
|
3532 | cur.second->reserve(new_capacity); |
| 302 | } | ||
| 303 | 8040 | capacity_ = new_capacity; | |
| 304 | } | ||
| 305 | |||
| 306 | 28 | void AttributesManager::apply_permutation( | |
| 307 | const vector<index_t>& permutation | ||
| 308 | ) { | ||
| 309 |
2/2✓ Branch 5 taken 14 times.
✓ Branch 6 taken 28 times.
|
42 | for(auto& cur : attributes_) { |
| 310 |
1/2✓ Branch 1 taken 14 times.
✗ Branch 2 not taken.
|
14 | cur.second->apply_permutation(permutation); |
| 311 | } | ||
| 312 | 28 | } | |
| 313 | |||
| 314 | 500 | void AttributesManager::compress( | |
| 315 | const vector<index_t>& old2new | ||
| 316 | ) { | ||
| 317 |
2/2✓ Branch 5 taken 1398 times.
✓ Branch 6 taken 500 times.
|
1898 | for(auto& cur : attributes_) { |
| 318 |
1/2✓ Branch 1 taken 1398 times.
✗ Branch 2 not taken.
|
1398 | cur.second->compress(old2new); |
| 319 | } | ||
| 320 | 500 | } | |
| 321 | |||
| 322 | |||
| 323 | 2078 | void AttributesManager::bind_attribute_store( | |
| 324 | const std::string& name, AttributeStore* as | ||
| 325 | ) { | ||
| 326 |
1/6✗ Branch 1 not taken.
✓ Branch 2 taken 2078 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
✗ Branch 7 not taken.
✗ Branch 8 not taken.
|
2078 | geo_assert(find_attribute_store(name) == nullptr); |
| 327 | 2078 | attributes_[name] = as; | |
| 328 | 2078 | as->reserve(capacity_); | |
| 329 | 2078 | as->resize(size_); | |
| 330 | 2078 | } | |
| 331 | |||
| 332 | 754 | void AttributesManager::list_attribute_names( | |
| 333 | vector<std::string>& names | ||
| 334 | ) const { | ||
| 335 | 754 | names.clear(); | |
| 336 |
2/2✓ Branch 5 taken 681 times.
✓ Branch 6 taken 754 times.
|
1435 | for(auto& cur : attributes_) { |
| 337 |
1/2✓ Branch 1 taken 681 times.
✗ Branch 2 not taken.
|
681 | names.push_back(cur.first); |
| 338 | } | ||
| 339 | 754 | } | |
| 340 | |||
| 341 | 8837 | AttributeStore* AttributesManager::find_attribute_store( | |
| 342 | const std::string& name | ||
| 343 | ) { | ||
| 344 |
1/2✓ Branch 1 taken 8837 times.
✗ Branch 2 not taken.
|
8837 | auto it = attributes_.find(name); |
| 345 |
2/2✓ Branch 2 taken 6199 times.
✓ Branch 3 taken 2638 times.
|
8837 | if(it == attributes_.end()) { |
| 346 | 6199 | return nullptr; | |
| 347 | } | ||
| 348 | 2638 | return it->second; | |
| 349 | } | ||
| 350 | |||
| 351 | 46 | const AttributeStore* AttributesManager::find_attribute_store( | |
| 352 | const std::string& name | ||
| 353 | ) const { | ||
| 354 |
1/2✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
|
46 | auto it = attributes_.find(name); |
| 355 |
1/2✓ Branch 2 taken 46 times.
✗ Branch 3 not taken.
|
46 | if(it == attributes_.end()) { |
| 356 | 46 | return nullptr; | |
| 357 | } | ||
| 358 | ✗ | return it->second; | |
| 359 | } | ||
| 360 | |||
| 361 | ✗ | bool AttributesManager::get_doubles( | |
| 362 | const std::string& name, vector<double>& out, index_t& dim | ||
| 363 | ) const { | ||
| 364 | ✗ | const AttributeStore* store = find_attribute_store(name); | |
| 365 | ✗ | if( | |
| 366 | ✗ | store == nullptr || | |
| 367 | ✗ | !store->elements_type_matches(typeid(double).name()) | |
| 368 | ) { | ||
| 369 | ✗ | return false; | |
| 370 | } | ||
| 371 | ✗ | dim = store->dimension(); | |
| 372 | ✗ | const double* p = static_cast<const double*>(store->data()); | |
| 373 | ✗ | out.assign(p, p + store->size() * dim); | |
| 374 | ✗ | return true; | |
| 375 | } | ||
| 376 | |||
| 377 | ✗ | bool AttributesManager::set_doubles( | |
| 378 | const std::string& name, const vector<double>& in, index_t dim | ||
| 379 | ) { | ||
| 380 | ✗ | AttributeStore* store = find_attribute_store(name); | |
| 381 | ✗ | if(store == nullptr) { | |
| 382 | ✗ | if(in.size() != size_t(size()) * dim) { | |
| 383 | ✗ | return false; // do not create on size mismatch | |
| 384 | } | ||
| 385 | ✗ | store = new TypedAttributeStore<double>(dim); | |
| 386 | ✗ | bind_attribute_store(name, store); // sizes it to size_, takes ownership | |
| 387 | } | ||
| 388 | ✗ | if( | |
| 389 | ✗ | !store->elements_type_matches(typeid(double).name()) || | |
| 390 | ✗ | store->dimension() != dim || | |
| 391 | ✗ | in.size() != size_t(store->size()) * dim | |
| 392 | ) { | ||
| 393 | ✗ | return false; | |
| 394 | } | ||
| 395 | ✗ | Memory::copy(store->data(), in.data(), in.size() * sizeof(double)); | |
| 396 | ✗ | return true; | |
| 397 | } | ||
| 398 | |||
| 399 | |||
| 400 | ✗ | void AttributesManager::delete_attribute_store(const std::string& name) { | |
| 401 | ✗ | auto it = attributes_.find(name); | |
| 402 | ✗ | geo_assert(it != attributes_.end()); | |
| 403 | ✗ | delete it->second; | |
| 404 | ✗ | attributes_.erase(it); | |
| 405 | ✗ | } | |
| 406 | |||
| 407 | 236 | void AttributesManager::delete_attribute_store(AttributeStore* as) { | |
| 408 |
1/2✓ Branch 4 taken 437 times.
✗ Branch 5 not taken.
|
437 | for(auto it=attributes_.begin(); it != attributes_.end(); ++it) { |
| 409 |
2/2✓ Branch 1 taken 236 times.
✓ Branch 2 taken 201 times.
|
437 | if(it->second == as) { |
| 410 |
1/2✓ Branch 0 taken 236 times.
✗ Branch 1 not taken.
|
236 | delete as; |
| 411 |
1/2✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
|
236 | attributes_.erase(it); |
| 412 | 236 | return; | |
| 413 | } | ||
| 414 | } | ||
| 415 | ✗ | geo_assert_not_reached; | |
| 416 | } | ||
| 417 | |||
| 418 | |||
| 419 | 9359 | void AttributesManager::clear(bool keep_attributes, bool keep_memory) { | |
| 420 |
2/2✓ Branch 0 taken 3171 times.
✓ Branch 1 taken 6188 times.
|
9359 | if(keep_attributes) { |
| 421 |
2/2✓ Branch 5 taken 546 times.
✓ Branch 6 taken 3171 times.
|
3717 | for(auto& cur : attributes_) { |
| 422 |
1/2✓ Branch 1 taken 546 times.
✗ Branch 2 not taken.
|
546 | cur.second->clear(keep_memory); |
| 423 | } | ||
| 424 | } else { | ||
| 425 |
2/2✓ Branch 5 taken 1842 times.
✓ Branch 6 taken 6188 times.
|
8030 | for(auto& cur : attributes_) { |
| 426 |
1/2✓ Branch 0 taken 1842 times.
✗ Branch 1 not taken.
|
1842 | delete cur.second; |
| 427 | } | ||
| 428 | 6188 | attributes_.clear(); | |
| 429 | } | ||
| 430 | 9359 | size_ = 0; | |
| 431 | 9359 | } | |
| 432 | |||
| 433 | 79 | void AttributesManager::zero() { | |
| 434 |
2/2✓ Branch 5 taken 18 times.
✓ Branch 6 taken 79 times.
|
97 | for(auto& cur : attributes_) { |
| 435 |
1/2✓ Branch 1 taken 18 times.
✗ Branch 2 not taken.
|
18 | cur.second->zero(); |
| 436 | } | ||
| 437 | 79 | } | |
| 438 | |||
| 439 | 427 | void AttributesManager::copy(const AttributesManager& rhs) { | |
| 440 | 427 | clear(false, false); | |
| 441 | 427 | reserve(rhs.capacity()); | |
| 442 | 427 | resize(rhs.size()); | |
| 443 |
2/2✓ Branch 5 taken 300 times.
✓ Branch 6 taken 427 times.
|
727 | for(auto& cur : rhs.attributes_) { |
| 444 |
2/4✓ Branch 1 taken 300 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 300 times.
✗ Branch 5 not taken.
|
300 | bind_attribute_store(cur.first, cur.second->clone()); |
| 445 | } | ||
| 446 | 427 | } | |
| 447 | |||
| 448 | 536914 | void AttributesManager::copy_item(index_t to, index_t from) { | |
| 449 |
2/2✓ Branch 5 taken 786797 times.
✓ Branch 6 taken 536914 times.
|
1323711 | for(auto& cur : attributes_) { |
| 450 |
1/2✓ Branch 1 taken 786797 times.
✗ Branch 2 not taken.
|
786797 | cur.second->copy_item(to,from); |
| 451 | } | ||
| 452 | 536914 | } | |
| 453 | |||
| 454 | 1581050 | void AttributesManager::swap_items(index_t i, index_t j) { | |
| 455 |
2/2✓ Branch 5 taken 429538 times.
✓ Branch 6 taken 1581050 times.
|
2010588 | for(auto& cur : attributes_) { |
| 456 |
1/2✓ Branch 1 taken 429538 times.
✗ Branch 2 not taken.
|
429538 | cur.second->swap_items(i,j); |
| 457 | } | ||
| 458 | 1581050 | } | |
| 459 | |||
| 460 | 209840 | void AttributesManager::zero_item(index_t i) { | |
| 461 |
2/2✓ Branch 5 taken 291740 times.
✓ Branch 6 taken 209840 times.
|
501580 | for(auto& cur : attributes_) { |
| 462 |
1/2✓ Branch 1 taken 291740 times.
✗ Branch 2 not taken.
|
291740 | cur.second->zero_item(i); |
| 463 | } | ||
| 464 | 209840 | } | |
| 465 | |||
| 466 | 5120 | void AttributesManager::scale_item(index_t i, double s) { | |
| 467 |
2/2✓ Branch 5 taken 5120 times.
✓ Branch 6 taken 5120 times.
|
10240 | for(auto& cur : attributes_) { |
| 468 |
1/2✓ Branch 1 taken 5120 times.
✗ Branch 2 not taken.
|
5120 | cur.second->scale_item(i,s); |
| 469 | } | ||
| 470 | 5120 | } | |
| 471 | |||
| 472 | 429900 | void AttributesManager::madd_item(index_t i, double s, index_t j) { | |
| 473 |
2/2✓ Branch 5 taken 593700 times.
✓ Branch 6 taken 429900 times.
|
1023600 | for(auto& cur : attributes_) { |
| 474 |
1/2✓ Branch 1 taken 593700 times.
✗ Branch 2 not taken.
|
593700 | cur.second->madd_item(i,s,j); |
| 475 | } | ||
| 476 | 429900 | } | |
| 477 | |||
| 478 | ✗ | bool AttributesManager::copy_attribute( | |
| 479 | const std::string& name, const std::string& new_name | ||
| 480 | ) { | ||
| 481 | ✗ | const auto old_itr = attributes_.find(name); | |
| 482 | ✗ | if( old_itr == attributes_.end() ) { | |
| 483 | ✗ | return false; | |
| 484 | } | ||
| 485 | ✗ | const AttributeStore* store = old_itr->second; | |
| 486 | |||
| 487 | ✗ | const auto new_itr = attributes_.find(new_name); | |
| 488 | ✗ | if( new_itr != attributes_.end() ) { | |
| 489 | ✗ | AttributeStore* new_store = new_itr->second; | |
| 490 | ✗ | if( !store->elements_type_matches( | |
| 491 | ✗ | new_store->element_typeid_name()) | |
| 492 | ) { | ||
| 493 | ✗ | return false; | |
| 494 | } | ||
| 495 | ✗ | if( | |
| 496 | ✗ | (store->size() != new_store->size()) && | |
| 497 | ✗ | (store->dimension() != new_store->dimension()) && | |
| 498 | ✗ | (store->element_size() != new_store->element_size()) | |
| 499 | ) { | ||
| 500 | ✗ | return false; | |
| 501 | } | ||
| 502 | |||
| 503 | ✗ | geo_debug_assert(store->lifecycle() == new_store->lifecycle()); | |
| 504 | ✗ | if(store->lifecycle() == nullptr) { | |
| 505 | ✗ | memcpy( | |
| 506 | new_store->data(), store->data(), | ||
| 507 | ✗ | store->size() * store->dimension() * store->element_size() | |
| 508 | ); | ||
| 509 | } else { | ||
| 510 | ✗ | store->lifecycle()->assign_array( | |
| 511 | ✗ | Memory::pointer(new_store->data()), | |
| 512 | ✗ | Memory::const_pointer(store->data()), | |
| 513 | ✗ | store->size() * store->dimension() | |
| 514 | ); | ||
| 515 | } | ||
| 516 | } else { | ||
| 517 | ✗ | AttributeStore* new_store = store->clone(); | |
| 518 | ✗ | attributes_[new_name] = new_store; | |
| 519 | } | ||
| 520 | |||
| 521 | ✗ | return true; | |
| 522 | } | ||
| 523 | |||
| 524 | ✗ | bool AttributesManager::rename_attribute( | |
| 525 | const std::string& old_name, const std::string& new_name | ||
| 526 | ) { | ||
| 527 | ✗ | const auto old_itr = attributes_.find(old_name); | |
| 528 | ✗ | if( old_itr == attributes_.end() ) { | |
| 529 | ✗ | return false; | |
| 530 | } | ||
| 531 | ✗ | const auto new_itr = attributes_.find(new_name); | |
| 532 | ✗ | if( new_itr != attributes_.end() ) { | |
| 533 | ✗ | return false; | |
| 534 | } | ||
| 535 | ✗ | attributes_[new_name] = old_itr->second; | |
| 536 | ✗ | attributes_.erase(old_itr); | |
| 537 | ✗ | return true; | |
| 538 | } | ||
| 539 | |||
| 540 | |||
| 541 | /************************************************************************/ | ||
| 542 | |||
| 543 | ✗ | index_t ScalarAttributeAdapterBase::nb_scalar_elements_per_item( | |
| 544 | const AttributeStore* store | ||
| 545 | ) { | ||
| 546 | ✗ | ElementType et = element_type(store); | |
| 547 | ✗ | if(et == ET_NONE) { | |
| 548 | ✗ | return 0; | |
| 549 | } | ||
| 550 | ✗ | index_t result = store->dimension(); | |
| 551 | ✗ | if(et == ET_VEC2) { | |
| 552 | ✗ | result *= 2; | |
| 553 | ✗ | } else if(et == ET_VEC3) { | |
| 554 | ✗ | result *= 3; | |
| 555 | } | ||
| 556 | ✗ | return result; | |
| 557 | } | ||
| 558 | |||
| 559 | ✗ | std::string ScalarAttributeAdapterBase::attribute_base_name( | |
| 560 | const std::string& name | ||
| 561 | ) { | ||
| 562 | ✗ | size_t pos = name.find('['); | |
| 563 | ✗ | if(pos == std::string::npos) { | |
| 564 | ✗ | return name; | |
| 565 | } | ||
| 566 | ✗ | return name.substr(0,pos); | |
| 567 | } | ||
| 568 | |||
| 569 | ✗ | index_t ScalarAttributeAdapterBase::attribute_element_index( | |
| 570 | const std::string& name | ||
| 571 | ) { | ||
| 572 | ✗ | index_t result = 0; | |
| 573 | ✗ | size_t pos = name.find('['); | |
| 574 | ✗ | if(pos != std::string::npos) { | |
| 575 | try { | ||
| 576 | ✗ | if(pos+2 > name.length()) { | |
| 577 | ✗ | result = NO_INDEX; | |
| 578 | } else { | ||
| 579 | ✗ | result = String::to_uint( | |
| 580 | ✗ | name.substr(pos+1, name.length()-pos-2) | |
| 581 | ); | ||
| 582 | } | ||
| 583 | ✗ | } catch(...) { | |
| 584 | ✗ | result = NO_INDEX; | |
| 585 | ✗ | } | |
| 586 | } | ||
| 587 | ✗ | return result; | |
| 588 | } | ||
| 589 | |||
| 590 | ScalarAttributeAdapterBase::ElementType | ||
| 591 | ✗ | ScalarAttributeAdapterBase::element_type(const AttributeStore* store) { | |
| 592 | ✗ | if(store->element_typeid_name() == typeid(Numeric::uint8).name()) { | |
| 593 | ✗ | return ET_UINT8; | |
| 594 | } | ||
| 595 | |||
| 596 | ✗ | if( | |
| 597 | ✗ | store->element_typeid_name() == typeid(char).name() || | |
| 598 | ✗ | store->element_typeid_name() == typeid(Numeric::int8).name() | |
| 599 | ) { | ||
| 600 | ✗ | return ET_INT8; | |
| 601 | } | ||
| 602 | |||
| 603 | ✗ | if( | |
| 604 | ✗ | store->element_typeid_name() == typeid(Numeric::uint32).name() || | |
| 605 | ✗ | store->element_typeid_name() == typeid(index_t).name() || | |
| 606 | ✗ | store->element_typeid_name() == typeid(unsigned int).name() | |
| 607 | ) { | ||
| 608 | ✗ | return ET_UINT32; | |
| 609 | } | ||
| 610 | |||
| 611 | ✗ | if( | |
| 612 | ✗ | store->element_typeid_name() == typeid(Numeric::int32).name() || | |
| 613 | ✗ | store->element_typeid_name() == typeid(int).name() | |
| 614 | ) { | ||
| 615 | ✗ | return ET_INT32; | |
| 616 | } | ||
| 617 | |||
| 618 | ✗ | if( | |
| 619 | ✗ | store->element_typeid_name() == typeid(Numeric::float32).name() || | |
| 620 | ✗ | store->element_typeid_name() == typeid(float).name() | |
| 621 | ) { | ||
| 622 | ✗ | return ET_FLOAT32; | |
| 623 | } | ||
| 624 | |||
| 625 | ✗ | if( | |
| 626 | ✗ | store->element_typeid_name() == typeid(Numeric::float64).name() || | |
| 627 | ✗ | store->element_typeid_name() == typeid(double).name() | |
| 628 | ) { | ||
| 629 | ✗ | return ET_FLOAT64; | |
| 630 | } | ||
| 631 | |||
| 632 | ✗ | if(store->element_typeid_name() == typeid(vec2).name()) { | |
| 633 | ✗ | return ET_VEC2; | |
| 634 | } | ||
| 635 | |||
| 636 | ✗ | if(store->element_typeid_name() == typeid(vec3).name()) { | |
| 637 | ✗ | return ET_VEC3; | |
| 638 | } | ||
| 639 | |||
| 640 | ✗ | return ET_NONE; | |
| 641 | } | ||
| 642 | |||
| 643 | ✗ | void ScalarAttributeAdapterBase::bind_if_is_defined( | |
| 644 | const AttributesManager& manager, const std::string& name | ||
| 645 | ) { | ||
| 646 | ✗ | geo_assert(!is_bound()); | |
| 647 | ✗ | manager_ = &manager; | |
| 648 | ✗ | element_index_ = attribute_element_index(name); | |
| 649 | ✗ | store_ = manager_->find_attribute_store(attribute_base_name(name)); | |
| 650 | |||
| 651 | ✗ | if(store_ == nullptr || element_index_ == NO_INDEX) { | |
| 652 | ✗ | store_ = nullptr; | |
| 653 | ✗ | element_index_ = NO_INDEX; | |
| 654 | ✗ | return; | |
| 655 | } | ||
| 656 | |||
| 657 | ✗ | element_type_ = element_type(store_); | |
| 658 | |||
| 659 | ✗ | if(element_type_ == ET_NONE) { | |
| 660 | ✗ | store_ = nullptr; | |
| 661 | ✗ | element_index_ = NO_INDEX; | |
| 662 | ✗ | return; | |
| 663 | } | ||
| 664 | |||
| 665 | // Test element_index_ validity: should be smaller than | ||
| 666 | // store's dimension (or 2*store dimension if a vec2, | ||
| 667 | // or 3*store's dimension if a vec3) | ||
| 668 | ✗ | if(element_index_ >= nb_scalar_elements_per_item(store_)) { | |
| 669 | ✗ | store_ = nullptr; | |
| 670 | ✗ | element_index_ = NO_INDEX; | |
| 671 | ✗ | element_type_ = ET_NONE; | |
| 672 | ✗ | return; | |
| 673 | } | ||
| 674 | |||
| 675 | ✗ | register_me(const_cast<AttributeStore*>(store_)); | |
| 676 | } | ||
| 677 | |||
| 678 | ✗ | bool ScalarAttributeAdapterBase::is_defined( | |
| 679 | const AttributesManager& manager, const std::string& name | ||
| 680 | ) { | ||
| 681 | ✗ | std::string attribute_name = attribute_base_name(name); | |
| 682 | ✗ | const AttributeStore* store = manager.find_attribute_store( | |
| 683 | attribute_name | ||
| 684 | ); | ||
| 685 | |||
| 686 | ✗ | if(store == nullptr) { | |
| 687 | ✗ | return false; | |
| 688 | } | ||
| 689 | |||
| 690 | ✗ | index_t element_index = attribute_element_index(name); | |
| 691 | ✗ | if(element_index == NO_INDEX) { | |
| 692 | ✗ | return false; | |
| 693 | } | ||
| 694 | |||
| 695 | ✗ | if(element_index >= nb_scalar_elements_per_item(store)) { | |
| 696 | ✗ | return false; | |
| 697 | } | ||
| 698 | |||
| 699 | ✗ | if(element_type(store) == ET_NONE) { | |
| 700 | ✗ | return false; | |
| 701 | } | ||
| 702 | |||
| 703 | ✗ | return true; | |
| 704 | ✗ | } | |
| 705 | |||
| 706 | /************************************************************************/ | ||
| 707 | |||
| 708 | } | ||
| 709 |