1 // Copyright 2016 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "quiche/common/quiche_simple_arena.h"
6
7 #include <algorithm>
8 #include <cstring>
9
10 #include "quiche/common/platform/api/quiche_logging.h"
11
12 namespace quiche {
13
QuicheSimpleArena(size_t block_size)14 QuicheSimpleArena::QuicheSimpleArena(size_t block_size)
15 : block_size_(block_size) {}
16
17 QuicheSimpleArena::~QuicheSimpleArena() = default;
18
19 QuicheSimpleArena::QuicheSimpleArena(QuicheSimpleArena&& other) = default;
20 QuicheSimpleArena& QuicheSimpleArena::operator=(QuicheSimpleArena&& other) =
21 default;
22
Alloc(size_t size)23 char* QuicheSimpleArena::Alloc(size_t size) {
24 Reserve(size);
25 Block& b = blocks_.back();
26 QUICHE_DCHECK_GE(b.size, b.used + size);
27 char* out = b.data.get() + b.used;
28 b.used += size;
29 return out;
30 }
31
Realloc(char * original,size_t oldsize,size_t newsize)32 char* QuicheSimpleArena::Realloc(char* original, size_t oldsize,
33 size_t newsize) {
34 QUICHE_DCHECK(!blocks_.empty());
35 Block& last = blocks_.back();
36 if (last.data.get() <= original && original < last.data.get() + last.size) {
37 // (original, oldsize) is in the last Block.
38 QUICHE_DCHECK_GE(last.data.get() + last.used, original + oldsize);
39 if (original + oldsize == last.data.get() + last.used) {
40 // (original, oldsize) was the most recent allocation,
41 if (original + newsize < last.data.get() + last.size) {
42 // (original, newsize) fits in the same Block.
43 last.used += newsize - oldsize;
44 return original;
45 }
46 }
47 }
48 char* out = Alloc(newsize);
49 memcpy(out, original, oldsize);
50 return out;
51 }
52
Memdup(const char * data,size_t size)53 char* QuicheSimpleArena::Memdup(const char* data, size_t size) {
54 char* out = Alloc(size);
55 memcpy(out, data, size);
56 return out;
57 }
58
Free(char * data,size_t size)59 void QuicheSimpleArena::Free(char* data, size_t size) {
60 if (blocks_.empty()) {
61 return;
62 }
63 Block& b = blocks_.back();
64 if (size <= b.used && data + size == b.data.get() + b.used) {
65 // The memory region passed by the caller was the most recent allocation
66 // from the final block in this arena.
67 b.used -= size;
68 }
69 }
70
Reset()71 void QuicheSimpleArena::Reset() {
72 blocks_.clear();
73 status_.bytes_allocated_ = 0;
74 }
75
Reserve(size_t additional_space)76 void QuicheSimpleArena::Reserve(size_t additional_space) {
77 if (blocks_.empty()) {
78 AllocBlock(std::max(additional_space, block_size_));
79 } else {
80 const Block& last = blocks_.back();
81 if (last.size < last.used + additional_space) {
82 AllocBlock(std::max(additional_space, block_size_));
83 }
84 }
85 }
86
AllocBlock(size_t size)87 void QuicheSimpleArena::AllocBlock(size_t size) {
88 blocks_.push_back(Block(size));
89 status_.bytes_allocated_ += size;
90 }
91
Block(size_t s)92 QuicheSimpleArena::Block::Block(size_t s)
93 : data(new char[s]), size(s), used(0) {}
94
95 QuicheSimpleArena::Block::~Block() = default;
96
Block(QuicheSimpleArena::Block && other)97 QuicheSimpleArena::Block::Block(QuicheSimpleArena::Block&& other)
98 : size(other.size), used(other.used) {
99 data = std::move(other.data);
100 }
101
operator =(QuicheSimpleArena::Block && other)102 QuicheSimpleArena::Block& QuicheSimpleArena::Block::operator=(
103 QuicheSimpleArena::Block&& other) {
104 size = other.size;
105 used = other.used;
106 data = std::move(other.data);
107 return *this;
108 }
109
110 } // namespace quiche
111