util/{HugeAllocator,SparseBuffer}: use std::span

This commit is contained in:
Max Kellermann 2022-05-20 10:17:20 +02:00
parent 84e5da4bf0
commit b37c031fd1
6 changed files with 89 additions and 47 deletions

View File

@ -20,6 +20,7 @@
#ifndef MPD_MUSIC_BUFFER_HXX
#define MPD_MUSIC_BUFFER_HXX
#include "MusicChunk.hxx"
#include "MusicChunkPtr.hxx"
#include "util/SliceBuffer.hxx"
#include "thread/Mutex.hxx"

View File

@ -84,8 +84,8 @@ BufferingInputStream::Read(std::unique_lock<Mutex> &lock, size_t offset,
auto r = buffer.Read(offset);
if (r.HasData()) {
/* yay, we have some data */
size_t nbytes = std::min(s, r.defined_buffer.size);
memcpy(ptr, r.defined_buffer.data, nbytes);
size_t nbytes = std::min(s, r.defined_buffer.size());
memcpy(ptr, r.defined_buffer.data(), nbytes);
return nbytes;
}
@ -107,9 +107,9 @@ BufferingInputStream::FindFirstHole() const noexcept
/* a hole at the beginning */
return 0;
if (r.defined_buffer.size < size())
if (r.defined_buffer.size() < size())
/* a hole in the middle */
return r.defined_buffer.size;
return r.defined_buffer.size();
/* the file has been read completely */
return INVALID_OFFSET;
@ -163,10 +163,10 @@ BufferingInputStream::RunThreadLocked(std::unique_lock<Mutex> &lock)
hard disk, instead of returning when "some"
data has been read */
constexpr size_t MAX_READ = 64 * 1024;
if (w.size > MAX_READ)
w.size = MAX_READ;
size_t nbytes = input->Read(lock, w.data, w.size);
size_t nbytes = input->Read(lock, w.data(),
std::min(w.size(),
MAX_READ));
buffer.Commit(read_offset, read_offset + nbytes);
client_cond.notify_all();

View File

@ -56,7 +56,7 @@ AlignToPageSize(size_t size) noexcept
return (size + ps - 1) / ps * ps;
}
WritableBuffer<void>
std::span<std::byte>
HugeAllocate(size_t size)
{
size = AlignToPageSize(size);
@ -74,7 +74,7 @@ HugeAllocate(size_t size)
madvise(p, size, MADV_HUGEPAGE);
#endif
return {p, size};
return {(std::byte *)p, size};
}
void
@ -108,7 +108,7 @@ HugeDiscard(void *p, size_t size) noexcept
#elif defined(_WIN32)
WritableBuffer<void>
std::span<std::byte>
HugeAllocate(size_t size)
{
// TODO: use MEM_LARGE_PAGES
@ -119,7 +119,7 @@ HugeAllocate(size_t size)
throw std::bad_alloc();
// TODO: round size up to the page size
return {p, size};
return {(std::byte *)p, size};
}
#endif

View File

