util/{HugeAllocator,SparseBuffer}: use std::span
This commit is contained in:
parent
84e5da4bf0
commit
b37c031fd1
@ -20,6 +20,7 @@
|
|||||||
#ifndef MPD_MUSIC_BUFFER_HXX
|
#ifndef MPD_MUSIC_BUFFER_HXX
|
||||||
#define MPD_MUSIC_BUFFER_HXX
|
#define MPD_MUSIC_BUFFER_HXX
|
||||||
|
|
||||||
|
#include "MusicChunk.hxx"
|
||||||
#include "MusicChunkPtr.hxx"
|
#include "MusicChunkPtr.hxx"
|
||||||
#include "util/SliceBuffer.hxx"
|
#include "util/SliceBuffer.hxx"
|
||||||
#include "thread/Mutex.hxx"
|
#include "thread/Mutex.hxx"
|
||||||
|
@ -84,8 +84,8 @@ BufferingInputStream::Read(std::unique_lock<Mutex> &lock, size_t offset,
|
|||||||
auto r = buffer.Read(offset);
|
auto r = buffer.Read(offset);
|
||||||
if (r.HasData()) {
|
if (r.HasData()) {
|
||||||
/* yay, we have some data */
|
/* yay, we have some data */
|
||||||
size_t nbytes = std::min(s, r.defined_buffer.size);
|
size_t nbytes = std::min(s, r.defined_buffer.size());
|
||||||
memcpy(ptr, r.defined_buffer.data, nbytes);
|
memcpy(ptr, r.defined_buffer.data(), nbytes);
|
||||||
return nbytes;
|
return nbytes;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -107,9 +107,9 @@ BufferingInputStream::FindFirstHole() const noexcept
|
|||||||
/* a hole at the beginning */
|
/* a hole at the beginning */
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
if (r.defined_buffer.size < size())
|
if (r.defined_buffer.size() < size())
|
||||||
/* a hole in the middle */
|
/* a hole in the middle */
|
||||||
return r.defined_buffer.size;
|
return r.defined_buffer.size();
|
||||||
|
|
||||||
/* the file has been read completely */
|
/* the file has been read completely */
|
||||||
return INVALID_OFFSET;
|
return INVALID_OFFSET;
|
||||||
@ -163,10 +163,10 @@ BufferingInputStream::RunThreadLocked(std::unique_lock<Mutex> &lock)
|
|||||||
hard disk, instead of returning when "some"
|
hard disk, instead of returning when "some"
|
||||||
data has been read */
|
data has been read */
|
||||||
constexpr size_t MAX_READ = 64 * 1024;
|
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);
|
buffer.Commit(read_offset, read_offset + nbytes);
|
||||||
|
|
||||||
client_cond.notify_all();
|
client_cond.notify_all();
|
||||||
|
@ -56,7 +56,7 @@ AlignToPageSize(size_t size) noexcept
|
|||||||
return (size + ps - 1) / ps * ps;
|
return (size + ps - 1) / ps * ps;
|
||||||
}
|
}
|
||||||
|
|
||||||
WritableBuffer<void>
|
std::span<std::byte>
|
||||||
HugeAllocate(size_t size)
|
HugeAllocate(size_t size)
|
||||||
{
|
{
|
||||||
size = AlignToPageSize(size);
|
size = AlignToPageSize(size);
|
||||||
@ -74,7 +74,7 @@ HugeAllocate(size_t size)
|
|||||||
madvise(p, size, MADV_HUGEPAGE);
|
madvise(p, size, MADV_HUGEPAGE);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
return {p, size};
|
return {(std::byte *)p, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -108,7 +108,7 @@ HugeDiscard(void *p, size_t size) noexcept
|
|||||||
|
|
||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
|
|
||||||
WritableBuffer<void>
|
std::span<std::byte>
|
||||||
HugeAllocate(size_t size)
|
HugeAllocate(size_t size)
|
||||||
{
|
{
|
||||||
// TODO: use MEM_LARGE_PAGES
|
// TODO: use MEM_LARGE_PAGES
|
||||||
@ -119,7 +119,7 @@ HugeAllocate(size_t size)
|
|||||||
throw std::bad_alloc();
|
throw std::bad_alloc();
|
||||||
|
|
||||||
// TODO: round size up to the page size
|
// TODO: round size up to the page size
|
||||||
return {p, size};
|
return {(std::byte *)p, size};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -27,12 +27,12 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef HUGE_ALLOCATOR_HXX
|
#pragma once
|
||||||
#define HUGE_ALLOCATOR_HXX
|
|
||||||
|
|
||||||
#include "WritableBuffer.hxx"
|
#include "SpanCast.hxx"
|
||||||
|
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <span>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
@ -48,7 +48,7 @@
|
|||||||
* (to the next page size), so callers can take advantage of this
|
* (to the next page size), so callers can take advantage of this
|
||||||
* allocation overhead
|
* allocation overhead
|
||||||
*/
|
*/
|
||||||
WritableBuffer<void>
|
std::span<std::byte>
|
||||||
HugeAllocate(size_t size);
|
HugeAllocate(size_t size);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -87,7 +87,7 @@ HugeDiscard(void *p, size_t size) noexcept;
|
|||||||
#elif defined(_WIN32)
|
#elif defined(_WIN32)
|
||||||
#include <memoryapi.h>
|
#include <memoryapi.h>
|
||||||
|
|
||||||
WritableBuffer<void>
|
std::span<std::byte>
|
||||||
HugeAllocate(size_t size);
|
HugeAllocate(size_t size);
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
@ -118,16 +118,16 @@ HugeDiscard(void *p, size_t size) noexcept
|
|||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
static inline WritableBuffer<void>
|
static inline std::span<std::byte>
|
||||||
HugeAllocate(size_t size)
|
HugeAllocate(size_t size)
|
||||||
{
|
{
|
||||||
return {new uint8_t[size], size};
|
return {new std::byte[size], size};
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void
|
static inline void
|
||||||
HugeFree(void *_p, size_t) noexcept
|
HugeFree(void *_p, size_t) noexcept
|
||||||
{
|
{
|
||||||
auto *p = (uint8_t *)_p;
|
auto *p = (std::byte *)_p;
|
||||||
delete[] p;
|
delete[] p;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,7 +153,7 @@ HugeDiscard(void *, size_t) noexcept
|
|||||||
*/
|
*/
|
||||||
template<typename T>
|
template<typename T>
|
||||||
class HugeArray {
|
class HugeArray {
|
||||||
typedef WritableBuffer<T> Buffer;
|
using Buffer = std::span<T>;
|
||||||
Buffer buffer{nullptr};
|
Buffer buffer{nullptr};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
@ -162,20 +162,19 @@ public:
|
|||||||
typedef typename Buffer::reference reference;
|
typedef typename Buffer::reference reference;
|
||||||
typedef typename Buffer::const_reference const_reference;
|
typedef typename Buffer::const_reference const_reference;
|
||||||
typedef typename Buffer::iterator iterator;
|
typedef typename Buffer::iterator iterator;
|
||||||
typedef typename Buffer::const_iterator const_iterator;
|
|
||||||
|
|
||||||
constexpr HugeArray() = default;
|
constexpr HugeArray() = default;
|
||||||
|
|
||||||
explicit HugeArray(size_type _size)
|
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
|
constexpr HugeArray(HugeArray &&other) noexcept
|
||||||
:buffer(std::exchange(other.buffer, nullptr)) {}
|
:buffer(std::exchange(other.buffer, nullptr)) {}
|
||||||
|
|
||||||
~HugeArray() noexcept {
|
~HugeArray() noexcept {
|
||||||
if (buffer != nullptr) {
|
if (!buffer.empty()) {
|
||||||
auto v = buffer.ToVoid();
|
auto v = std::as_writable_bytes(buffer);
|
||||||
HugeFree(v.data, v.size);
|
HugeFree(v.data(), v.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -186,18 +185,18 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
void SetName(const char *name) noexcept {
|
void SetName(const char *name) noexcept {
|
||||||
const auto v = buffer.ToVoid();
|
const auto v = std::as_writable_bytes(buffer);
|
||||||
HugeSetName(v.data, v.size, name);
|
HugeSetName(v.data(), v.size(), name);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ForkCow(bool enable) noexcept {
|
void ForkCow(bool enable) noexcept {
|
||||||
auto v = buffer.ToVoid();
|
const auto v = std::as_writable_bytes(buffer);
|
||||||
HugeForkCow(v.data, v.size, enable);
|
HugeForkCow(v.data(), v.size(), enable);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Discard() noexcept {
|
void Discard() noexcept {
|
||||||
auto v = buffer.ToVoid();
|
const auto v = std::as_writable_bytes(buffer);
|
||||||
HugeDiscard(v.data, v.size);
|
HugeDiscard(v.data(), v.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(std::nullptr_t) const noexcept {
|
constexpr bool operator==(std::nullptr_t) const noexcept {
|
||||||
@ -212,7 +211,7 @@ public:
|
|||||||
* Returns the number of allocated elements.
|
* Returns the number of allocated elements.
|
||||||
*/
|
*/
|
||||||
constexpr size_type size() const noexcept {
|
constexpr size_type size() const noexcept {
|
||||||
return buffer.size;
|
return buffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
reference front() noexcept {
|
reference front() noexcept {
|
||||||
@ -249,17 +248,15 @@ public:
|
|||||||
return buffer.begin();
|
return buffer.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const_iterator begin() const noexcept {
|
constexpr auto begin() const noexcept {
|
||||||
return buffer.cbegin();
|
return buffer.begin();
|
||||||
}
|
}
|
||||||
|
|
||||||
iterator end() noexcept {
|
iterator end() noexcept {
|
||||||
return buffer.end();
|
return buffer.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr const_iterator end() const noexcept {
|
constexpr auto end() const noexcept {
|
||||||
return buffer.cend();
|
return buffer.end();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
49
src/util/SpanCast.hxx
Normal file
49
src/util/SpanCast.hxx
Normal 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),
|
||||||
|
};
|
||||||
|
}
|
@ -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
|
* Redistribution and use in source and binary forms, with or without
|
||||||
* modification, are permitted provided that the following conditions
|
* modification, are permitted provided that the following conditions
|
||||||
@ -27,12 +27,9 @@
|
|||||||
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
* OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#ifndef SPARSE_BUFFER_HXX
|
#pragma once
|
||||||
#define SPARSE_BUFFER_HXX
|
|
||||||
|
|
||||||
#include "HugeAllocator.hxx"
|
#include "HugeAllocator.hxx"
|
||||||
#include "ConstBuffer.hxx"
|
|
||||||
#include "WritableBuffer.hxx"
|
|
||||||
|
|
||||||
#include <cassert>
|
#include <cassert>
|
||||||
#include <map>
|
#include <map>
|
||||||
@ -118,7 +115,7 @@ public:
|
|||||||
|
|
||||||
struct ReadResult {
|
struct ReadResult {
|
||||||
size_type undefined_size;
|
size_type undefined_size;
|
||||||
ConstBuffer<T> defined_buffer;
|
std::span<const T> defined_buffer;
|
||||||
|
|
||||||
constexpr bool HasData() const noexcept {
|
constexpr bool HasData() const noexcept {
|
||||||
return undefined_size == 0 &&
|
return undefined_size == 0 &&
|
||||||
@ -131,7 +128,7 @@ public:
|
|||||||
return {c.undefined_size, {&buffer.front() + offset + c.undefined_size, c.defined_size}};
|
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);
|
auto c = map.Check(offset);
|
||||||
return {&buffer.front() + offset, c.undefined_size};
|
return {&buffer.front() + offset, c.undefined_size};
|
||||||
}
|
}
|
||||||
@ -140,5 +137,3 @@ public:
|
|||||||
map.Commit(start_offset, end_offset);
|
map.Commit(start_offset, end_offset);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
|
||||||
|
Loading…
Reference in New Issue
Block a user