/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #ifndef ART_COMPILER_UTILS_GROWABLE_ARRAY_H_ #define ART_COMPILER_UTILS_GROWABLE_ARRAY_H_ #include <stdint.h> #include <stddef.h> #include "arena_allocator.h" namespace art { // Type of growable list for memory tuning. enum OatListKind { kGrowableArrayMisc = 0, kGrowableArrayBlockList, kGrowableArraySSAtoDalvikMap, kGrowableArrayDfsOrder, kGrowableArrayDfsPostOrder, kGrowableArrayDomPostOrderTraversal, kGrowableArraySwitchTables, kGrowableArrayFillArrayData, kGrowableArraySuccessorBlocks, kGrowableArrayPredecessors, kGrowableArraySlowPaths, kGNumListKinds }; template<typename T> class GrowableArray { public: class Iterator { public: explicit Iterator(GrowableArray* g_list) : idx_(0), g_list_(g_list) {} explicit Iterator() : idx_(0), g_list_(nullptr) {} // NOTE: returns 0/NULL when no next. // TODO: redo to make usage consistent with other iterators. T Next() { DCHECK(g_list_ != nullptr); if (idx_ >= g_list_->Size()) { return 0; } else { return g_list_->Get(idx_++); } } void Reset() { idx_ = 0; } void Reset(GrowableArray* g_list) { idx_ = 0; g_list_ = g_list; } size_t GetIndex() const { return idx_; } private: size_t idx_; GrowableArray* g_list_; }; GrowableArray(ArenaAllocator* arena, size_t init_length, OatListKind kind = kGrowableArrayMisc) : arena_(arena), num_allocated_(init_length), num_used_(0), kind_(kind) { elem_list_ = static_cast<T*>(arena_->Alloc(sizeof(T) * init_length, kArenaAllocGrowableArray)); }; // Expand the list size to at least new length. void Resize(size_t new_length) { if (new_length <= num_allocated_) return; // If it's a small list double the size, else grow 1.5x. size_t target_length = (num_allocated_ < 128) ? num_allocated_ << 1 : num_allocated_ + (num_allocated_ >> 1); if (new_length > target_length) { target_length = new_length; } T* new_array = static_cast<T*>(arena_->Alloc(sizeof(T) * target_length, kArenaAllocGrowableArray)); memcpy(new_array, elem_list_, sizeof(T) * num_allocated_); num_allocated_ = target_length; elem_list_ = new_array; }; // NOTE: does not return storage, just resets use count. void Reset() { num_used_ = 0; } // Insert an element to the end of a list, resizing if necessary. void Insert(T elem) { if (num_used_ == num_allocated_) { Resize(num_used_ + 1); } elem_list_[num_used_++] = elem; } void InsertAt(size_t index, T elem) { DCHECK(index <= Size()); Insert(elem); for (size_t i = Size() - 1; i > index; --i) { elem_list_[i] = elem_list_[i - 1]; } elem_list_[index] = elem; } void Add(T elem) { Insert(elem); } T Get(size_t index) const { DCHECK_LT(index, num_used_); return elem_list_[index]; }; // Overwrite existing element at position index. List must be large enough. void Put(size_t index, T elem) { DCHECK_LT(index, num_used_); elem_list_[index] = elem; } void Increment(size_t index) { DCHECK_LT(index, num_used_); elem_list_[index]++; } /* * Remove an existing element from list. If there are more than one copy * of the element, only the first one encountered will be deleted. */ // TODO: consider renaming this. void Delete(T element) { bool found = false; for (size_t i = 0; i < num_used_ - 1; i++) { if (!found && elem_list_[i] == element) { found = true; } if (found) { elem_list_[i] = elem_list_[i+1]; } } // We should either have found the element, or it was the last (unscanned) element. DCHECK(found || (element == elem_list_[num_used_ - 1])); num_used_--; }; void DeleteAt(size_t index) { for (size_t i = index; i < num_used_ - 1; i++) { elem_list_[i] = elem_list_[i + 1]; } num_used_--; }; size_t GetNumAllocated() const { return num_allocated_; } size_t Size() const { return num_used_; } bool IsEmpty() const { return num_used_ == 0; } T Pop() { DCHECK_GE(num_used_, (size_t)0); return elem_list_[--num_used_]; } T Peek() const { DCHECK_GE(num_used_, (size_t)0); return elem_list_[num_used_ - 1]; } void SetSize(size_t new_size) { Resize(new_size); num_used_ = new_size; } T* GetRawStorage() const { return elem_list_; } static void* operator new(size_t size, ArenaAllocator* arena) { return arena->Alloc(sizeof(GrowableArray<T>), kArenaAllocGrowableArray); }; static void operator delete(void* p) {} // Nop. private: ArenaAllocator* const arena_; size_t num_allocated_; size_t num_used_; OatListKind kind_; T* elem_list_; }; } // namespace art #endif // ART_COMPILER_UTILS_GROWABLE_ARRAY_H_