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