180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//
280ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//  SkTRefArray.h
380ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//  core
480ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//
580ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//  Created by Mike Reed on 7/17/12.
680ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//  Copyright (c) 2012 __MyCompanyName__. All rights reserved.
780ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com//
880ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
980ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com#ifndef SkTRefArray_DEFINED
1080ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com#define SkTRefArray_DEFINED
1180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
12f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com#include "SkRefCnt.h"
130c6a736617d242547135b731adb8333581b2f2dcreed@google.com#include <new>
1480ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
1580ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com/**
1680ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com *  Wrapper to manage thread-safe sharing of an array of T objects. The array
1780ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com *  cannot be grown or shrunk.
1880ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com */
19f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comtemplate <typename T> class SkTRefArray : public SkRefCnt {
20f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /*
21f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Shared factory to allocate the space needed for our instance plus N
22f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  T entries at the end. We call our constructor, but not the constructors
23f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  for the elements. Those are called by the proper Create method.
24f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
25f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    static SkTRefArray<T>* Alloc(int count) {
26f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        // space for us, and our [count] elements
2780ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        size_t size = sizeof(SkTRefArray<T>) + count * sizeof(T);
2880ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        SkTRefArray<T>* obj = (SkTRefArray<T>*)sk_malloc_throw(size);
29fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
30f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkNEW_PLACEMENT(obj, SkTRefArray<T>);
3180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        obj->fCount = count;
32f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        return obj;
33f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    }
340c6a736617d242547135b731adb8333581b2f2dcreed@google.com
35f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.compublic:
36f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
37f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Return a new array with 'count' elements, initialized to their default
38f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  value. To change them to some other value, use writableBegin/End or
39f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  writableAt(), but do that before this array is given to another thread.
40f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
41f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    static SkTRefArray<T>* Create(int count) {
42f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkTRefArray<T>* obj = Alloc(count);
4380ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        T* array = const_cast<T*>(obj->begin());
4480ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        for (int i = 0; i < count; ++i) {
45f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com            SkNEW_PLACEMENT(&array[i], T);
4680ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        }
4780ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        return obj;
4880ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    }
49fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
50f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    /**
51f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  Return a new array with 'count' elements, initialized from the provided
52f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  src array. To change them to some other value, use writableBegin/End or
53f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     *  writableAt(), but do that before this array is given to another thread.
54f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com     */
55f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    static SkTRefArray<T>* Create(const T src[], int count) {
56f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkTRefArray<T>* obj = Alloc(count);
57f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        T* array = const_cast<T*>(obj->begin());
58f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        for (int i = 0; i < count; ++i) {
59f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com            SkNEW_PLACEMENT_ARGS(&array[i], T, (src[i]));
60f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        }
61f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        return obj;
62f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    }
63fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
6480ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    int count() const { return fCount; }
6580ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    const T* begin() const { return (const T*)(this + 1); }
66f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    const T* end() const { return this->begin() + fCount; }
67f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    const T& at(int index) const {
6880ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
6980ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        return this->begin()[index];
7080ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    }
71f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    const T& operator[](int index) const { return this->at(index); }
7280ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
73f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    // For the writable methods, we assert that we are the only owner if we
74f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    // call these, since other owners are not informed if we change an element.
7580ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
76f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    T* writableBegin() {
77f64c6842c15e1ba126639be7578e4642cb396987bungeman@google.com        SkASSERT(this->unique());
78f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        return (T*)(this + 1);
7980ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    }
80f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    T* writableEnd() {
81f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        return this->writableBegin() + fCount;
82f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    }
83f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    T& writableAt(int index) {
84f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        SkASSERT((unsigned)index < (unsigned)fCount);
85f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        return this->writableBegin()[index];
8680ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    }
8780ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
88f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprotected:
89f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    virtual void internal_dispose() const SK_OVERRIDE {
9080ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        T* array = const_cast<T*>(this->begin());
9180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        int n = fCount;
92fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
9380ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        for (int i = 0; i < n; ++i) {
9480ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com            array->~T();
9580ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com            array += 1;
9680ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com        }
97fbfcd5602128ec010c82cb733c9cdc0a3254f9f3rmistry@google.com
98f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        this->internal_dispose_restore_refcnt_to_1();
99f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        this->~SkTRefArray<T>();
100f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com        sk_free((void*)this);
10180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com    }
102f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com
103f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.comprivate:
104f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    int fCount;
105f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com
106f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    // hide this
107f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    virtual ~SkTRefArray() {}
108f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com
109f79430350d9f06a72b307af879d7f3bdec7ff706reed@google.com    typedef SkRefCnt INHERITED;
11080ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com};
11180ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com
11280ba7964cde0f7805d76cf0170cf3b920146a007reed@google.com#endif
113