group_coordinator-impl.h 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188
  1. // Copyright 2018 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #ifndef SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_
  5. #define SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_
  6. #include "base/compiler_specific.h"
  7. #include "base/containers/contains.h"
  8. #include "base/no_destructor.h"
  9. #if DCHECK_IS_ON()
  10. #define DCHECK_INCREMENT_MUTATION_COUNT() ++mutation_count_
  11. #define DCHECK_REMEMBER_CURRENT_MUTATION_COUNT() \
  12. const auto change_number = mutation_count_
  13. #define DCHECK_MUTATION_COUNT_UNCHANGED() \
  14. DCHECK_EQ(mutation_count_, change_number)
  15. #else
  16. #define DCHECK_INCREMENT_MUTATION_COUNT()
  17. #define DCHECK_REMEMBER_CURRENT_MUTATION_COUNT()
  18. #define DCHECK_MUTATION_COUNT_UNCHANGED()
  19. #endif
  20. namespace audio {
  21. template <typename Member>
  22. GroupCoordinator<Member>::GroupCoordinator() {
  23. DETACH_FROM_SEQUENCE(sequence_checker_);
  24. }
  25. template <typename Member>
  26. GroupCoordinator<Member>::~GroupCoordinator() {
  27. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  28. DCHECK(groups_.empty());
  29. }
  30. template <typename Member>
  31. void GroupCoordinator<Member>::RegisterMember(
  32. const base::UnguessableToken& group_id,
  33. Member* member) {
  34. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  35. DCHECK(member);
  36. const auto it = FindGroup(group_id);
  37. std::vector<Member*>& members = it->second.members;
  38. DCHECK(!base::Contains(members, member));
  39. members.push_back(member);
  40. DCHECK_INCREMENT_MUTATION_COUNT();
  41. DCHECK_REMEMBER_CURRENT_MUTATION_COUNT();
  42. for (Observer* observer : it->second.observers) {
  43. observer->OnMemberJoinedGroup(member);
  44. DCHECK_MUTATION_COUNT_UNCHANGED();
  45. }
  46. }
  47. template <typename Member>
  48. void GroupCoordinator<Member>::UnregisterMember(
  49. const base::UnguessableToken& group_id,
  50. Member* member) {
  51. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  52. DCHECK(member);
  53. const auto group_it = FindGroup(group_id);
  54. std::vector<Member*>& members = group_it->second.members;
  55. const auto member_it = std::find(members.begin(), members.end(), member);
  56. DCHECK(member_it != members.end());
  57. members.erase(member_it);
  58. DCHECK_INCREMENT_MUTATION_COUNT();
  59. DCHECK_REMEMBER_CURRENT_MUTATION_COUNT();
  60. for (Observer* observer : group_it->second.observers) {
  61. observer->OnMemberLeftGroup(member);
  62. DCHECK_MUTATION_COUNT_UNCHANGED();
  63. }
  64. MaybePruneGroupMapEntry(group_it);
  65. }
  66. template <typename Member>
  67. void GroupCoordinator<Member>::AddObserver(
  68. const base::UnguessableToken& group_id,
  69. Observer* observer) {
  70. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  71. DCHECK(observer);
  72. std::vector<Observer*>& observers = FindGroup(group_id)->second.observers;
  73. DCHECK(!base::Contains(observers, observer));
  74. observers.push_back(observer);
  75. DCHECK_INCREMENT_MUTATION_COUNT();
  76. }
  77. template <typename Member>
  78. void GroupCoordinator<Member>::RemoveObserver(
  79. const base::UnguessableToken& group_id,
  80. Observer* observer) {
  81. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  82. DCHECK(observer);
  83. const auto group_it = FindGroup(group_id);
  84. std::vector<Observer*>& observers = group_it->second.observers;
  85. const auto it = std::find(observers.begin(), observers.end(), observer);
  86. DCHECK(it != observers.end());
  87. observers.erase(it);
  88. DCHECK_INCREMENT_MUTATION_COUNT();
  89. MaybePruneGroupMapEntry(group_it);
  90. }
  91. template <typename Member>
  92. void GroupCoordinator<Member>::ForEachMemberInGroup(
  93. const base::UnguessableToken& group_id,
  94. base::RepeatingCallback<void(Member*)> callback) const {
  95. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  96. DCHECK_REMEMBER_CURRENT_MUTATION_COUNT();
  97. for (Member* member : this->GetCurrentMembersUnsafe(group_id)) {
  98. callback.Run(member);
  99. // Note: If this fails, then not only is there a re-entrancy problem, but
  100. // also the iterator being used by this for-loop is no longer valid!
  101. DCHECK_MUTATION_COUNT_UNCHANGED();
  102. }
  103. }
  104. template <typename Member>
  105. const std::vector<Member*>& GroupCoordinator<Member>::GetCurrentMembersUnsafe(
  106. const base::UnguessableToken& group_id) const {
  107. DCHECK_CALLED_ON_VALID_SEQUENCE(sequence_checker_);
  108. for (const auto& entry : groups_) {
  109. if (entry.first == group_id) {
  110. return entry.second.members;
  111. }
  112. }
  113. static const base::NoDestructor<std::vector<Member*>> empty_set;
  114. return *empty_set;
  115. }
  116. template <typename Member>
  117. typename GroupCoordinator<Member>::GroupMap::iterator
  118. GroupCoordinator<Member>::FindGroup(const base::UnguessableToken& group_id) {
  119. for (auto it = groups_.begin(); it != groups_.end(); ++it) {
  120. if (it->first == group_id) {
  121. return it;
  122. }
  123. }
  124. // Group does not exist. Create a new entry.
  125. groups_.emplace_back();
  126. const auto new_it = groups_.end() - 1;
  127. new_it->first = group_id;
  128. DCHECK_INCREMENT_MUTATION_COUNT();
  129. return new_it;
  130. }
  131. template <typename Member>
  132. void GroupCoordinator<Member>::MaybePruneGroupMapEntry(
  133. typename GroupMap::iterator it) {
  134. if (it->second.members.empty() && it->second.observers.empty()) {
  135. groups_.erase(it);
  136. DCHECK_INCREMENT_MUTATION_COUNT();
  137. }
  138. }
  139. template <typename Member>
  140. GroupCoordinator<Member>::Observer::~Observer() = default;
  141. template <typename Member>
  142. GroupCoordinator<Member>::Group::Group() = default;
  143. template <typename Member>
  144. GroupCoordinator<Member>::Group::~Group() = default;
  145. template <typename Member>
  146. GroupCoordinator<Member>::Group::Group(
  147. GroupCoordinator<Member>::Group&& other) = default;
  148. template <typename Member>
  149. typename GroupCoordinator<Member>::Group& GroupCoordinator<Member>::Group::
  150. operator=(GroupCoordinator::Group&& other) = default;
  151. } // namespace audio
  152. #if DCHECK_IS_ON()
  153. #undef DCHECK_INCREMENT_MUTATION_COUNT
  154. #undef DCHECK_REMEMBER_CURRENT_MUTATION_COUNT
  155. #undef DCHECK_MUTATION_COUNT_UNCHANGED
  156. #endif
  157. #endif // SERVICES_AUDIO_GROUP_COORDINATOR_IMPL_H_