ADTF  3.18.2
dd_access_list.h
Go to the documentation of this file.
1 
15 #ifndef DD_DD_ACCESS_LIST_H_INCLUDED
16 #define DD_DD_ACCESS_LIST_H_INCLUDED
17 
19 #include <ddl/dd/dd_common_types.h>
20 #include <ddl/dd/dd_error.h>
22 
23 #include <algorithm>
24 #include <memory>
25 #include <unordered_map>
26 #if HAS_STRING_VIEW
27 #include <string_view>
28 #endif // HAS_STRING_VIEW
29 
30 namespace ddl {
31 namespace dd {
32 namespace utility {
41  list_item_added,
42  list_item_removed,
43  list_item_changed,
44  list_item_renamed,
45  list_subitem_added,
46  list_subitem_removed,
47  list_subitem_changed,
48  list_item_popped,
49  list_subitem_popped,
50  list_item_inserted,
51  list_subitem_inserted
52 };
53 
60 template <typename T>
62 
69 template <typename T>
71 
78 template <typename DDL_TYPE_TO_ACCESS, typename TYPE_VALIDATOR_CLASS>
79 class TypeAccessList : public TypeAccessListObserver<DDL_TYPE_TO_ACCESS> {
80 public:
82  typedef DDL_TYPE_TO_ACCESS access_type;
84  typedef std::shared_ptr<DDL_TYPE_TO_ACCESS> value_type;
86  typedef std::vector<value_type> container_type;
88 #if HAS_STRING_VIEW
89  typedef std::unordered_map<std::string_view, value_type> container_named_type;
92  #ifndef dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY
93  #if defined(__GNUC__) && (__GNUC__ > 7)
94  #define dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY 0
95  #elif defined(_MSC_VER) && (_MSC_VER >= 1920)
96  #define dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY 0
97  #else
98  #define dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY 1
99  #endif
100  #endif
101 #else
102  typedef std::unordered_map<std::string, value_type> container_named_type;
103  #ifndef dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY
104  #define dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY 0
105  #endif
106 #endif // HAS_STRING_VIEW
108  #if dev_essential_TYPE_ACCESS_LIST_COMPATIBILITY
109  typedef std::unordered_map<std::string, value_type> container_named_compatibility_type;
110  #else
111  #ifdef HAS_STRING_VIEW
112  typedef std::unordered_map<std::string_view, value_type> container_named_compatibility_type;
113  #else
114  typedef std::unordered_map<std::string, value_type> container_named_compatibility_type;
115  #endif
116  #endif
118  typedef typename container_type::iterator iterator;
120  typedef typename container_type::const_iterator const_iterator;
133 
134 public:
139  TypeAccessList() = delete;
146  TypeAccessList(TYPE_VALIDATOR_CLASS* validator, const std::string& validation_info)
147  : _validator(validator), _validation_info(validation_info)
148  {
149  }
154  virtual ~TypeAccessList()
155  {
156  clear();
157  }
162  {
163  *this = std::move(other);
164  }
171  {
172  clear();
173  _validation_info = std::move(other._validation_info);
174  _types = std::move(other._types);
175  // the other will not observe this anymore after this clear
176  for (const auto& current: _types) {
177  // the other will not observe this anymore
178  (static_cast<map_subject_type*>(current.get()))
179  ->detachObserver(static_cast<observer_type*>(&other));
180  // i want to observe this
181  (static_cast<map_subject_type*>(current.get()))
182  ->attachObserver(static_cast<observer_type*>(this));
183  }
184  _validator = nullptr;
185  return *this;
186  }
187 
194  : _validator(nullptr), _validation_info(other._validation_info)
195  {
196  for (auto current: other._types) {
197  auto new_type = std::make_shared<DDL_TYPE_TO_ACCESS>(*current);
198  // i want to observe this
199  (static_cast<map_subject_type*>(new_type.get()))
200  ->attachObserver(static_cast<observer_type*>(this));
201  _types.push_back(new_type);
202  }
203  }
211  {
212  clear();
213  _validation_info = other._validation_info;
214  for (auto current: other._types) {
215  auto new_type = std::make_shared<DDL_TYPE_TO_ACCESS>(*current);
216  // i want to observe this
217  (static_cast<map_subject_type*>(new_type.get()))
218  ->attachObserver(static_cast<observer_type*>(this));
219  _types.push_back(new_type);
220  }
221  _validator = nullptr;
222  return *this;
223  }
224 
225 public:
232  std::shared_ptr<const DDL_TYPE_TO_ACCESS> get(const std::string& type_name) const
233  {
234  if (_validator) {
235  const auto named_items = getNamedContainer();
236  const auto found = named_items->find(type_name);
237  if (found != named_items->end()) {
238  return found->second;
239  }
240  }
241  else {
242  for (auto& current: _types) {
243  if (current->getName() == type_name) {
244  std::shared_ptr<const DDL_TYPE_TO_ACCESS> const_return = current;
245  return const_return;
246  }
247  }
248  }
249  return {};
250  }
251 
259  OptionalSize getPosOf(const std::string& type_name) const
260  {
261  size_t current_pos = 0;
262  for (auto& current: _types) {
263  if (current->getName() == type_name) {
264  return current_pos;
265  }
266  ++current_pos;
267  }
268 
269  return {};
270  }
271 
279  bool contains(const std::string& type_name) const
280  {
281  if (_validator) {
282  const auto named_items = getNamedContainer();
283  const auto found = named_items->find(type_name);
284  if (found != named_items->end()) {
285  return true;
286  }
287  }
288  else {
289  for (auto& current: _types) {
290  if (current->getName() == type_name) {
291  return true;
292  }
293  }
294  }
295  return false;
296  }
297 
305  bool contains(const DDL_TYPE_TO_ACCESS& type_to_find) const
306  {
307  const auto value_found = get(type_to_find.getName());
308  if (value_found) {
309  return type_to_find == *value_found;
310  }
311  return false;
312  }
313 
321  bool contains(const TypeAccessList& other) const
322  {
323  for (const auto& other_content: other._types) {
324  if (!contains(*other_content)) {
325  return false;
326  }
327  }
328  return true;
329  }
330 
337  void add(const DDL_TYPE_TO_ACCESS& type_to_add)
338  {
339  if (checkExistenceAndEquality(type_to_add)) {
340  // this will immediatelly return if the type exists and is equal
341  // otherwise the check will throw!
342  return;
343  }
344 
345  auto new_type_value = std::make_shared<DDL_TYPE_TO_ACCESS>(type_to_add);
346  // i want to observe this
347  (static_cast<map_subject_type*>(new_type_value.get()))
348  ->attachObserver(static_cast<observer_type*>(this));
349  _types.push_back(new_type_value);
350  if (_validator) {
351  const auto named_items = getNamedContainer();
352  (*named_items)[new_type_value->getName()] = new_type_value;
353  }
354  if (_validator) {
355  _validator->notifyChangedListContent(
356  TypeAccessListEventCode::list_item_added, *new_type_value, type_to_add.getName());
357  }
358  }
359 
368  void insert(const size_t pos_idx, const DDL_TYPE_TO_ACCESS& type_to_add)
369  {
370  if (pos_idx > getSize()) {
371  throw ddl::dd::Error(
372  _validation_info + "::insert", {type_to_add.getName()}, "given pos_idx is invalid");
373  }
374  else if (pos_idx == getSize()) {
375  add(type_to_add);
376  }
377  else {
378  if (checkExistenceAndEquality(type_to_add)) {
379  // this will immediatelly return if the type exists and is equal
380  // otherwise the check will throw!
381  return;
382  }
383  auto new_type_value = std::make_shared<DDL_TYPE_TO_ACCESS>(type_to_add);
384  // i want to observe this
385  (static_cast<map_subject_type*>(new_type_value.get()))
386  ->attachObserver(static_cast<observer_type*>(this));
387 
388  auto cit = cbegin();
389  std::advance(cit, pos_idx);
390  _types.insert(cit, new_type_value);
391  if (_validator) {
392  const auto named_items = getNamedContainer();
393  (*named_items)[new_type_value->getName()] = new_type_value;
394  }
395  if (_validator) {
396  _validator->notifyChangedListContent(TypeAccessListEventCode::list_item_inserted,
397  *new_type_value,
398  type_to_add.getName());
399  }
400  }
401  }
402 
409  void emplace(DDL_TYPE_TO_ACCESS&& type_to_add)
410  {
411  if (checkExistenceAndEquality(type_to_add)) {
412  // this will immediatelly return if the type exists and is equal
413  // otherwise the check will throw!
414  return;
415  }
416  auto new_type_value = std::make_shared<DDL_TYPE_TO_ACCESS>(std::move(type_to_add));
417  // i want to observe this
418  (static_cast<map_subject_type*>(new_type_value.get()))
419  ->attachObserver(static_cast<observer_type*>(this));
420  _types.push_back(new_type_value);
421  if (_validator) {
422  const auto named_items = getNamedContainer();
423  (*named_items)[new_type_value->getName()] = new_type_value;
424  }
425  if (_validator) {
426  _validator->notifyChangedListContent(TypeAccessListEventCode::list_item_added,
427  *new_type_value,
428  new_type_value->getName());
429  }
430  }
431 
437  void remove(const std::string& type_name)
438  {
439  value_type removed_value;
440  typename container_type::iterator current_it;
441  for (current_it = _types.begin(); current_it != _types.end(); ++current_it) {
442  if ((*current_it)->getName() == type_name) {
443  removed_value = (*current_it);
444  break;
445  }
446  }
447  if (removed_value) {
448  _types.erase(current_it);
449  if (_validator) {
450  const auto named_items = getNamedContainer();
451  named_items->erase(type_name);
452  }
453  (static_cast<subject_type*>(removed_value.get()))
454  ->detachObserver(static_cast<observer_type*>(this));
455  if (_validator) {
456  _validator->notifyChangedListContent(
457  TypeAccessListEventCode::list_item_removed, *removed_value, type_name);
458  }
459  return;
460  }
461  throw ddl::dd::Error(
462  _validation_info + "::remove", {type_name}, "value with the given name does not exist");
463  }
464 
471  std::shared_ptr<DDL_TYPE_TO_ACCESS> access(const std::string& type_name)
472  {
473  if (_validator) {
474  const auto named_items = getNamedContainer();
475  auto value_found = named_items->find(type_name);
476  if (value_found != named_items->end()) {
477  return value_found->second;
478  }
479  }
480  else {
481  for (const auto& current: _types) {
482  if (current->getName() == type_name) {
483  return current;
484  }
485  }
486  }
487  return {};
488  }
489 
495  size_t getSize() const
496  {
497  return _types.size();
498  }
499 
506  {
507  return _types.begin();
508  }
509 
516  {
517  return _types.end();
518  }
519 
526  {
527  return _types.cbegin();
528  }
529 
536  {
537  return _types.cend();
538  }
539 
546  {
547  return cbegin();
548  }
549 
556  {
557  return cend();
558  }
559 
567  bool operator==(const TypeAccessList& other) const
568  {
569  return std::equal(begin(), end(), other.begin(), [](const auto& local, const auto& other) {
570  return *(local) == *(other);
571  });
572  }
573 
581  bool operator!=(const TypeAccessList& other) const
582  {
583  return !operator==(other);
584  }
585 
590  void clear()
591  {
592  for (auto& current: _types) {
593  // unregister me as observer
594  (static_cast<subject_type*>(current.get()))
595  ->detachObserver(static_cast<observer_type*>(this));
596  }
597  if (_validator) {
598  const auto named_items = getNamedContainer();
599  named_items->clear();
600  }
601  _types.clear();
602  }
603 
608  void popBack()
609  {
610  if (!_types.empty()) {
611  auto last_element = _types[_types.size() - 1];
612  // unregister me as observer
613  (static_cast<subject_type*>(last_element.get()))
614  ->detachObserver(static_cast<observer_type*>(this));
615  // pop last element
616  if (_validator) {
617  const auto named_items = getNamedContainer();
618  named_items->erase(last_element->getName());
619  }
620  _types.pop_back();
621  if (_validator) {
622  _validator->notifyChangedListContent(TypeAccessListEventCode::list_item_popped,
623  *last_element,
624  last_element->getName());
625  }
626  }
627  else {
628  throw ddl::dd::Error(_validation_info + "::popBack", {}, "list is empty");
629  }
630  }
631 
632 public:
640  void modelChanged(event_code_type event_code,
641  subject_type& subject_changed,
642  const std::string& additional_info)
643  {
644  if (event_code == list_item_renamed) {
645  bool already_exists = false;
646  if (_validator) {
647  already_exists = _validator->validateContains(subject_changed);
648  }
649  else {
650  already_exists = countContains(subject_changed.getName()) > 1;
651  }
652  if (already_exists) {
653  throw ddl::dd::Error(
654  _validation_info + "::modelChanged",
655  {subject_changed.getName()},
656  "Renaming not possible. Value with the given name already exists");
657  }
658  else {
659  if (_validator) {
660  const auto named_items = getNamedContainer();
661  auto found_in_names = named_items->begin();
662  for (; found_in_names != named_items->end(); ++found_in_names) {
663  // we need to search it to reset the stringview
664  if (found_in_names->second->getName() == subject_changed.getName()) {
665  auto old_value = found_in_names->second;
666  named_items->erase(found_in_names);
667  (*named_items)[old_value->getName()] = old_value;
668  break;
669  }
670  }
671  }
672  }
673  }
674  if (_validator) {
675  // i should discover the shared_ptr here, but not needed at the moment
676  _validator->notifyChangedListContent(event_code, subject_changed, additional_info);
677  }
678  }
679 
680 private:
689  void deepCopy(TypeAccessList& destination, TYPE_VALIDATOR_CLASS* validator) const
690  {
691  destination = *this;
692  destination.setValidator(validator);
693  }
701  size_t countContains(const std::string& type_name) const
702  {
703  return std::count_if(_types.begin(), _types.end(), [type_name](const value_type& value) {
704  return value->getName() == type_name;
705  });
706  }
707 
708  bool checkExistenceAndEquality(const DDL_TYPE_TO_ACCESS& type_to_add)
709  {
710  // has already another type
711  bool already_exists = false;
712  if (_validator) {
713  already_exists = _validator->validateContains(type_to_add);
714  }
715  else {
716  already_exists = contains(type_to_add.getName());
717  }
718  if (already_exists) {
719  // have a look if the type does exist in this list
720  const auto type_found = get(type_to_add.getName());
721  // have a look if the type already exists here
722  if (type_found) {
723  // check if they are equal
724  if (*type_found == type_to_add) {
725  // its okay ... its the same type/content
726  return true;
727  }
728  throw ddl::dd::Error(_validation_info + "::add",
729  {type_to_add.getName()},
730  "value with the given name already exists");
731  }
732  else {
733  throw ddl::dd::Error(_validation_info + "::add",
734  {type_to_add.getName()},
735  "value with the given name already exists");
736  }
737  }
738  return false;
739  }
740 
741  void setValidator(TYPE_VALIDATOR_CLASS* validator)
742  {
743  _validator = validator;
744  if (_validator) {
745  auto named_items = getNamedContainer(); named_items->clear();
746  for (auto& value: _types) {
747  (*named_items)[value->getName()] = value;
748  }
749  }
750  }
751 
752  const container_named_type* getNamedContainer() const
753  {
754  // getNamedItemList is dead, but it must be implemented within the _validator for
755  // binary compatibility reason
756  return _validator->getNamedItemViewList();
757  }
758 
759  container_named_type* getNamedContainer()
760  {
761  // getNamedItemList is dead, but it must be implemented within the _validator for
762  // binary compatibility reason
763  return _validator->getNamedItemViewList();
764  }
765 
766  container_type _types;
767  TYPE_VALIDATOR_CLASS* _validator = {};
768  std::string _validation_info;
769 };
770 
771 } // namespace utility
772 } // namespace dd
773 } // namespace ddl
774 
775 #endif // DD_DD_ACCESS_LIST_H_INCLUDED
The ModelObserver utility template.
MODEL_SUBJECT_T subject_type
local definition of the subject code type
EVENT_CODE_T event_code_type
local definition of the event code type
Model Subject utility to define a Model Subject that notifies one or more observers.
Utility class for observable named items where the order is important.
void add(const DDL_TYPE_TO_ACCESS &type_to_add)
adds the given item
bool operator!=(const TypeAccessList &other) const
non equality operator.
container_type::const_iterator const_iterator
local definition of the container const_iterator
const_iterator begin() const
range based begin operator for const access
void insert(const size_t pos_idx, const DDL_TYPE_TO_ACCESS &type_to_add)
inserts the given item at the given pos
const_iterator cbegin() const
const begin iterator access
container_type::iterator iterator
local definition of the container iterator
void popBack()
removes the last element if exists.
void remove(const std::string &type_name)
item to remove
void emplace(DDL_TYPE_TO_ACCESS &&type_to_add)
emplace the given item
TypeAccessList & operator=(const TypeAccessList &other)
copies (deepcopy!) and overwrite the current content.
TypeAccessList(TYPE_VALIDATOR_CLASS *validator, const std::string &validation_info)
CTOR.
bool contains(const std::string &type_name) const
determines is the type name exists in this list
std::shared_ptr< DDL_TYPE_TO_ACCESS > value_type
local definition of the value type
size_t countContains(const std::string &type_name) const
determines the count of the type name exists in this list
parent_type::event_code_type event_code_type
local definition of the eventcode type
map_subject_type::observer_type observer_type
local definition of the observer type
void modelChanged(event_code_type event_code, subject_type &subject_changed, const std::string &additional_info)
overrides the observers utility function.
std::vector< value_type > container_type
local definition of the container type
OptionalSize getPosOf(const std::string &type_name) const
Get the Pos Of the item with the name type_name.
bool contains(const TypeAccessList &other) const
determines if the other is a subset of this list
const_iterator cend() const
const end iterator access
TypeAccessList(const TypeAccessList &other)
copies (deepcopy!) CTOR
size_t getSize() const
Get the Size.
TypeAccessList()=delete
no default CTOR!
bool operator==(const TypeAccessList &other) const
equality operator.
bool contains(const DDL_TYPE_TO_ACCESS &type_to_find) const
determines if the item is in this list.
DDL_TYPE_TO_ACCESS access_type
local definition of the access type
std::shared_ptr< const DDL_TYPE_TO_ACCESS > get(const std::string &type_name) const
get the item with the given name type_name
friend TYPE_VALIDATOR_CLASS
friend validator class
std::shared_ptr< DDL_TYPE_TO_ACCESS > access(const std::string &type_name)
change access to an item
TypeAccessList(TypeAccessList &&other)
move CTOR
TypeAccessListSubject< DDL_TYPE_TO_ACCESS > map_subject_type
local definition of the internal subject type
void deepCopy(TypeAccessList &destination, TYPE_VALIDATOR_CLASS *validator) const
copies the content of the of the list (by reseting the observer) and resets the validator to the give...
void clear()
clears the list and remove this as observer
std::unordered_map< std::string, value_type > container_named_compatibility_type
local definition of the container type for getNamedItemList, which was had incompatible changes withi...
iterator end()
the range based end iterator
const_iterator end() const
range based end operator for const access
TypeAccessListObserver< DDL_TYPE_TO_ACCESS > parent_type
local definition of the parent type to register observer
std::unordered_map< std::string, value_type > container_named_type
local definition of the container type for getNamedItemViewList
parent_type::subject_type subject_type
local definition of the subject type
iterator begin()
the range based begin iterator
TypeAccessList & operator=(TypeAccessList &&other)
move assignment operator
DataDefinition Model-Observer pattern utility.
OO DataDefinition Common Design.
OO DataDefinition Redesign.
TypeAccessListEventCode
Internal event code to inform the parent DD Object about the change of an item within the list.
@ validation_info
Validation Info.
Checks for std::string_view and defines HAS_STRING_VIEW accordingly.