xref: /aosp_15_r20/external/libtextclassifier/native/utils/base/arena.h (revision 993b0882672172b81d12fad7a7ac0c3e5c824a12)
1*993b0882SAndroid Build Coastguard Worker /*
2*993b0882SAndroid Build Coastguard Worker  * Copyright (C) 2018 The Android Open Source Project
3*993b0882SAndroid Build Coastguard Worker  *
4*993b0882SAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*993b0882SAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*993b0882SAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*993b0882SAndroid Build Coastguard Worker  *
8*993b0882SAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*993b0882SAndroid Build Coastguard Worker  *
10*993b0882SAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*993b0882SAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*993b0882SAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*993b0882SAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*993b0882SAndroid Build Coastguard Worker  * limitations under the License.
15*993b0882SAndroid Build Coastguard Worker  */
16*993b0882SAndroid Build Coastguard Worker 
17*993b0882SAndroid Build Coastguard Worker // Sometimes it is necessary to allocate a large number of small
18*993b0882SAndroid Build Coastguard Worker // objects.  Doing this the usual way (malloc, new) is slow,
19*993b0882SAndroid Build Coastguard Worker // especially for multithreaded programs.  A BaseArena provides a
20*993b0882SAndroid Build Coastguard Worker // mark/release method of memory management: it asks for a large chunk
21*993b0882SAndroid Build Coastguard Worker // from the operating system and doles it out bit by bit as required.
22*993b0882SAndroid Build Coastguard Worker // Then you free all the memory at once by calling BaseArena::Reset().
23*993b0882SAndroid Build Coastguard Worker //
24*993b0882SAndroid Build Coastguard Worker //
25*993b0882SAndroid Build Coastguard Worker // --Example Uses Of UnsafeArena
26*993b0882SAndroid Build Coastguard Worker //    This is the simplest way.  Just create an arena, and whenever you
27*993b0882SAndroid Build Coastguard Worker //    need a block of memory to put something in, call BaseArena::Alloc().  eg
28*993b0882SAndroid Build Coastguard Worker //        s = arena.Alloc(100);
29*993b0882SAndroid Build Coastguard Worker //        snprintf(s, 100, "%s:%d", host, port);
30*993b0882SAndroid Build Coastguard Worker //        arena.Shrink(strlen(s)+1);     // optional; see below for use
31*993b0882SAndroid Build Coastguard Worker //
32*993b0882SAndroid Build Coastguard Worker //    You'll probably use the convenience routines more often:
33*993b0882SAndroid Build Coastguard Worker //        s = arena.Strdup(host);        // a copy of host lives in the arena
34*993b0882SAndroid Build Coastguard Worker //        s = arena.Strndup(host, 100);  // we guarantee to NUL-terminate!
35*993b0882SAndroid Build Coastguard Worker //        s = arena.Memdup(protobuf, sizeof(protobuf);
36*993b0882SAndroid Build Coastguard Worker //
37*993b0882SAndroid Build Coastguard Worker //    If you go the Alloc() route, you'll probably allocate too-much-space.
38*993b0882SAndroid Build Coastguard Worker //    You can reclaim the extra space by calling Shrink() before the next
39*993b0882SAndroid Build Coastguard Worker //    Alloc() (or Strdup(), or whatever), with the #bytes you actually used.
40*993b0882SAndroid Build Coastguard Worker //       If you use this method, memory management is easy: just call Alloc()
41*993b0882SAndroid Build Coastguard Worker //    and friends a lot, and call Reset() when you're done with the data.
42*993b0882SAndroid Build Coastguard Worker //
43*993b0882SAndroid Build Coastguard Worker // FOR STRINGS: --Uses UnsafeArena
44*993b0882SAndroid Build Coastguard Worker //    This is a special case of STL (below), but is simpler.  Use an
45*993b0882SAndroid Build Coastguard Worker //    astring, which acts like a string but allocates from the passed-in
46*993b0882SAndroid Build Coastguard Worker //    arena:
47*993b0882SAndroid Build Coastguard Worker //       astring s(arena);             // or "sastring" to use a SafeArena
48*993b0882SAndroid Build Coastguard Worker //       s.assign(host);
49*993b0882SAndroid Build Coastguard Worker //       astring s2(host, hostlen, arena);
50*993b0882SAndroid Build Coastguard Worker 
51*993b0882SAndroid Build Coastguard Worker #ifndef LIBTEXTCLASSIFIER_UTILS_BASE_ARENA_H_
52*993b0882SAndroid Build Coastguard Worker #define LIBTEXTCLASSIFIER_UTILS_BASE_ARENA_H_
53*993b0882SAndroid Build Coastguard Worker 
54*993b0882SAndroid Build Coastguard Worker #include <assert.h>
55*993b0882SAndroid Build Coastguard Worker #include <string.h>
56*993b0882SAndroid Build Coastguard Worker 
57*993b0882SAndroid Build Coastguard Worker #include <vector>
58*993b0882SAndroid Build Coastguard Worker #ifdef ADDRESS_SANITIZER
59*993b0882SAndroid Build Coastguard Worker #include <sanitizer/asan_interface.h>
60*993b0882SAndroid Build Coastguard Worker #endif
61*993b0882SAndroid Build Coastguard Worker 
62*993b0882SAndroid Build Coastguard Worker #include "utils/base/integral_types.h"
63*993b0882SAndroid Build Coastguard Worker #include "utils/base/logging.h"
64*993b0882SAndroid Build Coastguard Worker 
65*993b0882SAndroid Build Coastguard Worker namespace libtextclassifier3 {
66*993b0882SAndroid Build Coastguard Worker 
67*993b0882SAndroid Build Coastguard Worker // This class is "thread-compatible": different threads can access the
68*993b0882SAndroid Build Coastguard Worker // arena at the same time without locking, as long as they use only
69*993b0882SAndroid Build Coastguard Worker // const methods.
70*993b0882SAndroid Build Coastguard Worker class BaseArena {
71*993b0882SAndroid Build Coastguard Worker  protected:  // You can't make an arena directly; only a subclass of one
72*993b0882SAndroid Build Coastguard Worker   BaseArena(char* first_block, const size_t block_size, bool align_to_page);
73*993b0882SAndroid Build Coastguard Worker 
74*993b0882SAndroid Build Coastguard Worker  public:
75*993b0882SAndroid Build Coastguard Worker   virtual ~BaseArena();
76*993b0882SAndroid Build Coastguard Worker 
77*993b0882SAndroid Build Coastguard Worker   virtual void Reset();
78*993b0882SAndroid Build Coastguard Worker 
79*993b0882SAndroid Build Coastguard Worker   // they're "slow" only 'cause they're virtual (subclasses define "fast" ones)
80*993b0882SAndroid Build Coastguard Worker   virtual char* SlowAlloc(size_t size) = 0;
81*993b0882SAndroid Build Coastguard Worker   virtual void SlowFree(void* memory, size_t size) = 0;
82*993b0882SAndroid Build Coastguard Worker   virtual char* SlowRealloc(char* memory, size_t old_size, size_t new_size) = 0;
83*993b0882SAndroid Build Coastguard Worker 
84*993b0882SAndroid Build Coastguard Worker   class Status {
85*993b0882SAndroid Build Coastguard Worker    private:
86*993b0882SAndroid Build Coastguard Worker     friend class BaseArena;
87*993b0882SAndroid Build Coastguard Worker     size_t bytes_allocated_;
88*993b0882SAndroid Build Coastguard Worker 
89*993b0882SAndroid Build Coastguard Worker    public:
Status()90*993b0882SAndroid Build Coastguard Worker     Status() : bytes_allocated_(0) {}
bytes_allocated()91*993b0882SAndroid Build Coastguard Worker     size_t bytes_allocated() const { return bytes_allocated_; }
92*993b0882SAndroid Build Coastguard Worker   };
93*993b0882SAndroid Build Coastguard Worker 
94*993b0882SAndroid Build Coastguard Worker   // Accessors and stats counters
95*993b0882SAndroid Build Coastguard Worker   // This accessor isn't so useful here, but is included so we can be
96*993b0882SAndroid Build Coastguard Worker   // type-compatible with ArenaAllocator (in arena_allocator.h).  That is,
97*993b0882SAndroid Build Coastguard Worker   // we define arena() because ArenaAllocator does, and that way you
98*993b0882SAndroid Build Coastguard Worker   // can template on either of these and know it's safe to call arena().
arena()99*993b0882SAndroid Build Coastguard Worker   virtual BaseArena* arena() { return this; }
block_size()100*993b0882SAndroid Build Coastguard Worker   size_t block_size() const { return block_size_; }
101*993b0882SAndroid Build Coastguard Worker   int block_count() const;
is_empty()102*993b0882SAndroid Build Coastguard Worker   bool is_empty() const {
103*993b0882SAndroid Build Coastguard Worker     // must check block count in case we allocated a block larger than blksize
104*993b0882SAndroid Build Coastguard Worker     return freestart_ == freestart_when_empty_ && 1 == block_count();
105*993b0882SAndroid Build Coastguard Worker   }
106*993b0882SAndroid Build Coastguard Worker 
107*993b0882SAndroid Build Coastguard Worker   // The alignment that ArenaAllocator uses except for 1-byte objects.
108*993b0882SAndroid Build Coastguard Worker   static constexpr int kDefaultAlignment = 8;
109*993b0882SAndroid Build Coastguard Worker 
110*993b0882SAndroid Build Coastguard Worker  protected:
111*993b0882SAndroid Build Coastguard Worker   bool SatisfyAlignment(const size_t alignment);
112*993b0882SAndroid Build Coastguard Worker   void MakeNewBlock(const uint32 alignment);
113*993b0882SAndroid Build Coastguard Worker   void* GetMemoryFallback(const size_t size, const int align);
GetMemory(const size_t size,const int align)114*993b0882SAndroid Build Coastguard Worker   void* GetMemory(const size_t size, const int align) {
115*993b0882SAndroid Build Coastguard Worker     assert(remaining_ <= block_size_);                   // an invariant
116*993b0882SAndroid Build Coastguard Worker     if (size > 0 && size <= remaining_ && align == 1) {  // common case
117*993b0882SAndroid Build Coastguard Worker       last_alloc_ = freestart_;
118*993b0882SAndroid Build Coastguard Worker       freestart_ += size;
119*993b0882SAndroid Build Coastguard Worker       remaining_ -= size;
120*993b0882SAndroid Build Coastguard Worker #ifdef ADDRESS_SANITIZER
121*993b0882SAndroid Build Coastguard Worker       ASAN_UNPOISON_MEMORY_REGION(last_alloc_, size);
122*993b0882SAndroid Build Coastguard Worker #endif
123*993b0882SAndroid Build Coastguard Worker       return reinterpret_cast<void*>(last_alloc_);
124*993b0882SAndroid Build Coastguard Worker     }
125*993b0882SAndroid Build Coastguard Worker     return GetMemoryFallback(size, align);
126*993b0882SAndroid Build Coastguard Worker   }
127*993b0882SAndroid Build Coastguard Worker 
128*993b0882SAndroid Build Coastguard Worker   // This doesn't actually free any memory except for the last piece allocated
ReturnMemory(void * memory,const size_t size)129*993b0882SAndroid Build Coastguard Worker   void ReturnMemory(void* memory, const size_t size) {
130*993b0882SAndroid Build Coastguard Worker     if (memory == last_alloc_ &&
131*993b0882SAndroid Build Coastguard Worker         size == static_cast<size_t>(freestart_ - last_alloc_)) {
132*993b0882SAndroid Build Coastguard Worker       remaining_ += size;
133*993b0882SAndroid Build Coastguard Worker       freestart_ = last_alloc_;
134*993b0882SAndroid Build Coastguard Worker     }
135*993b0882SAndroid Build Coastguard Worker #ifdef ADDRESS_SANITIZER
136*993b0882SAndroid Build Coastguard Worker     ASAN_POISON_MEMORY_REGION(memory, size);
137*993b0882SAndroid Build Coastguard Worker #endif
138*993b0882SAndroid Build Coastguard Worker   }
139*993b0882SAndroid Build Coastguard Worker 
140*993b0882SAndroid Build Coastguard Worker   // This is used by Realloc() -- usually we Realloc just by copying to a
141*993b0882SAndroid Build Coastguard Worker   // bigger space, but for the last alloc we can realloc by growing the region.
142*993b0882SAndroid Build Coastguard Worker   bool AdjustLastAlloc(void* last_alloc, const size_t newsize);
143*993b0882SAndroid Build Coastguard Worker 
144*993b0882SAndroid Build Coastguard Worker   Status status_;
145*993b0882SAndroid Build Coastguard Worker   size_t remaining_;
146*993b0882SAndroid Build Coastguard Worker 
147*993b0882SAndroid Build Coastguard Worker  private:
148*993b0882SAndroid Build Coastguard Worker   struct AllocatedBlock {
149*993b0882SAndroid Build Coastguard Worker     char* mem;
150*993b0882SAndroid Build Coastguard Worker     size_t size;
151*993b0882SAndroid Build Coastguard Worker     size_t alignment;
152*993b0882SAndroid Build Coastguard Worker   };
153*993b0882SAndroid Build Coastguard Worker 
154*993b0882SAndroid Build Coastguard Worker   // Allocate new new block of at least block_size, with the specified
155*993b0882SAndroid Build Coastguard Worker   // alignment.
156*993b0882SAndroid Build Coastguard Worker   // The returned AllocatedBlock* is valid until the next call to AllocNewBlock
157*993b0882SAndroid Build Coastguard Worker   // or Reset (i.e. anything that might affect overflow_blocks_).
158*993b0882SAndroid Build Coastguard Worker   AllocatedBlock* AllocNewBlock(const size_t block_size,
159*993b0882SAndroid Build Coastguard Worker                                 const uint32 alignment);
160*993b0882SAndroid Build Coastguard Worker 
161*993b0882SAndroid Build Coastguard Worker   const AllocatedBlock* IndexToBlock(int index) const;
162*993b0882SAndroid Build Coastguard Worker 
163*993b0882SAndroid Build Coastguard Worker   const size_t block_size_;
164*993b0882SAndroid Build Coastguard Worker   char* freestart_;  // beginning of the free space in most recent block
165*993b0882SAndroid Build Coastguard Worker   char* freestart_when_empty_;  // beginning of the free space when we're empty
166*993b0882SAndroid Build Coastguard Worker   char* last_alloc_;            // used to make sure ReturnBytes() is safe
167*993b0882SAndroid Build Coastguard Worker   // if the first_blocks_ aren't enough, expand into overflow_blocks_.
168*993b0882SAndroid Build Coastguard Worker   std::vector<AllocatedBlock>* overflow_blocks_;
169*993b0882SAndroid Build Coastguard Worker   // STL vector isn't as efficient as it could be, so we use an array at first
170*993b0882SAndroid Build Coastguard Worker   const bool first_block_externally_owned_;  // true if they pass in 1st block
171*993b0882SAndroid Build Coastguard Worker   const bool page_aligned_;  // when true, all blocks need to be page aligned
172*993b0882SAndroid Build Coastguard Worker   int8_t blocks_alloced_;  // how many of the first_blocks_ have been allocated
173*993b0882SAndroid Build Coastguard Worker   AllocatedBlock first_blocks_[16];  // the length of this array is arbitrary
174*993b0882SAndroid Build Coastguard Worker 
175*993b0882SAndroid Build Coastguard Worker   void FreeBlocks();  // Frees all except first block
176*993b0882SAndroid Build Coastguard Worker 
177*993b0882SAndroid Build Coastguard Worker   BaseArena(const BaseArena&) = delete;
178*993b0882SAndroid Build Coastguard Worker   BaseArena& operator=(const BaseArena&) = delete;
179*993b0882SAndroid Build Coastguard Worker };
180*993b0882SAndroid Build Coastguard Worker 
181*993b0882SAndroid Build Coastguard Worker class UnsafeArena : public BaseArena {
182*993b0882SAndroid Build Coastguard Worker  public:
183*993b0882SAndroid Build Coastguard Worker   // Allocates a thread-compatible arena with the specified block size.
UnsafeArena(const size_t block_size)184*993b0882SAndroid Build Coastguard Worker   explicit UnsafeArena(const size_t block_size)
185*993b0882SAndroid Build Coastguard Worker       : BaseArena(nullptr, block_size, false) {}
UnsafeArena(const size_t block_size,bool align)186*993b0882SAndroid Build Coastguard Worker   UnsafeArena(const size_t block_size, bool align)
187*993b0882SAndroid Build Coastguard Worker       : BaseArena(nullptr, block_size, align) {}
188*993b0882SAndroid Build Coastguard Worker 
189*993b0882SAndroid Build Coastguard Worker   // Allocates a thread-compatible arena with the specified block
190*993b0882SAndroid Build Coastguard Worker   // size. "first_block" must have size "block_size". Memory is
191*993b0882SAndroid Build Coastguard Worker   // allocated from "first_block" until it is exhausted; after that
192*993b0882SAndroid Build Coastguard Worker   // memory is allocated by allocating new blocks from the heap.
UnsafeArena(char * first_block,const size_t block_size)193*993b0882SAndroid Build Coastguard Worker   UnsafeArena(char* first_block, const size_t block_size)
194*993b0882SAndroid Build Coastguard Worker       : BaseArena(first_block, block_size, false) {}
UnsafeArena(char * first_block,const size_t block_size,bool align)195*993b0882SAndroid Build Coastguard Worker   UnsafeArena(char* first_block, const size_t block_size, bool align)
196*993b0882SAndroid Build Coastguard Worker       : BaseArena(first_block, block_size, align) {}
197*993b0882SAndroid Build Coastguard Worker 
Alloc(const size_t size)198*993b0882SAndroid Build Coastguard Worker   char* Alloc(const size_t size) {
199*993b0882SAndroid Build Coastguard Worker     return reinterpret_cast<char*>(GetMemory(size, 1));
200*993b0882SAndroid Build Coastguard Worker   }
AllocAligned(const size_t size,const int align)201*993b0882SAndroid Build Coastguard Worker   void* AllocAligned(const size_t size, const int align) {
202*993b0882SAndroid Build Coastguard Worker     return GetMemory(size, align);
203*993b0882SAndroid Build Coastguard Worker   }
204*993b0882SAndroid Build Coastguard Worker 
205*993b0882SAndroid Build Coastguard Worker   // Allocates and initializes an object on the arena.
206*993b0882SAndroid Build Coastguard Worker   template <typename T, typename... Args>
AllocAndInit(Args &&...args)207*993b0882SAndroid Build Coastguard Worker   T* AllocAndInit(Args&&... args) {
208*993b0882SAndroid Build Coastguard Worker     return new (reinterpret_cast<T*>(AllocAligned(sizeof(T), alignof(T))))
209*993b0882SAndroid Build Coastguard Worker         T(std::forward<Args>(args)...);
210*993b0882SAndroid Build Coastguard Worker   }
211*993b0882SAndroid Build Coastguard Worker 
Calloc(const size_t size)212*993b0882SAndroid Build Coastguard Worker   char* Calloc(const size_t size) {
213*993b0882SAndroid Build Coastguard Worker     void* return_value = Alloc(size);
214*993b0882SAndroid Build Coastguard Worker     memset(return_value, 0, size);
215*993b0882SAndroid Build Coastguard Worker     return reinterpret_cast<char*>(return_value);
216*993b0882SAndroid Build Coastguard Worker   }
217*993b0882SAndroid Build Coastguard Worker 
CallocAligned(const size_t size,const int align)218*993b0882SAndroid Build Coastguard Worker   void* CallocAligned(const size_t size, const int align) {
219*993b0882SAndroid Build Coastguard Worker     void* return_value = AllocAligned(size, align);
220*993b0882SAndroid Build Coastguard Worker     memset(return_value, 0, size);
221*993b0882SAndroid Build Coastguard Worker     return return_value;
222*993b0882SAndroid Build Coastguard Worker   }
223*993b0882SAndroid Build Coastguard Worker 
224*993b0882SAndroid Build Coastguard Worker   // Free does nothing except for the last piece allocated.
Free(void * memory,size_t size)225*993b0882SAndroid Build Coastguard Worker   void Free(void* memory, size_t size) { ReturnMemory(memory, size); }
SlowAlloc(size_t size)226*993b0882SAndroid Build Coastguard Worker   char* SlowAlloc(size_t size) override {  // "slow" 'cause it's virtual
227*993b0882SAndroid Build Coastguard Worker     return Alloc(size);
228*993b0882SAndroid Build Coastguard Worker   }
SlowFree(void * memory,size_t size)229*993b0882SAndroid Build Coastguard Worker   void SlowFree(void* memory,
230*993b0882SAndroid Build Coastguard Worker                 size_t size) override {  // "slow" 'cause it's virt
231*993b0882SAndroid Build Coastguard Worker     Free(memory, size);
232*993b0882SAndroid Build Coastguard Worker   }
SlowRealloc(char * memory,size_t old_size,size_t new_size)233*993b0882SAndroid Build Coastguard Worker   char* SlowRealloc(char* memory, size_t old_size, size_t new_size) override {
234*993b0882SAndroid Build Coastguard Worker     return Realloc(memory, old_size, new_size);
235*993b0882SAndroid Build Coastguard Worker   }
236*993b0882SAndroid Build Coastguard Worker 
Memdup(const char * s,size_t bytes)237*993b0882SAndroid Build Coastguard Worker   char* Memdup(const char* s, size_t bytes) {
238*993b0882SAndroid Build Coastguard Worker     char* newstr = Alloc(bytes);
239*993b0882SAndroid Build Coastguard Worker     memcpy(newstr, s, bytes);
240*993b0882SAndroid Build Coastguard Worker     return newstr;
241*993b0882SAndroid Build Coastguard Worker   }
MemdupPlusNUL(const char * s,size_t bytes)242*993b0882SAndroid Build Coastguard Worker   char* MemdupPlusNUL(const char* s, size_t bytes) {  // like "string(s, len)"
243*993b0882SAndroid Build Coastguard Worker     char* newstr = Alloc(bytes + 1);
244*993b0882SAndroid Build Coastguard Worker     memcpy(newstr, s, bytes);
245*993b0882SAndroid Build Coastguard Worker     newstr[bytes] = '\0';
246*993b0882SAndroid Build Coastguard Worker     return newstr;
247*993b0882SAndroid Build Coastguard Worker   }
Strdup(const char * s)248*993b0882SAndroid Build Coastguard Worker   char* Strdup(const char* s) { return Memdup(s, strlen(s) + 1); }
249*993b0882SAndroid Build Coastguard Worker   // Unlike libc's strncpy, I always NUL-terminate.  libc's semantics are dumb.
250*993b0882SAndroid Build Coastguard Worker   // This will allocate at most n+1 bytes (+1 is for the nul terminator).
Strndup(const char * s,size_t n)251*993b0882SAndroid Build Coastguard Worker   char* Strndup(const char* s, size_t n) {
252*993b0882SAndroid Build Coastguard Worker     // Use memchr so we don't walk past n.
253*993b0882SAndroid Build Coastguard Worker     // We can't use the one in //strings since this is the base library,
254*993b0882SAndroid Build Coastguard Worker     // so we have to reinterpret_cast from the libc void*.
255*993b0882SAndroid Build Coastguard Worker     const char* eos = reinterpret_cast<const char*>(memchr(s, '\0', n));
256*993b0882SAndroid Build Coastguard Worker     // if no null terminator found, use full n
257*993b0882SAndroid Build Coastguard Worker     const size_t bytes = (eos == nullptr) ? n : eos - s;
258*993b0882SAndroid Build Coastguard Worker     return MemdupPlusNUL(s, bytes);
259*993b0882SAndroid Build Coastguard Worker   }
260*993b0882SAndroid Build Coastguard Worker 
261*993b0882SAndroid Build Coastguard Worker   // You can realloc a previously-allocated string either bigger or smaller.
262*993b0882SAndroid Build Coastguard Worker   // We can be more efficient if you realloc a string right after you allocate
263*993b0882SAndroid Build Coastguard Worker   // it (eg allocate way-too-much space, fill it, realloc to just-big-enough)
264*993b0882SAndroid Build Coastguard Worker   char* Realloc(char* original, size_t oldsize, size_t newsize);
265*993b0882SAndroid Build Coastguard Worker   // If you know the new size is smaller (or equal), you don't need to know
266*993b0882SAndroid Build Coastguard Worker   // oldsize.  We don't check that newsize is smaller, so you'd better be sure!
Shrink(char * s,size_t newsize)267*993b0882SAndroid Build Coastguard Worker   char* Shrink(char* s, size_t newsize) {
268*993b0882SAndroid Build Coastguard Worker     AdjustLastAlloc(s, newsize);  // reclaim space if we can
269*993b0882SAndroid Build Coastguard Worker     return s;                     // never need to move if we go smaller
270*993b0882SAndroid Build Coastguard Worker   }
271*993b0882SAndroid Build Coastguard Worker 
272*993b0882SAndroid Build Coastguard Worker   // We make a copy so you can keep track of status at a given point in time
status()273*993b0882SAndroid Build Coastguard Worker   Status status() const { return status_; }
274*993b0882SAndroid Build Coastguard Worker 
275*993b0882SAndroid Build Coastguard Worker   // Number of bytes remaining before the arena has to allocate another block.
bytes_until_next_allocation()276*993b0882SAndroid Build Coastguard Worker   size_t bytes_until_next_allocation() const { return remaining_; }
277*993b0882SAndroid Build Coastguard Worker 
278*993b0882SAndroid Build Coastguard Worker  private:
279*993b0882SAndroid Build Coastguard Worker   UnsafeArena(const UnsafeArena&) = delete;
280*993b0882SAndroid Build Coastguard Worker   UnsafeArena& operator=(const UnsafeArena&) = delete;
281*993b0882SAndroid Build Coastguard Worker 
282*993b0882SAndroid Build Coastguard Worker   virtual void UnusedKeyMethod();  // Dummy key method to avoid weak vtable.
283*993b0882SAndroid Build Coastguard Worker };
284*993b0882SAndroid Build Coastguard Worker 
285*993b0882SAndroid Build Coastguard Worker }  // namespace libtextclassifier3
286*993b0882SAndroid Build Coastguard Worker 
287*993b0882SAndroid Build Coastguard Worker #endif  // LIBTEXTCLASSIFIER_UTILS_BASE_ARENA_H_
288