1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef nsCategoryCache_h_
8 #define nsCategoryCache_h_
10 #include "mozilla/Attributes.h"
12 #include "nsIObserver.h"
14 #include "nsServiceManagerUtils.h"
16 #include "nsCOMArray.h"
17 #include "nsInterfaceHashtable.h"
20 #include "MainThreadUtils.h"
22 class nsCategoryObserver final
: public nsIObserver
{
23 ~nsCategoryObserver();
26 explicit nsCategoryObserver(const nsACString
& aCategory
);
29 void SetListener(void(aCallback
)(void*), void* aClosure
);
30 nsInterfaceHashtable
<nsCStringHashKey
, nsISupports
>& GetHash() {
37 void RemoveObservers();
39 nsInterfaceHashtable
<nsCStringHashKey
, nsISupports
> mHash
;
41 void (*mCallback
)(void*);
43 bool mObserversRemoved
;
47 * This is a helper class that caches services that are registered in a certain
48 * category. The intended usage is that a service stores a variable of type
49 * nsCategoryCache<nsIFoo> in a member variable, where nsIFoo is the interface
50 * that these services should implement. The constructor of this class should
51 * then get the name of the category.
54 class nsCategoryCache final
{
56 explicit nsCategoryCache(const char* aCategory
) : mCategoryName(aCategory
) {
57 MOZ_ASSERT(NS_IsMainThread());
60 MOZ_ASSERT(NS_IsMainThread());
62 mObserver
->ListenerDied();
66 void GetEntries(nsCOMArray
<T
>& aResult
) {
67 MOZ_ASSERT(NS_IsMainThread());
74 * This function returns an nsCOMArray of interface pointers to the cached
75 * category enries for the requested category. This was added in order to be
76 * used in call sites where the overhead of excessive allocations can be
77 * unacceptable. See bug 1360971 for an example.
79 const nsCOMArray
<T
>& GetCachedEntries() {
80 MOZ_ASSERT(NS_IsMainThread());
83 if (mCachedEntries
.IsEmpty()) {
84 AddEntries(mCachedEntries
);
86 return mCachedEntries
;
91 // Lazy initialization, so that services in this category can't
92 // cause reentrant getService (bug 386376)
94 mObserver
= new nsCategoryObserver(mCategoryName
);
95 mObserver
->SetListener(nsCategoryCache
<T
>::OnCategoryChanged
, this);
99 void AddEntries(nsCOMArray
<T
>& aResult
) {
100 for (nsISupports
* entry
: mObserver
->GetHash().Values()) {
101 nsCOMPtr
<T
> service
= do_QueryInterface(entry
);
103 aResult
.AppendElement(service
.forget());
108 static void OnCategoryChanged(void* aClosure
) {
109 MOZ_ASSERT(NS_IsMainThread());
110 auto self
= static_cast<nsCategoryCache
<T
>*>(aClosure
);
111 self
->mCachedEntries
.Clear();
115 // Not to be implemented
116 nsCategoryCache(const nsCategoryCache
<T
>&);
118 nsCString mCategoryName
;
119 RefPtr
<nsCategoryObserver
> mObserver
;
120 nsCOMArray
<T
> mCachedEntries
;