blob: 5e4af82f3e6e46b81327f1772d703e900551b463 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP Authors
* Copyright (c) 2013 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <lib/support/Pool.h>
#include <nlassert.h>
namespace chip {
StaticAllocatorBitmap::StaticAllocatorBitmap(void * storage, std::atomic<tBitChunkType> * usage, size_t capacity,
size_t elementSize) :
StaticAllocatorBase(capacity),
mElements(storage), mElementSize(elementSize), mUsage(usage)
{
for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
{
mUsage[word].store(0);
}
}
void * StaticAllocatorBitmap::Allocate()
{
for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
{
auto & usage = mUsage[word];
auto value = usage.load(std::memory_order_relaxed);
for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
{
if ((value & (kBit1 << offset)) == 0)
{
if (usage.compare_exchange_strong(value, value | (kBit1 << offset)))
{
mAllocated++;
return At(word * kBitChunkSize + offset);
}
else
{
value = usage.load(std::memory_order_relaxed); // if there is a race, update new usage
}
}
}
}
return nullptr;
}
void StaticAllocatorBitmap::Deallocate(void * element)
{
size_t index = IndexOf(element);
size_t word = index / kBitChunkSize;
size_t offset = index - (word * kBitChunkSize);
// ensure the element is in the pool
assert(index < Capacity());
auto value = mUsage[word].fetch_and(~(kBit1 << offset));
nlASSERT((value & (kBit1 << offset)) != 0); // assert fail when free an unused slot
mAllocated--;
}
size_t StaticAllocatorBitmap::IndexOf(void * element)
{
std::ptrdiff_t diff = static_cast<uint8_t *>(element) - static_cast<uint8_t *>(mElements);
assert(diff >= 0);
assert(static_cast<size_t>(diff) % mElementSize == 0);
auto index = static_cast<size_t>(diff) / mElementSize;
assert(index < Capacity());
return index;
}
bool StaticAllocatorBitmap::ForEachActiveObjectInner(void * context, Lambda lambda)
{
for (size_t word = 0; word * kBitChunkSize < Capacity(); ++word)
{
auto & usage = mUsage[word];
auto value = usage.load(std::memory_order_relaxed);
for (size_t offset = 0; offset < kBitChunkSize && offset + word * kBitChunkSize < Capacity(); ++offset)
{
if ((value & (kBit1 << offset)) != 0)
{
if (!lambda(context, At(word * kBitChunkSize + offset)))
return false;
}
}
}
return true;
}
} // namespace chip