1/*
2 * Copyright (C) 2006 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#ifndef SkTemplates_DEFINED
18#define SkTemplates_DEFINED
19
20#include "SkTypes.h"
21
22/** \file SkTemplates.h
23
24    This file contains light-weight template classes for type-safe and exception-safe
25    resource management.
26*/
27
28/** \class SkAutoTCallVProc
29
30    Call a function when this goes out of scope. The template uses two
31    parameters, the object, and a function that is to be called in the destructor.
32    If detach() is called, the object reference is set to null. If the object
33    reference is null when the destructor is called, we do not call the
34    function.
35*/
36template <typename T, void (*P)(T*)> class SkAutoTCallVProc : SkNoncopyable {
37public:
38    SkAutoTCallVProc(T* obj): fObj(obj) {}
39    ~SkAutoTCallVProc() { if (fObj) P(fObj); }
40    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
41private:
42    T* fObj;
43};
44
45/** \class SkAutoTCallIProc
46
47Call a function when this goes out of scope. The template uses two
48parameters, the object, and a function that is to be called in the destructor.
49If detach() is called, the object reference is set to null. If the object
50reference is null when the destructor is called, we do not call the
51function.
52*/
53template <typename T, int (*P)(T*)> class SkAutoTCallIProc : SkNoncopyable {
54public:
55    SkAutoTCallIProc(T* obj): fObj(obj) {}
56    ~SkAutoTCallIProc() { if (fObj) P(fObj); }
57    T* detach() { T* obj = fObj; fObj = NULL; return obj; }
58private:
59    T* fObj;
60};
61
62// See also SkTScopedPtr.
63template <typename T> class SkAutoTDelete : SkNoncopyable {
64public:
65    SkAutoTDelete(T* obj, bool deleteWhenDone = true) : fObj(obj) {
66        fDeleteWhenDone = deleteWhenDone;
67    }
68    ~SkAutoTDelete() { if (fDeleteWhenDone) delete fObj; }
69
70    T*      get() const { return fObj; }
71    void    free() { delete fObj; fObj = NULL; }
72    T*      detach() { T* obj = fObj; fObj = NULL; return obj; }
73
74private:
75    T*  fObj;
76    bool fDeleteWhenDone;
77};
78
79template <typename T> class SkAutoTDeleteArray : SkNoncopyable {
80public:
81    SkAutoTDeleteArray(T array[]) : fArray(array) {}
82    ~SkAutoTDeleteArray() { delete[] fArray; }
83
84    T*      get() const { return fArray; }
85    void    free() { delete[] fArray; fArray = NULL; }
86    T*      detach() { T* array = fArray; fArray = NULL; return array; }
87
88private:
89    T*  fArray;
90};
91
92/** Allocate an array of T elements, and free the array in the destructor
93 */
94template <typename T> class SkAutoTArray : SkNoncopyable {
95public:
96    /** Allocate count number of T elements
97     */
98    SkAutoTArray(size_t count) {
99        fArray = NULL;
100        if (count) {
101            fArray = new T[count];
102        }
103        SkDEBUGCODE(fCount = count;)
104    }
105
106    ~SkAutoTArray() {
107        delete[] fArray;
108    }
109
110    /** Return the array of T elements. Will be NULL if count == 0
111     */
112    T* get() const { return fArray; }
113
114    /** Return the nth element in the array
115     */
116    T&  operator[](int index) const {
117        SkASSERT((unsigned)index < fCount);
118        return fArray[index];
119    }
120
121private:
122    T*  fArray;
123    SkDEBUGCODE(size_t fCount;)
124};
125
126/** Wraps SkAutoTArray, with room for up to N elements preallocated
127 */
128template <size_t N, typename T> class SkAutoSTArray : SkNoncopyable {
129public:
130    /** Allocate count number of T elements
131     */
132    SkAutoSTArray(size_t count) {
133        if (count > N) {
134            fArray = new T[count];
135        } else if (count) {
136            fArray = new (fStorage) T[count];
137        } else {
138            fArray = NULL;
139        }
140        fCount = count;
141    }
142
143    ~SkAutoSTArray() {
144        if (fCount > N) {
145            delete[] fArray;
146        } else {
147            T* start = fArray;
148            T* iter = start + fCount;
149            while (iter > start) {
150                (--iter)->~T();
151            }
152        }
153    }
154
155    /** Return the number of T elements in the array
156     */
157    size_t count() const { return fCount; }
158
159    /** Return the array of T elements. Will be NULL if count == 0
160     */
161    T* get() const { return fArray; }
162
163    /** Return the nth element in the array
164     */
165    T&  operator[](int index) const {
166        SkASSERT((unsigned)index < fCount);
167        return fArray[index];
168    }
169
170private:
171    size_t  fCount;
172    T*      fArray;
173    // since we come right after fArray, fStorage should be properly aligned
174    char    fStorage[N * sizeof(T)];
175};
176
177/** Allocate a temp array on the stack/heap.
178    Does NOT call any constructors/destructors on T (i.e. T must be POD)
179*/
180template <typename T> class SkAutoTMalloc : SkNoncopyable {
181public:
182    SkAutoTMalloc(size_t count)
183    {
184        fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
185    }
186    ~SkAutoTMalloc()
187    {
188        sk_free(fPtr);
189    }
190    T* get() const { return fPtr; }
191
192private:
193    T*  fPtr;
194};
195
196template <size_t N, typename T> class SkAutoSTMalloc : SkNoncopyable {
197public:
198    SkAutoSTMalloc(size_t count)
199    {
200        if (count <= N)
201            fPtr = fTStorage;
202        else
203            fPtr = (T*)sk_malloc_flags(count * sizeof(T), SK_MALLOC_THROW | SK_MALLOC_TEMP);
204    }
205    ~SkAutoSTMalloc()
206    {
207        if (fPtr != fTStorage)
208            sk_free(fPtr);
209    }
210    T* get() const { return fPtr; }
211
212private:
213    T*          fPtr;
214    union {
215        uint32_t    fStorage32[(N*sizeof(T) + 3) >> 2];
216        T           fTStorage[1];   // do NOT want to invoke T::T()
217    };
218};
219
220#endif
221
222