1 /**
2 * MOAB, a Mesh-Oriented datABase, is a software component for creating,
3 * storing and accessing finite element mesh data.
4 *
5 * Copyright 2004 Sandia Corporation. Under the terms of Contract
6 * DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government
7 * retains certain rights in this software.
8 *
9 * This library is free software; you can redistribute it and/or
10 * modify it under the terms of the GNU Lesser General Public
11 * License as published by the Free Software Foundation; either
12 * version 2.1 of the License, or (at your option) any later version.
13 *
14 */
15
16 #include <memory.h>
17 #include <algorithm>
18
19 #include "SparseTag.hpp"
20 #include "moab/Range.hpp"
21 #include "TagCompare.hpp"
22 #include "SysUtil.hpp"
23 #include "SequenceManager.hpp"
24 #include "moab/Error.hpp"
25 #include "moab/ErrorHandler.hpp"
26 #include "moab/CN.hpp"
27
28 namespace moab {
29
SparseTag(const char * name,int size,DataType type,const void * default_value)30 SparseTag::SparseTag(const char* name,
31 int size,
32 DataType type,
33 const void* default_value)
34 : TagInfo(name, size, type, default_value, size)
35 {}
36
~SparseTag()37 SparseTag::~SparseTag()
38 {
39 release_all_data(0, 0, true);
40 }
41
get_storage_type() const42 TagType SparseTag::get_storage_type() const
43 {
44 return MB_TAG_SPARSE;
45 }
46
release_all_data(SequenceManager *,Error *,bool)47 ErrorCode SparseTag::release_all_data(SequenceManager*, Error*, bool)
48 {
49 for(MapType::iterator i = mData.begin(); i != mData.end(); ++i)
50 mAllocator.destroy(i->second);
51 mData.clear();
52 return MB_SUCCESS;
53 }
54
set_data(Error *,EntityHandle entity_handle,const void * data)55 ErrorCode SparseTag::set_data(Error*, EntityHandle entity_handle, const void* data)
56 {
57 #ifdef MOAB_HAVE_UNORDERED_MAP
58 MapType::iterator iter = mData.find(entity_handle);
59 #else
60 MapType::iterator iter = mData.lower_bound(entity_handle);
61 #endif
62
63 // Data space already exists
64 if (iter!= mData.end() && iter->first == entity_handle)
65 memcpy(iter->second, data, get_size());
66 // We need to make some data space
67 else {
68 void *new_data = allocate_data(entity_handle, iter, false);
69 memcpy(new_data, data, get_size());
70 }
71
72 return MB_SUCCESS;
73 }
74
get_data_ptr(EntityHandle entity_handle,const void * & ptr,bool allocate) const75 ErrorCode SparseTag::get_data_ptr(EntityHandle entity_handle, const void*& ptr, bool allocate) const
76 {
77 MapType::const_iterator iter = mData.find(entity_handle);
78
79 if (iter != mData.end())
80 ptr = iter->second;
81 else if (get_default_value() && allocate)
82 ptr = const_cast<SparseTag*>(this)->allocate_data(entity_handle, iter, allocate);
83 else
84 return MB_FAILURE;
85
86 return MB_SUCCESS;
87 }
88
get_data(Error *,EntityHandle entity_handle,void * data) const89 ErrorCode SparseTag::get_data(Error* /* error */, EntityHandle entity_handle, void* data) const
90 {
91 const void* ptr = 0;
92 ErrorCode rval = get_data_ptr(entity_handle, ptr, false);
93 if (MB_SUCCESS == rval) {
94 memcpy(data, ptr, get_size());
95 return rval;
96 }
97 else if (get_default_value()) {
98 memcpy(data, get_default_value(), get_size());
99 return MB_SUCCESS;
100 }
101 else
102 return MB_TAG_NOT_FOUND;
103 }
104
remove_data(Error *,EntityHandle entity_handle)105 ErrorCode SparseTag::remove_data(Error* /* error */, EntityHandle entity_handle)
106 {
107 MapType::iterator i = mData.find(entity_handle);
108 if (i == mData.end())
109 return MB_TAG_NOT_FOUND;
110
111 mAllocator.destroy(i->second);
112 mData.erase(i);
113
114 return MB_SUCCESS;
115 }
116
get_data(const SequenceManager *,Error *,const EntityHandle * entities,size_t num_entities,void * data) const117 ErrorCode SparseTag::get_data(const SequenceManager*,
118 Error* /* error */,
119 const EntityHandle* entities,
120 size_t num_entities,
121 void* data) const
122 {
123 ErrorCode rval;
124 unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
125 for (size_t i = 0; i < num_entities; ++i, ptr += get_size()) {
126 rval = get_data(NULL, entities[i], ptr);
127 if (MB_SUCCESS != rval) return rval;
128 }
129
130 return MB_SUCCESS;
131 }
132
get_data(const SequenceManager *,Error *,const Range & entities,void * data) const133 ErrorCode SparseTag::get_data(const SequenceManager*,
134 Error* /* error */,
135 const Range& entities,
136 void* data) const
137 {
138 ErrorCode rval;
139 unsigned char* ptr = reinterpret_cast<unsigned char*>(data);
140 Range::const_iterator i;
141 for (i = entities.begin(); i != entities.end(); ++i, ptr += get_size()) {
142 rval = get_data(NULL, *i, ptr);
143 if (MB_SUCCESS != rval) return rval;
144 }
145
146 return MB_SUCCESS;
147 }
148
get_data(const SequenceManager *,Error *,const EntityHandle * entities,size_t num_entities,const void ** pointers,int * data_lengths) const149 ErrorCode SparseTag::get_data(const SequenceManager*,
150 Error* /* error */,
151 const EntityHandle* entities,
152 size_t num_entities,
153 const void** pointers,
154 int* data_lengths) const
155 {
156 if (data_lengths) {
157 int len = get_size();
158 SysUtil::setmem(data_lengths, &len, sizeof(int), num_entities);
159 }
160
161 ErrorCode rval = MB_SUCCESS, rval_tmp;
162 for (size_t i = 0; i < num_entities; ++i, ++pointers) {
163 rval_tmp = get_data_ptr(entities[i], *pointers);
164 if (MB_SUCCESS != rval_tmp && get_default_value()) {
165 *pointers = get_default_value();
166 }
167 else if (MB_SUCCESS != rval_tmp) {
168 return MB_TAG_NOT_FOUND;
169 }
170 }
171
172 return rval;
173 }
174
get_data(const SequenceManager *,Error *,const Range & entities,const void ** pointers,int * data_lengths) const175 ErrorCode SparseTag::get_data(const SequenceManager*,
176 Error* /* error */,
177 const Range& entities,
178 const void** pointers,
179 int* data_lengths) const
180 {
181 if (data_lengths) {
182 int len = get_size();
183 SysUtil::setmem(data_lengths, &len, sizeof(int), entities.size());
184 }
185
186 ErrorCode rval = MB_SUCCESS, rval_tmp;
187 Range::const_iterator i;
188 for (i = entities.begin(); i != entities.end(); ++i, ++pointers) {
189 rval_tmp = get_data_ptr(*i, *pointers);
190 if (MB_SUCCESS != rval_tmp && get_default_value()) {
191 *pointers = get_default_value();
192 }
193 else if (MB_SUCCESS != rval_tmp) {
194 return MB_TAG_NOT_FOUND;
195 }
196 }
197
198 return rval;
199 }
200
set_data(SequenceManager * seqman,Error *,const EntityHandle * entities,size_t num_entities,const void * data)201 ErrorCode SparseTag::set_data(SequenceManager* seqman,
202 Error* /* error */,
203 const EntityHandle* entities,
204 size_t num_entities,
205 const void* data)
206 {
207 ErrorCode rval = seqman->check_valid_entities(NULL, entities, num_entities, true);MB_CHK_ERR(rval);
208
209 const unsigned char* ptr = reinterpret_cast<const unsigned char*>(data);
210 for (size_t i = 0; i < num_entities; ++i, ptr += get_size()) {
211 rval = set_data(NULL, entities[i], ptr);MB_CHK_ERR(rval);
212 }
213
214 return MB_SUCCESS;
215 }
216
set_data(SequenceManager * seqman,Error *,const Range & entities,const void * data)217 ErrorCode SparseTag::set_data(SequenceManager* seqman,
218 Error* /* error */,
219 const Range& entities,
220 const void* data)
221 {
222 ErrorCode rval = seqman->check_valid_entities(NULL, entities);MB_CHK_ERR(rval);
223
224 const unsigned char* ptr = reinterpret_cast<const unsigned char*>(data);
225 Range::const_iterator i;
226 for (i = entities.begin(); i != entities.end(); ++i, ptr += get_size())
227 if (MB_SUCCESS != (rval = set_data(NULL, *i, ptr)))
228 return rval;
229
230 return MB_SUCCESS;
231 }
232
set_data(SequenceManager * seqman,Error *,const EntityHandle * entities,size_t num_entities,void const * const * pointers,const int * lengths)233 ErrorCode SparseTag::set_data(SequenceManager* seqman,
234 Error* /* error */,
235 const EntityHandle* entities,
236 size_t num_entities,
237 void const* const* pointers,
238 const int* lengths)
239 {
240 ErrorCode rval = validate_lengths(NULL, lengths, num_entities);MB_CHK_ERR(rval);
241
242 rval = seqman->check_valid_entities(NULL, entities, num_entities, true);MB_CHK_ERR(rval);
243
244 for (size_t i = 0; i < num_entities; ++i, ++pointers) {
245 rval = set_data(NULL, entities[i], *pointers);MB_CHK_ERR(rval);
246 }
247
248 return MB_SUCCESS;
249 }
250
set_data(SequenceManager * seqman,Error *,const Range & entities,void const * const * pointers,const int * lengths)251 ErrorCode SparseTag::set_data(SequenceManager* seqman,
252 Error* /* error */,
253 const Range& entities,
254 void const* const* pointers,
255 const int* lengths)
256 {
257 ErrorCode rval = validate_lengths(NULL, lengths, entities.size());MB_CHK_ERR(rval);
258
259 rval = seqman->check_valid_entities(NULL, entities);MB_CHK_ERR(rval);
260
261 Range::const_iterator i;
262 for (i = entities.begin(); i != entities.end(); ++i, ++pointers) {
263 rval = set_data(NULL, *i, *pointers);MB_CHK_ERR(rval);
264 }
265
266 return MB_SUCCESS;
267 }
268
clear_data(SequenceManager * seqman,Error *,const EntityHandle * entities,size_t num_entities,const void * value_ptr,int value_len)269 ErrorCode SparseTag::clear_data(SequenceManager* seqman,
270 Error* /* error */,
271 const EntityHandle* entities,
272 size_t num_entities,
273 const void* value_ptr,
274 int value_len)
275 {
276 if (value_len && value_len != get_size()) {
277 MB_SET_ERR(MB_INVALID_SIZE, "Invalid data size " << get_size() << " specified for sparse tag " << get_name() << " of size " << value_len);
278 }
279
280 ErrorCode rval = seqman->check_valid_entities(NULL, entities, num_entities, true);MB_CHK_ERR(rval);
281
282 for (size_t i = 0; i < num_entities; ++i) {
283 rval = set_data(NULL, entities[i], value_ptr);MB_CHK_ERR(rval);
284 }
285
286 return MB_SUCCESS;
287 }
288
clear_data(SequenceManager * seqman,Error *,const Range & entities,const void * value_ptr,int value_len)289 ErrorCode SparseTag::clear_data(SequenceManager* seqman,
290 Error* /* error */,
291 const Range& entities,
292 const void* value_ptr,
293 int value_len)
294 {
295 if (value_len && value_len != get_size()) {
296 MB_SET_ERR(MB_INVALID_SIZE, "Invalid data size " << get_size() << " specified for sparse tag " << get_name() << " of size " << value_len);
297 }
298
299 ErrorCode rval = seqman->check_valid_entities(NULL, entities);MB_CHK_ERR(rval);
300
301 Range::const_iterator i;
302 for (i = entities.begin(); i != entities.end(); ++i) {
303 rval = set_data(NULL, *i, value_ptr);MB_CHK_ERR(rval);
304 }
305
306 return MB_SUCCESS;
307 }
308
remove_data(SequenceManager *,Error *,const EntityHandle * entities,size_t num_entities)309 ErrorCode SparseTag::remove_data(SequenceManager*,
310 Error* /* error */,
311 const EntityHandle* entities,
312 size_t num_entities)
313 {
314 ErrorCode rval;
315 for (size_t i = 0; i < num_entities; ++i) {
316 rval = remove_data(NULL, entities[i]);
317 if (MB_SUCCESS != rval)
318 return rval;
319 }
320
321 return MB_SUCCESS;
322 }
323
remove_data(SequenceManager *,Error *,const Range & entities)324 ErrorCode SparseTag::remove_data(SequenceManager*,
325 Error* /* error */,
326 const Range& entities)
327 {
328 for (Range::const_iterator i = entities.begin(); i != entities.end(); ++i)
329 if (MB_SUCCESS != remove_data(NULL, *i))
330 return MB_TAG_NOT_FOUND;
331
332 return MB_SUCCESS;
333 }
334
tag_iterate(SequenceManager * seqman,Error *,Range::iterator & iter,const Range::iterator & end,void * & data_ptr,bool allocate)335 ErrorCode SparseTag::tag_iterate(SequenceManager* seqman,
336 Error* /* error */,
337 Range::iterator& iter,
338 const Range::iterator& end,
339 void*& data_ptr,
340 bool allocate)
341 {
342 // Note: We are asked to returning a block of contiguous storage
343 // for some block of contiguous handles for which the tag
344 // storage is also contiguous. As sparse tag storage is
345 // never contiguous, all we can do is return a pointer to the
346 // data for the first entity.
347
348 // If asked for nothing, successfully return nothing.
349 if (iter == end)
350 return MB_SUCCESS;
351
352 // Note: get_data_ptr will return the default value if the
353 // handle is not found, so test to make sure that the
354 // handle is valid.
355 ErrorCode rval = seqman->check_valid_entities(NULL, &*iter, 1);MB_CHK_ERR(rval);
356
357 // Get pointer to tag storage for entity pointed to by iter
358 const void* ptr = NULL;
359 rval = get_data_ptr(*iter, ptr);
360 if (MB_SUCCESS == rval)
361 data_ptr = const_cast<void*>(ptr);
362 else if (get_default_value() && allocate) {
363 ptr = allocate_data(*iter, mData.end());
364 data_ptr = const_cast<void*>(ptr);
365 }
366 else {
367 // If allocation was not requested, need to increment the iterator so that
368 // the count can be computed properly
369 if (get_default_value() && !allocate)
370 ++iter;
371 // return not_found(get_name(), *iter);
372 }
373
374 // Increment iterator and return
375 ++iter;
376 return MB_SUCCESS;
377 }
378
379 template <class Container> static inline
get_tagged(const SparseTag::MapType & mData,EntityType type,Container & output_range)380 void get_tagged(const SparseTag::MapType& mData,
381 EntityType type,
382 Container& output_range)
383 {
384 SparseTag::MapType::const_iterator iter;
385 typename Container::iterator hint = output_range.begin();
386 if (MBMAXTYPE == type) {
387 for (iter = mData.begin(); iter != mData.end(); ++iter)
388 hint = output_range.insert(hint, iter->first);
389 }
390 else {
391 #ifdef MOAB_HAVE_UNORDERED_MAP
392 for (iter = mData.begin(); iter != mData.end(); ++iter)
393 if (TYPE_FROM_HANDLE(iter->first) == type)
394 hint = output_range.insert(hint, iter->first);
395 #else
396 iter = mData.lower_bound(FIRST_HANDLE(type));
397 SparseTag::MapType::const_iterator end = mData.lower_bound(LAST_HANDLE(type) + 1);
398 for (; iter != end; ++iter)
399 hint = output_range.insert(hint, iter->first);
400 #endif
401 }
402 }
403
404 template <class Container> static inline
get_tagged(const SparseTag::MapType & mData,Range::const_iterator begin,Range::const_iterator end,Container & output_range)405 void get_tagged(const SparseTag::MapType& mData,
406 Range::const_iterator begin,
407 Range::const_iterator end,
408 Container& output_range)
409 {
410 typename Container::iterator hint = output_range.begin();
411 for (Range::const_iterator i = begin; i != end; ++i)
412 if (mData.find(*i) != mData.end())
413 hint = output_range.insert(hint, *i);
414 }
415
416 template <class Container> static inline
get_tagged(const SparseTag::MapType & mData,Container & entities,EntityType type,const Range * intersect)417 void get_tagged(const SparseTag::MapType& mData,
418 Container& entities,
419 EntityType type,
420 const Range* intersect)
421 {
422 if (!intersect)
423 get_tagged<Container>(mData, type, entities);
424 else if (MBMAXTYPE == type)
425 get_tagged<Container>(mData, intersect->begin(), intersect->end(), entities);
426 else {
427 std::pair<Range::iterator,Range::iterator> r = intersect->equal_range(type);
428 get_tagged<Container>(mData, r.first, r.second, entities);
429 }
430 }
431
432 //! Gets all entity handles that match a type and tag
get_tagged_entities(const SequenceManager *,Range & output_range,EntityType type,const Range * intersect) const433 ErrorCode SparseTag::get_tagged_entities(const SequenceManager*,
434 Range& output_range,
435 EntityType type,
436 const Range* intersect) const
437 {
438 get_tagged(mData, output_range, type, intersect);
439 return MB_SUCCESS;
440 }
441
442 //! Gets all entity handles that match a type and tag
num_tagged_entities(const SequenceManager *,size_t & output_count,EntityType type,const Range * intersect) const443 ErrorCode SparseTag::num_tagged_entities(const SequenceManager*,
444 size_t& output_count,
445 EntityType type,
446 const Range* intersect) const
447 {
448 InsertCount counter(output_count);
449 get_tagged(mData, counter, type, intersect);
450 output_count = counter.end();
451 return MB_SUCCESS;
452 }
453
find_entities_with_value(const SequenceManager * seqman,Error *,Range & output_entities,const void * value,int value_bytes,EntityType type,const Range * intersect_entities) const454 ErrorCode SparseTag::find_entities_with_value(
455 #ifdef MOAB_HAVE_UNORDERED_MAP
456 const SequenceManager* seqman,
457 #else
458 const SequenceManager*,
459 #endif
460 Error* /* error */,
461 Range& output_entities,
462 const void* value,
463 int value_bytes,
464 EntityType type,
465 const Range* intersect_entities) const
466 {
467 if (value_bytes && value_bytes != get_size()) {
468 MB_SET_ERR(MB_INVALID_SIZE, "Invalid data size " << get_size() << " specified for sparse tag " << get_name() << " of size " << value_bytes);
469 }
470
471 MapType::const_iterator iter, end;
472 #ifdef MOAB_HAVE_UNORDERED_MAP
473 if (intersect_entities) {
474 std::pair<Range::iterator,Range::iterator> r;
475 if (type == MBMAXTYPE) {
476 r.first = intersect_entities->begin();
477 r.second = intersect_entities->end();
478 }
479 else {
480 r = intersect_entities->equal_range(type);
481 }
482
483 find_map_values_equal(*this, value, get_size(),
484 r.first, r.second,
485 mData, output_entities);
486 }
487 else if (type == MBMAXTYPE) {
488 find_tag_values_equal(*this, value, get_size(),
489 mData.begin(), mData.end(),
490 output_entities);
491 }
492 else {
493 Range tmp;
494 seqman->get_entities(type, tmp);
495 find_map_values_equal(*this, value, get_size(),
496 tmp.begin(), tmp.end(),
497 mData, output_entities);
498 }
499 #else
500 if (intersect_entities) {
501 for (Range::const_pair_iterator p = intersect_entities->begin();
502 p != intersect_entities->end(); ++p) {
503 iter = mData.lower_bound(p->first);
504 end = mData.upper_bound(p->second);
505 find_tag_values_equal(*this, value, get_size(), iter, end,
506 output_entities);
507 }
508 }
509 else {
510 if (type == MBMAXTYPE) {
511 iter = mData.begin();
512 end = mData.end();
513 }
514 else {
515 iter = mData.lower_bound(CREATE_HANDLE(type, MB_START_ID));
516 end = mData.upper_bound(CREATE_HANDLE(type, MB_END_ID));
517 }
518 find_tag_values_equal(*this, value, get_size(), iter, end,
519 output_entities);
520 }
521 #endif
522
523 return MB_SUCCESS;
524 }
525
is_tagged(const SequenceManager *,EntityHandle h) const526 bool SparseTag::is_tagged(const SequenceManager*, EntityHandle h) const
527 {
528 return mData.find(h) != mData.end();
529 }
530
get_memory_use(const SequenceManager *,unsigned long & total,unsigned long & per_entity) const531 ErrorCode SparseTag::get_memory_use(const SequenceManager*,
532 unsigned long& total,
533 unsigned long& per_entity) const
534
535 {
536 per_entity = get_size() + 4*sizeof(void*);
537 total = (mData.size() * per_entity)
538 + sizeof(*this) + TagInfo::get_memory_use();
539
540 return MB_SUCCESS;
541 }
542
543 } // namespace moab
544