#ifndef PPAPI_CPP_DEV_ARRAY_DEV_H_
#define PPAPI_CPP_DEV_ARRAY_DEV_H_
#include <cstdlib>
#include <vector>
#include "ppapi/cpp/dev/may_own_ptr_dev.h"
#include "ppapi/cpp/logging.h"
#include "ppapi/cpp/output_traits.h"
namespace pp {
template <typename T>
class Array;
namespace internal {
class ArrayAllocator {
public:
static void* Alloc(uint32_t count, uint32_t size) {
if (count == 0 || size == 0)
return NULL;
return calloc(count, size);
}
static void Free(void* mem) { free(mem); }
static PP_ArrayOutput Get() {
PP_ArrayOutput array_output = { &ArrayAllocator::GetDataBuffer, NULL };
return array_output;
}
private:
static void* GetDataBuffer(void* ,
uint32_t element_count,
uint32_t element_size) {
return Alloc(element_count, element_size);
}
};
template <typename T>
struct CallbackOutputTraits<Array<T> > {
typedef typename Array<T>::CArrayType* APIArgType;
typedef Array<T> StorageType;
static inline APIArgType StorageToAPIArg(StorageType& t) {
return t.StartRawUpdate();
}
static inline Array<T>& StorageToPluginArg(StorageType& t) {
t.EndRawUpdate();
return t;
}
static inline void Initialize(StorageType* ) {}
};
}
template <class T>
class Array {
public:
typedef typename T::CArrayType CArrayType;
typedef typename T::CType CType;
Array() {}
explicit Array(uint32_t size) { Reset(size); }
Array(CArrayType* storage, NotOwned) : storage_(storage, NOT_OWNED) {
CreateWrappers();
}
Array(const Array<T>& other) { DeepCopy(*other.storage_); }
~Array() { Reset(0); }
Array<T>& operator=(const Array<T>& other) {
return operator=(*other.storage_);
}
Array<T>& operator=(const CArrayType& other) {
if (storage_.get() == &other)
return *this;
Reset(0);
DeepCopy(other);
return *this;
}
uint32_t size() const { return storage_->size; }
T& operator[](uint32_t index) {
PP_DCHECK(storage_->size == wrappers_.size());
PP_DCHECK(index < storage_->size);
PP_DCHECK(wrappers_[index]->ToStruct() == storage_->elements + index);
return *wrappers_[index];
}
const T& operator[](uint32_t index) const {
PP_DCHECK(storage_->size == wrappers_.size());
PP_DCHECK(index < storage_->size);
PP_DCHECK(wrappers_[index]->ToStruct() == storage_->elements + index);
return *wrappers_[index];
}
void Reset(uint32_t size) {
DeleteWrappers();
internal::ArrayAllocator::Free(storage_->elements);
storage_->elements = NULL;
storage_->size = size;
if (size > 0) {
storage_->elements = static_cast<CType*>(
internal::ArrayAllocator::Alloc(size, sizeof(CType)));
}
CreateWrappers();
}
CArrayType* StartRawUpdate() {
Reset(0);
return storage_.get();
}
void EndRawUpdate() { CreateWrappers(); }
private:
void DeepCopy(const CArrayType& other) {
storage_->size = other.size;
if (storage_->size > 0) {
storage_->elements = static_cast<CType*>(
internal::ArrayAllocator::Alloc(storage_->size, sizeof(CType)));
}
CreateWrappers();
for (size_t i = 0; i < storage_->size; ++i)
wrappers_[i] = other.elements[i];
}
void DeleteWrappers() {
for (typename std::vector<T*>::iterator iter = wrappers_.begin();
iter != wrappers_.end();
++iter) {
delete *iter;
}
wrappers_.clear();
}
void CreateWrappers() {
PP_DCHECK(wrappers_.empty());
uint32_t size = storage_->size;
if (size == 0)
return;
wrappers_.reserve(size);
for (size_t i = 0; i < size; ++i)
wrappers_.push_back(new T(&storage_->elements[i], NOT_OWNED));
}
internal::MayOwnPtr<CArrayType> storage_;
std::vector<T*> wrappers_;
};
}
#endif