blob: 84781c175a2f61b9c8269c6dcf3a2003e301ff5d [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "read_cache.h"
#include <string.h>
#include <zircon/assert.h>
namespace nand {
ReadCache::ReadCache(uint32_t cache_size, size_t data_size, size_t spare_size)
: data_size_(data_size), spare_size_(spare_size), max_entries_(cache_size) {
ZX_DEBUG_ASSERT(max_entries_ > 0);
}
void ReadCache::Insert(uint32_t page, const void* data, const void* spare) {
// First purge this page if it exists. For the use case of this library it should never actually
// occur, but for the ease of usability, make it correct. That's why it isn't being optimized
// for at all.
PurgeRange(page, 1);
ReadCache::FifoEntry entry;
if (fifo_.size() >= max_entries_) {
// If the fifo is full we free from the head and steal the memory allocation.
entry.entry = std::move(fifo_[0].entry);
fifo_.pop_front();
} else {
// Allocate the memory for a new entry.
entry.entry = std::make_unique<uint8_t[]>(data_size_ + spare_size_);
}
entry.page = page;
// Copy in the data followed by the spare.
memcpy(entry.entry.get(), data, data_size_);
memcpy(&entry.entry.get()[data_size_], spare, spare_size_);
// Insert to the tail
fifo_.push_back(std::move(entry));
}
bool ReadCache::GetPage(uint32_t page_num, void* out_data, void* out_spare) {
for (auto& entry : fifo_) {
if (entry.page == page_num) {
memcpy(out_data, entry.entry.get(), data_size_);
memcpy(out_spare, &entry.entry.get()[data_size_], spare_size_);
return true;
}
}
return false;
}
size_t ReadCache::PurgeRange(uint32_t first_page, uint32_t length) {
size_t purged = 0;
for (auto it = fifo_.begin(); it != fifo_.end();) {
if (it->page >= first_page && it->page <= first_page + (length - 1)) {
it = fifo_.erase(it);
++purged;
} else {
++it;
}
}
return purged;
}
} // namespace nand