Home | History | Annotate | Download | only in utils
      1 /*
      2  * Copyright (C) 2013 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 ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
     18 #define ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
     19 
     20 #include <stdint.h>
     21 #include <stddef.h>
     22 #include "arena_allocator.h"
     23 
     24 namespace art {
     25 
     26 // Type of growable list for memory tuning.
     27 enum OatListKind {
     28   kGrowableArrayMisc = 0,
     29   kGrowableArrayBlockList,
     30   kGrowableArraySSAtoDalvikMap,
     31   kGrowableArrayDfsOrder,
     32   kGrowableArrayDfsPostOrder,
     33   kGrowableArrayDomPostOrderTraversal,
     34   kGrowableArraySwitchTables,
     35   kGrowableArrayFillArrayData,
     36   kGrowableArraySuccessorBlocks,
     37   kGrowableArrayPredecessors,
     38   kGrowableArraySlowPaths,
     39   kGNumListKinds
     40 };
     41 
     42 template<typename T>
     43 class GrowableArray {
     44   public:
     45     class Iterator {
     46       public:
     47         explicit Iterator(GrowableArray* g_list)
     48           : idx_(0),
     49             g_list_(g_list) {}
     50 
     51         explicit Iterator()
     52           : idx_(0),
     53             g_list_(nullptr) {}
     54 
     55         // NOTE: returns 0/NULL when no next.
     56         // TODO: redo to make usage consistent with other iterators.
     57         T Next() {
     58           DCHECK(g_list_ != nullptr);
     59           if (idx_ >= g_list_->Size()) {
     60             return 0;
     61           } else {
     62             return g_list_->Get(idx_++);
     63           }
     64         }
     65 
     66         void Reset() {
     67           idx_ = 0;
     68         }
     69 
     70         void Reset(GrowableArray* g_list) {
     71           idx_ = 0;
     72           g_list_ = g_list;
     73         }
     74 
     75         size_t GetIndex() const {
     76           return idx_;
     77         }
     78 
     79       private:
     80         size_t idx_;
     81         GrowableArray* g_list_;
     82     };
     83 
     84     GrowableArray(ArenaAllocator* arena, size_t init_length, OatListKind kind = kGrowableArrayMisc)
     85       : arena_(arena),
     86         num_allocated_(init_length),
     87         num_used_(0),
     88         kind_(kind) {
     89       elem_list_ = static_cast<T*>(arena_->Alloc(sizeof(T) * init_length,
     90                                                  kArenaAllocGrowableArray));
     91     };
     92 
     93 
     94     // Expand the list size to at least new length.
     95     void Resize(size_t new_length) {
     96       if (new_length <= num_allocated_) return;
     97       // If it's a small list double the size, else grow 1.5x.
     98       size_t target_length =
     99           (num_allocated_ < 128) ? num_allocated_ << 1 : num_allocated_ + (num_allocated_ >> 1);
    100       if (new_length > target_length) {
    101          target_length = new_length;
    102       }
    103       T* new_array = static_cast<T*>(arena_->Alloc(sizeof(T) * target_length,
    104                                                    kArenaAllocGrowableArray));
    105       memcpy(new_array, elem_list_, sizeof(T) * num_allocated_);
    106       num_allocated_ = target_length;
    107       elem_list_ = new_array;
    108     };
    109 
    110     // NOTE: does not return storage, just resets use count.
    111     void Reset() {
    112       num_used_ = 0;
    113     }
    114 
    115     // Insert an element to the end of a list, resizing if necessary.
    116     void Insert(T elem) {
    117       if (num_used_ == num_allocated_) {
    118         Resize(num_used_ + 1);
    119       }
    120       elem_list_[num_used_++] = elem;
    121     }
    122 
    123     void InsertAt(size_t index, T elem) {
    124       DCHECK(index <= Size());
    125       Insert(elem);
    126       for (size_t i = Size() - 1; i > index; --i) {
    127         elem_list_[i] = elem_list_[i - 1];
    128       }
    129       elem_list_[index] = elem;
    130     }
    131 
    132     void Add(T elem) {
    133       Insert(elem);
    134     }
    135 
    136     T Get(size_t index) const {
    137       DCHECK_LT(index, num_used_);
    138       return elem_list_[index];
    139     };
    140 
    141     // Overwrite existing element at position index.  List must be large enough.
    142     void Put(size_t index, T elem) {
    143       DCHECK_LT(index, num_used_);
    144       elem_list_[index] = elem;
    145     }
    146 
    147     void Increment(size_t index) {
    148       DCHECK_LT(index, num_used_);
    149       elem_list_[index]++;
    150     }
    151 
    152     /*
    153      * Remove an existing element from list.  If there are more than one copy
    154      * of the element, only the first one encountered will be deleted.
    155      */
    156     // TODO: consider renaming this.
    157     void Delete(T element) {
    158       bool found = false;
    159       for (size_t i = 0; i < num_used_ - 1; i++) {
    160         if (!found && elem_list_[i] == element) {
    161           found = true;
    162         }
    163         if (found) {
    164           elem_list_[i] = elem_list_[i+1];
    165         }
    166       }
    167       // We should either have found the element, or it was the last (unscanned) element.
    168       DCHECK(found || (element == elem_list_[num_used_ - 1]));
    169       num_used_--;
    170     };
    171 
    172     void DeleteAt(size_t index) {
    173       for (size_t i = index; i < num_used_ - 1; i++) {
    174         elem_list_[i] = elem_list_[i + 1];
    175       }
    176       num_used_--;
    177     };
    178 
    179     size_t GetNumAllocated() const { return num_allocated_; }
    180 
    181     size_t Size() const { return num_used_; }
    182 
    183     bool IsEmpty() const { return num_used_ == 0; }
    184 
    185     T Pop() {
    186       DCHECK_GE(num_used_, (size_t)0);
    187       return elem_list_[--num_used_];
    188     }
    189 
    190     T Peek() const {
    191       DCHECK_GE(num_used_, (size_t)0);
    192       return elem_list_[num_used_ - 1];
    193     }
    194 
    195     void SetSize(size_t new_size) {
    196       Resize(new_size);
    197       num_used_ = new_size;
    198     }
    199 
    200     T* GetRawStorage() const { return elem_list_; }
    201 
    202     static void* operator new(size_t size, ArenaAllocator* arena) {
    203       return arena->Alloc(sizeof(GrowableArray<T>), kArenaAllocGrowableArray);
    204     };
    205     static void operator delete(void* p) {}  // Nop.
    206 
    207   private:
    208     ArenaAllocator* const arena_;
    209     size_t num_allocated_;
    210     size_t num_used_;
    211     OatListKind kind_;
    212     T* elem_list_;
    213 };
    214 
    215 }  // namespace art
    216 
    217 #endif  // ART_COMPILER_UTILS_GROWABLE_ARRAY_H_
    218