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