Use std::vector with a custom allocator wrapping PageAllocator for wasteful_vector

Patch by Mike Hommey <mh@glandium.org>, R=me at https://breakpad.appspot.com/581002/

git-svn-id: http://google-breakpad.googlecode.com/svn/trunk@1184 4c0a9323-5329-0410-9bdc-e9ce6186880e
This commit is contained in:
ted.mielczarek@gmail.com 2013-05-17 19:47:10 +00:00
parent 54e75078d6
commit bcf029f333

View file

@ -30,13 +30,13 @@
#ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_ #ifndef GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#define GOOGLE_BREAKPAD_COMMON_MEMORY_H_ #define GOOGLE_BREAKPAD_COMMON_MEMORY_H_
#include <memory>
#include <vector>
#include <stdint.h> #include <stdint.h>
#include <stdlib.h> #include <stdlib.h>
#include <unistd.h> #include <unistd.h>
#include <sys/mman.h> #include <sys/mman.h>
#include <algorithm>
#ifdef __APPLE__ #ifdef __APPLE__
#define sys_mmap mmap #define sys_mmap mmap
#define sys_mmap2 mmap #define sys_mmap2 mmap
@ -133,83 +133,42 @@ class PageAllocator {
unsigned page_offset_; unsigned page_offset_;
}; };
// A wasteful vector is like a normal std::vector, except that it's very much // Wrapper to use with STL containers
// simplier and it allocates memory from a PageAllocator. It's wasteful template <typename T>
// because, when resizing, it always allocates a whole new array since the struct PageStdAllocator: public std::allocator<T> {
// PageAllocator doesn't support realloc. typedef typename std::allocator<T>::pointer pointer;
template<class T> typedef typename std::allocator<T>::size_type size_type;
class wasteful_vector {
public: PageStdAllocator(PageAllocator& allocator): allocator_(allocator) {}
wasteful_vector(PageAllocator *allocator, unsigned size_hint = 16) template <class Other> PageStdAllocator(const PageStdAllocator<Other>& other):
: allocator_(allocator), allocator_(other.allocator_) {}
a_((T*) allocator->Alloc(sizeof(T) * size_hint)),
allocated_(size_hint), inline pointer allocator(size_type n, const void* = 0) {
used_(0) { return allocator_.Alloc(sizeof(T) * n);
} }
T& back() { inline void deallocate(pointer, size_type) {
return a_[used_ - 1]; // The PageAllocator doesn't free.
} }
const T& back() const { template <typename U> struct rebind {
return a_[used_ - 1]; typedef PageStdAllocator<U> other;
} };
bool empty() const {
return used_ == 0;
}
void push_back(const T& new_element) {
if (used_ == allocated_)
Realloc(std::max(allocated_ * 2, 1u));
a_[used_++] = new_element;
}
size_t size() const {
return used_;
}
void resize(unsigned sz, T c = T()) {
// No need to test "sz >= 0", as "sz" is unsigned.
if (sz <= used_) {
used_ = sz;
} else {
unsigned a = allocated_;
if (sz > a) {
while (sz > a) {
a *= 2;
}
Realloc(a);
}
while (sz > used_) {
a_[used_++] = c;
}
}
}
T& operator[](size_t index) {
return a_[index];
}
const T& operator[](size_t index) const {
return a_[index];
}
private: private:
void Realloc(unsigned new_size) { PageAllocator& allocator_;
T *new_array = };
reinterpret_cast<T*>(allocator_->Alloc(sizeof(T) * new_size));
if (new_size > 0) {
memcpy(new_array, a_, used_ * sizeof(T));
}
a_ = new_array;
allocated_ = new_size;
}
PageAllocator *const allocator_; // A wasteful vector is a std::vector, except that it allocates memory from a
T *a_; // pointer to an array of |allocated_| elements. // PageAllocator. It's wasteful because, when resizing, it always allocates a
unsigned allocated_; // size of |a_|, in elements. // whole new array since the PageAllocator doesn't support realloc.
unsigned used_; // number of used slots in |a_|. template<class T>
class wasteful_vector: public std::vector<T, PageStdAllocator<T> > {
public:
wasteful_vector(PageAllocator* allocator, unsigned size_hint = 16)
: std::vector<T, PageStdAllocator<T> >(PageStdAllocator<T>(*allocator)) {
std::vector<T, PageStdAllocator<T> >::reserve(size_hint);
}
}; };
} // namespace google_breakpad } // namespace google_breakpad