blob: ad89755514a74162474aac1f7c51efbfcc666ced [file] [log] [blame]
// Copyright 2024 The Pigweed Authors
//
// 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
//
// https://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 "pw_multibuf/from_span.h"
namespace pw::multibuf {
namespace {
/// A simple ``ChunkRegionTracker`` that calls ``deleter`` for destruction.
class SpanTracker final : public ChunkRegionTracker {
private:
class PrivateConstructorType {};
static constexpr PrivateConstructorType kPrivateConstructor{};
public:
static std::optional<OwnedChunk> New(Allocator& alloc,
ByteSpan region,
pw::Function<void(ByteSpan)>&& deleter) {
SpanTracker* tracker = alloc.New<SpanTracker>(
kPrivateConstructor, alloc, region, std::move(deleter));
if (tracker == nullptr) {
return std::nullopt;
}
std::optional<OwnedChunk> chunk = tracker->CreateFirstChunk();
if (!chunk.has_value()) {
// Delete without destroying the associated memory.
alloc.Delete(tracker);
return std::nullopt;
}
return chunk;
}
SpanTracker(PrivateConstructorType,
pw::Allocator& alloc,
ByteSpan region,
pw::Function<void(ByteSpan)>&& deleter)
: alloc_(alloc), region_(region), deleter_(std::move(deleter)) {}
~SpanTracker() final = default;
// SpanTracker is not copyable nor movable.
SpanTracker(const SpanTracker&) = delete;
SpanTracker& operator=(const SpanTracker&) = delete;
SpanTracker(SpanTracker&&) = delete;
SpanTracker& operator=(SpanTracker&&) = delete;
private:
void Destroy() final {
deleter_(region_);
alloc_.Delete(this);
}
ByteSpan Region() const final { return region_; }
void* AllocateChunkClass() final {
return alloc_.Allocate(allocator::Layout::Of<Chunk>());
}
void DeallocateChunkClass(void* ptr) final { return alloc_.Deallocate(ptr); }
pw::Allocator& alloc_;
const ByteSpan region_;
pw::Function<void(ByteSpan)> deleter_;
};
} // namespace
std::optional<MultiBuf> FromSpan(pw::Allocator& metadata_allocator,
ByteSpan region,
pw::Function<void(ByteSpan)>&& deleter) {
std::optional<OwnedChunk> chunk =
SpanTracker::New(metadata_allocator, region, std::move(deleter));
if (chunk == std::nullopt) {
return std::nullopt;
}
return MultiBuf::FromChunk(std::move(*chunk));
}
} // namespace pw::multibuf