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