Global Metrics
path: .metrics.nexits.average
old: 0.6666666666666666
new: 0.625
path: .metrics.nexits.sum
old: 2.0
new: 10.0
path: .metrics.mi.mi_original
old: 47.36758446757308
new: 34.47695963612769
path: .metrics.mi.mi_sei
old: 29.53892801721436
new: 14.120119608881318
path: .metrics.mi.mi_visual_studio
old: 27.700341793902385
new: 20.16196469948988
path: .metrics.nargs.sum
old: 9.0
new: 4.0
path: .metrics.nargs.average
old: 3.0
new: 0.25
path: .metrics.cognitive.sum
old: 16.0
new: 8.0
path: .metrics.cognitive.average
old: 5.333333333333333
new: 0.5
path: .metrics.halstead.bugs
old: 1.1770127325598896
new: 1.1121853057972957
path: .metrics.halstead.level
old: 0.013403880070546737
new: 0.01908957415565345
path: .metrics.halstead.purity_ratio
old: 0.7019340643881582
new: 0.9618939744912592
path: .metrics.halstead.N1
old: 257.0
new: 333.0
path: .metrics.halstead.difficulty
old: 74.60526315789474
new: 52.38461538461539
path: .metrics.halstead.length
old: 467.0
new: 560.0
path: .metrics.halstead.n1
old: 27.0
new: 30.0
path: .metrics.halstead.n2
old: 38.0
new: 65.0
path: .metrics.halstead.effort
old: 209823.2566899989
new: 192729.24113793
path: .metrics.halstead.estimated_program_length
old: 327.8032080692699
new: 538.6606257151051
path: .metrics.halstead.time
old: 11656.847593888828
new: 10707.180063218337
path: .metrics.halstead.N2
old: 210.0
new: 227.0
path: .metrics.halstead.volume
old: 2812.4457686842884
new: 3679.11914066533
path: .metrics.halstead.vocabulary
old: 65.0
new: 95.0
path: .metrics.loc.lloc
old: 49.0
new: 36.0
path: .metrics.loc.blank
old: 6.0
new: 33.0
path: .metrics.loc.cloc
old: 35.0
new: 62.0
path: .metrics.loc.sloc
old: 134.0
new: 214.0
path: .metrics.loc.ploc
old: 93.0
new: 119.0
path: .metrics.cyclomatic.average
old: 3.25
new: 1.4285714285714286
path: .metrics.cyclomatic.sum
old: 13.0
new: 30.0
path: .metrics.nom.functions
old: 3.0
new: 16.0
path: .metrics.nom.total
old: 3.0
new: 16.0
Spaces Data
Minimal test - lines (23, 212)
path: .spaces[0].metrics.loc.ploc
old: 6.0
new: 105.0
path: .spaces[0].metrics.loc.sloc
old: 6.0
new: 190.0
path: .spaces[0].metrics.loc.blank
old: 0.0
new: 30.0
path: .spaces[0].metrics.loc.lloc
old: 2.0
new: 36.0
path: .spaces[0].metrics.loc.cloc
old: 0.0
new: 55.0
path: .spaces[0].metrics.nom.functions
old: 1.0
new: 16.0
path: .spaces[0].metrics.nom.total
old: 1.0
new: 16.0
path: .spaces[0].metrics.cyclomatic.average
old: 1.0
new: 1.45
path: .spaces[0].metrics.cyclomatic.sum
old: 1.0
new: 29.0
path: .spaces[0].metrics.mi.mi_original
old: 115.7111656028849
new: 36.8657240421452
path: .spaces[0].metrics.mi.mi_sei
old: 91.33689265815536
new: 17.45266100771967
path: .spaces[0].metrics.mi.mi_visual_studio
old: 67.66734830578065
new: 21.55890294862293
path: .spaces[0].metrics.nexits.sum
old: 1.0
new: 10.0
path: .spaces[0].metrics.nexits.average
old: 1.0
new: 0.625
path: .spaces[0].metrics.cognitive.sum
old: 0.0
new: 8.0
path: .spaces[0].metrics.cognitive.average
old: 0.0
new: 0.5
path: .spaces[0].metrics.halstead.time
old: 56.56772438427192
new: 11515.927496529594
path: .spaces[0].metrics.halstead.n1
old: 10.0
new: 30.0
path: .spaces[0].metrics.halstead.level
old: 0.14666666666666667
new: 0.016975308641975308
path: .spaces[0].metrics.halstead.estimated_program_length
old: 71.27302875388389
new: 465.18150211211184
path: .spaces[0].metrics.halstead.N1
old: 19.0
new: 333.0
path: .spaces[0].metrics.halstead.purity_ratio
old: 2.0962655515848203
new: 0.8473251404592201
path: .spaces[0].metrics.halstead.n2
old: 11.0
new: 55.0
path: .spaces[0].metrics.halstead.effort
old: 1018.2190389168944
new: 207286.69493753268
path: .spaces[0].metrics.halstead.N2
old: 15.0
new: 216.0
path: .spaces[0].metrics.halstead.bugs
old: 0.033736981332150334
new: 1.167507547056946
path: .spaces[0].metrics.halstead.difficulty
old: 6.818181818181818
new: 58.90909090909091
path: .spaces[0].metrics.halstead.vocabulary
old: 21.0
new: 85.0
path: .spaces[0].metrics.halstead.volume
old: 149.33879237447786
new: 3518.755623939598
path: .spaces[0].metrics.halstead.length
old: 34.0
new: 549.0
path: .spaces[0].metrics.nargs.average
old: 2.0
new: 0.25
path: .spaces[0].metrics.nargs.sum
old: 2.0
new: 4.0
Code
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
class ArenaAllocator {
public:
constexpr ArenaAllocator() : mHead(), mCurrent(nullptr) {
static_assert(mozilla::tl::FloorLog2::value ==
mozilla::tl::CeilingLog2::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(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