blob: 6c35578cb4b603be95bd726145d36f854a0a2a58 [file] [log] [blame]
reed@android.com00bf85a2009-01-22 13:04:56 +00001/*
epoger@google.comec3ed6a2011-07-28 14:26:00 +00002 * Copyright 2009 The Android Open Source Project
reed@android.com00bf85a2009-01-22 13:04:56 +00003 *
epoger@google.comec3ed6a2011-07-28 14:26:00 +00004 * Use of this source code is governed by a BSD-style license that can be
5 * found in the LICENSE file.
reed@android.com00bf85a2009-01-22 13:04:56 +00006 */
7
Mike Reedab273fa2017-01-11 13:58:55 -05008#ifndef sk_tools_Registry_DEFINED
9#define sk_tools_Registry_DEFINED
reed@android.com00bf85a2009-01-22 13:04:56 +000010
Ben Wagnerd5148e32018-07-16 17:44:06 -040011#include "SkNoncopyable.h"
reed@android.com00bf85a2009-01-22 13:04:56 +000012#include "SkTypes.h"
13
Mike Reedab273fa2017-01-11 13:58:55 -050014namespace sk_tools {
15
reed@android.com00bf85a2009-01-22 13:04:56 +000016/** Template class that registers itself (in the constructor) into a linked-list
17 and provides a function-pointer. This can be used to auto-register a set of
18 services, e.g. a set of image codecs.
19 */
Mike Reedab273fa2017-01-11 13:58:55 -050020template <typename T> class Registry : SkNoncopyable {
reed@android.com00bf85a2009-01-22 13:04:56 +000021public:
Hal Canary972eba32018-07-30 17:07:07 -040022 explicit Registry(T value) : fValue(value) {
djsollen@google.com56c69772011-11-08 19:00:26 +000023#ifdef SK_BUILD_FOR_ANDROID
reed@android.com57b799e2009-04-01 20:26:42 +000024 // work-around for double-initialization bug
25 {
Mike Reedab273fa2017-01-11 13:58:55 -050026 Registry* reg = gHead;
reed@android.com57b799e2009-04-01 20:26:42 +000027 while (reg) {
28 if (reg == this) {
29 return;
30 }
31 reg = reg->fChain;
32 }
33 }
34#endif
reed@android.com00bf85a2009-01-22 13:04:56 +000035 fChain = gHead;
mtklein@google.combd6343b2013-09-04 17:20:18 +000036 gHead = this;
reed@android.com00bf85a2009-01-22 13:04:56 +000037 }
38
Mike Reedab273fa2017-01-11 13:58:55 -050039 static const Registry* Head() { return gHead; }
reed@android.com00bf85a2009-01-22 13:04:56 +000040
Mike Reedab273fa2017-01-11 13:58:55 -050041 const Registry* next() const { return fChain; }
Hal Canary972eba32018-07-30 17:07:07 -040042 const T& get() const { return fValue; }
43
44 // for (const T& t : sk_tools::Registry<T>::Range()) { process(t); }
45 struct Range {
46 struct Iterator {
47 const Registry* fPtr;
48 const T& operator*() { return SkASSERT(fPtr), fPtr->get(); }
49 void operator++() { if (fPtr) { fPtr = fPtr->next(); } }
50 bool operator!=(const Iterator& other) const { return fPtr != other.fPtr; }
51 };
52 Iterator begin() const { return Iterator{Registry::Head()}; }
53 Iterator end() const { return Iterator{nullptr}; }
54 };
reed@android.com00bf85a2009-01-22 13:04:56 +000055
56private:
Hal Canary972eba32018-07-30 17:07:07 -040057 T fValue;
Mike Reedab273fa2017-01-11 13:58:55 -050058 Registry* fChain;
reed@android.com00bf85a2009-01-22 13:04:56 +000059
Mike Reedab273fa2017-01-11 13:58:55 -050060 static Registry* gHead;
reed@android.com00bf85a2009-01-22 13:04:56 +000061};
62
reed@android.comf523e252009-01-26 23:15:37 +000063// The caller still needs to declare an instance of this somewhere
Mike Reedab273fa2017-01-11 13:58:55 -050064template <typename T> Registry<T>* Registry<T>::gHead;
65
66} // namespace sk_tools
reed@android.com00bf85a2009-01-22 13:04:56 +000067
68#endif