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 
5 #ifndef SERVICES_AUDIO_GROUP_COORDINATOR_H_
6 #define SERVICES_AUDIO_GROUP_COORDINATOR_H_
7 
8 #include <algorithm>
9 #include <utility>
10 #include <vector>
11 
12 #include "base/callback.h"
13 #include "base/logging.h"
14 #include "base/macros.h"
15 #include "base/sequence_checker.h"
16 #include "base/stl_util.h"
17 #include "base/unguessable_token.h"
18 
19 namespace audio {
20 
21 // Manages a registry of group members and notifies observers as membership in
22 // the group changes.
23 template <typename Member>
24 class GroupCoordinator {
25  public:
26   // Interface for entities that wish to montior and take action as members
27   // join/leave a particular group.
28   class Observer {
29    public:
30     virtual void OnMemberJoinedGroup(Member* member) = 0;
31     virtual void OnMemberLeftGroup(Member* member) = 0;
32 
33    protected:
34     virtual ~Observer();
35   };
36 
37   GroupCoordinator();
38   ~GroupCoordinator();
39 
40   // Registers/Unregisters a group |member|. The member must remain valid until
41   // after UnregisterMember() is called.
42   void RegisterMember(const base::UnguessableToken& group_id, Member* member);
43   void UnregisterMember(const base::UnguessableToken& group_id, Member* member);
44 
45   void AddObserver(const base::UnguessableToken& group_id, Observer* observer);
46   void RemoveObserver(const base::UnguessableToken& group_id,
47                       Observer* observer);
48 
49   // Runs a |callback| for each member associated with the given |group_id|.
50   void ForEachMemberInGroup(
51       const base::UnguessableToken& group_id,
52       base::RepeatingCallback<void(Member*)> callback) const;
53 
54  protected:
55   // Returns the current members in the group having the given |group_id|. Note
56   // that the validity of the returned reference is uncertain once any of the
57   // other non-const methods are called.
58   const std::vector<Member*>& GetCurrentMembersUnsafe(
59       const base::UnguessableToken& group_id) const;
60 
61  private:
62   struct Group {
63     std::vector<Member*> members;
64     std::vector<Observer*> observers;
65 
66     Group();
67     ~Group();
68     Group(Group&& other);
69     Group& operator=(Group&& other);
70 
71    private:
72     DISALLOW_COPY_AND_ASSIGN(Group);
73   };
74 
75   using GroupMap = std::vector<std::pair<base::UnguessableToken, Group>>;
76 
77   // Returns an iterator to the entry associated with the given |group_id|,
78   // creating a new one if necessary.
79   typename GroupMap::iterator FindGroup(const base::UnguessableToken& group_id);
80 
81   // Deletes the entry in |groups_| if it has no members or observers remaining.
82   void MaybePruneGroupMapEntry(typename GroupMap::iterator it);
83 
84   GroupMap groups_;
85 
86 #if DCHECK_IS_ON()
87   // Incremented with each mutation, and used to sanity-check that there aren't
88   // any possible re-entrancy bugs. It's okay if this rolls over, since the
89   // implementation is only doing DCHECK_EQ's.
90   size_t mutation_count_ = 0;
91 #endif
92 
93   SEQUENCE_CHECKER(sequence_checker_);
94 
95   DISALLOW_COPY_AND_ASSIGN(GroupCoordinator);
96 };
97 
98 }  // namespace audio
99 
100 #endif  // SERVICES_AUDIO_GROUP_COORDINATOR_H_
101