|
23 | 23 | #include "openPMD/backend/Attributable.hpp" |
24 | 24 |
|
25 | 25 | #include <initializer_list> |
26 | | -#include <type_traits> |
27 | | -#include <stdexcept> |
28 | 26 | #include <map> |
| 27 | +#include <set> |
| 28 | +#include <stdexcept> |
29 | 29 | #include <string> |
| 30 | +#include <type_traits> |
| 31 | +#include <utility> |
30 | 32 |
|
31 | 33 | // expose private and protected members for invasive testing |
32 | 34 | #ifndef OPENPMD_protected |
@@ -106,14 +108,16 @@ class Container : public LegacyAttributable |
106 | 108 | static_assert( |
107 | 109 | std::is_base_of< AttributableImpl, T >::value, |
108 | 110 | "Type of container element must be derived from Writable"); |
109 | | - using InternalContainer = T_container; |
110 | 111 |
|
111 | 112 | friend class Iteration; |
112 | 113 | friend class ParticleSpecies; |
113 | 114 | friend class internal::SeriesData; |
114 | 115 | friend class SeriesImpl; |
115 | 116 | friend class Series; |
116 | 117 |
|
| 118 | +protected: |
| 119 | + using InternalContainer = T_container; |
| 120 | + |
117 | 121 | public: |
118 | 122 | using key_type = typename InternalContainer::key_type; |
119 | 123 | using mapped_type = typename InternalContainer::mapped_type; |
@@ -321,6 +325,72 @@ class Container : public LegacyAttributable |
321 | 325 | } |
322 | 326 |
|
323 | 327 | std::shared_ptr< InternalContainer > m_container; |
| 328 | + |
| 329 | + /** |
| 330 | + * This class wraps a Container and forwards operator[]() and at() to it. |
| 331 | + * It remembers the keys used for accessing. Upon going out of scope, all |
| 332 | + * keys not yet accessed are removed from the Container. |
| 333 | + * Note that the container is stored by non-owning reference, thus |
| 334 | + * requiring that the original Container stay in scope while using this |
| 335 | + * class. |
| 336 | + */ |
| 337 | + class EraseStaleEntries |
| 338 | + { |
| 339 | + std::set< key_type > m_accessedKeys; |
| 340 | + /* |
| 341 | + * Note: Putting a copy here leads to weird bugs due to destructors |
| 342 | + * being called too eagerly upon destruction. |
| 343 | + * Should be avoidable by extending the frontend redesign to the |
| 344 | + * Container class template |
| 345 | + * (https://github.com/openPMD/openPMD-api/pull/886) |
| 346 | + */ |
| 347 | + Container & m_originalContainer; |
| 348 | + |
| 349 | + public: |
| 350 | + explicit EraseStaleEntries( Container & container_in ) |
| 351 | + : m_originalContainer( container_in ) |
| 352 | + { |
| 353 | + } |
| 354 | + |
| 355 | + template< typename K > |
| 356 | + mapped_type & operator[]( K && k ) |
| 357 | + { |
| 358 | + m_accessedKeys.insert( k ); // copy |
| 359 | + return m_originalContainer[ std::forward< K >( k ) ]; |
| 360 | + } |
| 361 | + |
| 362 | + template< typename K > |
| 363 | + mapped_type & at( K && k ) |
| 364 | + { |
| 365 | + m_accessedKeys.insert( k ); // copy |
| 366 | + return m_originalContainer.at( std::forward< K >( k ) ); |
| 367 | + } |
| 368 | + |
| 369 | + ~EraseStaleEntries() |
| 370 | + { |
| 371 | + auto & map = *m_originalContainer.m_container; |
| 372 | + using iterator_t = typename InternalContainer::const_iterator; |
| 373 | + std::vector< iterator_t > deleteMe; |
| 374 | + deleteMe.reserve( map.size() - m_accessedKeys.size() ); |
| 375 | + for( iterator_t it = map.begin(); it != map.end(); ++it ) |
| 376 | + { |
| 377 | + auto lookup = m_accessedKeys.find( it->first ); |
| 378 | + if( lookup == m_accessedKeys.end() ) |
| 379 | + { |
| 380 | + deleteMe.push_back( it ); |
| 381 | + } |
| 382 | + } |
| 383 | + for( auto & it : deleteMe ) |
| 384 | + { |
| 385 | + map.erase( it ); |
| 386 | + } |
| 387 | + } |
| 388 | + }; |
| 389 | + |
| 390 | + EraseStaleEntries eraseStaleEntries() |
| 391 | + { |
| 392 | + return EraseStaleEntries( *this ); |
| 393 | + } |
324 | 394 | }; |
325 | 395 |
|
326 | 396 | } // openPMD |
0 commit comments