Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  ArenaAllocator.h   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#ifndef mozilla_ArenaAllocator_h
#define mozilla_ArenaAllocator_h

#include <algorithm>
#include <cstdint>

#include "mozilla/Assertions.h"
#include "mozilla/fallible.h"
#include "mozilla/Likely.h"
#include "mozilla/MemoryChecking.h"
#include "mozilla/MemoryReporting.h"
#include "mozilla/OperatorNewExtensions.h"
#include "mozilla/Poison.h"
#include "mozilla/TemplateLib.h"
#include "nsDebug.h"

namespace mozilla {

/**
 * A very simple arena allocator based on NSPR's PLArena.
 *
 * The arena allocator only provides for allocation, all memory is retained
 * until the allocator is destroyed. It's useful for situations where a large
 * amount of small transient allocations are expected.
 *
 * Example usage:
 *
 * // Define an allocator that is page sized and returns allocations that are
 * // 8-byte aligned.
 * ArenaAllocator<4096, 8> a;
 * for (int i = 0; i < 1000; i++) {
 *   DoSomething(a.Allocate(i));
 * }
 */

template <size_t ArenaSize, size_t Alignment = 1>
class ArenaAllocator {
 public:
  constexpr ArenaAllocator() : mHead(), mCurrent(nullptr) {
    static_assert(mozilla::tl::FloorLog2<Alignment>::value ==
                      mozilla::tl::CeilingLog2<Alignment>::value,
                  "ArenaAllocator alignment must be a power of two");
  }

  ArenaAllocator(const ArenaAllocator&) = delete;
  ArenaAllocator& operator=(const ArenaAllocator&) = delete;

  /**
   * Frees all internal arenas but does not call destructors for objects
   * allocated out of the arena.
   */

  ~ArenaAllocator() { Clear(); }

  /**
   * Fallibly allocates a chunk of memory with the given size from the internal
   * arenas. If the allocation size is larger than the chosen arena a size an
   * entire arena is allocated and used.
   */

  MOZ_ALWAYS_INLINE void* Allocate(size_t aSize, const fallible_t&) {
    MOZ_RELEASE_ASSERT(aSize, "Allocation size must be non-zero");
    return InternalAllocate(AlignedSize(aSize));
  }

  void* Allocate(size_t aSize) {
    void* p = Allocate(aSize, fallible);
    if (MOZ_UNLIKELY(!p)) {
      NS_ABORT_OOM(std::max(aSize, ArenaSize));
    }

    return p;
  }

  /**
   * Frees all entries. The allocator can be reused after this is called.
   *
   * NB: This will not run destructors of any objects that were allocated from
   * the arena.
   */

  void Clear() {
    // Free all chunks.
    auto a = mHead.next;
    while (a) {
      auto tmp = a;
      a = a->next;
      free(tmp);
    }

    // Reset the list head.
    mHead.next = nullptr;
    mCurrent = nullptr;
  }

  /**
   * Adjusts the given size to the required alignment.
   */

  static constexpr size_t AlignedSize(size_t aSize) {
    return (aSize + (Alignment - 1)) & ~(Alignment - 1);
  }

  size_t SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
    size_t s = 0;
    for (auto arena = mHead.next; arena; arena = arena->next) {
      s += aMallocSizeOf(arena);
    }

    return s;
  }

  void Check() {
    if (mCurrent) {
      mCurrent->canary.Check();
    }
  }

 private:
  struct ArenaHeader {
    /**
     * The location in memory of the data portion of the arena.
     */

    uintptr_t offset;
    /**
     * The location in memory of the end of the data portion of the arena.
     */

    uintptr_t tail;
  };

  struct ArenaChunk {
    constexpr ArenaChunk() : header{0, 0}, next(nullptr) {}

    explicit ArenaChunk(size_t aSize)
        : header{AlignedSize(uintptr_t(this + 1)), uintptr_t(this) + aSize},
          next(nullptr) {}

    CorruptionCanary canary;
    ArenaHeader header;
    ArenaChunk* next;

    /**
     * Allocates a chunk of memory out of the arena and advances the offset.
     */

    void* Allocate(size_t aSize) {
      MOZ_ASSERT(aSize <= Available());
      char* p = reinterpret_cast<char*>(header.offset);
      MOZ_RELEASE_ASSERT(p);
      header.offset += aSize;
      canary.Check();
      MOZ_MAKE_MEM_UNDEFINED(p, aSize);
      return p;
    }

    /**
     * Calculates the amount of space available for allocation in this chunk.
     */

    size_t Available() const { return header.tail - header.offset; }
  };

  /**
   * Allocates an arena chunk of the given size and initializes its header.
   */

  ArenaChunk* AllocateChunk(size_t aSize) {
    static const size_t kOffset = AlignedSize(sizeof(ArenaChunk));
    MOZ_ASSERT(kOffset < aSize);

    const size_t chunkSize = aSize + kOffset;
    void* p = malloc(chunkSize);
    if (!p) {
      return nullptr;
    }

    ArenaChunk* arena = new (KnownNotNull, p) ArenaChunk(chunkSize);
    MOZ_MAKE_MEM_NOACCESS((void*)arena->header.offset,
                          arena->header.tail - arena->header.offset);

    // Insert into the head of the list.
    arena->next = mHead.next;
    mHead.next = arena;

    // Only update |mCurrent| if this is a standard allocation, large
    // allocations will always end up full so there's no point in updating
    // |mCurrent| in that case.
    if (aSize == ArenaSize - kOffset) {
      mCurrent = arena;
    }

    return arena;
  }

  MOZ_ALWAYS_INLINE void* InternalAllocate(size_t aSize) {
    static_assert(ArenaSize > AlignedSize(sizeof(ArenaChunk)),
                  "Arena size must be greater than the header size");

    static const size_t kMaxArenaCapacity =
        ArenaSize - AlignedSize(sizeof(ArenaChunk));

    if (mCurrent && aSize <= mCurrent->Available()) {
      return mCurrent->Allocate(aSize);
    }

    ArenaChunk* arena = AllocateChunk(std::max(kMaxArenaCapacity, aSize));
    return arena ? arena->Allocate(aSize) : nullptr;
  }

  ArenaChunk mHead;
  ArenaChunk* mCurrent;
};

}  // namespace mozilla

#endif  // mozilla_ArenaAllocator_h

Messung V0.5
C=94 H=94 G=93

¤ Dauer der Verarbeitung: 0.23 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.






                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....
    

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge