xref: /aosp_15_r20/external/cronet/net/third_party/quiche/src/quiche/common/quiche_simple_arena.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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