1 /* 2 * Copyright (c) 2012-2014, Bruno Levy 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 * If you modify this software, you should include a notice giving the 30 * name of the person performing the modification, the date of modification, 31 * and the reason for such modification. 32 * 33 * Contact: Bruno Levy 34 * 35 * Bruno.Levy@inria.fr 36 * http://www.loria.fr/~levy 37 * 38 * ALICE Project 39 * LORIA, INRIA Lorraine, 40 * Campus Scientifique, BP 239 41 * 54506 VANDOEUVRE LES NANCY CEDEX 42 * FRANCE 43 * 44 */ 45 46 #include <geogram/basic/attributes.h> 47 #include <geogram/basic/permutation.h> 48 #include <geogram/basic/string.h> 49 #include <geogram/basic/geometry.h> 50 #include <algorithm> 51 52 namespace GEO { 53 register_me(AttributeStore * store)54 void AttributeStoreObserver::register_me(AttributeStore* store) { 55 store->register_observer(this); 56 } 57 unregister_me(AttributeStore * store)58 void AttributeStoreObserver::unregister_me(AttributeStore* store) { 59 store->unregister_observer(this); 60 } 61 62 /******************************************************************/ 63 ~AttributeStoreCreator()64 AttributeStoreCreator::~AttributeStoreCreator() { 65 } 66 67 /******************************************************************/ 68 69 std::map<std::string, AttributeStoreCreator_var> 70 AttributeStore::type_name_to_creator_; 71 72 std::map<std::string, std::string> 73 AttributeStore::typeid_name_to_type_name_; 74 75 std::map<std::string, std::string> 76 AttributeStore::type_name_to_typeid_name_; 77 AttributeStore(index_t elemsize,index_t dim)78 AttributeStore::AttributeStore( 79 index_t elemsize, 80 index_t dim 81 ) : 82 element_size_(elemsize), 83 dimension_(dim), 84 cached_base_addr_(nullptr), 85 cached_size_(0), 86 cached_capacity_(0), 87 lock_(GEOGRAM_SPINLOCK_INIT) 88 { 89 } 90 notify(Memory::pointer base_addr,index_t size,index_t dim)91 void AttributeStore::notify( 92 Memory::pointer base_addr, index_t size, index_t dim 93 ) { 94 if( 95 size != cached_size_ || 96 base_addr != cached_base_addr_ || 97 dim != dimension_ 98 ) { 99 cached_base_addr_ = base_addr; 100 cached_size_ = size; 101 dimension_ = dim; 102 for(auto cur : observers_) { 103 cur->notify(cached_base_addr_, cached_size_, dim); 104 } 105 } 106 } 107 ~AttributeStore()108 AttributeStore::~AttributeStore() { 109 // Disconnect all the attributes, for the special case where 110 // the AttributeStore is destroyed before the Attributes, can 111 // occur for instance when using Lua scripting with Attribute wrapper 112 // objects. 113 for(auto cur : observers_) { 114 cur->disconnect(); 115 } 116 } 117 register_observer(AttributeStoreObserver * observer)118 void AttributeStore::register_observer(AttributeStoreObserver* observer) { 119 Process::acquire_spinlock(lock_); 120 geo_assert(observers_.find(observer) == observers_.end()); 121 observers_.insert(observer); 122 observer->notify(cached_base_addr_, cached_size_, dimension_); 123 Process::release_spinlock(lock_); 124 } 125 unregister_observer(AttributeStoreObserver * observer)126 void AttributeStore::unregister_observer(AttributeStoreObserver* observer) { 127 Process::acquire_spinlock(lock_); 128 auto it = observers_.find(observer); 129 geo_assert(it != observers_.end()); 130 observers_.erase(it); 131 Process::release_spinlock(lock_); 132 } 133 apply_permutation(const vector<index_t> & permutation)134 void AttributeStore::apply_permutation( 135 const vector<index_t>& permutation 136 ) { 137 geo_debug_assert(permutation.size() <= cached_size_); 138 Permutation::apply( 139 cached_base_addr_, permutation, element_size_ * dimension_ 140 ); 141 } 142 compress(const vector<index_t> & old2new)143 void AttributeStore::compress( 144 const vector<index_t>& old2new 145 ) { 146 geo_debug_assert(old2new.size() <= cached_size_); 147 index_t item_size = element_size_ * dimension_; 148 for(index_t i=0; i<old2new.size(); ++i) { 149 index_t j = old2new[i]; 150 if(j == index_t(-1) || j == i) { 151 continue; 152 } 153 geo_debug_assert(j <= i); 154 Memory::copy( 155 cached_base_addr_+j*item_size, 156 cached_base_addr_+i*item_size, 157 item_size 158 ); 159 } 160 } 161 zero()162 void AttributeStore::zero() { 163 Memory::clear( 164 cached_base_addr_, element_size_ * dimension_ * cached_size_ 165 ); 166 } 167 168 /*************************************************************************/ 169 AttributesManager()170 AttributesManager::AttributesManager() : size_(0), capacity_(0) { 171 } 172 ~AttributesManager()173 AttributesManager::~AttributesManager() { 174 clear(false,false); 175 } 176 resize(index_t new_size)177 void AttributesManager::resize(index_t new_size) { 178 if(new_size == size_) { 179 return; 180 } 181 for(auto& cur : attributes_) { 182 cur.second->resize(new_size); 183 } 184 size_ = new_size; 185 } 186 reserve(index_t new_capacity)187 void AttributesManager::reserve(index_t new_capacity) { 188 if(new_capacity <= capacity_) { 189 return; 190 } 191 for(auto& cur : attributes_) { 192 cur.second->reserve(new_capacity); 193 } 194 capacity_ = new_capacity; 195 } 196 apply_permutation(const vector<index_t> & permutation)197 void AttributesManager::apply_permutation( 198 const vector<index_t>& permutation 199 ) { 200 for(auto& cur : attributes_) { 201 cur.second->apply_permutation(permutation); 202 } 203 } 204 compress(const vector<index_t> & old2new)205 void AttributesManager::compress( 206 const vector<index_t>& old2new 207 ) { 208 for(auto& cur : attributes_) { 209 cur.second->compress(old2new); 210 } 211 } 212 213 bind_attribute_store(const std::string & name,AttributeStore * as)214 void AttributesManager::bind_attribute_store( 215 const std::string& name, AttributeStore* as 216 ) { 217 geo_assert(find_attribute_store(name) == nullptr); 218 attributes_[name] = as; 219 as->reserve(capacity_); 220 as->resize(size_); 221 } 222 list_attribute_names(vector<std::string> & names) const223 void AttributesManager::list_attribute_names( 224 vector<std::string>& names 225 ) const { 226 names.clear(); 227 for(auto& cur : attributes_) { 228 names.push_back(cur.first); 229 } 230 } 231 find_attribute_store(const std::string & name)232 AttributeStore* AttributesManager::find_attribute_store( 233 const std::string& name 234 ) { 235 auto it = attributes_.find(name); 236 if(it == attributes_.end()) { 237 return nullptr; 238 } 239 return it->second; 240 } 241 find_attribute_store(const std::string & name) const242 const AttributeStore* AttributesManager::find_attribute_store( 243 const std::string& name 244 ) const { 245 auto it = attributes_.find(name); 246 if(it == attributes_.end()) { 247 return nullptr; 248 } 249 return it->second; 250 } 251 252 delete_attribute_store(const std::string & name)253 void AttributesManager::delete_attribute_store(const std::string& name) { 254 auto it = attributes_.find(name); 255 geo_assert(it != attributes_.end()); 256 geo_assert(!it->second->has_observers()); 257 delete it->second; 258 attributes_.erase(it); 259 } 260 delete_attribute_store(AttributeStore * as)261 void AttributesManager::delete_attribute_store(AttributeStore* as) { 262 for(auto it=attributes_.begin(); it != attributes_.end(); ++it) { 263 if(it->second == as) { 264 delete as; 265 attributes_.erase(it); 266 return; 267 } 268 } 269 geo_assert_not_reached; 270 } 271 272 clear(bool keep_attributes,bool keep_memory)273 void AttributesManager::clear(bool keep_attributes, bool keep_memory) { 274 if(keep_attributes) { 275 for(auto& cur : attributes_) { 276 cur.second->clear(keep_memory); 277 } 278 } else { 279 for(auto& cur : attributes_) { 280 delete cur.second; 281 } 282 attributes_.clear(); 283 } 284 size_ = 0; 285 } 286 zero()287 void AttributesManager::zero() { 288 for(auto& cur : attributes_) { 289 cur.second->zero(); 290 } 291 } 292 copy(const AttributesManager & rhs)293 void AttributesManager::copy(const AttributesManager& rhs) { 294 clear(false, false); 295 reserve(rhs.capacity()); 296 resize(rhs.size()); 297 for(auto& cur : rhs.attributes_) { 298 bind_attribute_store(cur.first, cur.second->clone()); 299 } 300 } 301 copy_item(index_t to,index_t from)302 void AttributesManager::copy_item(index_t to, index_t from) { 303 for(auto& cur : attributes_) { 304 cur.second->copy_item(to,from); 305 } 306 } 307 308 /************************************************************************/ 309 nb_scalar_elements_per_item(const AttributeStore * store)310 index_t ReadOnlyScalarAttributeAdapter::nb_scalar_elements_per_item( 311 const AttributeStore* store 312 ) { 313 ElementType et = element_type(store); 314 if(et == ET_NONE) { 315 return 0; 316 } 317 index_t result = store->dimension(); 318 if(et == ET_VEC2) { 319 result *= 2; 320 } else if(et == ET_VEC3) { 321 result *= 3; 322 } 323 return result; 324 } 325 attribute_base_name(const std::string & name)326 std::string ReadOnlyScalarAttributeAdapter::attribute_base_name( 327 const std::string& name 328 ) { 329 size_t pos = name.find('['); 330 if(pos == std::string::npos) { 331 return name; 332 } 333 return name.substr(0,pos); 334 } 335 attribute_element_index(const std::string & name)336 index_t ReadOnlyScalarAttributeAdapter::attribute_element_index( 337 const std::string& name 338 ) { 339 index_t result = 0; 340 size_t pos = name.find('['); 341 if(pos != std::string::npos) { 342 try { 343 if(pos+2 > name.length()) { 344 result = index_t(-1); 345 } else { 346 result = String::to_uint( 347 name.substr(pos+1, name.length()-pos-2) 348 ); 349 } 350 } catch(...) { 351 result = index_t(-1); 352 } 353 } 354 return result; 355 } 356 357 ReadOnlyScalarAttributeAdapter::ElementType element_type(const AttributeStore * store)358 ReadOnlyScalarAttributeAdapter::element_type(const AttributeStore* store) { 359 if(store->element_typeid_name() == typeid(Numeric::uint8).name()) { 360 return ET_UINT8; 361 } 362 363 if( 364 store->element_typeid_name() == typeid(char).name() || 365 store->element_typeid_name() == typeid(Numeric::int8).name() 366 ) { 367 return ET_INT8; 368 } 369 370 if( 371 store->element_typeid_name() == typeid(Numeric::uint32).name() || 372 store->element_typeid_name() == typeid(index_t).name() || 373 store->element_typeid_name() == typeid(unsigned int).name() 374 ) { 375 return ET_UINT32; 376 } 377 378 if( 379 store->element_typeid_name() == typeid(Numeric::int32).name() || 380 store->element_typeid_name() == typeid(int).name() 381 ) { 382 return ET_INT32; 383 } 384 385 if( 386 store->element_typeid_name() == typeid(Numeric::float32).name() || 387 store->element_typeid_name() == typeid(float).name() 388 ) { 389 return ET_FLOAT32; 390 } 391 392 if( 393 store->element_typeid_name() == typeid(Numeric::float64).name() || 394 store->element_typeid_name() == typeid(double).name() 395 ) { 396 return ET_FLOAT64; 397 } 398 399 if(store->element_typeid_name() == typeid(vec2).name()) { 400 return ET_VEC2; 401 } 402 403 if(store->element_typeid_name() == typeid(vec3).name()) { 404 return ET_VEC3; 405 } 406 407 return ET_NONE; 408 } 409 bind_if_is_defined(const AttributesManager & manager,const std::string & name)410 void ReadOnlyScalarAttributeAdapter::bind_if_is_defined( 411 const AttributesManager& manager, const std::string& name 412 ) { 413 geo_assert(!is_bound()); 414 manager_ = &manager; 415 element_index_ = attribute_element_index(name); 416 store_ = manager_->find_attribute_store(attribute_base_name(name)); 417 418 if(store_ == nullptr || element_index_ == index_t(-1)) { 419 store_ = nullptr; 420 element_index_ = index_t(-1); 421 return; 422 } 423 424 element_type_ = element_type(store_); 425 426 if(element_type_ == ET_NONE) { 427 store_ = nullptr; 428 element_index_ = index_t(-1); 429 return; 430 } 431 432 // Test element_index_ validity: should be smaller than 433 // store's dimension (or 2*store dimension if a vec2, 434 // or 3*store's dimension if a vec3) 435 if(element_index_ >= nb_scalar_elements_per_item(store_)) { 436 store_ = nullptr; 437 element_index_ = index_t(-1); 438 element_type_ = ET_NONE; 439 return; 440 } 441 442 register_me(const_cast<AttributeStore*>(store_)); 443 } 444 is_defined(const AttributesManager & manager,const std::string & name)445 bool ReadOnlyScalarAttributeAdapter::is_defined( 446 const AttributesManager& manager, const std::string& name 447 ) { 448 std::string attribute_name = attribute_base_name(name); 449 const AttributeStore* store = manager.find_attribute_store( 450 attribute_name 451 ); 452 453 if(store == nullptr) { 454 return false; 455 } 456 457 index_t element_index = attribute_element_index(name); 458 if(element_index == index_t(-1)) { 459 return false; 460 } 461 462 if(element_index >= nb_scalar_elements_per_item(store)) { 463 return false; 464 } 465 466 if(element_type(store) == ET_NONE) { 467 return false; 468 } 469 470 return true; 471 } 472 473 /************************************************************************/ 474 475 } 476 477