Loading system/gd/common/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -13,5 +13,6 @@ filegroup { "blocking_queue_unittest.cc", "class_of_device_unittest.cc", "bidi_queue_unittest.cc", "observer_registry_test.cc", ], } system/gd/common/observer_registry.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <array> #include "common/bind.h" #include "common/callback.h" #include "os/log.h" namespace bluetooth { namespace common { // Tracks an observer registration on client (observer) code. Register() returns a wrapped callback object which can // be passed to server's register API. Unregister() invalidates the wrapped callback so all callbacks that are posted // to the client handler after the client called Unregister() call and before the server processed the Unregister() // call on its handler, are dropped. // Note: Register() invalidates the previous registration. class SingleObserverRegistry { public: template <typename R, typename... T> decltype(auto) Register(Callback<R(T...)> callback) { session_++; return Bind(&SingleObserverRegistry::callback_wrapper<R, T...>, Unretained(this), session_, callback); } void Unregister() { session_++; } private: template <typename R, typename... T> void callback_wrapper(int session, Callback<R(T...)> callback, T... t) { if (session == session_) { callback.Run(std::forward<T>(t)...); } } uint8_t session_ = 0; }; // Tracks observer registration for multiple event type. Each event type is represented as an integer in [0, Capacity). template <int Capacity = 10> class MultipleObserverRegistry { public: template <typename R, typename... T> decltype(auto) Register(int event_type, Callback<R(T...)> callback) { ASSERT(event_type < Capacity); return registry_[event_type].Register(callback); } void Unregister(int event_type) { ASSERT(event_type < Capacity); registry_[event_type].Unregister(); } std::array<SingleObserverRegistry, Capacity> registry_; }; } // namespace common } // namespace bluetooth system/gd/common/observer_registry_test.cc 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/observer_registry.h" #include "common/bind.h" #include "gtest/gtest.h" namespace bluetooth { namespace common { class SingleObserverRegistryTest : public ::testing::Test { protected: void SetUp() override { registry_ = new SingleObserverRegistry; } void TearDown() override { delete registry_; } SingleObserverRegistry* registry_; }; void Increment(int* count) { (*count)++; } void IncrementBy(int* count, int n) { (*count) += n; } TEST_F(SingleObserverRegistryTest, wrapped_callback) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 1); wrapped_callback.Run(); EXPECT_EQ(count, 2); wrapped_callback.Run(); EXPECT_EQ(count, 3); registry_->Unregister(); } TEST_F(SingleObserverRegistryTest, unregister) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); registry_->Unregister(); wrapped_callback.Run(); EXPECT_EQ(count, 0); } TEST_F(SingleObserverRegistryTest, second_register) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); registry_->Unregister(); auto wrapped_callback2 = registry_->Register(Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 0); wrapped_callback2.Run(); EXPECT_EQ(count, 1); } class MultipleObserverRegistryTest : public ::testing::Test { protected: void SetUp() override { registry_ = new MultipleObserverRegistry<2>; } void TearDown() override { delete registry_; } MultipleObserverRegistry<2>* registry_; }; TEST_F(MultipleObserverRegistryTest, single_wrapped_callback) { int count = 0; auto wrapped_callback = registry_->Register(0, Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 1); wrapped_callback.Run(); EXPECT_EQ(count, 2); wrapped_callback.Run(); EXPECT_EQ(count, 3); registry_->Unregister(0); } TEST_F(MultipleObserverRegistryTest, multiple_wrapped_callback) { int count = 0; auto wrapped_callback0 = registry_->Register(0, Bind(&Increment, Unretained(&count))); auto wrapped_callback1 = registry_->Register(1, Bind(&IncrementBy, Unretained(&count), 10)); wrapped_callback0.Run(); EXPECT_EQ(count, 1); wrapped_callback1.Run(); EXPECT_EQ(count, 11); registry_->Unregister(0); wrapped_callback0.Run(); EXPECT_EQ(count, 11); wrapped_callback1.Run(); EXPECT_EQ(count, 21); registry_->Unregister(1); EXPECT_EQ(count, 21); } } // namespace common } // namespace bluetooth Loading
system/gd/common/Android.bp +1 −0 Original line number Diff line number Diff line Loading @@ -13,5 +13,6 @@ filegroup { "blocking_queue_unittest.cc", "class_of_device_unittest.cc", "bidi_queue_unittest.cc", "observer_registry_test.cc", ], }
system/gd/common/observer_registry.h 0 → 100644 +75 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #pragma once #include <array> #include "common/bind.h" #include "common/callback.h" #include "os/log.h" namespace bluetooth { namespace common { // Tracks an observer registration on client (observer) code. Register() returns a wrapped callback object which can // be passed to server's register API. Unregister() invalidates the wrapped callback so all callbacks that are posted // to the client handler after the client called Unregister() call and before the server processed the Unregister() // call on its handler, are dropped. // Note: Register() invalidates the previous registration. class SingleObserverRegistry { public: template <typename R, typename... T> decltype(auto) Register(Callback<R(T...)> callback) { session_++; return Bind(&SingleObserverRegistry::callback_wrapper<R, T...>, Unretained(this), session_, callback); } void Unregister() { session_++; } private: template <typename R, typename... T> void callback_wrapper(int session, Callback<R(T...)> callback, T... t) { if (session == session_) { callback.Run(std::forward<T>(t)...); } } uint8_t session_ = 0; }; // Tracks observer registration for multiple event type. Each event type is represented as an integer in [0, Capacity). template <int Capacity = 10> class MultipleObserverRegistry { public: template <typename R, typename... T> decltype(auto) Register(int event_type, Callback<R(T...)> callback) { ASSERT(event_type < Capacity); return registry_[event_type].Register(callback); } void Unregister(int event_type) { ASSERT(event_type < Capacity); registry_[event_type].Unregister(); } std::array<SingleObserverRegistry, Capacity> registry_; }; } // namespace common } // namespace bluetooth
system/gd/common/observer_registry_test.cc 0 → 100644 +120 −0 Original line number Diff line number Diff line /* * Copyright 2019 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "common/observer_registry.h" #include "common/bind.h" #include "gtest/gtest.h" namespace bluetooth { namespace common { class SingleObserverRegistryTest : public ::testing::Test { protected: void SetUp() override { registry_ = new SingleObserverRegistry; } void TearDown() override { delete registry_; } SingleObserverRegistry* registry_; }; void Increment(int* count) { (*count)++; } void IncrementBy(int* count, int n) { (*count) += n; } TEST_F(SingleObserverRegistryTest, wrapped_callback) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 1); wrapped_callback.Run(); EXPECT_EQ(count, 2); wrapped_callback.Run(); EXPECT_EQ(count, 3); registry_->Unregister(); } TEST_F(SingleObserverRegistryTest, unregister) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); registry_->Unregister(); wrapped_callback.Run(); EXPECT_EQ(count, 0); } TEST_F(SingleObserverRegistryTest, second_register) { int count = 0; auto wrapped_callback = registry_->Register(Bind(&Increment, Unretained(&count))); registry_->Unregister(); auto wrapped_callback2 = registry_->Register(Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 0); wrapped_callback2.Run(); EXPECT_EQ(count, 1); } class MultipleObserverRegistryTest : public ::testing::Test { protected: void SetUp() override { registry_ = new MultipleObserverRegistry<2>; } void TearDown() override { delete registry_; } MultipleObserverRegistry<2>* registry_; }; TEST_F(MultipleObserverRegistryTest, single_wrapped_callback) { int count = 0; auto wrapped_callback = registry_->Register(0, Bind(&Increment, Unretained(&count))); wrapped_callback.Run(); EXPECT_EQ(count, 1); wrapped_callback.Run(); EXPECT_EQ(count, 2); wrapped_callback.Run(); EXPECT_EQ(count, 3); registry_->Unregister(0); } TEST_F(MultipleObserverRegistryTest, multiple_wrapped_callback) { int count = 0; auto wrapped_callback0 = registry_->Register(0, Bind(&Increment, Unretained(&count))); auto wrapped_callback1 = registry_->Register(1, Bind(&IncrementBy, Unretained(&count), 10)); wrapped_callback0.Run(); EXPECT_EQ(count, 1); wrapped_callback1.Run(); EXPECT_EQ(count, 11); registry_->Unregister(0); wrapped_callback0.Run(); EXPECT_EQ(count, 11); wrapped_callback1.Run(); EXPECT_EQ(count, 21); registry_->Unregister(1); EXPECT_EQ(count, 21); } } // namespace common } // namespace bluetooth