Teuchos - Trilinos Tools Package Version of the Day
Loading...
Searching...
No Matches
Teuchos_StringIndexedOrderedValueObjectContainer.hpp
1// @HEADER
2// *****************************************************************************
3// Teuchos: Common Tools Package
4//
5// Copyright 2004 NTESS and the Teuchos contributors.
6// SPDX-License-Identifier: BSD-3-Clause
7// *****************************************************************************
8// @HEADER
9
10#ifndef TEUCHOS_STRING_INDEXED_ORDERED_VALUE_OBJECT_CONTAINER_HPP
11#define TEUCHOS_STRING_INDEXED_ORDERED_VALUE_OBJECT_CONTAINER_HPP
12
13
14#include "Teuchos_Array.hpp"
15#include "Teuchos_FilteredIterator.hpp"
16#include <deque>
17#include <map>
18#include <string>
19
20namespace Teuchos {
21
22
23
27public:
28
30 typedef Teuchos_Ordinal Ordinal;
31
33 static Ordinal getInvalidOrdinal() { return -1; }
34
37
38public: // Public members (but only for unit testing purposes!)
39
58
72 template<class ObjType>
74 public:
76 const std::string &first;
80 std::string key;
82 KeyObjectPair() : first(key), second(ObjType()), key(""), isActive_(true) {}
84 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, ObjType>>>
85 KeyObjectPair(const std::string &key_in, U&& obj_in, bool isActive_in = true)
86 : first(key), second(std::forward<U>(obj_in)), key(key_in), isActive_(isActive_in) {}
89 : first(key), second(kop.second), key(kop.key), isActive_(kop.isActive_) {}
92 : first(key), second(std::move(kop.second)), key(std::move(kop.key)), isActive_(kop.isActive_) {}
95 {
96 second = kop.second;
97 key = kop.key;
98 isActive_ = kop.isActive_;
99 return *this;
100 }
103 { return KeyObjectPair("", ObjType(), false); }
105 bool isActive() const { return isActive_; }
106 private:
107 bool isActive_;
108 };
109
111 template<class ObjType>
113 public:
114 bool operator()(const KeyObjectPair<ObjType> &key_and_obj) const
115 { return key_and_obj.isActive(); }
116 };
117
121
124 {public:InvalidKeyError(const std::string& what_arg) : ExceptionBase(what_arg) {}};
125
126};
127
128
150template<class ObjType>
153{
154private:
155
159 typedef std::deque<key_and_obj_t> key_and_obj_array_t; // See notes below!
161 typedef std::map<std::string, OrdinalIndex> key_to_idx_map_t;
162
163public:
164
167
170
174
178
180
183
186
189
192
194
197
206 template <typename U, typename = std::enable_if_t<std::is_convertible_v<U, ObjType>>>
207 Ordinal setObj(const std::string &key, U&& obj);
208
213 inline Ordinal getObjOrdinalIndex(const std::string &key) const;
214
219
223 inline Ptr<const ObjType> getObjPtr(const Ordinal &idx) const;
224
228 inline Ptr<ObjType> getNonconstObjPtr(const std::string &key);
229
233 inline Ptr<const ObjType> getObjPtr(const std::string &key) const;
234
241 void removeObj(const Ordinal &idx);
242
244 void removeObj(const std::string &key);
245
247
250
253
256
258 inline ConstIterator begin() const;
259
261 inline ConstIterator end() const;
262
264
265private: // data members
266
268 key_and_obj_array_t key_and_obj_array_;
270 key_to_idx_map_t key_to_idx_map_;
271
272 // The above is a fairly simple data-structure.
273 //
274 // key_and_obj_array_: Array that stores the objects (and key names), by
275 // value, in the order they are inserted. Any removed objects will have the
276 // index valuie of getInvalidOrdinal(). The key strings are also storied
277 // with the objects so that a clean iterator can over the objects has access
278 // to both the key and the object value.
279 //
280 // key_to_idx_map_: Maps the unique string key to the unigue ordinal index
281 // for an object.
282 //
283 // NOTES:
284 //
285 // A) This data-structure stores the key names twice in order to allow for
286 // optimal iterator performance. The array key_and_obj_array_ allows fast
287 // ordered iterators through the data but in order to also provide the names
288 // in a fast manner, they have to be stored twice.
289 //
290 // B) Deleting objects is done by just removing an entry from
291 // key_to_idx_map_ but the corresponding entry in key_and_obj_array_ is just
292 // abandoned with the object value set to ObjType().
293
294private: // member functions
295
297 void assertOrdinalIndex(const Ordinal idx) const;
298
300 key_and_obj_t& getNonconstKeyAndObject(const Ordinal idx);
301
303 const key_and_obj_t& getKeyAndObject(const Ordinal idx) const;
304
306 void throwInvalidKeyError(const Ordinal idx, const std::string &key) const;
307
309 Ordinal assertKeyGetOrdinal(const std::string &key) const;
310
311};
312
313
314//
315// StringIndexedOrderedValueObjectContainer: Inline Implementations
316//
317
318
319// Set, get, and remove functions
320
321
322template<class ObjType>
323inline
326{
327 return ptrFromRef(getNonconstKeyAndObject(idx).second);
328}
329
330
331template<class ObjType>
332inline
335{
336 return ptrFromRef(getKeyAndObject(idx).second);
337}
338
339
340template<class ObjType>
341inline
344{
345 return getNonconstObjPtr(assertKeyGetOrdinal(key));
346}
347
348
349template<class ObjType>
350inline
353{
354 return getObjPtr(assertKeyGetOrdinal(key));
355}
356
357
358// Iterator access
359
360
361template<class ObjType>
362inline
365{
366 return Iterator(key_and_obj_array_.begin(), key_and_obj_array_.begin(),
367 key_and_obj_array_.end());
368}
369
370
371template<class ObjType>
372inline
375{
376 return Iterator(key_and_obj_array_.end(), key_and_obj_array_.begin(),
377 key_and_obj_array_.end());
378}
379
380
381template<class ObjType>
382inline
385{
386 return ConstIterator(key_and_obj_array_.begin(), key_and_obj_array_.begin(),
387 key_and_obj_array_.end());
388}
389
390
391template<class ObjType>
392inline
395{
396 return ConstIterator(key_and_obj_array_.end(), key_and_obj_array_.begin(),
397 key_and_obj_array_.end());
398}
399
400
401//
402// StringIndexedOrderedValueObjectContainer: Template Implementations
403//
404
405
406// Constructors/Destructors/Info
407
408
409template<class ObjType>
412
413
414template<class ObjType>
417{
418 return key_to_idx_map_.size();
419}
420
421
422template<class ObjType>
425{
426 return key_and_obj_array_.size();
427}
428
429
430// Set, get, and remove functions
431
432
433template<class ObjType>
434inline
437{
438 key_to_idx_map_t::const_iterator itr = key_to_idx_map_.find(key);
439 if (itr != key_to_idx_map_.end()) {
440 return itr->second.idx;
441 }
442 return getInvalidOrdinal();
443}
444
445
446template <typename ObjType>
447template <typename U, typename>
450 U&& obj)
451{
452 typename key_to_idx_map_t::iterator obj_idx_itr = key_to_idx_map_.find(key);
453 if (obj_idx_itr != key_to_idx_map_.end()) {
454 // Object with the given key already exists
455 const Ordinal obj_idx = obj_idx_itr->second.idx;
456 key_and_obj_array_[obj_idx].second = std::forward<U>(obj);
457 return obj_idx;
458 }
459 // Object with the given key does not already exist so create a new one.
460 key_and_obj_array_.emplace_back(key, std::forward<U>(obj));
461 const Ordinal new_idx = key_and_obj_array_.size()-1;
462 key_to_idx_map_[key] = new_idx;
463 return new_idx;
464}
465
466
467template<class ObjType>
469{
470 key_and_obj_t &key_and_obj = getNonconstKeyAndObject(idx);
471 key_to_idx_map_.erase(key_and_obj.first);
472 key_and_obj = key_and_obj_t::makeInvalid();
473}
474
475
476template<class ObjType>
478{
479 typename key_to_idx_map_t::iterator itr = key_to_idx_map_.find(key);
480 if (itr == key_to_idx_map_.end()) {
481 throwInvalidKeyError(getInvalidOrdinal(), key);
482 }
483 const Ordinal idx = itr->second.idx;
484 key_to_idx_map_.erase(itr);
485 key_and_obj_array_[idx] = key_and_obj_t::makeInvalid();
486}
487
488
489// private
490
491
492template<class ObjType>
494{
495 TEUCHOS_TEST_FOR_EXCEPTION( !(0 <= idx && idx < numStorage()),
496 InvalidOrdinalIndexError,
497 "Error, the ordinal index " << idx << " is invalid"
498 << " because it falls outside of the range of valid objects"
499 << " [0,"<<numStorage()-1<<"]!");
500}
501
502
503template<class ObjType>
504typename StringIndexedOrderedValueObjectContainer<ObjType>::key_and_obj_t&
505StringIndexedOrderedValueObjectContainer<ObjType>::getNonconstKeyAndObject(const Ordinal idx)
506{
507 assertOrdinalIndex(idx);
508 key_and_obj_t &key_and_obj = key_and_obj_array_[idx];
509 TEUCHOS_TEST_FOR_EXCEPTION( !key_and_obj.isActive(),
510 InvalidOrdinalIndexError,
511 "Error, the ordinal index " << idx << " is invalid"
512 << " because the object has been deleted!");
513 return key_and_obj;
514}
515
516
517template<class ObjType>
518const typename StringIndexedOrderedValueObjectContainer<ObjType>::key_and_obj_t&
519StringIndexedOrderedValueObjectContainer<ObjType>::getKeyAndObject(const Ordinal idx) const
520{
521 assertOrdinalIndex(idx);
522 const key_and_obj_t &key_and_obj = key_and_obj_array_[idx];
523 TEUCHOS_TEST_FOR_EXCEPTION( !key_and_obj.isActive(),
524 InvalidOrdinalIndexError,
525 "Error, the ordinal index " << idx << " is invalid"
526 << " because the object has been deleted!");
527 return key_and_obj;
528}
529
530
531template<class ObjType>
532void
533StringIndexedOrderedValueObjectContainer<ObjType>::throwInvalidKeyError(
534 const Ordinal idx, const std::string &key) const
535{
536 TEUCHOS_TEST_FOR_EXCEPTION( idx == getInvalidOrdinal(), InvalidKeyError,
537 "Error, the key '" << key << "' does not exist!");
538}
539
540
541template<class ObjType>
543StringIndexedOrderedValueObjectContainer<ObjType>::assertKeyGetOrdinal(const std::string &key) const
544{
545 const Ordinal idx = getObjOrdinalIndex(key);
546 throwInvalidKeyError(idx, key);
547 return idx;
548}
549
550
551} // end of Teuchos namespace
552
553/* Notes:
554 *
555 * This class may have a bit of a fragile implemenation. It uses std::deque
556 * instead of std::vector to hold the stored objects. This is so that once an
557 * object is added, it will keep the exact same address no matter how many
558 * other objects are added. This is not the case with std::vector because
559 * when the memory is resized it will copy the value objects making the old
560 * objects invalid. My guess with the std::deque class is that it would
561 * allocate and store the chunks such that once an objects was added to a
562 * chunk that it would not get reallocated and moved like in std::vector. I
563 * don't feel very good about relying on this behavior but my guess is that
564 * this will be pretty portable. If this turns out not to be portable, we can
565 * always just use RCP<ObjType> to store the object and that will guarantee
566 * that the object address will never be moved. Going with an RCP<ObjType>
567 * implementation would also allow the Ptr<ObjType> views to catch dangling
568 * references in a debug-mode build.
569 */
570
571
572#endif // TEUCHOS_STRING_INDEXED_ORDERED_VALUE_OBJECT_CONTAINER_HPP
573
574
Templated array class derived from the STL std::vector.
Base exception class for Teuchos.
Smart reference counting pointer class for automatic garbage collection.
Ptr< const ObjType > getObjPtr(const std::string &key) const
Get a const semi-persisting association with the stored object indexed by string key.
Ordinal setObj(const std::string &key, U &&obj)
Set (or reset) object by value and return its ordinal index.
Ordinal getObjOrdinalIndex(const std::string &key) const
Get the ordinal index given the string key.
FilteredIterator< typename key_and_obj_array_t::const_iterator, SelectActive< ObjType > > ConstIterator
The const iterator type.
FilteredIterator< typename key_and_obj_array_t::iterator, SelectActive< ObjType > > Iterator
The non-const iterator type.
void removeObj(const Ordinal &idx)
Remove an object given its ordinal index.
Ptr< ObjType > getNonconstObjPtr(const std::string &key)
Get a nonconst semi-persisting association with the stored object indexed by string key.
Ptr< ObjType > getNonconstObjPtr(const Ordinal &idx)
Get a nonconst semi-persisting association with the stored object indexed by ordinal.
StringIndexedOrderedValueObjectContainerBase::Ordinal Ordinal
Ordinal used for the index.
Ptr< const ObjType > getObjPtr(const Ordinal &idx) const
Get a const semi-persisting association with the stored object indexed by ordinal.
void removeObj(const std::string &key)
Remove an object given its string key.
#define TEUCHOS_TEST_FOR_EXCEPTION(throw_exception_test, Exception, msg)
Macro for throwing an exception with breakpointing to ease debugging.
The Teuchos namespace contains all of the classes, structs and enums used by Teuchos,...