Home | History | Annotate | Download | only in common
      1 // Copyright (C) 2014 The Android Open Source Project
      2 //
      3 // Licensed under the Apache License, Version 2.0 (the "License");
      4 // you may not use this file except in compliance with the License.
      5 // You may obtain a copy of the License at
      6 //
      7 // http://www.apache.org/licenses/LICENSE-2.0
      8 //
      9 // Unless required by applicable law or agreed to in writing, software
     10 // distributed under the License is distributed on an "AS IS" BASIS,
     11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     12 // See the License for the specific language governing permissions and
     13 // limitations under the License.
     14 
     15 #include "emugl/common/pod_vector.h"
     16 
     17 #include <stdlib.h>
     18 #include <string.h>
     19 
     20 #define USE_MALLOC_USABLE_SIZE 0
     21 
     22 namespace emugl {
     23 
     24 static inline void swapPointers(char** p1, char** p2) {
     25     char* tmp = *p1;
     26     *p1 = *p2;
     27     *p2 = tmp;
     28 }
     29 
     30 PodVectorBase::PodVectorBase(const PodVectorBase& other) {
     31     initFrom(other.begin(), other.byteSize());
     32 }
     33 
     34 PodVectorBase& PodVectorBase::operator=(const PodVectorBase& other) {
     35     initFrom(other.begin(), other.byteSize());
     36     return *this;
     37 }
     38 
     39 PodVectorBase::~PodVectorBase() {
     40     if (mBegin) {
     41         // Sanity.
     42         ::memset(mBegin, 0xee, byteSize());
     43         ::free(mBegin);
     44         mBegin = NULL;
     45         mEnd = NULL;
     46         mLimit = NULL;
     47     }
     48 }
     49 
     50 void PodVectorBase::initFrom(const void* from, size_t fromLen) {
     51     if (!fromLen || !from) {
     52         mBegin = NULL;
     53         mEnd = NULL;
     54         mLimit = NULL;
     55     } else {
     56         mBegin = static_cast<char*>(::malloc(fromLen));
     57         mEnd = mLimit = mBegin + fromLen;
     58         ::memcpy(mBegin, from, fromLen);
     59     }
     60 }
     61 
     62 void PodVectorBase::assignFrom(const PodVectorBase& other) {
     63     resize(other.byteSize(), 1U);
     64     ::memmove(begin(), other.begin(), byteSize());
     65 }
     66 
     67 void PodVectorBase::resize(size_t newSize, size_t itemSize) {
     68     const size_t kMaxSize = maxItemCapacity(itemSize);
     69     size_t oldCapacity = itemCapacity(itemSize);
     70     const size_t kMinCapacity = 256 / itemSize;
     71 
     72     if (newSize < oldCapacity) {
     73         // Only shrink if the new size is really small.
     74         if (newSize < oldCapacity / 2 && oldCapacity > kMinCapacity) {
     75             reserve(newSize, itemSize);
     76         }
     77     } else if (newSize > oldCapacity) {
     78         size_t newCapacity = oldCapacity;
     79         while (newCapacity < newSize) {
     80             size_t newCapacity2 = newCapacity + (newCapacity >> 2) + 8;
     81             if (newCapacity2 < newCapacity || newCapacity > kMaxSize) {
     82                 newCapacity = kMaxSize;
     83             } else {
     84                 newCapacity = newCapacity2;
     85             }
     86         }
     87         reserve(newCapacity, itemSize);
     88     }
     89     mEnd = mBegin + newSize * itemSize;
     90 }
     91 
     92 void PodVectorBase::reserve(size_t newSize, size_t itemSize) {
     93     if (newSize == 0) {
     94         ::free(mBegin);
     95         mBegin = NULL;
     96         mEnd = NULL;
     97         mLimit = NULL;
     98         return;
     99     }
    100 
    101     size_t oldByteSize = byteSize();
    102     size_t newByteCapacity = newSize * itemSize;
    103     char* newBegin = static_cast<char*>(::realloc(mBegin, newByteCapacity));
    104     mBegin = newBegin;
    105     mEnd = newBegin + oldByteSize;
    106 #if USE_MALLOC_USABLE_SIZE
    107     size_t usableSize = malloc_usable_size(mBegin);
    108     if (usableSize > newByteCapacity) {
    109         newByteCapacity = usableSize - (usableSize % itemSize);
    110     }
    111 #endif
    112     mLimit = newBegin + newByteCapacity;
    113     // Sanity.
    114     if (newByteCapacity > oldByteSize) {
    115         ::memset(mBegin + oldByteSize, 0, newByteCapacity - oldByteSize);
    116     }
    117 }
    118 
    119 void PodVectorBase::removeAt(size_t itemPos, size_t itemSize) {
    120     size_t count = itemCount(itemSize);
    121     if (itemPos < count) {
    122         size_t  pos = itemPos * itemSize;
    123         ::memmove(mBegin + pos,
    124                   mBegin + pos + itemSize,
    125                   byteSize() - pos - itemSize);
    126         resize(count - 1U, itemSize);
    127     }
    128 }
    129 
    130 void* PodVectorBase::insertAt(size_t itemPos, size_t itemSize) {
    131     size_t count = this->itemCount(itemSize);
    132     resize(count + 1, itemSize);
    133     size_t pos = itemPos * itemSize;
    134     if (itemPos < count) {
    135         ::memmove(mBegin + pos + itemSize,
    136                   mBegin + pos,
    137                   count * itemSize - pos);
    138         // Sanity to avoid copying pointers and other bad stuff.
    139         ::memset(mBegin + pos, 0, itemSize);
    140     }
    141     return mBegin + pos;
    142 }
    143 
    144 void PodVectorBase::swapAll(PodVectorBase* other) {
    145     swapPointers(&mBegin, &other->mBegin);
    146     swapPointers(&mEnd, &other->mEnd);
    147     swapPointers(&mLimit, &other->mLimit);
    148 }
    149 
    150 }  // namespace emugl
    151