@ -27,12 +27,12 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef HUGE_ALLOCATOR_HXX
#define HUGE_ALLOCATOR_HXX
#pragma once
#include "WritableBuffer.hxx"
#include "SpanCast.hxx"
#include <cstddef>
#include <span>
#include <utility>
#ifdef __linux__
@ -48,7 +48,7 @@
* (to the next page size), so callers can take advantage of this
* allocation overhead
*/
WritableBuffer<void>
std::span<std::byte>
HugeAllocate(size_t size);
/**
@ -87,7 +87,7 @@ HugeDiscard(void *p, size_t size) noexcept;
#elif defined(_WIN32)
#include <memoryapi.h>
WritableBuffer<void>
std::span<std::byte>
HugeAllocate(size_t size);
static inline void
@ -118,16 +118,16 @@ HugeDiscard(void *p, size_t size) noexcept
#include <cstdint>
static inline WritableBuffer<void>
static inline std::span<std::byte>
HugeAllocate(size_t size)
{
return {new uint8_t[size], size};
return {new std::byte[size], size};
}
static inline void
HugeFree(void *_p, size_t) noexcept
{
auto *p = (uint8_t *)_p;
auto *p = (std::byte *)_p;
delete[] p;
}
@ -153,7 +153,7 @@ HugeDiscard(void *, size_t) noexcept
*/
template<typename T>
class HugeArray {
typedef WritableBuffer<T> Buffer;
using Buffer = std::span<T>;
Buffer buffer{nullptr};
public:
@ -162,20 +162,19 @@ public:
typedef typename Buffer::reference reference;
typedef typename Buffer::const_reference const_reference;
typedef typename Buffer::iterator iterator;
typedef typename Buffer::const_iterator const_iterator;
constexpr HugeArray() = default;
explicit HugeArray(size_type _size)
:buffer(Buffer::FromVoidFloor(HugeAllocate(sizeof(value_type) * _size))) {}
:buffer(FromBytesFloor<value_type>(HugeAllocate(sizeof(value_type) * _size))) {}
constexpr HugeArray(HugeArray &&other) noexcept
:buffer(std::exchange(other.buffer, nullptr)) {}
~HugeArray() noexcept {
if (buffer != nullptr) {
auto v = buffer.ToVoid();
HugeFree(v.data, v.size);
if (!buffer.empty()) {
auto v = std::as_writable_bytes(buffer);
HugeFree(v.data(), v.size());
}
}
@ -186,18 +185,18 @@ public:
}
void SetName(const char *name) noexcept {
const auto v = buffer.ToVoid();
HugeSetName(v.data, v.size, name);
const auto v = std::as_writable_bytes(buffer);
HugeSetName(v.data(), v.size(), name);
}
void ForkCow(bool enable) noexcept {
auto v = buffer.ToVoid();
HugeForkCow(v.data, v.size, enable);
const auto v = std::as_writable_bytes(buffer);
HugeForkCow(v.data(), v.size(), enable);
}
void Discard() noexcept {
auto v = buffer.ToVoid();
HugeDiscard(v.data, v.size);
const auto v = std::as_writable_bytes(buffer);
HugeDiscard(v.data(), v.size());
}
constexpr bool operator==(std::nullptr_t) const noexcept {
@ -212,7 +211,7 @@ public:
* Returns the number of allocated elements.
*/
constexpr size_type size() const noexcept {
return buffer.size;
return buffer.size();
}
reference front() noexcept {
@ -249,17 +248,15 @@ public:
return buffer.begin();
}
constexpr const_iterator begin() const noexcept {
return buffer.cbegin();
constexpr auto begin() const noexcept {
return buffer.begin();
}
iterator end() noexcept {
return buffer.end();
}
constexpr const_iterator end() const noexcept {
return buffer.cend();
constexpr auto end() const noexcept {
return buffer.end();
}
};
#endif

49
src/util/SpanCast.hxx Normal file
View File

@ -0,0 +1,49 @@
/*
* Copyright 2022 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
*
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* FOUNDATION OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
* SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
* STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#pragma once
#include <cstddef>
#include <span>
/**
* Cast a std::span<std::byte> to a std::span<T>, rounding down to the
* next multiple of T's size.
*/
template<typename T>
constexpr std::span<T>
FromBytesFloor(std::span<std::byte> other) noexcept
{
static_assert(sizeof(T) > 0, "Empty base type");
return {
reinterpret_cast<T *>(other.data()),
other.size() / sizeof(T),
};
}

View File

@ -1,5 +1,5 @@
/*
* Copyright (C) 2013-2018 Max Kellermann <max.kellermann@gmail.com>
* Copyright 2013-2022 Max Kellermann <max.kellermann@gmail.com>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@ -27,12 +27,9 @@
* OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef SPARSE_BUFFER_HXX
#define SPARSE_BUFFER_HXX
#pragma once
#include "HugeAllocator.hxx"
#include "ConstBuffer.hxx"
#include "WritableBuffer.hxx"
#include <cassert>
#include <map>
@ -118,7 +115,7 @@ public:
struct ReadResult {
size_type undefined_size;
ConstBuffer<T> defined_buffer;
std::span<const T> defined_buffer;
constexpr bool HasData() const noexcept {
return undefined_size == 0 &&
@ -131,7 +128,7 @@ public:
return {c.undefined_size, {&buffer.front() + offset + c.undefined_size, c.defined_size}};
}
WritableBuffer<T> Write(size_type offset) noexcept {
std::span<T> Write(size_type offset) noexcept {
auto c = map.Check(offset);
return {&buffer.front() + offset, c.undefined_size};
}
@ -140,5 +137,3 @@ public:
map.Commit(start_offset, end_offset);
}
};
#endif