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/. */
6 
7 #ifndef MOZILLA_GFX_USERDATA_H_
8 #define MOZILLA_GFX_USERDATA_H_
9 
10 #include <stdlib.h>
11 #include "Types.h"
12 #include "mozilla/Assertions.h"
13 
14 namespace mozilla {
15 namespace gfx {
16 
17 struct UserDataKey {
18   int unused;
19 };
20 
21 /* this class is basically a clone of the user data concept from cairo */
22 class UserData {
23   typedef void (*destroyFunc)(void* data);
24 
25  public:
UserData()26   UserData() : count(0), entries(nullptr) {}
27 
28   /* Attaches untyped userData associated with key. destroy is called on
29    * destruction */
Add(UserDataKey * key,void * userData,destroyFunc destroy)30   void Add(UserDataKey* key, void* userData, destroyFunc destroy) {
31     for (int i = 0; i < count; i++) {
32       if (key == entries[i].key) {
33         if (entries[i].destroy) {
34           entries[i].destroy(entries[i].userData);
35         }
36         entries[i].userData = userData;
37         entries[i].destroy = destroy;
38         return;
39       }
40     }
41 
42     // We could keep entries in a std::vector instead of managing it by hand
43     // but that would propagate an stl dependency out which we'd rather not
44     // do (see bug 666609). Plus, the entries array is expect to stay small
45     // so doing a realloc everytime we add a new entry shouldn't be too costly
46     entries =
47         static_cast<Entry*>(realloc(entries, sizeof(Entry) * (count + 1)));
48 
49     if (!entries) {
50       MOZ_CRASH("GFX: UserData::Add");
51     }
52 
53     entries[count].key = key;
54     entries[count].userData = userData;
55     entries[count].destroy = destroy;
56 
57     count++;
58   }
59 
60   /* Remove and return user data associated with key, without destroying it */
Remove(UserDataKey * key)61   void* Remove(UserDataKey* key) {
62     for (int i = 0; i < count; i++) {
63       if (key == entries[i].key) {
64         void* userData = entries[i].userData;
65         // decrement before looping so entries[i+1] doesn't read past the end:
66         --count;
67         for (; i < count; i++) {
68           entries[i] = entries[i + 1];
69         }
70         return userData;
71       }
72     }
73     return nullptr;
74   }
75 
76   /* Remove and destroy a given key */
RemoveAndDestroy(UserDataKey * key)77   void RemoveAndDestroy(UserDataKey* key) {
78     for (int i = 0; i < count; i++) {
79       if (key == entries[i].key) {
80         if (entries[i].destroy) {
81           entries[i].destroy(entries[i].userData);
82         }
83         // decrement before looping so entries[i+1] doesn't read past the end:
84         --count;
85         for (; i < count; i++) {
86           entries[i] = entries[i + 1];
87         }
88       }
89     }
90   }
91 
92   /* Retrives the userData for the associated key */
Get(UserDataKey * key)93   void* Get(UserDataKey* key) const {
94     for (int i = 0; i < count; i++) {
95       if (key == entries[i].key) {
96         return entries[i].userData;
97       }
98     }
99     return nullptr;
100   }
101 
Has(UserDataKey * key)102   bool Has(UserDataKey* key) {
103     for (int i = 0; i < count; i++) {
104       if (key == entries[i].key) {
105         return true;
106       }
107     }
108     return false;
109   }
110 
Destroy()111   void Destroy() {
112     for (int i = 0; i < count; i++) {
113       if (entries[i].destroy) {
114         entries[i].destroy(entries[i].userData);
115       }
116     }
117     free(entries);
118     entries = nullptr;
119     count = 0;
120   }
121 
~UserData()122   ~UserData() { Destroy(); }
123 
124  private:
125   struct Entry {
126     const UserDataKey* key;
127     void* userData;
128     destroyFunc destroy;
129   };
130 
131   int count;
132   Entry* entries;
133 };
134 
135 }  // namespace gfx
136 }  // namespace mozilla
137 
138 #endif /* MOZILLA_GFX_USERDATA_H_ */
139