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