| Index: third_party/re2/util/arena.cc
|
| diff --git a/third_party/re2/util/arena.cc b/third_party/re2/util/arena.cc
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..25753c5df5cca24eead3ca9e3f4527797e24b895
|
| --- /dev/null
|
| +++ b/third_party/re2/util/arena.cc
|
| @@ -0,0 +1,168 @@
|
| +// Copyright 2000 The RE2 Authors. All Rights Reserved.
|
| +// Use of this source code is governed by a BSD-style
|
| +// license that can be found in the LICENSE file.
|
| +
|
| +#include "util/util.h"
|
| +
|
| +namespace re2 {
|
| +
|
| +// ----------------------------------------------------------------------
|
| +// UnsafeArena::UnsafeArena()
|
| +// UnsafeArena::~UnsafeArena()
|
| +// Destroying the arena automatically calls Reset()
|
| +// ----------------------------------------------------------------------
|
| +
|
| +
|
| +UnsafeArena::UnsafeArena(const size_t block_size)
|
| + : block_size_(block_size),
|
| + freestart_(NULL), // set for real in Reset()
|
| + last_alloc_(NULL),
|
| + remaining_(0),
|
| + blocks_alloced_(1),
|
| + overflow_blocks_(NULL) {
|
| + assert(block_size > kDefaultAlignment);
|
| +
|
| + first_blocks_[0].mem = reinterpret_cast<char*>(malloc(block_size_));
|
| + first_blocks_[0].size = block_size_;
|
| +
|
| + Reset();
|
| +}
|
| +
|
| +UnsafeArena::~UnsafeArena() {
|
| + FreeBlocks();
|
| + assert(overflow_blocks_ == NULL); // FreeBlocks() should do that
|
| + // The first X blocks stay allocated always by default. Delete them now.
|
| + for (int i = 0; i < blocks_alloced_; i++)
|
| + free(first_blocks_[i].mem);
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------
|
| +// UnsafeArena::Reset()
|
| +// Clears all the memory an arena is using.
|
| +// ----------------------------------------------------------------------
|
| +
|
| +void UnsafeArena::Reset() {
|
| + FreeBlocks();
|
| + freestart_ = first_blocks_[0].mem;
|
| + remaining_ = first_blocks_[0].size;
|
| + last_alloc_ = NULL;
|
| +
|
| + // We do not know for sure whether or not the first block is aligned,
|
| + // so we fix that right now.
|
| + const int overage = reinterpret_cast<uintptr_t>(freestart_) &
|
| + (kDefaultAlignment-1);
|
| + if (overage > 0) {
|
| + const int waste = kDefaultAlignment - overage;
|
| + freestart_ += waste;
|
| + remaining_ -= waste;
|
| + }
|
| + freestart_when_empty_ = freestart_;
|
| + assert(!(reinterpret_cast<uintptr_t>(freestart_)&(kDefaultAlignment-1)));
|
| +}
|
| +
|
| +// -------------------------------------------------------------
|
| +// UnsafeArena::AllocNewBlock()
|
| +// Adds and returns an AllocatedBlock.
|
| +// The returned AllocatedBlock* is valid until the next call
|
| +// to AllocNewBlock or Reset. (i.e. anything that might
|
| +// affect overflow_blocks_).
|
| +// -------------------------------------------------------------
|
| +
|
| +UnsafeArena::AllocatedBlock* UnsafeArena::AllocNewBlock(const size_t block_size) {
|
| + AllocatedBlock *block;
|
| + // Find the next block.
|
| + if ( blocks_alloced_ < arraysize(first_blocks_) ) {
|
| + // Use one of the pre-allocated blocks
|
| + block = &first_blocks_[blocks_alloced_++];
|
| + } else { // oops, out of space, move to the vector
|
| + if (overflow_blocks_ == NULL) overflow_blocks_ = new vector<AllocatedBlock>;
|
| + // Adds another block to the vector.
|
| + overflow_blocks_->resize(overflow_blocks_->size()+1);
|
| + // block points to the last block of the vector.
|
| + block = &overflow_blocks_->back();
|
| + }
|
| +
|
| + block->mem = reinterpret_cast<char*>(malloc(block_size));
|
| + block->size = block_size;
|
| +
|
| + return block;
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------
|
| +// UnsafeArena::GetMemoryFallback()
|
| +// We take memory out of our pool, aligned on the byte boundary
|
| +// requested. If we don't have space in our current pool, we
|
| +// allocate a new block (wasting the remaining space in the
|
| +// current block) and give you that. If your memory needs are
|
| +// too big for a single block, we make a special your-memory-only
|
| +// allocation -- this is equivalent to not using the arena at all.
|
| +// ----------------------------------------------------------------------
|
| +
|
| +void* UnsafeArena::GetMemoryFallback(const size_t size, const int align) {
|
| + if (size == 0)
|
| + return NULL; // stl/stl_alloc.h says this is okay
|
| +
|
| + assert(align > 0 && 0 == (align & (align - 1))); // must be power of 2
|
| +
|
| + // If the object is more than a quarter of the block size, allocate
|
| + // it separately to avoid wasting too much space in leftover bytes
|
| + if (block_size_ == 0 || size > block_size_/4) {
|
| + // then it gets its own block in the arena
|
| + assert(align <= kDefaultAlignment); // because that's what new gives us
|
| + // This block stays separate from the rest of the world; in particular
|
| + // we don't update last_alloc_ so you can't reclaim space on this block.
|
| + return AllocNewBlock(size)->mem;
|
| + }
|
| +
|
| + const int overage =
|
| + (reinterpret_cast<uintptr_t>(freestart_) & (align-1));
|
| + if (overage) {
|
| + const int waste = align - overage;
|
| + freestart_ += waste;
|
| + if (waste < remaining_) {
|
| + remaining_ -= waste;
|
| + } else {
|
| + remaining_ = 0;
|
| + }
|
| + }
|
| + if (size > remaining_) {
|
| + AllocatedBlock *block = AllocNewBlock(block_size_);
|
| + freestart_ = block->mem;
|
| + remaining_ = block->size;
|
| + }
|
| + remaining_ -= size;
|
| + last_alloc_ = freestart_;
|
| + freestart_ += size;
|
| + assert((reinterpret_cast<uintptr_t>(last_alloc_) & (align-1)) == 0);
|
| + return reinterpret_cast<void*>(last_alloc_);
|
| +}
|
| +
|
| +// ----------------------------------------------------------------------
|
| +// UnsafeArena::FreeBlocks()
|
| +// Unlike GetMemory(), which does actual work, ReturnMemory() is a
|
| +// no-op: we don't "free" memory until Reset() is called. We do
|
| +// update some stats, though. Note we do no checking that the
|
| +// pointer you pass in was actually allocated by us, or that it
|
| +// was allocated for the size you say, so be careful here!
|
| +// FreeBlocks() does the work for Reset(), actually freeing all
|
| +// memory allocated in one fell swoop.
|
| +// ----------------------------------------------------------------------
|
| +
|
| +void UnsafeArena::FreeBlocks() {
|
| + for ( int i = 1; i < blocks_alloced_; ++i ) { // keep first block alloced
|
| + free(first_blocks_[i].mem);
|
| + first_blocks_[i].mem = NULL;
|
| + first_blocks_[i].size = 0;
|
| + }
|
| + blocks_alloced_ = 1;
|
| + if (overflow_blocks_ != NULL) {
|
| + vector<AllocatedBlock>::iterator it;
|
| + for (it = overflow_blocks_->begin(); it != overflow_blocks_->end(); ++it) {
|
| + free(it->mem);
|
| + }
|
| + delete overflow_blocks_; // These should be used very rarely
|
| + overflow_blocks_ = NULL;
|
| + }
|
| +}
|
| +
|
| +} // namespace re2
|
|
|