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 /*! 7 ****************************************************************************** 8 * 9 * \file Group.hpp 10 * 11 * \brief Header file containing definition of Group class. 12 * 13 ****************************************************************************** 14 */ 15 16 #ifndef SIDRE_GROUP_HPP_ 17 #define SIDRE_GROUP_HPP_ 18 19 // axom headers 20 #include "axom/config.hpp" 21 #include "axom/core/Macros.hpp" 22 #include "axom/core/Types.hpp" 23 #include "axom/slic.hpp" 24 25 // Standard C++ headers 26 #include <memory> 27 #include <map> 28 #include <string> 29 #include <vector> 30 #include <set> 31 #include <cstring> 32 33 // third party lib headers 34 #ifdef AXOM_USE_HDF5 35 #include "hdf5.h" 36 #endif 37 38 // Sidre headers 39 #include "SidreTypes.hpp" 40 #include "View.hpp" 41 42 // Define the default protocol for sidre I/O 43 #ifdef AXOM_USE_HDF5 44 #define SIDRE_DEFAULT_PROTOCOL "sidre_hdf5" 45 #else 46 #define SIDRE_DEFAULT_PROTOCOL "sidre_conduit_json" 47 #endif 48 49 namespace axom 50 { 51 namespace sidre 52 { 53 class Buffer; 54 class Group; 55 class DataStore; 56 template <typename TYPE> 57 class ItemCollection; 58 59 /*! 60 * \class Group 61 * 62 * \brief Group holds a collection of Views and (child) Groups. 63 * 64 * The Group class has the following properties: 65 * 66 * - Groups can be organized into a (tree) hierarchy by creating 67 * child Groups from the root Group owned by a DataStore object. 68 * - A Group object can only be created by another Group; the 69 * Group ctor is not visible externally. A Group is owned 70 * by the Group that creates it (its parent) and becomes a 71 * (direct) child Group of the parent. Groups in the subtree 72 * rooted at an ancestor Group are that Group's descendants. 73 * - A Group object has a unique name (string) within its parent 74 * Group. 75 * - A Group object maintains a pointer to its parent Group. 76 * - A Group object can be moved or copied to another Group. 77 * - Group objects can create View objects within them. The 78 * Group that creates a View owns it. 79 * - A View object has a unique name (string) within the Group 80 * that owns it. 81 * - A View object can be moved or copied to another Group. 82 * 83 * Note that Views and child Groups within a Group can be accessed 84 * by name or index. 85 * 86 * Note that certain methods for querying, creating, retrieving, and 87 * deleting Groups and Views take a string with path syntax, 88 * while others take the name of a direct child of the current Group. 89 * Methods that require the name of a direct child are marked with 90 * "Child", for example hasChildView() and hasChildGroup(). When a path 91 * string is passed to a method that accepts path syntax, the last item in 92 * the path indicates the item to be created, accessed, etc. For example, 93 * 94 * View* view = group->createView("foo/bar/baz"); 95 * 96 * is equivalent to 97 * 98 * View* view = 99 * group->createGroup("foo")->createGroup("bar")->createView("baz"); 100 * 101 * In particular, intermediate Groups "foo" and "bar" will be created in 102 * this case if they don't already exist. 103 * 104 * Methods that access Views or Groups by index work with the direct 105 * children of the current Group because an index has no meaning outside 106 * of the indexed group. None of these methods is marked with "Child". 107 * 108 * A Group can optionally be created to hold items in a "list format". In 109 * this format, any number of child Group or View items can be created with 110 * empty strings for their names, and none of the methods that access 111 * child items by name or path will return a valid pointer. 112 * 113 * \attention when Views or Groups are created, destroyed, copied, or moved, 114 * indices of other Views and Groups in associated Group objects may 115 * become invalid. This is analogous to iterator invalidation for STL 116 * containers when the container contents change. 117 * 118 */ 119 class Group 120 { 121 public: 122 // 123 // Friend declarations to constrain usage via controlled access to 124 // private members. 125 // 126 friend class DataStore; 127 friend class View; 128 129 //@{ 130 //! @name Basic query and accessor methods. 131 132 /*! 133 * \brief Return the path delimiter 134 */ getPathDelimiter() const135 char getPathDelimiter() const { return s_path_delimiter; } 136 137 /*! 138 * \brief Return index of Group object within parent Group. 139 */ getIndex() const140 IndexType getIndex() const { return m_index; } 141 142 /*! 143 * \brief Return const reference to name of Group object. 144 * 145 * \sa getPath(), getPathName() 146 */ getName() const147 const std::string& getName() const { return m_name; } 148 149 /*! 150 * \brief Return path of Group object, not including its name. 151 * 152 * \sa getName(), getPathName() 153 */ 154 std::string getPath() const; 155 156 /*! 157 * \brief Return full path of Group object, including its name. 158 * 159 * If a DataStore contains a Group tree structure a/b/c/d/e, the 160 * following results are expected: 161 * 162 * Method Call | Result 163 * -----------------|---------- 164 * e->getName() | e 165 * e->getPath() | a/b/c/d 166 * e->getPathName() | a/b/c/d/e 167 * 168 * \sa getName(), getPath(), View::getPathName() 169 */ getPathName() const170 std::string getPathName() const 171 { 172 const auto path = getPath(); 173 174 if(path.length() < 1) 175 { 176 return getName(); 177 } 178 179 return path + getPathDelimiter() + getName(); 180 } 181 182 /*! 183 * \brief Return pointer to non-const parent Group of a Group. 184 * 185 * Note that if this method is called on the root Group in a 186 * DataStore, a pointer to itself is returned. 187 * This allows root->getParent()->getParent() to always work similar 188 * to how the filesystem's `cd /; cd ../..` works. 189 */ getParent()190 Group* getParent() { return m_parent; } 191 192 /*! 193 * \brief Return pointer to const parent Group of a Group. 194 * 195 * Note that if this method is called on the root Group in a 196 * DataStore, a pointer to itself is returned. 197 * This allows root->getParent()->getParent() to always work similar 198 * to how the filesystem's `cd /; cd ../..` works. 199 */ getParent() const200 const Group* getParent() const { return m_parent; } 201 202 /*! 203 * \brief Return number of child Groups in a Group object. 204 */ 205 IndexType getNumGroups() const; 206 207 /*! 208 * \brief Return number of Views owned by a Group object. 209 */ 210 IndexType getNumViews() const; 211 212 /*! 213 * \brief Return pointer to non-const DataStore object that owns this 214 * object. 215 */ getDataStore()216 DataStore* getDataStore() { return m_datastore; } 217 218 /*! 219 * \brief Return pointer to const DataStore object that owns this 220 * object. 221 */ getDataStore() const222 const DataStore* getDataStore() const { return m_datastore; } 223 224 /*! 225 * \brief Return true if this Group is the DataStore's root Group. 226 */ isRoot() const227 bool isRoot() const { return m_parent == this; } 228 229 #ifdef AXOM_USE_UMPIRE 230 231 /*! 232 * \brief Return the ID of the default umpire::Allocator associated with this 233 * Group. 234 */ getDefaultAllocatorID() const235 int getDefaultAllocatorID() const { return m_default_allocator_id; } 236 237 /*! 238 * \brief Return the default umpire::Allocator associated with this Group. 239 */ getDefaultAllocator() const240 umpire::Allocator getDefaultAllocator() const 241 { 242 umpire::ResourceManager& rm = umpire::ResourceManager::getInstance(); 243 return rm.getAllocator(m_default_allocator_id); 244 } 245 246 /*! 247 * \brief Set the default umpire::Allocator associated with this Group. 248 */ setDefaultAllocator(umpire::Allocator alloc)249 Group* setDefaultAllocator(umpire::Allocator alloc) 250 { 251 m_default_allocator_id = alloc.getId(); 252 return this; 253 } 254 255 /*! 256 * \brief Set the default umpire::Allocator associated with this Group. 257 */ setDefaultAllocator(int allocId)258 Group* setDefaultAllocator(int allocId) 259 { 260 m_default_allocator_id = allocId; 261 return this; 262 } 263 #endif 264 265 //@} 266 267 //@{ 268 //! @name View query methods. 269 270 /*! 271 * \brief Return true if Group includes a descendant View with 272 * given name or path; else false. 273 */ 274 bool hasView(const std::string& path) const; 275 276 /*! 277 * \brief Return true if this Group owns a View with given name (not path); 278 * else false. 279 */ 280 bool hasChildView(const std::string& name) const; 281 282 /*! 283 * \brief Return true if this Group owns a View with given index; else false. 284 */ 285 bool hasView(IndexType idx) const; 286 287 /*! 288 * \brief Return index of View with given name owned by this Group object. 289 * 290 * If no such View exists, return sidre::InvalidIndex; 291 */ 292 IndexType getViewIndex(const std::string& name) const; 293 294 /*! 295 * \brief Return name of View with given index owned by Group object. 296 * 297 * If no such View exists, return sidre::InvalidName. 298 */ 299 const std::string& getViewName(IndexType idx) const; 300 301 //@} 302 303 //@{ 304 //! @name View access methods. 305 306 /*! 307 308 * \brief Return pointer to non-const View with given name or path. 309 * 310 * This method requires that all groups in the path exist if a path is given. 311 * 312 * If no such View exists, nullptr is returned. 313 */ 314 View* getView(const std::string& path); 315 316 /*! 317 * \brief Return pointer to const View with given name or path. 318 * 319 * This method requires that all Groups in the path exist if a path is given. 320 * 321 * If no such View exists, nullptr is returned. 322 */ 323 const View* getView(const std::string& path) const; 324 325 /*! 326 * \brief Return pointer to non-const View with given index. 327 * 328 * If no such View exists, nullptr is returned. 329 */ 330 View* getView(IndexType idx); 331 332 /*! 333 * \brief Return pointer to const View with given index. 334 * 335 * If no such View exists, nullptr is returned. 336 */ 337 const View* getView(IndexType idx) const; 338 339 //@} 340 341 //@{ 342 //! @name View iteration methods. 343 //! 344 //! Using these methods, a code can get the first View index and each 345 //! succeeding index. This allows View iteration using the same 346 //! constructs in C++, C, and Fortran. Example: 347 //! 348 //! sidre::IndexType idx = grp->getFirstValidViewIndex(); 349 //! while( sidre::indexIsValid(idx) ) 350 //! { 351 //! View* view = grp->getView(idx); 352 //! 353 //! /// code here using view 354 //! 355 //! idx = grp -> getNextValidViewIndex(idx); 356 //! } 357 358 /*! 359 * \brief Return first valid View index in Group object 360 * (i.e., smallest index over all Views). 361 * 362 * sidre::InvalidIndex is returned if Group has no Views. 363 * 364 * \sa sidre::IndexType 365 * \sa sidre::indexIsValid() 366 */ 367 IndexType getFirstValidViewIndex() const; 368 369 /*! 370 * \brief Return next valid View index in Group object after given index 371 * (i.e., smallest index over all View indices larger than given one). 372 * 373 * sidre::InvalidIndex is returned if there is no valid index greater 374 * than given one. 375 * 376 * \sa sidre::IndexType 377 * \sa sidre::indexIsValid() 378 */ 379 IndexType getNextValidViewIndex(IndexType idx) const; 380 381 //@} 382 383 //@{ 384 //! @name Methods to create a View that has no associated data. 385 //! 386 //! \attention These methods do not allocate data or associate a View 387 //! with data. Thus, to do anything useful with a View created by one 388 //! of these methods, the View should be allocated, attached to a Buffer 389 //! or attached to externally-owned data. 390 //! 391 //! Each of these methods is a no-op if the given View name is an 392 //! empty string or the Group already has a View with given name or path. 393 //! 394 //! Additional conditions under which a method can be a no-op are described 395 //! for each method. 396 397 /*! 398 * \brief Create an undescribed (i.e., empty) View object with given name 399 * or path in this Group. 400 * 401 * If path is an empty string, an unnamed view can be created only if 402 * this Group was created to hold items in a list format. Otherwise 403 * an empty string will result in a nullptr being returned. 404 * 405 * \return pointer to new View object or nullptr if one is not created. 406 */ 407 View* createView(const std::string& path); 408 409 /*! 410 * \brief Create View object with given name or path in this Group that 411 * has a data description with data type and number of elements. 412 * 413 * If given data type is undefined, or given number of elements is < 0, 414 * method is a no-op. 415 * 416 * \return pointer to new View object or nullptr if one is not created. 417 */ 418 View* createView(const std::string& path, TypeID type, IndexType num_elems); 419 420 /*! 421 * \brief Create View object with given name or path in this Group that 422 * has a data description with data type and shape. 423 * 424 * If given data type is undefined, or given number of dimensions is < 0, 425 * or given shape ptr is null, method is a no-op. 426 * 427 * \return pointer to new View object or nullptr if one is not created. 428 */ 429 View* createView(const std::string& path, 430 TypeID type, 431 int ndims, 432 const IndexType* shape); 433 434 /*! 435 * \brief Create View object with given name or path in this Group that 436 * is described by a Conduit DataType object. 437 * 438 * \return pointer to new View object or nullptr if one is not created. 439 */ 440 View* createView(const std::string& path, const DataType& dtype); 441 442 //@} 443 444 //@{ 445 //! @name Methods to create a View with a Buffer attached. 446 //! 447 //! \attention The Buffer passed to each of these methods may or may not 448 //! be allocated. Thus, to do anything useful with a View created by one 449 //! of these methods, the Buffer must be allocated and it must be compatible 450 //! with the View data description. 451 //! 452 //! Each of these methods is a no-op if Group already has a View or child 453 //! Group with the given name or path. 454 //! 455 //! If this Group was created to hold items in list format, the path can 456 //! be an empty string. Otherwise an empty string for the path will result 457 //! in a no-op. 458 //! 459 //! Also, calling one of these methods with a null Buffer pointer is 460 //! similar to creating a View with no data association. 461 //! 462 //! Additional conditions under which a method can be a no-op are described 463 //! for each method. 464 465 /*! 466 * \brief Create an undescribed View object with given name or path in 467 * this Group and attach given Buffer to it. 468 * 469 * \attention The View cannot be used to access data in Buffer until it 470 * is described by calling a View::apply() method. 471 * 472 * This method is equivalent to: 473 * group->createView(name)->attachBuffer(buff). 474 * 475 * \return pointer to new View object or nullptr if one is not created. 476 * 477 * \sa View::attachBuffer() 478 */ 479 View* createView(const std::string& path, Buffer* buff); 480 481 /*! 482 * \brief Create View object with given name or path in this Group that 483 * has a data description with data type and number of elements and 484 * attach given Buffer to it. 485 * 486 * If given data type is undefined, or given number of elements is < 0, 487 * method is a no-op. 488 * 489 * This method is equivalent to: 490 * group->createView(name, type, num_elems)->attachBuffer(buff), or 491 * group->createView(name)->attachBuffer(buff)->apply(type, num_elems). 492 * 493 * \return pointer to new View object or nullptr if one is not created. 494 * 495 * \sa View::attachBuffer() 496 */ 497 View* createView(const std::string& path, 498 TypeID type, 499 IndexType num_elems, 500 Buffer* buff); 501 502 /*! 503 * \brief Create View object with given name or path in this Group that 504 * has a data description with data type and shape and attach given 505 * Buffer to it. 506 * 507 * If given data type is undefined, or given number of dimensions is < 0, 508 * or given shape ptr is null, method is a no-op. 509 * 510 * This method is equivalent to: 511 * group->createView(name, type, ndims, shape)->attachBuffer(buff), or 512 * group->createView(name)->attachBuffer(buff)->apply(type, ndims, shape). 513 * 514 * \return pointer to new View object or nullptr if one is not created. 515 * 516 * \sa View::attachBuffer() 517 */ 518 View* createView(const std::string& path, 519 TypeID type, 520 int ndims, 521 const IndexType* shape, 522 Buffer* buff); 523 524 /*! 525 * \brief Create View object with given name or path in this Group that 526 * is described by a Conduit DataType object and attach given Buffer to it. 527 * 528 * This method is equivalent to: 529 * group->createView(name, dtype)->attachBuffer(buff), or 530 * group->createView(name)->attachBuffer(buff)->apply(dtype). 531 * 532 * \return pointer to new View object or nullptr if one is not created. 533 * 534 * \sa View::attachBuffer() 535 */ 536 View* createView(const std::string& path, const DataType& dtype, Buffer* buff); 537 538 //@} 539 540 //@{ 541 //! @name Methods to create a View with externally-owned data attached. 542 //! 543 //! \attention To do anything useful with a View created by one of these 544 //! methods, the external data must be allocated and compatible with the 545 //! View description. 546 //! 547 //! Each of these methods is a no-op if the given View name is an 548 //! empty string or the Group already has a View with given name or path. 549 //! 550 //! Additional conditions under which a method can be a no-op are described 551 //! for each method. 552 553 /*! 554 * \brief Create View object with given name with given name or path in 555 * this Group and attach external data ptr to it. 556 * 557 * \attention Note that the View is "opaque" (it has no knowledge of 558 * the type or structure of the data) until a View::apply() method 559 * is called. 560 * 561 * This method is equivalent to: 562 * group->createView(name)->setExternalDataPtr(external_ptr). 563 * 564 * \return pointer to new View object or nullptr if one is not created. 565 * 566 * \sa View::setExternalDataPtr() 567 */ 568 View* createView(const std::string& path, void* external_ptr); 569 570 /*! 571 * \brief Create View object with given name or path in this Group that 572 * has a data description with data type and number of elements and 573 * attach externally-owned data to it. 574 * 575 * If given data type is undefined, or given number of elements is < 0, 576 * method is a no-op. 577 * 578 * This method is equivalent to: 579 * group->createView(name, type, num_elems)->setExternalDataPtr(external_ptr), 580 * or group->createView(name)->setExternalDataPtr(external_ptr)-> 581 * apply(type, num_elems). 582 * 583 * \return pointer to new View object or nullptr if one is not created. 584 * 585 * \sa View::setExternalDataPtr() 586 */ 587 View* createView(const std::string& path, 588 TypeID type, 589 IndexType num_elems, 590 void* external_ptr); 591 592 /*! 593 * \brief Create View object with given name or path in this Group that 594 * has a data description with data type and shape and attach 595 * externally-owned data to it. 596 * 597 * If given data type is undefined, or given number of dimensions is < 0, 598 * or given shape ptr is null, method is a no-op. 599 * 600 * This method is equivalent to: 601 * group->createView(name, type, ndims, shape)-> 602 * setExternalDataPtr(external_ptr), or 603 * group->createView(name)->setExternalDataPtr(external_ptr)-> 604 * apply(type, ndims, shape). 605 * 606 * \return pointer to new View object or nullptr if one is not created. 607 * 608 * \sa View::setExternalDataPtr() 609 */ 610 View* createView(const std::string& path, 611 TypeID type, 612 int ndims, 613 const IndexType* shape, 614 void* external_ptr); 615 /*! 616 * \brief Create View object with given name or path in this Group that 617 * is described by a Conduit DataType object and attach externally-owned 618 * data to it. 619 * 620 * This method is equivalent to: 621 * group->createView(name, dtype)->setExternalDataPtr(external_ptr), or 622 * group->createView(name)->setExternalDataPtr(external_ptr)->apply(dtype). 623 * 624 * \return pointer to new View object or nullptr if one is not created. 625 * 626 * \sa View::attachBuffer() 627 */ 628 View* createView(const std::string& path, 629 const DataType& dtype, 630 void* external_ptr); 631 632 //@} 633 634 //@{ 635 //! @name Methods to create a View and allocate data for it. 636 //! 637 //! Each of these methods is a no-op if the given View name is an 638 //! empty string or the Group already has a View with given name or path. 639 //! 640 //! Additional conditions under which a method can be a no-op are described 641 //! for each method. 642 643 /*! 644 * \brief Create View object with given name or path in this Group that 645 * has a data description with data type and number of elements and 646 * allocate data for it. 647 * 648 * If given data type is undefined, or given number of elements is < 0, 649 * method is a no-op. 650 * 651 * This is equivalent to: createView(name)->allocate(type, num_elems), or 652 * createView(name, type, num_elems)->allocate() 653 * 654 * \return pointer to new View object or nullptr if one is not created. 655 * 656 * \sa View::allocate() 657 */ 658 View* createViewAndAllocate(const std::string& path, 659 TypeID type, 660 IndexType num_elems, 661 int allocID = INVALID_ALLOCATOR_ID); 662 663 /*! 664 * \brief Create View object with given name or path in this Group that 665 * has a data description with data type and shape and allocate data for it. 666 * 667 * If given data type is undefined, or given number of dimensions is < 0, 668 * or given shape ptr is null, method is a no-op. 669 * 670 * This method is equivalent to: 671 * group->createView(name)->allocate(type, ndims, shape), or 672 * createView(name, type, ndims, shape)->allocate(). 673 * 674 * \return pointer to new View object or nullptr if one is not created. 675 * 676 * \sa View::allocate() 677 */ 678 View* createViewAndAllocate(const std::string& path, 679 TypeID type, 680 int ndims, 681 const IndexType* shape, 682 int allocID = INVALID_ALLOCATOR_ID); 683 684 /*! 685 * \brief Create View object with given name or path in this Group that 686 * is described by a Conduit DataType object and allocate data for it. 687 * 688 * This method is equivalent to: 689 * group->createView(name)->allocate(dtype), or 690 * group->createView(name, dtype)->allocate(). 691 * 692 * If given data type object is empty, data will not be allocated. 693 * 694 * \return pointer to new View object or nullptr if one is not created. 695 * 696 * \sa View::allocate() 697 */ 698 View* createViewAndAllocate(const std::string& path, 699 const DataType& dtype, 700 int allocID = INVALID_ALLOCATOR_ID); 701 702 /*! 703 * \brief Create View object with given name or path in this Group 704 * set its data to given scalar value. 705 * 706 * This is equivalent to: createView(name)->setScalar(value); 707 * 708 * If given data type object is empty, data will not be allocated. 709 * 710 * \return pointer to new View object or nullptr if one is not created. 711 * 712 * \sa View::setScalar() 713 */ 714 template <typename ScalarType> createViewScalar(const std::string & path,ScalarType value)715 View* createViewScalar(const std::string& path, ScalarType value) 716 { 717 View* view = createView(path); 718 if(view != nullptr) 719 { 720 view->setScalar(value); 721 } 722 723 return view; 724 } 725 726 /*! 727 * \brief Create View object with given name or path in this Group 728 * set its data to given string. 729 * 730 * This is equivalent to: createView(name)->setString(value); 731 * 732 * If given data type object is empty, data will not be allocated. 733 * 734 * \return pointer to new View object or nullptr if one is not created. 735 * 736 * \sa View::setString() 737 */ 738 View* createViewString(const std::string& path, const std::string& value); 739 740 //@} 741 742 //@{ 743 //! @name View destruction methods. 744 //! 745 //! Each of these methods is a no-op if the specified View does not exist. 746 747 /*! 748 * \brief Destroy View with given name or path owned by this Group, but leave 749 * its data intect. 750 */ 751 void destroyView(const std::string& path); 752 753 /*! 754 * \brief Destroy View with given index owned by this Group, but leave 755 * its data intect. 756 */ 757 void destroyView(IndexType idx); 758 759 /*! 760 * \brief Destroy all Views owned by this Group, but leave all their 761 * data intact. 762 */ 763 void destroyViews(); 764 765 /*! 766 * \brief Destroy View with given name or path owned by this Group and 767 * deallocate 768 * its data if it's the only View associated with that data. 769 */ 770 void destroyViewAndData(const std::string& path); 771 772 /*! 773 * \brief Destroy View with given index owned by this Group and deallocate 774 * its data if it's the only View associated with that data. 775 */ 776 void destroyViewAndData(IndexType idx); 777 778 /*! 779 * \brief Destroy all Views owned by this Group and deallocate 780 * data for each View when it's the only View associated with that data. 781 */ 782 void destroyViewsAndData(); 783 784 //@} 785 786 //@{ 787 //! @name View move and copy methods. 788 789 /*! 790 * \brief Remove given View object from its owning Group and move it 791 * to this Group. 792 * 793 * If given View pointer is null or Group already has a View with 794 * same name as given View, method is a no-op. 795 * 796 * \return pointer to given argument View object or nullptr if View 797 * is not moved into this Group. 798 */ 799 View* moveView(View* view); 800 801 /*! 802 * \brief Create a copy of given View object and add it to this Group. 803 * 804 * Note that View copying is a "shallow" copy; the data associated with 805 * the View is not copied. The new View object is associated with 806 * the same data as the original. 807 * 808 * If given Group pointer is null or Group already has a child Group with 809 * same name as given Group, method is a no-op. 810 * 811 * \return pointer to given argument Group object or nullptr if Group 812 * is not moved into this Group. 813 */ 814 View* copyView(View* view); 815 816 //@} 817 818 //@{ 819 //! @name Child Group query methods. 820 821 /*! 822 * \brief Return true if this Group has a descendant Group with given 823 * name or path; else false. 824 */ 825 bool hasGroup(const std::string& path) const; 826 827 /*! 828 * \brief Return true if this Group has a child Group with given 829 * name; else false. 830 */ 831 bool hasChildGroup(const std::string& name) const; 832 833 /*! 834 * \brief Return true if Group has an immediate child Group 835 * with given index; else false. 836 */ 837 bool hasGroup(IndexType idx) const; 838 839 /*! 840 * \brief Return the index of immediate child Group with given name. 841 * 842 * If no such child Group exists, return sidre::InvalidIndex; 843 */ 844 IndexType getGroupIndex(const std::string& name) const; 845 846 /*! 847 * \brief Return the name of immediate child Group with given index. 848 * 849 * If no such child Group exists, return sidre::InvalidName. 850 */ 851 const std::string& getGroupName(IndexType idx) const; 852 853 //@} 854 855 //@{ 856 //! @name Group access and iteration methods. 857 858 /*! 859 * \brief Return pointer to non-const child Group with given name or path. 860 * 861 * This method requires that all Groups in the path exist if a path is given. 862 * 863 * If no such Group exists, nullptr is returned. 864 */ 865 Group* getGroup(const std::string& path); 866 867 /*! 868 * \brief Return pointer to const child Group with given name or path. 869 * 870 * This method requires that all Groups in the path exist if a path is given. 871 * 872 * If no such Group exists, nullptr is returned. 873 */ 874 Group const* getGroup(const std::string& path) const; 875 876 /*! 877 * \brief Return pointer to non-const immediate child Group with given index. 878 * 879 * If no such Group exists, nullptr is returned. 880 */ 881 Group* getGroup(IndexType idx); 882 883 /*! 884 * \brief Return pointer to const immediate child Group with given index. 885 * 886 * If no such Group exists, nullptr is returned. 887 */ 888 const Group* getGroup(IndexType idx) const; 889 890 //@} 891 892 //@{ 893 //! @name Group iteration methods. 894 //! 895 //! Using these methods, a code can get the first Group index and each 896 //! succeeding index. This allows Group iteration using the same 897 //! constructs in C++, C, and Fortran. Example: 898 //! for (sidre::IndexType idx = grp->getFirstValidGroupIndex(); 899 //! sidre::indexIsValid(idx); 900 //! idx = grp->getNextValidGroupIndex(idx)) 901 //! { 902 //! Group * group = grp->getGroup(idx); 903 //! 904 //! /// code here using group 905 //! } 906 907 /*! 908 * \brief Return first valid child Group index (i.e., smallest 909 * index over all child Groups). 910 * 911 * sidre::InvalidIndex is returned if Group has no child Groups. 912 * 913 * \sa axom::sidre::indexIsValid() 914 */ 915 IndexType getFirstValidGroupIndex() const; 916 917 /*! 918 * \brief Return next valid child Group index after given index 919 * (i.e., smallest index over all child Group indices larger 920 * than given one). 921 * 922 * sidre::InvalidIndex is returned if there is no valid index greater 923 * than given one. 924 * 925 * \sa axom::sidre::indexIsValid() 926 */ 927 IndexType getNextValidGroupIndex(IndexType idx) const; 928 929 //@} 930 931 //@{ 932 //! @name Child Group creation and destruction methods. 933 934 /*! 935 * \brief Create a child Group within this Group with given name or path. 936 * 937 * If name is an empty string or Group already has a child Group with 938 * given name or path, method is a no-op. 939 * 940 * The optional is_list argument is used to determine if the created 941 * child Group will hold items in list format. 942 * 943 * \return pointer to created Group object or nullptr if new 944 * Group is not created. 945 */ 946 Group* createGroup(const std::string& path, bool is_list = false); 947 948 /* 949 * \brief Create a child Group within this Group with no name. 950 * 951 * This is intended only to be called when this Group holds items in list 952 * format. If this Group does not use list format, this method is a 953 * no-op. 954 * 955 * \return pointer to created Group object or nullptr if new Group is 956 * not created. 957 */ 958 Group* createUnnamedGroup(bool is_list = false); 959 960 /*! 961 * \brief Destroy child Group in this Group with given name or path. 962 * 963 * If no such Group exists, method is a no-op. 964 */ 965 void destroyGroup(const std::string& path); 966 967 /*! 968 * \brief Destroy child Group within this Group with given index. 969 * 970 * If no such Group exists, method is a no-op. 971 */ 972 void destroyGroup(IndexType idx); 973 974 /*! 975 * \brief Destroy all child Groups in this Group. 976 * 977 * Note that this will recursively destroy entire Group sub-tree below 978 * this Group. 979 */ 980 void destroyGroups(); 981 982 //@} 983 984 //@{ 985 //! @name Group move and copy methods. 986 987 /*! 988 * \brief Remove given Group object from its parent Group and make it 989 * a child of this Group. 990 * 991 * If given Group pointer is null or Group already has a child Group with 992 * same name as given Group, method is a no-op. 993 * 994 * \return pointer to given argument Group object or nullptr if Group 995 * is not moved into this Group. 996 */ 997 Group* moveGroup(Group* group); 998 999 /*! 1000 * \brief Create a copy of Group hierarchy rooted at given Group and make it 1001 * a child of this Group. 1002 * 1003 * Note that all Views in the Group hierarchy are copied as well. 1004 * 1005 * Note that Group copying is a "shallow" copy; the data associated 1006 * with Views in a Group are not copied. In particular, the new Group 1007 * hierarchy and all its Views is associated with the same data as the 1008 * given Group. 1009 * 1010 * If given Group pointer is null or Group already has a child Group with 1011 * same name as given Group, method is a no-op. 1012 * 1013 * \return pointer to given argument Group object or nullptr if Group 1014 * is not moved into this Group. 1015 */ 1016 Group* copyGroup(Group* group); 1017 1018 //@} 1019 1020 //@{ 1021 //! @name Group print methods. 1022 1023 /*! 1024 * \brief Print JSON description of data Group to stdout. 1025 * 1026 * Note that this will recursively print entire Group sub-tree 1027 * starting at this Group object. 1028 */ 1029 void print() const; 1030 1031 /*! 1032 * \brief Print JSON description of data Group to an ostream. 1033 * 1034 * Note that this will recursively print entire Group sub-tree 1035 * starting at this Group object. 1036 */ 1037 void print(std::ostream& os) const; 1038 1039 /*! 1040 * \brief Print given number of levels of Group sub-tree 1041 * starting at this Group object to an output stream. 1042 */ 1043 void printTree(const int nlevels, std::ostream& os) const; 1044 1045 //@} 1046 1047 /*! 1048 * \brief Copy description of Group hierarchy rooted at this Group to 1049 * given Conduit node. 1050 * 1051 * The description includes Views of this Group and all of its children 1052 * recursively. 1053 */ 1054 void copyToConduitNode(Node& n) const; 1055 1056 /*! 1057 * \brief Copy data Group native layout to given Conduit node. 1058 * 1059 * The native layout is a Conduit Node hierarchy that maps the Conduit Node 1060 * data 1061 * externally to the Sidre View data so that it can be filled in from the data 1062 * in the file (independent of file format) and can be accessed as a Conduit 1063 * tree. 1064 * 1065 * \return True if the Group or any of its children were added to the Node, 1066 * false otherwise. 1067 * 1068 */ 1069 bool createNativeLayout(Node& n, const Attribute* attr = nullptr) const; 1070 1071 /*! 1072 * \brief Copy data Group external layout to given Conduit node. 1073 * 1074 * The external layout is a Conduit Node hierarchy that maps the Conduit Node 1075 * data externally to the Sidre View data so that it can be filled in from the 1076 * data in the file (independent of file format) and can be accessed as a 1077 * Conduit tree. 1078 * 1079 * Only the Views which have external data are added to the node. 1080 * 1081 * \return True if the Group or any of its children have an external 1082 * View, false otherwise. 1083 */ 1084 bool createExternalLayout(Node& n, const Attribute* attr = nullptr) const; 1085 1086 /*! 1087 * \brief Return true if this Group is equivalent to given Group; else false. 1088 * 1089 * Two Groups are equivalent if they are the root Groups of identical 1090 * Group hierarchy structures with the same names for all Views and 1091 * Groups in the hierarchy, and the Views are also equivalent. 1092 * 1093 * \param other The group to compare with 1094 * \param checkName If true (default), groups must have the same name 1095 * to be equivalent. If false, disregard the name. 1096 * 1097 * \sa View::isEquivalentTo() 1098 */ 1099 bool isEquivalentTo(const Group* other, bool checkName = true) const; 1100 1101 /*! 1102 * \brief Return true if this Group holds items in map format. 1103 */ isUsingMap() const1104 bool isUsingMap() const { return !m_is_list; } 1105 1106 /*! 1107 * \brief Return true if this Group holds items in list format. 1108 */ isUsingList() const1109 bool isUsingList() const { return m_is_list; } 1110 1111 //@{ 1112 /*! 1113 * @name Group I/O methods 1114 * These methods save and load Group trees to and from files. 1115 * This includes the views and buffers used in by groups in the tree. 1116 * We provide several "protocol" options: 1117 * 1118 * protocols: 1119 * sidre_hdf5 (default when Axom is configured with hdf5) 1120 * sidre_conduit_json (default otherwise) 1121 * sidre_json 1122 * 1123 * conduit_hdf5 1124 * conduit_bin 1125 * conduit_json 1126 * json 1127 * 1128 * \note The sidre_hdf5 and conduit_hdf5 protocols are only available 1129 * when Axom is configured with hdf5. 1130 * 1131 * There are two overloaded versions for each of save, load, and 1132 * loadExternalData. The first of each takes a file path and is intended 1133 * for use in a serial context and can be called directly using any 1134 * of the supported protocols. The second takes an hdf5 handle that 1135 * has previously been created by the calling code. These mainly exist 1136 * to handle parallel I/O calls from the SPIO component. They can only 1137 * take the sidre_hdf5 or conduit_hdf5 protocols. 1138 * 1139 * \note The hdf5 overloads are only available when Axom is configured 1140 * with hdf5. 1141 */ 1142 1143 /*! 1144 * \brief Save the Group to a file. 1145 * 1146 * Saves the tree starting at this Group and the Buffers used by the Views 1147 * in this tree. 1148 * 1149 * If attr is a null pointer, dump all Views. Otherwise, only dump Views 1150 * which have the Attribute set. 1151 * 1152 * \param path file path 1153 * \param protocol I/O protocol 1154 * \param attr Save Views that have Attribute set. 1155 */ 1156 void save(const std::string& path, 1157 const std::string& protocol = SIDRE_DEFAULT_PROTOCOL, 1158 const Attribute* attr = nullptr) const; 1159 1160 /*! 1161 * \brief Load a Group hierarchy from a file into this Group 1162 * 1163 * This method instantiates the Group hierarchy and its Views stored 1164 * in the file under this Group. The name of this Group is not 1165 * changed. 1166 * 1167 * If preserve_contents is true, then the names of the children held by the 1168 * Node cannot be the same as the names of the children already held by this 1169 * Group. If there is a naming conflict, an error will occur. 1170 * 1171 * \param path file path 1172 * \param protocol I/O protocol 1173 * \param preserve_contents If true, any child Groups and Views held by 1174 * this Group remain in place. If false, all 1175 * child Groups and Views are destroyed before 1176 * loading data from the file. 1177 */ 1178 void load(const std::string& path, 1179 const std::string& protocol = SIDRE_DEFAULT_PROTOCOL, 1180 bool preserve_contents = false); 1181 1182 /*! 1183 * \brief Load a Group hierarchy from a file into this Group, reporting 1184 * the Group name stored in the file 1185 * 1186 * This method instantiates the Group hierarchy and its Views stored 1187 * in the file under this Group. The name of this Group is not 1188 * changed. The name of the group stored in the file is returned in 1189 * the output parameter name_from_file. This can be used to rename the 1190 * group in a subsequent call. 1191 * 1192 * If preserve_contents is true, then the names of the children held by the 1193 * Node cannot be the same as the names of the children already held by this 1194 * Group. If there is a naming conflict, an error will occur. 1195 * 1196 * \param [in] path file path to load 1197 * \param [in] protocol I/O protocol to use 1198 * \param [in] preserve_contents If true, any child Groups and Views 1199 * held by this Group remain in place. 1200 * If false, all child Groups and Views are 1201 * destroyed before loading data from the file. 1202 * \param [out] name_from_file Group name stored in the file 1203 */ 1204 void load(const std::string& path, 1205 const std::string& protocol, 1206 bool preserve_contents, 1207 std::string& name_from_file); 1208 1209 /*! 1210 * \brief Create a child Group and load a Group hierarchy from file 1211 * into the new Group. 1212 * 1213 * This is a convenience routine for the following sequence: 1214 * - create a group with name or path group_name 1215 * - load a Group hierarchy from a file into the newly-created Group 1216 * - return the newly created Group, or nullptr if creation failed 1217 * - out-parameters return: 1218 * - the group name from the file 1219 * - a flag indicating success reading the file 1220 * 1221 * As with the createGroup() method, if group_name is empty or there 1222 * already exists a child Group with that name or path, the child Group 1223 * will not be created and this method will return nullptr. 1224 * 1225 * As with the load() method, after calling createGroupAndLoad() a host 1226 * code may choose to rename the newly-created Group with the string 1227 * returned in group_name. 1228 * 1229 * \param [in,out] group_name In: name for the new group. 1230 * Out: the group name stored in the file. 1231 * \param [in] path file path 1232 * \param [in] protocol I/O protocol 1233 * \param [out] load_success Report success of the load operation 1234 * 1235 * \return pointer to created Group object or nullptr if new 1236 * Group is not created. 1237 */ 1238 Group* createGroupAndLoad(std::string& group_name, 1239 const std::string& path, 1240 const std::string& protocol, 1241 bool& load_success); 1242 1243 /*! 1244 * \brief Load data into the Group's external views from a file. 1245 * 1246 * No protocol argument is needed, as this only is used with the sidre_hdf5 1247 * protocol. 1248 * 1249 * \param path file path 1250 */ 1251 void loadExternalData(const std::string& path); 1252 1253 #ifdef AXOM_USE_HDF5 1254 1255 /*! 1256 * \brief Save the Group to an hdf5 handle. 1257 * 1258 * If attr is nullptr, dump all Views. Otherwise, only dump Views 1259 * which have the Attribute set. 1260 * 1261 * \param h5_id hdf5 handle 1262 * \param protocol I/O protocol sidre_hdf5 or conduit_hdf5 1263 * \param attr Save Views that have Attribute set. 1264 */ 1265 void save(const hid_t& h5_id, 1266 const std::string& protocol = SIDRE_DEFAULT_PROTOCOL, 1267 const Attribute* attr = nullptr) const; 1268 1269 /*! 1270 * \brief Load the Group from an hdf5 handle. 1271 * 1272 * If preserve_contents is true, then the names of the children held by the 1273 * Node cannot be the same as the names of the children already held by this 1274 * Group. If there is a naming conflict, an error will occur. 1275 * 1276 * \param h5_id hdf5 handle 1277 * \param protocol I/O protocol sidre_hdf5 or conduit_hdf5 1278 * \param preserve_contents If true, any child Groups and Views held by 1279 * this Group remain in place. If false, all 1280 * child Groups and Views are destroyed before 1281 * loading data from the file. 1282 */ 1283 void load(const hid_t& h5_id, 1284 const std::string& protocol = SIDRE_DEFAULT_PROTOCOL, 1285 bool preserve_contents = false); 1286 1287 /*! 1288 * \brief Load the Group from an hdf5 handle. 1289 * 1290 * If preserve_contents is true, then the names of the children held by the 1291 * Node cannot be the same as the names of the children already held by this 1292 * Group. If there is a naming conflict, an error will occur. 1293 * 1294 * \param [in] h5_id hdf5 handle 1295 * \param [in] protocol I/O protocol sidre_hdf5 or conduit_hdf5 1296 * \param [in] preserve_contents If true, any child Groups and Views held by 1297 * this Group remain in place. If false, all 1298 * child Groups and Views are destroyed before 1299 * loading data from the file. 1300 * \param [out] name_from_file Group name stored in the file 1301 */ 1302 void load(const hid_t& h5_id, 1303 const std::string& protocol, 1304 bool preserve_contents, 1305 std::string& name_from_file); 1306 1307 /*! 1308 * \brief Load data into the Group's external views from a hdf5 handle. 1309 * 1310 * No protocol argument is needed, as this only is used with the sidre_hdf5 1311 * protocol. 1312 * 1313 * \param h5_id hdf5 handle 1314 */ 1315 void loadExternalData(const hid_t& h5_id); 1316 1317 #endif /* AXOM_USE_HDF5 */ 1318 1319 //@} 1320 1321 /*! 1322 * \brief Change the name of this Group. 1323 * 1324 * The name of this group is changed to the new name. If this group 1325 * has a parent group, the name for this group held by the parent is 1326 * also changed. 1327 * 1328 * Warnings will occur and the name will not be changed under these 1329 * conditions: If the new name is an empty string, if the new name 1330 * contains a path delimiter (usually '/'), or if the new name is 1331 * identical to a name that is already held by the parent for another 1332 * Group or View object. 1333 * 1334 * It is possible to rename the root Group, but a code cannot 1335 * subsequently rename root Group back to its original empty string 1336 * name. 1337 * 1338 * \param new_name The new name for this group. 1339 * 1340 * \return Success or failure of rename. 1341 */ 1342 bool rename(const std::string& new_name); 1343 1344 /*! 1345 * \brief Import data from a conduit Node into a Group 1346 * 1347 * This imports the hierarchy from the Node into a Sidre Group with the 1348 * same tree structure. 1349 * 1350 * This does not support conduit's list datatype. If the Node contains a 1351 * list any where in its tree, the list and any child Nodes descending from 1352 * the list will not be imported. A warning will occur and an unsuccessful 1353 * return value will be returned. 1354 * 1355 * If preserve_contents is true, then the names of the children held by the 1356 * Node cannot be the same as the names of the children already held by this 1357 * Group. If there is a naming conflict, an error will occur. 1358 * 1359 * \param node A conduit Node containing hierarchical data. 1360 * \param preserve_contents If true, any child Groups and Views held by 1361 * this Group remain in place. If false, all 1362 * child Groups and Views are destroyed before 1363 * importing data from the Node. 1364 * 1365 * \return true for success, false if the full conduit 1366 * tree is not succesfully imported. 1367 */ 1368 bool importConduitTree(const conduit::Node& node, 1369 bool preserve_contents = false); 1370 1371 /*! 1372 * \brief Import data from a conduit Node into a Group without copying arrays 1373 * 1374 * This differs from the importConduitTree in that it does not copy any 1375 * data held by the Node as an array. Instead it imports the existing 1376 * pointer to the array as an external pointer. 1377 * 1378 * This imports the hierarchy from the Node into a Sidre Group with the 1379 * same tree structure. 1380 * 1381 * This does not support conduit's list datatype. If the Node contains a 1382 * list any where in its tree, the list and any child Nodes descending from 1383 * the list will not be imported. A warning will occur and an unsuccessful 1384 * return value will be returned. 1385 * 1386 * If preserve_contents is true, then the names of the children held by the 1387 * Node cannot be the same as the names of the children already held by this 1388 * Group. If there is a naming conflict, an error will occur. 1389 * 1390 * \param node A conduit Node containing hierarchical data. 1391 * \param preserve_contents If true, any child Groups and Views held by 1392 * this Group remain in place. If false, all 1393 * child Groups and Views are destroyed before 1394 * importing data from the Node. 1395 * 1396 * \return true for success, false if the full conduit 1397 * tree is not succesfully imported. 1398 */ 1399 bool importConduitTreeExternal(conduit::Node& node, 1400 bool preserve_contents = false); 1401 1402 private: 1403 DISABLE_DEFAULT_CTOR(Group); 1404 DISABLE_COPY_AND_ASSIGNMENT(Group); 1405 DISABLE_MOVE_AND_ASSIGNMENT(Group); 1406 1407 //@{ 1408 //! @name Private Group ctors and dtors 1409 //! (callable only by DataStore and Group methods). 1410 1411 /*! 1412 * \brief Private ctor that creates a Group with given name 1413 * in the given DataStore. 1414 * 1415 * attachGroup must be called on a newly created Group to insert it 1416 * into the hierarchy. The root group is an exception to this rule. 1417 * 1418 * The boolean argument is_list, if true, allows the Group to hold its 1419 * child items in list format, which allows those items to have empty 1420 * strings for names. If not in list format, all items must have unique 1421 * non-empty strings for names. 1422 */ 1423 Group(const std::string& name, DataStore* datastore, bool is_list); 1424 1425 /*! 1426 * \brief Destructor destroys all Views and child Groups. 1427 */ 1428 ~Group(); 1429 1430 //@} 1431 1432 //@{ 1433 //! @name View attach and detach methods. 1434 1435 /*! 1436 * \brief Attach View object to this Group. 1437 */ 1438 View* attachView(View* view); 1439 1440 /*! 1441 * \brief Detach View object from this Group. 1442 */ detachView(const View * view)1443 View* detachView(const View* view) { return detachView(view->getName()); } 1444 1445 /*! 1446 * \brief Detach View with given name from this Group. 1447 */ 1448 View* detachView(const std::string& name); 1449 1450 /*! 1451 * \brief Detach View with given index from this Group. 1452 */ 1453 View* detachView(IndexType idx); 1454 1455 //@} 1456 1457 //@{ 1458 //! @name Group attach and detach methods. 1459 1460 /*! 1461 * \brief Attach Group object to this Group. 1462 */ 1463 Group* attachGroup(Group* view); 1464 1465 /*! 1466 * \brief Detach Child Group with given name from this Group. 1467 */ 1468 Group* detachGroup(const std::string& name); 1469 1470 /*! 1471 * \brief Detach Child Group with given index from this Group. 1472 */ 1473 Group* detachGroup(IndexType idx); 1474 1475 //@} 1476 1477 //@{ 1478 //! @name Private Group View manipulation methods. 1479 1480 /*! 1481 * \brief Destroy View and its data if its data is not shared with any 1482 * other View. 1483 * 1484 * Data will not be destroyed as long as a View still exists that 1485 * references it. 1486 * 1487 * \attention this method assumes View is owned by this Group. 1488 */ 1489 void destroyViewAndData(View* view); 1490 1491 //@} 1492 1493 //@{ 1494 //! @name Private Group methods for interacting with Conduit Nodes. 1495 1496 /*! 1497 * \brief Private method to copy Group to Conduit Node. 1498 * 1499 * Note: This is for the "sidre_{zzz}" protocols. 1500 * 1501 * \return True if the group or any of its children have saved Views, 1502 * false otherwise. 1503 */ 1504 bool exportTo(conduit::Node& result, const Attribute* attr) const; 1505 1506 /*! 1507 * \brief Private method to copy Group to Conduit Node. 1508 * 1509 * \param buffer_indices Used to track what Buffers are referenced 1510 * by the Views in this Group and Groups in the sub-tree below it. 1511 * 1512 * \return True if the group or any of its children have saved Views, 1513 * false otherwise. 1514 */ 1515 bool exportTo(conduit::Node& data_holder, 1516 const Attribute* attr, 1517 std::set<IndexType>& buffer_indices) const; 1518 1519 /*! 1520 * \brief Private method to build a Group hierarchy from Conduit Node. 1521 * 1522 * Note: This is for the "sidre_{zzz}" protocols. 1523 */ 1524 void importFrom(conduit::Node& node, bool preserve_contents = false); 1525 1526 /*! 1527 * \brief Private method to copy Group from Conduit Node. 1528 * 1529 * Map of Buffer indices tracks old Buffer ids in the file to the 1530 * new Buffer ids in the datastore. Buffer ids are not guaranteed 1531 * to remain the same when a tree is restored. 1532 * 1533 */ 1534 void importFrom(conduit::Node& node, 1535 const std::map<IndexType, IndexType>& buffer_id_map); 1536 1537 //@} 1538 1539 /*! 1540 * \brief Private method that returns the Group that is the next-to-last 1541 * entry in a slash-delimited ("/") path string. 1542 * 1543 * The string before the last "/" character, if there is one, is the 1544 * next-to-last path entry. In this case, the return value is that Group 1545 * in the path. 1546 * 1547 * If there is no "/" in the given path, the entire string is considered 1548 * the next-to-last path entry. In this case, the return value is this 1549 * Group. 1550 * 1551 * The path argument is modified while walking the path. Its value when 1552 * the method returns is the last entry in the path, either the string 1553 * following the last "/" in the input (if there is one) or the entire 1554 * input path string if it contains no "/". 1555 */ 1556 Group* walkPath(std::string& path, bool create_groups_in_path); 1557 1558 /*! 1559 * \brief Const private method that returns the Group that is the 1560 * next-to-last entry in a delimited path string. 1561 * 1562 * The path argument is modified while walking the path. Its value when 1563 * the method returns is the last entry in the path, either the string 1564 * following the last "/" in the input (if there is one) or the entire 1565 * input path string if it contains no "/". 1566 */ 1567 const Group* walkPath(std::string& path) const; 1568 1569 /*! 1570 * \brief Private method. If allocatorID is a valid allocator ID then return 1571 * it. Otherwise return the ID of the default allocator of the owning group. 1572 */ 1573 int getValidAllocatorID(int allocatorID); 1574 1575 /// Name of this Group object. 1576 std::string m_name; 1577 1578 /// Index of this Group object within m_parent. 1579 IndexType m_index; 1580 1581 /// Parent Group of this Group object. 1582 Group* m_parent; 1583 1584 /// This Group object lives in the tree of this DataStore object. 1585 DataStore* m_datastore; 1586 1587 /// This identifies whether this Group holds items in list format. 1588 bool m_is_list; 1589 1590 /// Character used to denote a path string passed to get/create calls. 1591 AXOM_EXPORT static const char s_path_delimiter; 1592 1593 /////////////////////////////////////////////////////////////////// 1594 // 1595 using ViewCollection = ItemCollection<View>; 1596 // 1597 using GroupCollection = ItemCollection<Group>; 1598 /////////////////////////////////////////////////////////////////// 1599 1600 /// Collection of Views 1601 ViewCollection* m_view_coll; 1602 1603 /// Collection of child Groups 1604 GroupCollection* m_group_coll; 1605 1606 #ifdef AXOM_USE_UMPIRE 1607 int m_default_allocator_id; 1608 #endif 1609 }; 1610 1611 } /* end namespace sidre */ 1612 } /* end namespace axom */ 1613 1614 #endif /* SIDRE_GROUP_HPP_ */ 1615