| // Copyright 2013 The Flutter 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 "impeller/base/allocation.h" |
| |
| #include <algorithm> |
| #include <cstring> |
| |
| #include "flutter/fml/logging.h" |
| #include "impeller/base/validation.h" |
| |
| namespace impeller { |
| |
| Allocation::Allocation() = default; |
| |
| Allocation::~Allocation() { |
| ::free(buffer_); |
| } |
| |
| uint8_t* Allocation::GetBuffer() const { |
| return buffer_; |
| } |
| |
| size_t Allocation::GetLength() const { |
| return length_; |
| } |
| |
| size_t Allocation::GetReservedLength() const { |
| return reserved_; |
| } |
| |
| bool Allocation::Truncate(size_t length, bool npot) { |
| const auto reserved = npot ? ReserveNPOT(length) : Reserve(length); |
| if (!reserved) { |
| return false; |
| } |
| length_ = length; |
| return true; |
| } |
| |
| uint32_t Allocation::NextPowerOfTwoSize(uint32_t x) { |
| if (x == 0) { |
| return 1; |
| } |
| |
| --x; |
| |
| x |= x >> 1; |
| x |= x >> 2; |
| x |= x >> 4; |
| x |= x >> 8; |
| x |= x >> 16; |
| |
| return x + 1; |
| } |
| |
| bool Allocation::ReserveNPOT(size_t reserved) { |
| // Reserve at least one page of data. |
| reserved = std::max<size_t>(4096u, reserved); |
| return Reserve(NextPowerOfTwoSize(reserved)); |
| } |
| |
| bool Allocation::Reserve(size_t reserved) { |
| if (reserved == reserved_) { |
| return true; |
| } |
| |
| auto new_allocation = ::realloc(buffer_, reserved); |
| if (!new_allocation) { |
| // If new length is zero, a minimum non-zero sized allocation is returned. |
| // So this check will not trip and this routine will indicate success as |
| // expected. |
| VALIDATION_LOG << "Allocation failed. Out of host memory."; |
| return false; |
| } |
| |
| buffer_ = static_cast<uint8_t*>(new_allocation); |
| reserved_ = reserved; |
| |
| return true; |
| } |
| |
| std::shared_ptr<fml::Mapping> CreateMappingWithCopy(const uint8_t* contents, |
| size_t length) { |
| if (contents == nullptr) { |
| return nullptr; |
| } |
| |
| auto allocation = std::make_shared<Allocation>(); |
| if (!allocation->Truncate(length)) { |
| return nullptr; |
| } |
| |
| std::memmove(allocation->GetBuffer(), contents, length); |
| |
| return CreateMappingFromAllocation(allocation); |
| } |
| |
| std::shared_ptr<fml::Mapping> CreateMappingFromAllocation( |
| const std::shared_ptr<Allocation>& allocation) { |
| if (!allocation) { |
| return nullptr; |
| } |
| return std::make_shared<fml::NonOwnedMapping>( |
| reinterpret_cast<const uint8_t*>(allocation->GetBuffer()), // |
| allocation->GetLength(), // |
| [allocation](auto, auto) {} // |
| ); |
| } |
| |
| std::shared_ptr<fml::Mapping> CreateMappingWithString(std::string string) { |
| auto buffer = std::make_shared<std::string>(std::move(string)); |
| return std::make_unique<fml::NonOwnedMapping>( |
| reinterpret_cast<const uint8_t*>(buffer->c_str()), buffer->length(), |
| [buffer](auto, auto) {}); |
| } |
| |
| } // namespace impeller |