1 // Copyright (c) 2017-2021, Lawrence Livermore National Security, LLC and
2 // other Axom Project Developers. See the top-level LICENSE file for details.
3 //
4 // SPDX-License-Identifier: (BSD-3-Clause)
5
6 // Associated header file
7 #include "Group.hpp"
8
9 #include "conduit_relay.hpp"
10
11 #ifdef AXOM_USE_HDF5
12 #include "conduit_relay_io_hdf5.hpp"
13 #endif
14
15 #include "axom/core/Macros.hpp"
16 #include "axom/core/Path.hpp"
17
18 // Sidre headers
19 #include "ListCollection.hpp"
20 #include "MapCollection.hpp"
21 #include "Buffer.hpp"
22 #include "DataStore.hpp"
23
24 namespace axom
25 {
26 namespace sidre
27 {
28 // Helper macro for defining a prepend string for sidre::Group log messages
29 // We are using it to add the pathName() of the group
30 #ifndef SIDRE_GROUP_LOG_PREPEND
31 #define SIDRE_GROUP_LOG_PREPEND \
32 "[Group: '" << this->getPathName() << "'" \
33 << (this->isRoot() ? " (root)" : "") << "] "
34 #endif
35
36 // Initialization of static path delimiter character for methods that
37 // support path syntax.
38 const char Group::s_path_delimiter = '/';
39
40 ////////////////////////////////////////////////////////////////////////
41 //
42 // Basic query and accessor methods.
43 //
44 ////////////////////////////////////////////////////////////////////////
45
46 /*
47 *************************************************************************
48 *
49 * Return path of Group object, not including its name.
50 *
51 *************************************************************************
52 */
getPath() const53 std::string Group::getPath() const
54 {
55 const Group* root = getDataStore()->getRoot();
56 const Group* curr = getParent();
57 std::string thePath = curr->getName();
58 curr = curr->getParent();
59
60 while(curr != root)
61 {
62 thePath = curr->getName() + s_path_delimiter + thePath;
63 curr = curr->getParent();
64 }
65
66 return thePath;
67 }
68
69 ////////////////////////////////////////////////////////////////////////
70 //
71 // View query methods.
72 //
73 ////////////////////////////////////////////////////////////////////////
74
75 /*
76 *************************************************************************
77 *
78 * Return true if Group owns a View with given name or path; else false.
79 *
80 *************************************************************************
81 */
hasView(const std::string & path) const82 bool Group::hasView(const std::string& path) const
83 {
84 std::string intpath(path);
85 const Group* group = walkPath(intpath);
86
87 if(group == nullptr)
88 {
89 return false;
90 }
91
92 return group->hasChildView(intpath);
93 }
94
95 ////////////////////////////////////////////////////////////////////////
96 //
97 // View access methods.
98 //
99 ////////////////////////////////////////////////////////////////////////
100
101 /*
102 *************************************************************************
103 *
104 * Return pointer to non-const View with given name or path if it exists.
105 *
106 *************************************************************************
107 */
getView(const std::string & path)108 View* Group::getView(const std::string& path)
109 {
110 std::string intpath(path);
111 bool create_groups_in_path = false;
112 Group* group = walkPath(intpath, create_groups_in_path);
113
114 if(group == nullptr)
115 {
116 SLIC_CHECK_MSG(
117 group != nullptr,
118 SIDRE_GROUP_LOG_PREPEND << "Non-existent group in path " << path);
119 return nullptr;
120 }
121
122 SLIC_CHECK_MSG(
123 !intpath.empty() && group->hasChildView(intpath),
124 SIDRE_GROUP_LOG_PREPEND << "No View with name '" << intpath << "'");
125
126 return group->m_view_coll->getItem(intpath);
127 }
128
129 /*
130 *************************************************************************
131 *
132 * Return pointer to const View with given name or path if it exists.
133 *
134 *************************************************************************
135 */
getView(const std::string & path) const136 const View* Group::getView(const std::string& path) const
137 {
138 std::string intpath(path);
139 const Group* group = walkPath(intpath);
140
141 if(group == nullptr)
142 {
143 SLIC_CHECK_MSG(
144 group != nullptr,
145 SIDRE_GROUP_LOG_PREPEND << "Non-existent group in path " << path);
146 return nullptr;
147 }
148
149 SLIC_CHECK_MSG(
150 !intpath.empty() && group->hasChildView(intpath),
151 SIDRE_GROUP_LOG_PREPEND << "No View with name '" << intpath << "'");
152
153 return group->m_view_coll->getItem(intpath);
154 }
155
156 ////////////////////////////////////////////////////////////////////////
157 //
158 // Methods to create a View that has no associated data.
159 //
160 ////////////////////////////////////////////////////////////////////////
161
162 /*
163 *************************************************************************
164 *
165 * Create empty View (i.e., no data description) with given name or path
166 * in this Group.
167 *
168 *************************************************************************
169 */
createView(const std::string & path)170 View* Group::createView(const std::string& path)
171 {
172 std::string intpath(path);
173
174 Group* group;
175 if(intpath.empty())
176 {
177 SLIC_CHECK_MSG(m_is_list,
178 SIDRE_GROUP_LOG_PREPEND
179 << "Could not create View with empty string "
180 << "for the path.");
181 if(m_is_list)
182 {
183 group = this;
184 }
185 else
186 {
187 return nullptr;
188 }
189 }
190 else
191 {
192 bool create_groups_in_path = true;
193 group = walkPath(intpath, create_groups_in_path);
194
195 if(group == nullptr)
196 {
197 SLIC_CHECK_MSG(group != nullptr,
198 SIDRE_GROUP_LOG_PREPEND
199 << "Could not find or create path '" << path << "'."
200 << "There is already a view with that name.");
201 return nullptr;
202 }
203 else if(intpath.empty() || group->hasChildView(intpath) ||
204 group->hasChildGroup(intpath))
205 {
206 SLIC_CHECK_MSG(
207 !intpath.empty(),
208 SIDRE_GROUP_LOG_PREPEND << "Cannot create a View with an empty path.");
209 SLIC_CHECK_MSG(!group->hasChildView(intpath),
210 SIDRE_GROUP_LOG_PREPEND
211 << "Cannot create View with name '" << intpath << "'. "
212 << "There is already a View with that name.");
213 SLIC_CHECK_MSG(!group->hasChildGroup(intpath),
214 SIDRE_GROUP_LOG_PREPEND
215 << "Cannot create View with name '" << intpath << "'. "
216 << "There is already has a Group with that name.");
217 return nullptr;
218 }
219 }
220
221 View* view = new(std::nothrow) View(intpath);
222 if(view != nullptr)
223 {
224 group->attachView(view);
225 }
226 return view;
227 }
228
229 /*
230 *************************************************************************
231 *
232 * Create described View (type and # elems) with given name or path in
233 * this Group.
234 *
235 *************************************************************************
236 */
createView(const std::string & path,TypeID type,IndexType num_elems)237 View* Group::createView(const std::string& path, TypeID type, IndexType num_elems)
238 {
239 if(type == NO_TYPE_ID || num_elems < 0)
240 {
241 SLIC_CHECK_MSG(type != NO_TYPE_ID,
242 SIDRE_GROUP_LOG_PREPEND << "Cannot create View with name '"
243 << path << "'. "
244 << " Invalid type << " << type);
245 SLIC_CHECK_MSG(num_elems >= 0,
246 SIDRE_GROUP_LOG_PREPEND
247 << "Cannot create View with name '" << path << "'. "
248 << "Number of elements cannot be less than zero.");
249 return nullptr;
250 }
251
252 View* view = createView(path);
253 if(view != nullptr)
254 {
255 view->describe(type, num_elems);
256 }
257 return view;
258 }
259
260 /*
261 *************************************************************************
262 *
263 * Create described View (type and shape) with given name or path in this
264 * Group.
265 *
266 *************************************************************************
267 */
createView(const std::string & path,TypeID type,int ndims,const IndexType * shape)268 View* Group::createView(const std::string& path,
269 TypeID type,
270 int ndims,
271 const IndexType* shape)
272 {
273 if(type == NO_TYPE_ID || ndims < 0 || shape == nullptr)
274 {
275 SLIC_CHECK_MSG(type != NO_TYPE_ID,
276 SIDRE_GROUP_LOG_PREPEND
277 << "Problem creating View with name '" << path << "'. "
278 << " Invalid type: " << type);
279 SLIC_CHECK_MSG(ndims >= 0,
280 SIDRE_GROUP_LOG_PREPEND
281 << "Problem creating View with name '" << path << "'. "
282 << "ndims must be greater than 0.");
283 SLIC_CHECK_MSG(shape != nullptr,
284 SIDRE_GROUP_LOG_PREPEND
285 << "Problem creating View with name '" << path << "'. "
286 << "shape pointer was null.");
287 return nullptr;
288 }
289
290 View* view = createView(path);
291 if(view != nullptr)
292 {
293 view->describe(type, ndims, shape);
294 }
295 return view;
296 }
297
298 /*
299 *************************************************************************
300 *
301 * Create View with given name and data described by a conduit Datatype object.
302 *
303 *************************************************************************
304 */
createView(const std::string & path,const DataType & dtype)305 View* Group::createView(const std::string& path, const DataType& dtype)
306 {
307 View* view = createView(path);
308 if(view != nullptr)
309 {
310 view->describe(dtype);
311 }
312
313 return view;
314 }
315
316 ////////////////////////////////////////////////////////////////////////
317 //
318 // Methods to create a View and attach a Buffer to it.
319 //
320 ////////////////////////////////////////////////////////////////////////
321
322 /*
323 *************************************************************************
324 *
325 * Create an undescribed View with given name or path in
326 * this Group and attach Buffer to it.
327 *
328 *************************************************************************
329 */
createView(const std::string & path,Buffer * buff)330 View* Group::createView(const std::string& path, Buffer* buff)
331 {
332 View* view = createView(path);
333 if(view != nullptr)
334 {
335 view->attachBuffer(buff);
336 }
337 return view;
338 }
339
340 /*
341 *************************************************************************
342 *
343 * Create described View (type and # elems) with given name or path in
344 * this Group and attach Buffer to it.
345 *
346 *************************************************************************
347 */
createView(const std::string & path,TypeID type,IndexType num_elems,Buffer * buff)348 View* Group::createView(const std::string& path,
349 TypeID type,
350 IndexType num_elems,
351 Buffer* buff)
352 {
353 View* view = createView(path, type, num_elems);
354 if(view != nullptr)
355 {
356 view->attachBuffer(buff);
357 }
358 return view;
359 }
360
361 /*
362 *************************************************************************
363 *
364 * Create described View (type and shape) with given name or path in
365 * this Group and attach Buffer to it.
366 *
367 *************************************************************************
368 */
createView(const std::string & path,TypeID type,int ndims,const IndexType * shape,Buffer * buff)369 View* Group::createView(const std::string& path,
370 TypeID type,
371 int ndims,
372 const IndexType* shape,
373 Buffer* buff)
374 {
375 View* view = createView(path, type, ndims, shape);
376 if(view != nullptr)
377 {
378 view->attachBuffer(buff);
379 }
380 return view;
381 }
382
383 /*
384 *************************************************************************
385 *
386 * Create described View (Conduit DataType) with given name or path in
387 * this Group and attach Buffer to it.
388 *
389 *************************************************************************
390 */
createView(const std::string & path,const DataType & dtype,Buffer * buff)391 View* Group::createView(const std::string& path, const DataType& dtype, Buffer* buff)
392 {
393 View* view = createView(path, dtype);
394 if(view != nullptr)
395 {
396 view->attachBuffer(buff);
397 }
398
399 return view;
400 }
401
402 ////////////////////////////////////////////////////////////////////////
403 //
404 // Methods to create a View and attach external data to it.
405 //
406 ////////////////////////////////////////////////////////////////////////
407
408 /*
409 *************************************************************************
410 *
411 * Create an undescribed View with given name or path in
412 * this Group and attach external data ptr to it.
413 *
414 *************************************************************************
415 */
createView(const std::string & path,void * external_ptr)416 View* Group::createView(const std::string& path, void* external_ptr)
417 {
418 View* view = createView(path);
419 if(view != nullptr)
420 {
421 view->setExternalDataPtr(external_ptr);
422 }
423 return view;
424 }
425
426 /*
427 *************************************************************************
428 *
429 * Create described View (type and # elems) with given name or path in
430 * this Group and attach external data ptr to it.
431 *
432 *************************************************************************
433 */
createView(const std::string & path,TypeID type,IndexType num_elems,void * external_ptr)434 View* Group::createView(const std::string& path,
435 TypeID type,
436 IndexType num_elems,
437 void* external_ptr)
438 {
439 View* view = createView(path, type, num_elems);
440 if(view != nullptr)
441 {
442 view->setExternalDataPtr(external_ptr);
443 }
444 return view;
445 }
446
447 /*
448 *************************************************************************
449 *
450 * Create described View (type and shape) with given name or path in
451 * this Group and attach external data ptr to it.
452 *
453 *************************************************************************
454 */
createView(const std::string & path,TypeID type,int ndims,const IndexType * shape,void * external_ptr)455 View* Group::createView(const std::string& path,
456 TypeID type,
457 int ndims,
458 const IndexType* shape,
459 void* external_ptr)
460 {
461 View* view = createView(path, type, ndims, shape);
462 if(view != nullptr)
463 {
464 view->setExternalDataPtr(external_ptr);
465 }
466 return view;
467 }
468
469 /*
470 *************************************************************************
471 *
472 * Create described View (Conduit DataType) with given name or path in
473 * this Group and attach external data ptr to it.
474 *
475 *************************************************************************
476 */
createView(const std::string & path,const DataType & dtype,void * external_ptr)477 View* Group::createView(const std::string& path,
478 const DataType& dtype,
479 void* external_ptr)
480 {
481 View* view = createView(path, dtype);
482 if(view != nullptr)
483 {
484 view->setExternalDataPtr(external_ptr);
485 }
486 return view;
487 }
488
489 ////////////////////////////////////////////////////////////////////////
490 //
491 // Methods to create a View and allocate its data.
492 //
493 ////////////////////////////////////////////////////////////////////////
494
495 /*
496 *************************************************************************
497 *
498 * Create described View (type and # elems) with given name or path in
499 * this Group and allocate its data.
500 *
501 *************************************************************************
502 */
createViewAndAllocate(const std::string & path,TypeID type,IndexType num_elems,int allocID)503 View* Group::createViewAndAllocate(const std::string& path,
504 TypeID type,
505 IndexType num_elems,
506 int allocID)
507 {
508 allocID = getValidAllocatorID(allocID);
509
510 View* view = createView(path, type, num_elems);
511 if(view != nullptr)
512 {
513 view->allocate(allocID);
514 }
515 return view;
516 }
517
518 /*
519 *************************************************************************
520 *
521 * Create described View (type and shape) with given name or path in
522 * this Group and allocate its data.
523 *
524 *************************************************************************
525 */
createViewAndAllocate(const std::string & path,TypeID type,int ndims,const IndexType * shape,int allocID)526 View* Group::createViewAndAllocate(const std::string& path,
527 TypeID type,
528 int ndims,
529 const IndexType* shape,
530 int allocID)
531 {
532 allocID = getValidAllocatorID(allocID);
533
534 View* view = createView(path, type, ndims, shape);
535 if(view != nullptr)
536 {
537 view->allocate(allocID);
538 }
539 return view;
540 }
541
542 /*
543 *************************************************************************
544 *
545 * Create described View (Conduit DataType) with given name or path in
546 * this Group and allocate its data.
547 *
548 *************************************************************************
549 */
createViewAndAllocate(const std::string & path,const DataType & dtype,int allocID)550 View* Group::createViewAndAllocate(const std::string& path,
551 const DataType& dtype,
552 int allocID)
553 {
554 allocID = getValidAllocatorID(allocID);
555
556 View* view = createView(path, dtype);
557 if(view != nullptr)
558 {
559 view->allocate(allocID);
560 }
561 return view;
562 }
563
564 /*
565 *************************************************************************
566 *
567 * Create View with given name or path and set its data to given string.
568 *
569 *************************************************************************
570 */
createViewString(const std::string & path,const std::string & value)571 View* Group::createViewString(const std::string& path, const std::string& value)
572 {
573 View* view = createView(path);
574 if(view != nullptr)
575 {
576 view->setString(value);
577 }
578
579 return view;
580 }
581
582 ////////////////////////////////////////////////////////////////////////
583 //
584 // Methods for destroying Views and their data.
585 //
586 ////////////////////////////////////////////////////////////////////////
587
588 /*
589 *************************************************************************
590 *
591 * Destroy View with given name or path and leave its data intact.
592 *
593 *************************************************************************
594 */
destroyView(const std::string & path)595 void Group::destroyView(const std::string& path)
596 {
597 std::string intpath(path);
598 bool create_groups_in_path = false;
599 Group* group = walkPath(intpath, create_groups_in_path);
600
601 if(group != nullptr)
602 {
603 View* view = group->detachView(intpath);
604 if(view != nullptr)
605 {
606 delete view;
607 }
608 }
609 }
610
611 /*
612 *************************************************************************
613 *
614 * Destroy View with given index and leave its data intact.
615 *
616 *************************************************************************
617 */
destroyView(IndexType idx)618 void Group::destroyView(IndexType idx)
619 {
620 View* view = detachView(idx);
621 if(view != nullptr)
622 {
623 delete view;
624 }
625 }
626
627 /*
628 *************************************************************************
629 *
630 * Destroy all Views in Group and leave their data intact.
631 *
632 *************************************************************************
633 */
destroyViews()634 void Group::destroyViews()
635 {
636 IndexType vidx = getFirstValidViewIndex();
637 while(indexIsValid(vidx))
638 {
639 View* view = detachView(vidx);
640 if(view != nullptr)
641 {
642 delete view;
643 }
644
645 vidx = getNextValidViewIndex(vidx);
646 }
647
648 m_view_coll->removeAllItems();
649 }
650
651 /*
652 *************************************************************************
653 *
654 * Destroy View with given name or path and its data if it's the only View
655 * associated with that data.
656 *
657 *************************************************************************
658 */
destroyViewAndData(const std::string & path)659 void Group::destroyViewAndData(const std::string& path)
660 {
661 destroyViewAndData(getView(path));
662 }
663
664 /*
665 *************************************************************************
666 *
667 * Destroy View with given index and its data if it's the only View
668 * associated with that data.
669 *
670 *************************************************************************
671 */
destroyViewAndData(IndexType idx)672 void Group::destroyViewAndData(IndexType idx)
673 {
674 destroyViewAndData(getView(idx));
675 }
676
677 /*
678 *************************************************************************
679 *
680 * Destroy all Views in Group as well as the data for each View when it's
681 * the only View associated with that data.
682 *
683 *************************************************************************
684 */
destroyViewsAndData()685 void Group::destroyViewsAndData()
686 {
687 IndexType vidx = getFirstValidViewIndex();
688 while(indexIsValid(vidx))
689 {
690 destroyViewAndData(vidx);
691 vidx = getNextValidViewIndex(vidx);
692 }
693
694 m_view_coll->removeAllItems();
695 }
696
697 ////////////////////////////////////////////////////////////////////////
698 //
699 // Methods for moving and copying View objects from one Group to another.
700 //
701 ////////////////////////////////////////////////////////////////////////
702
703 /*
704 *************************************************************************
705 *
706 * Remove given View from its owning Group and attach to this Group.
707 *
708 *************************************************************************
709 */
moveView(View * view)710 View* Group::moveView(View* view)
711 {
712 if(view == nullptr)
713 {
714 SLIC_CHECK_MSG(
715 view != nullptr,
716 SIDRE_GROUP_LOG_PREPEND << "Null pointer provided, no View to move.");
717 return nullptr;
718 }
719
720 Group* curr_group = view->getOwningGroup();
721 if(curr_group == this)
722 {
723 // this Group already owns the View
724 return view;
725 }
726 else if(hasChildView(view->getName()))
727 {
728 SLIC_CHECK_MSG(!hasChildView(view->getName()),
729 SIDRE_GROUP_LOG_PREPEND
730 << "Group already has a View named '" << view->getName()
731 << "' so View move operation cannot happen");
732 return nullptr;
733 }
734
735 curr_group->detachView(view);
736 attachView(view);
737
738 return view;
739 }
740
741 /*
742 *************************************************************************
743 *
744 * Create a copy of given View and attach to this Group.
745 *
746 * Copying a View does not perform a deep copy of its data Buffer.
747 *
748 *************************************************************************
749 */
copyView(View * view)750 View* Group::copyView(View* view)
751 {
752 if(view == nullptr || hasChildView(view->getName()))
753 {
754 SLIC_CHECK_MSG(
755 view != nullptr,
756 SIDRE_GROUP_LOG_PREPEND << "Null pointer provided, no View to copy.");
757
758 if(view != nullptr)
759 {
760 SLIC_CHECK_MSG(!hasChildView(view->getName()),
761 SIDRE_GROUP_LOG_PREPEND
762 << "Group already has a View named '" << view->getName()
763 << "' so View copy operation cannot happen");
764 }
765
766 return nullptr;
767 }
768
769 View* copy = createView(view->getName());
770 view->copyView(copy);
771 return copy;
772 }
773
774 ////////////////////////////////////////////////////////////////////////
775 //
776 // Child Group query methods.
777 //
778 ////////////////////////////////////////////////////////////////////////
779
780 /*
781 ***********************************************************************
782 *
783 * Return true if this Group has a descendant Group with given name or path;
784 * else false.
785 *
786 ***********************************************************************
787 */
hasGroup(const std::string & path) const788 bool Group::hasGroup(const std::string& path) const
789 {
790 std::string intpath(path);
791 const Group* group = walkPath(intpath);
792
793 if(group == nullptr)
794 {
795 return false;
796 }
797 else
798 {
799 return group->hasChildGroup(intpath);
800 }
801 }
802
803 ////////////////////////////////////////////////////////////////////////
804 //
805 // Child Group access methods.
806 //
807 ////////////////////////////////////////////////////////////////////////
808
809 /*
810 *************************************************************************
811 *
812 * Return pointer to non-const child Group with given name or path
813 * if it exists.
814 *
815 *************************************************************************
816 */
getGroup(const std::string & path)817 Group* Group::getGroup(const std::string& path)
818 {
819 std::string intpath(path);
820 bool create_groups_in_path = false;
821 Group* group = walkPath(intpath, create_groups_in_path);
822
823 if(group == nullptr)
824 {
825 SLIC_CHECK_MSG(group != nullptr,
826 SIDRE_GROUP_LOG_PREPEND << "Non-existent group in path '"
827 << path << "'.");
828 return nullptr;
829 }
830
831 SLIC_CHECK_MSG(!intpath.empty() && group->hasChildGroup(intpath),
832 SIDRE_GROUP_LOG_PREPEND
833 << "Group has no descendant Group named '" << path << "'.");
834
835 return group->m_group_coll->getItem(intpath);
836 }
837
838 /*
839 *************************************************************************
840 *
841 * Return pointer to const child Group with given name or path if it exists.
842 *
843 *************************************************************************
844 */
getGroup(const std::string & path) const845 const Group* Group::getGroup(const std::string& path) const
846 {
847 std::string intpath(path);
848 const Group* group = walkPath(intpath);
849
850 if(group == nullptr)
851 {
852 SLIC_CHECK_MSG(
853 group != nullptr,
854 SIDRE_GROUP_LOG_PREPEND << "Non-existent group in path " << path);
855 return nullptr;
856 }
857
858 SLIC_CHECK_MSG(!intpath.empty() && group->hasChildGroup(intpath),
859 SIDRE_GROUP_LOG_PREPEND
860 << "Group has no descendant Group with name '" << path
861 << "'.");
862
863 return group->m_group_coll->getItem(intpath);
864 }
865
866 ////////////////////////////////////////////////////////////////////////
867 //
868 // Methods for managing child Group objects in Group
869 //
870 ////////////////////////////////////////////////////////////////////////
871
872 /*
873 *************************************************************************
874 *
875 * Create Group with given name or path and make it a child of this Group.
876 *
877 *************************************************************************
878 */
createGroup(const std::string & path,bool is_list)879 Group* Group::createGroup(const std::string& path, bool is_list)
880 {
881 std::string intpath(path);
882 bool create_groups_in_path = true;
883 Group* group = walkPath(intpath, create_groups_in_path);
884
885 if(group == nullptr)
886 {
887 SLIC_CHECK_MSG(group != nullptr,
888 SIDRE_GROUP_LOG_PREPEND
889 << "Could not find or create path '" << path
890 << "'. There is already a Group with that name");
891 return nullptr;
892 }
893 else if(intpath.empty() || group->hasChildGroup(intpath) ||
894 group->hasChildView(intpath))
895 {
896 SLIC_CHECK_MSG(
897 !intpath.empty(),
898 SIDRE_GROUP_LOG_PREPEND << "Cannot create a Group with an empty path.");
899 SLIC_CHECK_MSG(!group->hasChildGroup(intpath),
900 SIDRE_GROUP_LOG_PREPEND
901 << "Cannot create Group with name '" << path
902 << "'. There is already has a Group with that name.");
903 SLIC_CHECK_MSG(!group->hasChildView(intpath),
904 SIDRE_GROUP_LOG_PREPEND
905 << "Cannot create Group with name '" << path
906 << "'. There is already has a View with that name.");
907
908 return nullptr;
909 }
910
911 Group* new_group =
912 new(std::nothrow) Group(intpath, group->getDataStore(), is_list);
913 if(new_group == nullptr)
914 {
915 return nullptr;
916 }
917
918 #ifdef AXOM_USE_UMPIRE
919 new_group->setDefaultAllocator(group->getDefaultAllocator());
920 #endif
921 return group->attachGroup(new_group);
922 }
923
createUnnamedGroup(bool is_list)924 Group* Group::createUnnamedGroup(bool is_list)
925 {
926 SLIC_CHECK_MSG(m_is_list,
927 SIDRE_GROUP_LOG_PREPEND
928 << "Cannot create an unnamed Group when not using "
929 << "list format.");
930
931 Group* new_group;
932 if(m_is_list)
933 {
934 new_group = new(std::nothrow) Group("", getDataStore(), is_list);
935 }
936 else
937 {
938 new_group = nullptr;
939 }
940
941 if(new_group == nullptr)
942 {
943 return nullptr;
944 }
945
946 #ifdef AXOM_USE_UMPIRE
947 new_group->setDefaultAllocator(getDefaultAllocator());
948 #endif
949 return attachGroup(new_group);
950 }
951
952 /*
953 *************************************************************************
954 *
955 * Detach child Group with given name or path and destroy it.
956 *
957 *************************************************************************
958 */
destroyGroup(const std::string & path)959 void Group::destroyGroup(const std::string& path)
960 {
961 std::string intpath(path);
962 bool create_groups_in_path = false;
963 Group* group = walkPath(intpath, create_groups_in_path);
964
965 if(group != nullptr)
966 {
967 Group* targetgroup = group->detachGroup(intpath);
968 if(targetgroup != nullptr)
969 {
970 delete targetgroup;
971 }
972 }
973 }
974
975 /*
976 *************************************************************************
977 *
978 * Detach child Group with given index and destroy it.
979 *
980 *************************************************************************
981 */
destroyGroup(IndexType idx)982 void Group::destroyGroup(IndexType idx)
983 {
984 Group* group = detachGroup(idx);
985 if(group != nullptr)
986 {
987 delete group;
988 }
989 }
990
991 /*
992 *************************************************************************
993 *
994 * Detach all child Groups and destroy them.
995 *
996 *************************************************************************
997 */
destroyGroups()998 void Group::destroyGroups()
999 {
1000 IndexType gidx = getFirstValidGroupIndex();
1001 while(indexIsValid(gidx))
1002 {
1003 Group* group = this->getGroup(gidx);
1004 delete group;
1005
1006 gidx = getNextValidGroupIndex(gidx);
1007 }
1008
1009 m_group_coll->removeAllItems();
1010 }
1011
1012 /*
1013 *************************************************************************
1014 *
1015 * Remove given Group from its owning Group and make it a child of this Group.
1016 *
1017 *************************************************************************
1018 */
moveGroup(Group * group)1019 Group* Group::moveGroup(Group* group)
1020 {
1021 if(group == nullptr || hasChildGroup(group->getName()))
1022 {
1023 SLIC_CHECK_MSG(
1024 group != nullptr,
1025 SIDRE_GROUP_LOG_PREPEND << "Null pointer provided, no Group to move.");
1026
1027 if(group != nullptr)
1028 {
1029 SLIC_CHECK_MSG(!hasChildGroup(group->getName()),
1030 SIDRE_GROUP_LOG_PREPEND
1031 << "Invalid move operation. Group already has "
1032 << "a child named '" << group->getName() << "'.");
1033 }
1034
1035 return nullptr;
1036 }
1037
1038 Group* curr_group = group->getParent();
1039 curr_group->detachGroup(group->getName());
1040 attachGroup(group);
1041 return group;
1042 }
1043
1044 /*
1045 *************************************************************************
1046 *
1047 * Create a copy of given Group and make it a child of this Group.
1048 *
1049 * Copying a Group does not perform a deep copy of any of its Buffers.
1050 *
1051 *************************************************************************
1052 */
copyGroup(Group * group)1053 Group* Group::copyGroup(Group* group)
1054 {
1055 if(group == nullptr || hasChildGroup(group->getName()))
1056 {
1057 SLIC_CHECK_MSG(
1058 group != nullptr,
1059 SIDRE_GROUP_LOG_PREPEND << "Null pointer provided, no Group to copy.");
1060
1061 if(group != nullptr)
1062 {
1063 SLIC_CHECK_MSG(!hasChildGroup(group->getName()),
1064 SIDRE_GROUP_LOG_PREPEND
1065 << "Invalid copy operation. Group already has "
1066 << "a child named '" << group->getName() << "'.");
1067 }
1068
1069 return nullptr;
1070 }
1071
1072 Group* res = createGroup(group->getName());
1073
1074 // copy child Groups to new Group
1075 IndexType gidx = group->getFirstValidGroupIndex();
1076 while(indexIsValid(gidx))
1077 {
1078 res->copyGroup(group->getGroup(gidx));
1079 gidx = group->getNextValidGroupIndex(gidx);
1080 }
1081
1082 // copy Views to new Group
1083 IndexType vidx = group->getFirstValidViewIndex();
1084 while(indexIsValid(vidx))
1085 {
1086 res->copyView(group->getView(vidx));
1087 vidx = group->getNextValidViewIndex(vidx);
1088 }
1089
1090 return res;
1091 }
1092
1093 /*
1094 *************************************************************************
1095 *
1096 * Copy Group native layout to given Conduit node.
1097 *
1098 *************************************************************************
1099 */
createNativeLayout(Node & n,const Attribute * attr) const1100 bool Group::createNativeLayout(Node& n, const Attribute* attr) const
1101 {
1102 n.set(DataType::object());
1103 bool hasSavedViews = false;
1104
1105 // Dump the group's views
1106 IndexType vidx = getFirstValidViewIndex();
1107 while(indexIsValid(vidx))
1108 {
1109 const View* view = getView(vidx);
1110
1111 // Check that the view's name is not also a child group name
1112 SLIC_CHECK_MSG(m_is_list || !hasChildGroup(view->getName()),
1113 SIDRE_GROUP_LOG_PREPEND
1114 << "'" << view->getName()
1115 << "' is the name of both a group and a view.");
1116
1117 if(attr == nullptr || view->hasAttributeValue(attr))
1118 {
1119 conduit::Node& child_node = m_is_list ? n.append() : n[view->getName()];
1120 view->createNativeLayout(child_node);
1121 hasSavedViews = true;
1122 }
1123 vidx = getNextValidViewIndex(vidx);
1124 }
1125
1126 // Recursively dump the child groups
1127 IndexType gidx = getFirstValidGroupIndex();
1128 while(indexIsValid(gidx))
1129 {
1130 const Group* group = getGroup(gidx);
1131 conduit::Node& child_node = m_is_list ? n.append() : n[group->getName()];
1132 if(group->createNativeLayout(child_node, attr))
1133 {
1134 hasSavedViews = true;
1135 }
1136 else
1137 {
1138 if(m_is_list)
1139 {
1140 n.remove(group->getName());
1141 }
1142 else
1143 {
1144 n.remove(n.number_of_children() - 1);
1145 }
1146 }
1147 gidx = getNextValidGroupIndex(gidx);
1148 }
1149
1150 return hasSavedViews;
1151 }
1152
1153 /*
1154 *************************************************************************
1155 *
1156 * Adds a conduit node for this group if it has external views,
1157 * or if any of its children groups has an external view
1158 *
1159 *************************************************************************
1160 * see ATK-736 - Improvements to createNativeLayout and createExternalLayout
1161 */
createExternalLayout(Node & n,const Attribute * attr) const1162 bool Group::createExternalLayout(Node& n, const Attribute* attr) const
1163 {
1164 n.set(DataType::object());
1165
1166 bool hasExternalViews = false;
1167
1168 // Dump the group's views
1169 IndexType vidx = getFirstValidViewIndex();
1170 while(indexIsValid(vidx))
1171 {
1172 const View* view = getView(vidx);
1173
1174 // Check that the view's name is not also a child group name
1175 SLIC_CHECK_MSG(m_is_list || !hasChildGroup(view->getName()),
1176 SIDRE_GROUP_LOG_PREPEND
1177 << "'" << view->getName()
1178 << "' is the name of both a group and a view.");
1179
1180 if(attr == nullptr || view->hasAttributeValue(attr))
1181 {
1182 if(view->isExternal())
1183 {
1184 if(view->isDescribed())
1185 {
1186 conduit::Node& vnode = m_is_list ? n.append() : n[view->getName()];
1187 view->createNativeLayout(vnode);
1188 }
1189 hasExternalViews = true;
1190 }
1191 }
1192
1193 vidx = getNextValidViewIndex(vidx);
1194 }
1195
1196 // Recursively dump the child groups
1197 IndexType gidx = getFirstValidGroupIndex();
1198 while(indexIsValid(gidx))
1199 {
1200 const Group* group = getGroup(gidx);
1201
1202 conduit::Node& gnode = m_is_list ? n.append() : n[group->getName()];
1203 if(group->createExternalLayout(gnode, attr))
1204 {
1205 hasExternalViews = true;
1206 }
1207 else
1208 {
1209 // Remove nodes that do not have any external views
1210 if(m_is_list)
1211 {
1212 n.remove(n.number_of_children() - 1);
1213 }
1214 else
1215 {
1216 n.remove(group->getName());
1217 }
1218 }
1219
1220 gidx = getNextValidGroupIndex(gidx);
1221 }
1222
1223 return hasExternalViews;
1224 }
1225
1226 /*
1227 *************************************************************************
1228 *
1229 * Print JSON description of data Group to stdout.
1230 *
1231 *************************************************************************
1232 */
print() const1233 void Group::print() const { print(std::cout); }
1234
1235 /*
1236 *************************************************************************
1237 *
1238 * Print JSON description of data Group to an ostream.
1239 *
1240 *************************************************************************
1241 */
print(std::ostream & os) const1242 void Group::print(std::ostream& os) const
1243 {
1244 Node n;
1245 copyToConduitNode(n);
1246 n.to_json_stream(os);
1247 }
1248
1249 /*
1250 *************************************************************************
1251 *
1252 * Print given number of levels of Group sub-tree rooted at this
1253 * Group to stdout.
1254 *
1255 *************************************************************************
1256 */
printTree(const int nlevels,std::ostream & os) const1257 void Group::printTree(const int nlevels, std::ostream& os) const
1258 {
1259 for(int i = 0; i < nlevels; ++i)
1260 {
1261 os << " ";
1262 }
1263 os << "Group " << this->getName() << std::endl;
1264
1265 IndexType vidx = getFirstValidViewIndex();
1266 while(indexIsValid(vidx))
1267 {
1268 const View* view = getView(vidx);
1269
1270 for(int i = 0; i < nlevels + 1; ++i)
1271 {
1272 os << " ";
1273 }
1274 os << "View " << view->getName() << std::endl;
1275
1276 vidx = getNextValidViewIndex(vidx);
1277 }
1278
1279 IndexType gidx = getFirstValidGroupIndex();
1280 while(indexIsValid(gidx))
1281 {
1282 const Group* group = getGroup(gidx);
1283
1284 group->printTree(nlevels + 1, os);
1285
1286 gidx = getNextValidGroupIndex(gidx);
1287 }
1288 }
1289
1290 /*
1291 *************************************************************************
1292 *
1293 * Copy data Group description to given Conduit node.
1294 *
1295 *************************************************************************
1296 */
copyToConduitNode(Node & n) const1297 void Group::copyToConduitNode(Node& n) const
1298 {
1299 n["name"] = m_name;
1300
1301 IndexType vidx = getFirstValidViewIndex();
1302 while(indexIsValid(vidx))
1303 {
1304 const View* view = getView(vidx);
1305 Node& v = n["views"].fetch(view->getName());
1306 view->copyToConduitNode(v);
1307
1308 vidx = getNextValidViewIndex(vidx);
1309 }
1310
1311 IndexType gidx = getFirstValidGroupIndex();
1312 while(indexIsValid(gidx))
1313 {
1314 const Group* group = getGroup(gidx);
1315 Node& g = n["groups"].fetch(group->getName());
1316 group->copyToConduitNode(g);
1317
1318 gidx = getNextValidGroupIndex(gidx);
1319 }
1320 }
1321
1322 /*
1323 *************************************************************************
1324 *
1325 * Test this Group for equivalence to another Group.
1326 *
1327 *************************************************************************
1328 */
isEquivalentTo(const Group * other,bool checkName) const1329 bool Group::isEquivalentTo(const Group* other, bool checkName) const
1330 {
1331 // Equality of names
1332 bool is_equiv = true;
1333 if(checkName)
1334 {
1335 is_equiv = (m_name == other->m_name);
1336 }
1337
1338 // Sizes of collections of child items must be equal
1339 if(is_equiv)
1340 {
1341 is_equiv = (m_view_coll->getNumItems() == other->m_view_coll->getNumItems()) &&
1342 (m_group_coll->getNumItems() == other->m_group_coll->getNumItems());
1343 }
1344
1345 // Test equivalence of Views
1346 if(is_equiv)
1347 {
1348 IndexType vidx = getFirstValidViewIndex();
1349 while(is_equiv && indexIsValid(vidx))
1350 {
1351 const View* view = getView(vidx);
1352 const std::string& name = view->getName();
1353
1354 is_equiv =
1355 other->hasChildView(name) && view->isEquivalentTo(other->getView(name));
1356
1357 vidx = getNextValidViewIndex(vidx);
1358 }
1359 }
1360
1361 // Recursively call this method to test equivalence of child Groups
1362 if(is_equiv)
1363 {
1364 IndexType gidx = getFirstValidGroupIndex();
1365 while(is_equiv && indexIsValid(gidx))
1366 {
1367 const Group* group = getGroup(gidx);
1368 const std::string& name = group->getName();
1369
1370 is_equiv = other->hasChildGroup(name) &&
1371 group->isEquivalentTo(other->getGroup(name));
1372
1373 gidx = getNextValidGroupIndex(gidx);
1374 }
1375 }
1376
1377 return is_equiv;
1378 }
1379
1380 /*
1381 *************************************************************************
1382 *
1383 * Save Group (including Views and child Groups) to a file
1384 *
1385 *************************************************************************
1386 */
1387
save(const std::string & path,const std::string & protocol,const Attribute * attr) const1388 void Group::save(const std::string& path,
1389 const std::string& protocol,
1390 const Attribute* attr) const
1391 {
1392 const DataStore* ds = getDataStore();
1393
1394 if(protocol == "sidre_hdf5")
1395 {
1396 Node n;
1397 exportTo(n["sidre"], attr);
1398 ds->saveAttributeLayout(n["sidre/attribute"]);
1399 createExternalLayout(n["sidre/external"], attr);
1400 n["sidre_group_name"] = m_name;
1401 conduit::relay::io::save(n, path, "hdf5");
1402 }
1403 else if(protocol == "sidre_conduit_json")
1404 {
1405 Node n;
1406 exportTo(n["sidre"], attr);
1407 ds->saveAttributeLayout(n["sidre/attribute"]);
1408 createExternalLayout(n["sidre/external"], attr);
1409 n["sidre_group_name"] = m_name;
1410 conduit::relay::io::save(n, path, "conduit_json");
1411 }
1412 else if(protocol == "sidre_json")
1413 {
1414 Node n;
1415 exportTo(n["sidre"], attr);
1416 ds->saveAttributeLayout(n["sidre/attribute"]);
1417 createExternalLayout(n["sidre/external"], attr);
1418 n["sidre_group_name"] = m_name;
1419 conduit::relay::io::save(n, path, "json");
1420 }
1421 else if(protocol == "conduit_hdf5")
1422 {
1423 Node n;
1424 createNativeLayout(n, attr);
1425 n["sidre_group_name"] = m_name;
1426 conduit::relay::io::save(n, path, "hdf5");
1427 }
1428 else if(protocol == "conduit_bin" || protocol == "conduit_json" ||
1429 protocol == "json")
1430 {
1431 Node n;
1432 createNativeLayout(n, attr);
1433 n["sidre_group_name"] = m_name;
1434 conduit::relay::io::save(n, path, protocol);
1435 }
1436 else
1437 {
1438 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND << "Invalid protocol '" << protocol
1439 << "' for file save.");
1440 }
1441 }
1442
1443 /*************************************************************************/
1444
1445 /*
1446 *************************************************************************
1447 *
1448 * Load Group (including Views and child Groups) from a file
1449 *
1450 *************************************************************************
1451 */
load(const std::string & path,const std::string & protocol,bool preserve_contents)1452 void Group::load(const std::string& path,
1453 const std::string& protocol,
1454 bool preserve_contents)
1455 {
1456 std::string new_name;
1457 load(path, protocol, preserve_contents, new_name);
1458 }
1459
load(const std::string & path,const std::string & protocol,bool preserve_contents,std::string & name_from_file)1460 void Group::load(const std::string& path,
1461 const std::string& protocol,
1462 bool preserve_contents,
1463 std::string& name_from_file)
1464 {
1465 if(protocol == "sidre_hdf5")
1466 {
1467 Node n;
1468 conduit::relay::io::load(path, "hdf5", n);
1469 SLIC_ASSERT_MSG(n.has_path("sidre"),
1470 SIDRE_GROUP_LOG_PREPEND
1471 << "Conduit Node " << n.path() << " does not have sidre "
1472 << "data for this Group " << getPathName() << ".");
1473 importFrom(n["sidre"], preserve_contents);
1474 if(n.has_path("sidre_group_name"))
1475 {
1476 name_from_file = n["sidre_group_name"].as_string();
1477 }
1478 }
1479 else if(protocol == "sidre_conduit_json")
1480 {
1481 Node n;
1482 conduit::relay::io::load(path, "conduit_json", n);
1483 SLIC_ASSERT_MSG(n.has_path("sidre"),
1484 SIDRE_GROUP_LOG_PREPEND
1485 << "Conduit Node " << n.path() << " does not have sidre "
1486 << "data for Group " << getPathName() << ".");
1487 importFrom(n["sidre"], preserve_contents);
1488 if(n.has_path("sidre_group_name"))
1489 {
1490 name_from_file = n["sidre_group_name"].as_string();
1491 }
1492 }
1493 else if(protocol == "sidre_json")
1494 {
1495 Node n;
1496 conduit::relay::io::load(path, "json", n);
1497 SLIC_ASSERT_MSG(n.has_path("sidre"),
1498 SIDRE_GROUP_LOG_PREPEND
1499 << "Conduit Node " << n.path() << " does not have sidre "
1500 << "data for Group " << getPathName() << ".");
1501 importFrom(n["sidre"], preserve_contents);
1502 if(n.has_path("sidre_group_name"))
1503 {
1504 name_from_file = n["sidre_group_name"].as_string();
1505 }
1506 }
1507 else if(protocol == "conduit_hdf5")
1508 {
1509 Node n;
1510 conduit::relay::io::load(path, "hdf5", n);
1511 importConduitTree(n, preserve_contents);
1512 if(n.has_path("sidre_group_name"))
1513 {
1514 name_from_file = n["sidre_group_name"].as_string();
1515 }
1516 }
1517 else if(protocol == "conduit_bin" || protocol == "conduit_json" ||
1518 protocol == "json")
1519 {
1520 Node n;
1521 conduit::relay::io::load(path, protocol, n);
1522 importConduitTree(n, preserve_contents);
1523 if(n.has_path("sidre_group_name"))
1524 {
1525 name_from_file = n["sidre_group_name"].as_string();
1526 }
1527 }
1528 else
1529 {
1530 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND << "Invalid protocol '" << protocol
1531 << "' for file load.");
1532 }
1533 }
1534
1535 /*
1536 *************************************************************************
1537 *
1538 * Load Group (including Views and child Groups) from a file
1539 *
1540 *************************************************************************
1541 */
createGroupAndLoad(std::string & group_name,const std::string & path,const std::string & protocol,bool & load_success)1542 Group* Group::createGroupAndLoad(std::string& group_name,
1543 const std::string& path,
1544 const std::string& protocol,
1545 bool& load_success)
1546 {
1547 load_success = false;
1548 Group* child = createGroup(group_name);
1549 if(child != nullptr)
1550 {
1551 // In a forthcoming PR, load() will return a bool for success/failure
1552 load_success = true;
1553 child->load(path, protocol, false, group_name);
1554 }
1555
1556 return child;
1557 }
1558
1559 /*
1560 *************************************************************************
1561 *
1562 * Load External Data from a file
1563 *
1564 *************************************************************************
1565 */
loadExternalData(const std::string & path)1566 void Group::loadExternalData(const std::string& path)
1567 {
1568 Node n;
1569 createExternalLayout(n);
1570
1571 #ifdef AXOM_USE_HDF5
1572 // CYRUS'-NOTE, not sure ":" will work with multiple trees per
1573 // output file
1574 conduit::relay::io::hdf5_read(path + ":sidre/external", n);
1575 #else
1576 AXOM_UNUSED_VAR(path);
1577 SLIC_WARNING(SIDRE_GROUP_LOG_PREPEND
1578 << "External data not loaded. "
1579 << "This function requires hdf5 support. "
1580 << " Please reconfigure with hdf5.");
1581 #endif
1582 }
1583
1584 // Functions that directly use the hdf5 API in their signature
1585 #ifdef AXOM_USE_HDF5
1586
1587 /*
1588 *************************************************************************
1589 *
1590 * Save Group (including Views and child Groups) to a hdf5 handle
1591 *
1592 *************************************************************************
1593 */
save(const hid_t & h5_id,const std::string & protocol,const Attribute * attr) const1594 void Group::save(const hid_t& h5_id,
1595 const std::string& protocol,
1596 const Attribute* attr) const
1597 {
1598 // supported here:
1599 // "sidre_hdf5"
1600 // "conduit_hdf5"
1601 if(protocol == "sidre_hdf5")
1602 {
1603 Node n;
1604 exportTo(n["sidre"], attr);
1605 createExternalLayout(n["sidre/external"], attr);
1606 n["sidre_group_name"] = m_name;
1607 conduit::relay::io::hdf5_write(n, h5_id);
1608 }
1609 else if(protocol == "conduit_hdf5")
1610 {
1611 Node n;
1612 createNativeLayout(n, attr);
1613 n["sidre_group_name"] = m_name;
1614 conduit::relay::io::hdf5_write(n, h5_id);
1615 }
1616 else
1617 {
1618 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND << "Invalid protocol '" << protocol
1619 << "' for save with hdf5 handle.");
1620 }
1621 }
1622
1623 /*
1624 *************************************************************************
1625 *
1626 * Load Group (including Views and child Groups) from an hdf5 handle
1627 *
1628 *************************************************************************
1629 */
load(const hid_t & h5_id,const std::string & protocol,bool preserve_contents)1630 void Group::load(const hid_t& h5_id,
1631 const std::string& protocol,
1632 bool preserve_contents)
1633 {
1634 std::string name_from_file;
1635 load(h5_id, protocol, preserve_contents, name_from_file);
1636 }
1637
load(const hid_t & h5_id,const std::string & protocol,bool preserve_contents,std::string & name_from_file)1638 void Group::load(const hid_t& h5_id,
1639 const std::string& protocol,
1640 bool preserve_contents,
1641 std::string& name_from_file)
1642 {
1643 // supported here:
1644 // "sidre_hdf5"
1645 // "conduit_hdf5"
1646 if(protocol == "sidre_hdf5")
1647 {
1648 Node n;
1649 conduit::relay::io::hdf5_read(h5_id, n);
1650 SLIC_ASSERT_MSG(n.has_path("sidre"),
1651 SIDRE_GROUP_LOG_PREPEND
1652 << "Conduit Node " << n.path() << " does not have sidre "
1653 << "data for Group " << getPathName() << ".");
1654 importFrom(n["sidre"], preserve_contents);
1655 if(n.has_path("sidre_group_name"))
1656 {
1657 name_from_file = n["sidre_group_name"].as_string();
1658 }
1659 }
1660 else if(protocol == "conduit_hdf5")
1661 {
1662 SLIC_ERROR("Protocol " << protocol << " not yet supported for file load.");
1663 Node n;
1664 conduit::relay::io::hdf5_read(h5_id, n);
1665 importConduitTree(n, preserve_contents);
1666 if(n.has_path("sidre_group_name"))
1667 {
1668 name_from_file = n["sidre_group_name"].as_string();
1669 }
1670 }
1671 else
1672 {
1673 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND << "Invalid protocol '" << protocol
1674 << "' for file load.");
1675 }
1676 }
1677
1678 /*
1679 *************************************************************************
1680 *
1681 * Load External Data from an hdf5 file
1682 *
1683 * Note: this ASSUMES uses the "sidre_hdf5" protocol
1684 *************************************************************************
1685 */
loadExternalData(const hid_t & h5_id)1686 void Group::loadExternalData(const hid_t& h5_id)
1687 {
1688 Node n;
1689 createExternalLayout(n);
1690 conduit::relay::io::hdf5_read(h5_id, "sidre/external", n);
1691 }
1692
1693 #endif /* AXOM_USE_HDF5 */
1694
1695 ////////////////////////////////////////////////////////////////////////
1696 //
1697 // Private methods below
1698 //
1699 ////////////////////////////////////////////////////////////////////////
1700
1701 /*
1702 *************************************************************************
1703 *
1704 * PRIVATE ctor makes Group with given name and make it a child of
1705 * root Group in datastore.
1706 *
1707 *************************************************************************
1708 */
Group(const std::string & name,DataStore * datastore,bool is_list)1709 Group::Group(const std::string& name, DataStore* datastore, bool is_list)
1710 : m_name(name)
1711 , m_index(InvalidIndex)
1712 , m_parent(nullptr)
1713 , m_datastore(datastore)
1714 , m_is_list(is_list)
1715 , m_view_coll(nullptr)
1716 , m_group_coll(nullptr)
1717 #ifdef AXOM_USE_UMPIRE
1718 , m_default_allocator_id(axom::getDefaultAllocatorID())
1719 #endif
1720 {
1721 if(is_list)
1722 {
1723 m_view_coll = new ListCollection<View>();
1724 m_group_coll = new ListCollection<Group>();
1725 }
1726 else
1727 {
1728 m_view_coll = new MapCollection<View>();
1729 m_group_coll = new MapCollection<Group>();
1730 }
1731 }
1732
1733 /*
1734 *************************************************************************
1735 *
1736 * PRIVATE dtor destroys Group and all its contents.
1737 *
1738 *************************************************************************
1739 */
~Group()1740 Group::~Group()
1741 {
1742 destroyViews();
1743 destroyGroups();
1744 delete m_view_coll;
1745 delete m_group_coll;
1746 }
1747
1748 /*
1749 *************************************************************************
1750 *
1751 * PRIVATE method to attach given View to Group.
1752 *
1753 *************************************************************************
1754 */
attachView(View * view)1755 View* Group::attachView(View* view)
1756 {
1757 if(view == nullptr ||
1758 (!view->getName().empty() && hasChildView(view->getName())))
1759 {
1760 return nullptr;
1761 }
1762 else
1763 {
1764 SLIC_ASSERT_MSG(view->m_owning_group == nullptr,
1765 SIDRE_GROUP_LOG_PREPEND
1766 << "Provided View " << view->getPathName() << " is already "
1767 << "attatched to Group "
1768 << view->m_owning_group->getPathName() << " and can't be "
1769 << "attatched to Group " << getPathName() << ".");
1770 view->m_owning_group = this;
1771 view->m_index = m_view_coll->insertItem(view, view->getName());
1772 return view;
1773 }
1774 }
1775
1776 /*
1777 *************************************************************************
1778 *
1779 * PRIVATE method to detach View with given name from Group.
1780 *
1781 *************************************************************************
1782 */
detachView(const std::string & name)1783 View* Group::detachView(const std::string& name)
1784 {
1785 View* view = m_view_coll->removeItem(name);
1786 if(view != nullptr)
1787 {
1788 view->m_owning_group = nullptr;
1789 view->m_index = InvalidIndex;
1790 }
1791
1792 return view;
1793 }
1794
1795 /*
1796 *************************************************************************
1797 *
1798 * PRIVATE method to detach View with given index from Group.
1799 *
1800 *************************************************************************
1801 */
detachView(IndexType idx)1802 View* Group::detachView(IndexType idx)
1803 {
1804 View* view = m_view_coll->removeItem(idx);
1805 if(view != nullptr)
1806 {
1807 view->m_owning_group = nullptr;
1808 view->m_index = InvalidIndex;
1809 }
1810
1811 return view;
1812 }
1813
1814 /*
1815 *************************************************************************
1816 *
1817 * PRIVATE method to destroy View in this Group and its data.
1818 *
1819 *************************************************************************
1820 */
destroyViewAndData(View * view)1821 void Group::destroyViewAndData(View* view)
1822 {
1823 if(view != nullptr)
1824 {
1825 Group* group = view->getOwningGroup();
1826 group->detachView(view->getName());
1827 Buffer* const buffer = view->detachBuffer();
1828 if(buffer != nullptr && buffer->getNumViews() == 0)
1829 {
1830 getDataStore()->destroyBuffer(buffer);
1831 }
1832 delete view;
1833 }
1834 }
1835
1836 /*
1837 *************************************************************************
1838 *
1839 * PRIVATE method to make given Group a child of this Group.
1840 *
1841 *************************************************************************
1842 */
attachGroup(Group * group)1843 Group* Group::attachGroup(Group* group)
1844 {
1845 if(group == nullptr ||
1846 (!group->getName().empty() && hasChildGroup(group->getName())))
1847 {
1848 return nullptr;
1849 }
1850 else
1851 {
1852 group->m_parent = this;
1853 group->m_index = m_group_coll->insertItem(group, group->getName());
1854 return group;
1855 }
1856 }
1857
1858 /*
1859 *************************************************************************
1860 *
1861 * PRIVATE method to detach child Group with given name from Group.
1862 *
1863 *************************************************************************
1864 */
detachGroup(const std::string & name)1865 Group* Group::detachGroup(const std::string& name)
1866 {
1867 Group* group = m_group_coll->removeItem(name);
1868 if(group != nullptr)
1869 {
1870 group->m_parent = nullptr;
1871 group->m_index = InvalidIndex;
1872 }
1873
1874 return group;
1875 }
1876
1877 /*
1878 *************************************************************************
1879 *
1880 * PRIVATE method to detach child Group with given index from Group.
1881 *
1882 *************************************************************************
1883 */
detachGroup(IndexType idx)1884 Group* Group::detachGroup(IndexType idx)
1885 {
1886 Group* group = m_group_coll->removeItem(idx);
1887 if(group != nullptr)
1888 {
1889 group->m_parent = nullptr;
1890 group->m_index = InvalidIndex;
1891 }
1892
1893 return group;
1894 }
1895
1896 /*
1897 *************************************************************************
1898 *
1899 * Serialize tree identified by a Group into a conduit node. Include
1900 * any Buffers attached to Views in that tree.
1901 *
1902 * Note: This is for the "sidre_{zzz}" protocols.
1903 *
1904 *************************************************************************
1905 */
exportTo(conduit::Node & result,const Attribute * attr) const1906 bool Group::exportTo(conduit::Node& result, const Attribute* attr) const
1907 {
1908 result.set(DataType::object());
1909 // TODO - This implementation will change in the future. We want to write
1910 // out some separate set of conduit nodes:
1911 // #1 A set of nodes representing the Group and Views (hierarchy), with
1912 // the data descriptions ( schemas ).
1913 // #2 A set of nodes for our data ( Buffers, external data, etc ).
1914 // On a load, we want to be able to create our DataStore tree first,
1915 // then call allocate ourself, then have conduit load the data directly
1916 // into our allocated memory areas. Conduit can do this, as long as the
1917 // conduit node set is compatible with what's in the file.
1918 std::set<IndexType> buffer_indices;
1919
1920 // Tell Group to add itself and all sub-Groups and Views to node.
1921 // Any Buffers referenced by those Views will be tracked in the
1922 // buffer_indices
1923 bool hasSavedViews = exportTo(result, attr, buffer_indices);
1924
1925 if(!buffer_indices.empty())
1926 {
1927 // Now, add all the referenced buffers to the node.
1928 Node& bnode = result["buffers"];
1929 for(std::set<IndexType>::iterator s_it = buffer_indices.begin();
1930 s_it != buffer_indices.end();
1931 ++s_it)
1932 {
1933 // Use a dictionary layout here instead of conduit list.
1934 // Conduit IO HDF5 doesn't support conduit list objects.
1935 std::ostringstream oss;
1936 oss << "buffer_id_" << *s_it;
1937 Node& n_buffer = bnode.fetch(oss.str());
1938 getDataStore()->getBuffer(*s_it)->exportTo(n_buffer);
1939 }
1940 }
1941
1942 return hasSavedViews;
1943 }
1944
1945 /*
1946 *************************************************************************
1947 *
1948 * PRIVATE method to copy from Group to given Conduit node using
1949 * given set of ids to maintain correct association of data Buffers
1950 * to data Views.
1951 *
1952 * Note: This is for the "sidre_{zzz}" protocols.
1953 *
1954 *************************************************************************
1955 */
exportTo(conduit::Node & result,const Attribute * attr,std::set<IndexType> & buffer_indices) const1956 bool Group::exportTo(conduit::Node& result,
1957 const Attribute* attr,
1958 std::set<IndexType>& buffer_indices) const
1959 {
1960 result.set(DataType::object());
1961 bool hasSavedViews = false;
1962
1963 if(getNumViews() > 0)
1964 {
1965 Node& vnode = result["views"];
1966 IndexType vidx = getFirstValidViewIndex();
1967 while(indexIsValid(vidx))
1968 {
1969 const View* view = getView(vidx);
1970 if(attr == nullptr || view->hasAttributeValue(attr))
1971 {
1972 Node& n_view = m_is_list ? vnode.append() : vnode.fetch(view->getName());
1973 view->exportTo(n_view, buffer_indices);
1974 hasSavedViews = true;
1975 }
1976 vidx = getNextValidViewIndex(vidx);
1977 }
1978 if(!hasSavedViews)
1979 {
1980 result.remove("views");
1981 }
1982 }
1983
1984 bool hasSavedGroups = false;
1985 if(getNumGroups() > 0)
1986 {
1987 Node& gnode = result["groups"];
1988 IndexType gidx = getFirstValidGroupIndex();
1989 while(indexIsValid(gidx))
1990 {
1991 const Group* group = getGroup(gidx);
1992 Node& n_group = m_is_list ? gnode.append() : gnode.fetch(group->getName());
1993 bool hsv = group->exportTo(n_group, attr, buffer_indices);
1994 hasSavedViews = hasSavedViews || hsv;
1995 hasSavedGroups = true;
1996
1997 gidx = getNextValidGroupIndex(gidx);
1998 }
1999 if(!hasSavedGroups)
2000 {
2001 result.remove("groups");
2002 }
2003 }
2004
2005 return hasSavedViews;
2006 }
2007
2008 /*
2009 *************************************************************************
2010 *
2011 * Imports tree from a conduit node into this Group. Includes
2012 * any Buffers attached to Views in that tree.
2013 *
2014 *
2015 * Note: This is for the "sidre_{zzz}" protocols.
2016 *
2017 *************************************************************************
2018 */
2019
importFrom(conduit::Node & node,bool preserve_contents)2020 void Group::importFrom(conduit::Node& node, bool preserve_contents)
2021 {
2022 // TODO - May want to put in a little meta-data into these files like a
2023 // 'version'
2024 // or tag identifying the data. We don't want someone giving us a file that
2025 // doesn't have our full multiView->buffer connectivity in there.
2026
2027 if(!preserve_contents)
2028 {
2029 destroyGroups();
2030 destroyViews();
2031 }
2032
2033 getDataStore()->loadAttributeLayout(node);
2034
2035 // First - Import Buffers into the DataStore.
2036 std::map<IndexType, IndexType> buffer_indices_map;
2037
2038 if(node.has_path("buffers"))
2039 {
2040 conduit::NodeIterator buffs_itr = node["buffers"].children();
2041 while(buffs_itr.has_next())
2042 {
2043 Node& n_buffer = buffs_itr.next();
2044 IndexType old_buffer_id = n_buffer["id"].to_int64();
2045
2046 Buffer* buffer = getDataStore()->createBuffer();
2047
2048 // track change of old Buffer id to new Buffer id
2049 buffer_indices_map[old_buffer_id] = buffer->getIndex();
2050
2051 // populate the new Buffer's state
2052 buffer->importFrom(n_buffer);
2053 }
2054 }
2055
2056 // Next - import tree of Groups, sub-Groups, Views into the DataStore.
2057 // Use the mapping of old to new Buffer ids to connect the Views to the
2058 // right Buffers.
2059 importFrom(node, buffer_indices_map);
2060 }
2061
2062 /*
2063 *************************************************************************
2064 *
2065 * PRIVATE method to copy from given Conduit node to this Group using
2066 * given map of ids to indicate association of Buffer ids in node to
2067 * those in datastore.
2068 *
2069 * Note: This is for the "sidre_{zzz}" protocols.
2070 *
2071 *************************************************************************
2072 */
importFrom(conduit::Node & node,const std::map<IndexType,IndexType> & buffer_id_map)2073 void Group::importFrom(conduit::Node& node,
2074 const std::map<IndexType, IndexType>& buffer_id_map)
2075 {
2076 if(node.has_path("views"))
2077 {
2078 // create the Views
2079 conduit::NodeIterator views_itr = node["views"].children();
2080 while(views_itr.has_next())
2081 {
2082 Node& n_view = views_itr.next();
2083 std::string view_name = m_is_list ? "" : views_itr.name();
2084
2085 View* view = createView(view_name);
2086 view->importFrom(n_view, buffer_id_map);
2087 }
2088 }
2089 if(node.has_path("groups"))
2090 {
2091 // create the child Groups
2092 conduit::NodeIterator groups_itr = node["groups"].children();
2093 while(groups_itr.has_next())
2094 {
2095 Group* group;
2096 Node& n_group = groups_itr.next();
2097 bool create_list = false;
2098 if(n_group.has_child("views"))
2099 {
2100 if(n_group["views"].dtype().is_list())
2101 {
2102 create_list = true;
2103 }
2104 }
2105 if(!create_list && n_group.has_child("groups"))
2106 {
2107 if(n_group["groups"].dtype().is_list())
2108 {
2109 create_list = true;
2110 }
2111 }
2112 std::string group_name = groups_itr.name();
2113 if(m_is_list)
2114 {
2115 group = createUnnamedGroup(create_list);
2116 }
2117 else
2118 {
2119 std::string group_name = groups_itr.name();
2120 group = createGroup(group_name, create_list);
2121 }
2122 group->importFrom(n_group, buffer_id_map);
2123 }
2124 }
2125 }
2126
2127 /*
2128 *************************************************************************
2129 *
2130 * Imports tree from a conduit node into this Group.
2131 * This takes a generic conduit tree, not one with sidre conventions.
2132 *
2133 *************************************************************************
2134 */
2135
importConduitTree(const conduit::Node & node,bool preserve_contents)2136 bool Group::importConduitTree(const conduit::Node& node, bool preserve_contents)
2137 {
2138 bool success = true;
2139 if(!preserve_contents)
2140 {
2141 destroyGroups();
2142 destroyViews();
2143 }
2144
2145 //
2146 DataType node_dtype = node.dtype();
2147 if(node_dtype.is_object() || node_dtype.is_list())
2148 {
2149 conduit::NodeConstIterator itr = node.children();
2150 while(itr.has_next())
2151 {
2152 const Node& cld_node = itr.next();
2153 std::string cld_name = m_is_list ? "" : itr.name();
2154 DataType cld_dtype = cld_node.dtype();
2155
2156 if(cld_dtype.is_object() || cld_dtype.is_list())
2157 {
2158 // create group
2159 Group* grp = m_is_list ? createUnnamedGroup(cld_dtype.is_list())
2160 : createGroup(cld_name, cld_dtype.is_list());
2161 success = grp->importConduitTree(cld_node, preserve_contents);
2162 }
2163 else if(cld_dtype.is_empty())
2164 {
2165 //create empty view
2166 createView(cld_name);
2167 }
2168 else if(cld_dtype.is_string())
2169 {
2170 if(cld_name != "sidre_group_name")
2171 {
2172 //create string view
2173 createViewString(cld_name, cld_node.as_string());
2174 }
2175 }
2176 else if(cld_dtype.is_number())
2177 {
2178 if(cld_dtype.number_of_elements() == 1)
2179 {
2180 // create scalar view
2181 View* view = createView(cld_name);
2182 view->setScalar(cld_node);
2183 }
2184 else
2185 {
2186 View* view = createView(cld_name);
2187 view->importArrayNode(cld_node);
2188 }
2189 }
2190 else
2191 {
2192 // All Nodes should have one of the above datatypes, so if
2193 // we get here something is wrong.
2194 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND
2195 << "Conduit child Node " << cld_name
2196 << " does not have a recognized datatype."
2197 << " Cannot import into Group " << getPathName());
2198 }
2199 }
2200 }
2201 else
2202 {
2203 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND
2204 << "Group cannot import non-object Conduit Node");
2205 }
2206
2207 return success;
2208 }
2209
importConduitTreeExternal(conduit::Node & node,bool preserve_contents)2210 bool Group::importConduitTreeExternal(conduit::Node& node, bool preserve_contents)
2211 {
2212 bool success = true;
2213 if(!preserve_contents)
2214 {
2215 destroyGroups();
2216 destroyViews();
2217 }
2218
2219 DataType node_dtype = node.dtype();
2220 if(node_dtype.is_object() || node_dtype.is_list())
2221 {
2222 conduit::NodeIterator itr = node.children();
2223 while(itr.has_next())
2224 {
2225 Node& cld_node = itr.next();
2226 std::string cld_name = itr.name();
2227 DataType cld_dtype = cld_node.dtype();
2228
2229 if(cld_dtype.is_object() || cld_dtype.is_list())
2230 {
2231 // create group
2232 Group* grp = createGroup(cld_name, cld_dtype.is_list());
2233 success = grp->importConduitTreeExternal(cld_node, preserve_contents);
2234 }
2235 else if(cld_dtype.is_empty())
2236 {
2237 //create empty view
2238 createView(cld_name);
2239 }
2240 else if(cld_dtype.is_string())
2241 {
2242 if(cld_name != "sidre_group_name")
2243 {
2244 //create string view
2245 createViewString(cld_name, cld_node.as_string());
2246 }
2247 }
2248 else if(cld_dtype.is_number())
2249 {
2250 if(cld_dtype.number_of_elements() == 1)
2251 {
2252 // create scalar view
2253 View* view = createView(cld_name);
2254 view->setScalar(cld_node);
2255 }
2256 else
2257 {
2258 void* conduit_ptr = cld_node.data_ptr();
2259 View* view = createView(cld_name);
2260 view->setExternalDataPtr(conduit_ptr);
2261 view->apply(cld_dtype);
2262 }
2263 }
2264 else
2265 {
2266 // All Nodes should have one of the above datatypes, so if
2267 // we get here something is wrong.
2268 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND
2269 << "Conduit child Node " << cld_name
2270 << " does not have a recognized datatype."
2271 << " Cannot import into Group " << getPathName());
2272 }
2273 }
2274 }
2275 else
2276 {
2277 SLIC_ERROR(SIDRE_GROUP_LOG_PREPEND
2278 << "Group cannot import non-object Conduit Node");
2279 }
2280
2281 return success;
2282 }
2283
2284 /*
2285 *************************************************************************
2286 *
2287 * PRIVATE method to walk down a path to the next-to-last entry.
2288 *
2289 * If an error is encountered, this private function will return nullptr
2290 *
2291 *************************************************************************
2292 */
walkPath(std::string & path,bool create_groups_in_path)2293 Group* Group::walkPath(std::string& path, bool create_groups_in_path)
2294 {
2295 Group* group_ptr = this;
2296
2297 // Split path into parts
2298 std::vector<std::string> path_parts =
2299 axom::Path(path, s_path_delimiter).parts();
2300
2301 if(path_parts.size() > 0)
2302 {
2303 // Find stopping point (right before last part of path)
2304 std::vector<std::string>::const_iterator stop = path_parts.end() - 1;
2305
2306 // Navigate path down to desired Group
2307 for(std::vector<std::string>::const_iterator iter = path_parts.begin();
2308 iter < stop;
2309 ++iter)
2310 {
2311 if(group_ptr->hasChildGroup(*iter))
2312 {
2313 group_ptr = group_ptr->getGroup(*iter);
2314 }
2315 else if(create_groups_in_path)
2316 {
2317 group_ptr = group_ptr->createGroup(*iter);
2318
2319 if(group_ptr == nullptr)
2320 {
2321 iter = stop;
2322 }
2323 }
2324 else
2325 {
2326 iter = stop;
2327 group_ptr = nullptr;
2328 }
2329 }
2330 path = path_parts.back();
2331 }
2332
2333 return group_ptr;
2334 }
2335
2336 /*
2337 *************************************************************************
2338 *
2339 * PRIVATE const method to walk down a path to the next-to-last entry.
2340 *
2341 * If an error is encountered, this private function will return nullptr
2342 *
2343 *************************************************************************
2344 */
walkPath(std::string & path) const2345 const Group* Group::walkPath(std::string& path) const
2346 {
2347 const Group* group_ptr = this;
2348
2349 // Split path into parts
2350 std::vector<std::string> path_parts =
2351 axom::Path(path, s_path_delimiter).parts();
2352
2353 if(path_parts.size() > 0)
2354 {
2355 // Find stopping point (right before last part of path)
2356 std::vector<std::string>::const_iterator stop = path_parts.end() - 1;
2357
2358 // Navigate path down to desired Group
2359 for(std::vector<std::string>::const_iterator iter = path_parts.begin();
2360 iter < stop;
2361 ++iter)
2362 {
2363 if(group_ptr->hasChildGroup(*iter))
2364 {
2365 group_ptr = group_ptr->getGroup(*iter);
2366 }
2367 else
2368 {
2369 group_ptr = nullptr;
2370 iter = stop;
2371 }
2372 }
2373 path = path_parts.back();
2374 }
2375
2376 return group_ptr;
2377 }
2378
2379 /*
2380 *************************************************************************
2381 *
2382 * Return number of child Groups in a Group object.
2383 *
2384 *************************************************************************
2385 */
getNumGroups() const2386 IndexType Group::getNumGroups() const { return m_group_coll->getNumItems(); }
2387
2388 /*
2389 *************************************************************************
2390 *
2391 * Return number of Views owned by a Group object.
2392 *
2393 *************************************************************************
2394 */
getNumViews() const2395 IndexType Group::getNumViews() const { return m_view_coll->getNumItems(); }
2396
2397 /*
2398 *************************************************************************
2399 *
2400 * Return true if this Group owns a View with given name (not path);
2401 * else false.
2402 *
2403 *************************************************************************
2404 */
hasChildView(const std::string & name) const2405 bool Group::hasChildView(const std::string& name) const
2406 {
2407 return m_view_coll->hasItem(name);
2408 }
2409
2410 /*
2411 *************************************************************************
2412 *
2413 * Return true if this Group owns a View with given index; else false.
2414 *
2415 *************************************************************************
2416 */
hasView(IndexType idx) const2417 bool Group::hasView(IndexType idx) const { return m_view_coll->hasItem(idx); }
2418
2419 /*
2420 *************************************************************************
2421 *
2422 * Return index of View with given name owned by this Group object.
2423 *
2424 * If no such View exists, return sidre::InvalidIndex;
2425 *
2426 *************************************************************************
2427 */
getViewIndex(const std::string & name) const2428 IndexType Group::getViewIndex(const std::string& name) const
2429 {
2430 SLIC_CHECK_MSG(
2431 hasChildView(name),
2432 SIDRE_GROUP_LOG_PREPEND << "Group has no View with name '" << name << "'");
2433
2434 return m_view_coll->getItemIndex(name);
2435 }
2436
2437 /*
2438 *************************************************************************
2439 *
2440 * Return name of View with given index owned by Group object.
2441 *
2442 * If no such View exists, return sidre::InvalidName.
2443 *
2444 *************************************************************************
2445 */
getViewName(IndexType idx) const2446 const std::string& Group::getViewName(IndexType idx) const
2447 {
2448 SLIC_CHECK_MSG(
2449 hasView(idx),
2450 SIDRE_GROUP_LOG_PREPEND << "Group has no View with index " << idx);
2451
2452 return m_view_coll->getItemName(idx);
2453 }
2454
2455 /*
2456 *************************************************************************
2457 *
2458 * Return pointer to non-const View with given index.
2459 *
2460 * If no such View exists, nullptr is returned.
2461 *
2462 *************************************************************************
2463 */
getView(IndexType idx)2464 View* Group::getView(IndexType idx)
2465 {
2466 SLIC_CHECK_MSG(
2467 hasView(idx),
2468 SIDRE_GROUP_LOG_PREPEND << "Group has no View with index " << idx);
2469
2470 return m_view_coll->getItem(idx);
2471 }
2472
2473 /*
2474 *************************************************************************
2475 *
2476 * Return pointer to const View with given index.
2477 *
2478 * If no such View exists, nullptr is returned.
2479 *
2480 *************************************************************************
2481 */
getView(IndexType idx) const2482 const View* Group::getView(IndexType idx) const
2483 {
2484 SLIC_CHECK_MSG(
2485 hasView(idx),
2486 SIDRE_GROUP_LOG_PREPEND << "Group has no View with index " << idx);
2487
2488 return m_view_coll->getItem(idx);
2489 }
2490
2491 /*
2492 *************************************************************************
2493 *
2494 * Return first valid View index in Group object
2495 * (i.e., smallest index over all Views).
2496 *
2497 * sidre::InvalidIndex is returned if Group has no Views.
2498 *
2499 *************************************************************************
2500 */
getFirstValidViewIndex() const2501 IndexType Group::getFirstValidViewIndex() const
2502 {
2503 return m_view_coll->getFirstValidIndex();
2504 }
2505
2506 /*
2507 *************************************************************************
2508 *
2509 * Return next valid View index in Group object after given index
2510 * (i.e., smallest index over all View indices larger than given one).
2511 *
2512 * sidre::InvalidIndex is returned if there is no valid index greater
2513 * than given one.
2514 *
2515 *************************************************************************
2516 */
getNextValidViewIndex(IndexType idx) const2517 IndexType Group::getNextValidViewIndex(IndexType idx) const
2518 {
2519 return m_view_coll->getNextValidIndex(idx);
2520 }
2521
2522 /*
2523 *************************************************************************
2524 *
2525 * Return true if this Group has a child Group with given
2526 * name; else false.
2527 *
2528 *************************************************************************
2529 */
hasChildGroup(const std::string & name) const2530 bool Group::hasChildGroup(const std::string& name) const
2531 {
2532 return m_group_coll->hasItem(name);
2533 }
2534
2535 /*
2536 *************************************************************************
2537 *
2538 * Return true if Group has an immediate child Group
2539 * with given index; else false.
2540 *
2541 *************************************************************************
2542 */
hasGroup(IndexType idx) const2543 bool Group::hasGroup(IndexType idx) const { return m_group_coll->hasItem(idx); }
2544
2545 /*
2546 *************************************************************************
2547 * Return the index of immediate child Group with given name.
2548 *
2549 * If no such child Group exists, return sidre::InvalidIndex;
2550 *
2551 *************************************************************************
2552 */
getGroupIndex(const std::string & name) const2553 IndexType Group::getGroupIndex(const std::string& name) const
2554 {
2555 SLIC_CHECK_MSG(hasChildGroup(name),
2556 SIDRE_GROUP_LOG_PREPEND
2557 << "Group has no child Group with name '" << name << "'");
2558
2559 return m_group_coll->getItemIndex(name);
2560 }
2561
2562 /*
2563 *************************************************************************
2564 *
2565 * Return the name of immediate child Group with given index.
2566 *
2567 * If no such child Group exists, return sidre::InvalidName.
2568 *
2569 *************************************************************************
2570 */
getGroupName(IndexType idx) const2571 const std::string& Group::getGroupName(IndexType idx) const
2572 {
2573 SLIC_CHECK_MSG(
2574 hasGroup(idx),
2575 SIDRE_GROUP_LOG_PREPEND << "Group has no child Group with index " << idx);
2576
2577 return m_group_coll->getItemName(idx);
2578 }
2579
2580 /*
2581 *************************************************************************
2582 *
2583 * Return pointer to non-const immediate child Group with given index.
2584 *
2585 * If no such Group exists, nullptr is returned.
2586 *
2587 *************************************************************************
2588 */
getGroup(IndexType idx)2589 Group* Group::getGroup(IndexType idx)
2590 {
2591 SLIC_CHECK_MSG(
2592 hasGroup(idx),
2593 SIDRE_GROUP_LOG_PREPEND << "Group has no child Group with index " << idx);
2594
2595 return m_group_coll->getItem(idx);
2596 }
2597
2598 /*
2599 *************************************************************************
2600 *
2601 * Return pointer to const immediate child Group with given index.
2602 *
2603 * If no such Group exists, nullptr is returned.
2604 *
2605 *************************************************************************
2606 */
getGroup(IndexType idx) const2607 const Group* Group::getGroup(IndexType idx) const
2608 {
2609 SLIC_CHECK_MSG(
2610 hasGroup(idx),
2611 SIDRE_GROUP_LOG_PREPEND << "Group has no child Group with index " << idx);
2612
2613 return m_group_coll->getItem(idx);
2614 }
2615
2616 /*
2617 *************************************************************************
2618 *
2619 * Return first valid child Group index (i.e., smallest
2620 * index over all child Groups).
2621 *
2622 * sidre::InvalidIndex is returned if Group has no child Groups.
2623 *
2624 *************************************************************************
2625 */
getFirstValidGroupIndex() const2626 IndexType Group::getFirstValidGroupIndex() const
2627 {
2628 return m_group_coll->getFirstValidIndex();
2629 }
2630
2631 /*
2632 *************************************************************************
2633 *
2634 * Return next valid child Group index after given index
2635 * (i.e., smallest index over all child Group indices larger
2636 * than given one).
2637 *
2638 * sidre::InvalidIndex is returned if there is no valid index greater
2639 * than given one.
2640 *
2641 *************************************************************************
2642 */
getNextValidGroupIndex(IndexType idx) const2643 IndexType Group::getNextValidGroupIndex(IndexType idx) const
2644 {
2645 return m_group_coll->getNextValidIndex(idx);
2646 }
2647
2648 /*
2649 *************************************************************************
2650 *
2651 * Rename this Group with a new string name.
2652 *
2653 *************************************************************************
2654 */
rename(const std::string & new_name)2655 bool Group::rename(const std::string& new_name)
2656 {
2657 bool do_rename = true;
2658 if(new_name != m_name)
2659 {
2660 if(new_name.empty())
2661 {
2662 SLIC_WARNING(SIDRE_GROUP_LOG_PREPEND
2663 << "Cannot rename Group to an empty string.");
2664 do_rename = false;
2665 }
2666 else if(new_name.find(s_path_delimiter) != std::string::npos)
2667 {
2668 SLIC_WARNING(SIDRE_GROUP_LOG_PREPEND
2669 << "Cannot rename Group to path name '" << new_name << "'. "
2670 << "Only strings without path delimiters can "
2671 << "be passed into the rename method.");
2672 do_rename = false;
2673 }
2674
2675 if(do_rename)
2676 {
2677 const Group* root = getDataStore()->getRoot();
2678 Group* parent = getParent();
2679
2680 //If this is the root group, we don't need
2681 //to do anything to change the parent's handle to this group.
2682 if(this != root && parent != nullptr)
2683 {
2684 if(parent->hasGroup(new_name) || parent->hasView(new_name))
2685 {
2686 SLIC_WARNING(SIDRE_GROUP_LOG_PREPEND
2687 << "Parent group " << parent->getPathName()
2688 << " already has a child group named '" << new_name
2689 << "'. Group " << getPathName()
2690 << " will not be renamed.");
2691 do_rename = false;
2692 }
2693 else
2694 {
2695 Group* detached_group = parent->detachGroup(m_name);
2696 SLIC_CHECK_MSG(detached_group == this,
2697 SIDRE_GROUP_LOG_PREPEND
2698 << "Group detatched from parent '"
2699 << detached_group->getPathName() << "' is not "
2700 << "this Group '" << getPathName() << "'.");
2701
2702 m_name = new_name;
2703
2704 Group* attached_group = parent->attachGroup(detached_group);
2705 AXOM_UNUSED_VAR(attached_group);
2706 SLIC_CHECK_MSG(attached_group == this,
2707 SIDRE_GROUP_LOG_PREPEND
2708 << "Group attached to parent '"
2709 << attached_group->getPathName() << "' is not "
2710 << "this Group '" << getPathName() << "'.");
2711 }
2712 }
2713 else
2714 {
2715 m_name = new_name;
2716 }
2717 }
2718 }
2719
2720 return do_rename;
2721 }
2722
2723 /*
2724 *************************************************************************
2725 *
2726 * PRIVATE method to return a valid umpire::Allocator ID.
2727 *
2728 *************************************************************************
2729 */
getValidAllocatorID(int allocID)2730 int Group::getValidAllocatorID(int allocID)
2731 {
2732 #ifdef AXOM_USE_UMPIRE
2733 if(allocID == INVALID_ALLOCATOR_ID)
2734 {
2735 allocID = m_default_allocator_id;
2736 }
2737 #endif
2738
2739 return allocID;
2740 }
2741
2742 } /* end namespace sidre */
2743 } /* end namespace axom */
2744