|
1 // |
|
2 // SkTRefArray.h |
|
3 // core |
|
4 // |
|
5 // Created by Mike Reed on 7/17/12. |
|
6 // Copyright (c) 2012 __MyCompanyName__. All rights reserved. |
|
7 // |
|
8 |
|
9 #ifndef SkTRefArray_DEFINED |
|
10 #define SkTRefArray_DEFINED |
|
11 |
|
12 #include "SkRefCnt.h" |
|
13 #include <new> |
|
14 |
|
15 /** |
|
16 * Wrapper to manage thread-safe sharing of an array of T objects. The array |
|
17 * cannot be grown or shrunk. |
|
18 */ |
|
19 template <typename T> class SkTRefArray : public SkRefCnt { |
|
20 /* |
|
21 * Shared factory to allocate the space needed for our instance plus N |
|
22 * T entries at the end. We call our constructor, but not the constructors |
|
23 * for the elements. Those are called by the proper Create method. |
|
24 */ |
|
25 static SkTRefArray<T>* Alloc(int count) { |
|
26 // space for us, and our [count] elements |
|
27 size_t size = sizeof(SkTRefArray<T>) + count * sizeof(T); |
|
28 SkTRefArray<T>* obj = (SkTRefArray<T>*)sk_malloc_throw(size); |
|
29 |
|
30 SkNEW_PLACEMENT(obj, SkTRefArray<T>); |
|
31 obj->fCount = count; |
|
32 return obj; |
|
33 } |
|
34 |
|
35 public: |
|
36 /** |
|
37 * Return a new array with 'count' elements, initialized to their default |
|
38 * value. To change them to some other value, use writableBegin/End or |
|
39 * writableAt(), but do that before this array is given to another thread. |
|
40 */ |
|
41 static SkTRefArray<T>* Create(int count) { |
|
42 SkTRefArray<T>* obj = Alloc(count); |
|
43 T* array = const_cast<T*>(obj->begin()); |
|
44 for (int i = 0; i < count; ++i) { |
|
45 SkNEW_PLACEMENT(&array[i], T); |
|
46 } |
|
47 return obj; |
|
48 } |
|
49 |
|
50 /** |
|
51 * Return a new array with 'count' elements, initialized from the provided |
|
52 * src array. To change them to some other value, use writableBegin/End or |
|
53 * writableAt(), but do that before this array is given to another thread. |
|
54 */ |
|
55 static SkTRefArray<T>* Create(const T src[], int count) { |
|
56 SkTRefArray<T>* obj = Alloc(count); |
|
57 T* array = const_cast<T*>(obj->begin()); |
|
58 for (int i = 0; i < count; ++i) { |
|
59 SkNEW_PLACEMENT_ARGS(&array[i], T, (src[i])); |
|
60 } |
|
61 return obj; |
|
62 } |
|
63 |
|
64 int count() const { return fCount; } |
|
65 const T* begin() const { return (const T*)(this + 1); } |
|
66 const T* end() const { return this->begin() + fCount; } |
|
67 const T& at(int index) const { |
|
68 SkASSERT((unsigned)index < (unsigned)fCount); |
|
69 return this->begin()[index]; |
|
70 } |
|
71 const T& operator[](int index) const { return this->at(index); } |
|
72 |
|
73 // For the writable methods, we assert that we are the only owner if we |
|
74 // call these, since other owners are not informed if we change an element. |
|
75 |
|
76 T* writableBegin() { |
|
77 SkASSERT(this->unique()); |
|
78 return (T*)(this + 1); |
|
79 } |
|
80 T* writableEnd() { |
|
81 return this->writableBegin() + fCount; |
|
82 } |
|
83 T& writableAt(int index) { |
|
84 SkASSERT((unsigned)index < (unsigned)fCount); |
|
85 return this->writableBegin()[index]; |
|
86 } |
|
87 |
|
88 protected: |
|
89 virtual void internal_dispose() const SK_OVERRIDE { |
|
90 T* array = const_cast<T*>(this->begin()); |
|
91 int n = fCount; |
|
92 |
|
93 for (int i = 0; i < n; ++i) { |
|
94 array->~T(); |
|
95 array += 1; |
|
96 } |
|
97 |
|
98 this->internal_dispose_restore_refcnt_to_1(); |
|
99 this->~SkTRefArray<T>(); |
|
100 sk_free((void*)this); |
|
101 } |
|
102 |
|
103 private: |
|
104 int fCount; |
|
105 |
|
106 // hide this |
|
107 virtual ~SkTRefArray() {} |
|
108 |
|
109 typedef SkRefCnt INHERITED; |
|
110 }; |
|
111 |
|
112 #endif |