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