[ox] Move ptrarith into fs
This commit is contained in:
9
deps/ox/src/ox/fs/CMakeLists.txt
vendored
9
deps/ox/src/ox/fs/CMakeLists.txt
vendored
@@ -59,6 +59,14 @@ install(
|
||||
include/ox/fs/filesystem
|
||||
)
|
||||
|
||||
install(
|
||||
FILES
|
||||
ptrarith/nodebuffer.hpp
|
||||
ptrarith/ptr.hpp
|
||||
DESTINATION
|
||||
include/ox/fs/ptrarith
|
||||
)
|
||||
|
||||
install(
|
||||
TARGETS
|
||||
OxFS
|
||||
@@ -68,4 +76,5 @@ install(
|
||||
|
||||
if(OX_RUN_TESTS)
|
||||
add_subdirectory(test)
|
||||
add_subdirectory(ptrarith/test)
|
||||
endif()
|
||||
|
@@ -8,7 +8,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/fs/ptrarith/nodebuffer.hpp>
|
||||
|
||||
namespace ox {
|
||||
|
||||
|
2
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
2
deps/ox/src/ox/fs/filesystem/directory.hpp
vendored
@@ -10,7 +10,7 @@
|
||||
|
||||
#include <ox/fs/filesystem/pathiterator.hpp>
|
||||
#include <ox/fs/filestore/filestoretemplate.hpp>
|
||||
#include <ox/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/fs/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/std/byteswap.hpp>
|
||||
|
||||
#include "types.hpp"
|
||||
|
444
deps/ox/src/ox/fs/ptrarith/nodebuffer.hpp
vendored
Normal file
444
deps/ox/src/ox/fs/ptrarith/nodebuffer.hpp
vendored
Normal file
@@ -0,0 +1,444 @@
|
||||
/*
|
||||
* Copyright 2015 - 2021 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/stddef.hpp>
|
||||
#include <ox/std/trace.hpp>
|
||||
|
||||
#include "ptr.hpp"
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
class OX_PACKED NodeBuffer {
|
||||
|
||||
public:
|
||||
struct OX_PACKED Header {
|
||||
ox::LittleEndian<size_t> size = sizeof(Header); // capacity
|
||||
ox::LittleEndian<size_t> bytesUsed = sizeof(Header);
|
||||
ox::LittleEndian<size_t> firstItem = 0;
|
||||
};
|
||||
|
||||
using ItemPtr = Ptr<Item, size_t, sizeof(Header)>;
|
||||
|
||||
class Iterator {
|
||||
private:
|
||||
NodeBuffer *m_buffer = nullptr;
|
||||
ItemPtr m_current;
|
||||
size_t m_it = 0;
|
||||
|
||||
public:
|
||||
Iterator(NodeBuffer *buffer, ItemPtr current) {
|
||||
m_buffer = buffer;
|
||||
m_current = current;
|
||||
oxTrace("ox::ptrarith::Iterator::start") << current.offset();
|
||||
}
|
||||
|
||||
operator const Item*() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
ItemPtr ptr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *get() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator ItemPtr() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
operator Item*() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
const Item *operator->() const {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
Item *operator->() {
|
||||
return m_current;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool valid() const noexcept {
|
||||
return m_current.valid();
|
||||
}
|
||||
|
||||
bool hasNext() {
|
||||
if (m_current.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::hasNext::current") << m_current.offset();
|
||||
auto next = m_buffer->next(m_current);
|
||||
return next.valid() && m_buffer->firstItem() != next;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
void next() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::Iterator::next") << m_it++;
|
||||
if (hasNext()) {
|
||||
m_current = m_buffer->next(m_current);
|
||||
} else {
|
||||
m_current = nullptr;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Header m_header;
|
||||
|
||||
public:
|
||||
NodeBuffer();
|
||||
|
||||
NodeBuffer(const NodeBuffer &other, size_t size);
|
||||
|
||||
explicit NodeBuffer(size_t size);
|
||||
|
||||
const Iterator iterator() const;
|
||||
|
||||
Iterator iterator();
|
||||
|
||||
ItemPtr firstItem();
|
||||
|
||||
ItemPtr lastItem();
|
||||
|
||||
/**
|
||||
* @return the data section of the given item
|
||||
*/
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> dataOf(ItemPtr);
|
||||
|
||||
[[nodiscard]] ItemPtr prev(Item *item);
|
||||
|
||||
[[nodiscard]] ItemPtr next(Item *item);
|
||||
|
||||
/**
|
||||
* Like pointer but omits checks that assume the memory at the offset has
|
||||
* already been initialed as an Item.
|
||||
*/
|
||||
[[nodiscard]] ItemPtr uninitializedPtr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr ptr(size_t offset);
|
||||
|
||||
[[nodiscard]] ItemPtr malloc(size_t size);
|
||||
|
||||
Error free(ItemPtr item);
|
||||
|
||||
[[nodiscard]] bool valid(size_t maxSize);
|
||||
|
||||
/**
|
||||
* Set size, capacity.
|
||||
*/
|
||||
Error setSize(size_t size);
|
||||
|
||||
/**
|
||||
* Get size, capacity.
|
||||
* @return capacity
|
||||
*/
|
||||
size_t size();
|
||||
|
||||
/**
|
||||
* @return the bytes still available in this NodeBuffer
|
||||
*/
|
||||
size_t available();
|
||||
|
||||
/**
|
||||
* @return the actual number a bytes need to store the given number of
|
||||
* bytes
|
||||
*/
|
||||
static size_t spaceNeeded(size_t size);
|
||||
|
||||
template<typename F>
|
||||
Error compact(F cb = [](uint64_t, ItemPtr) {});
|
||||
|
||||
private:
|
||||
uint8_t *data();
|
||||
|
||||
};
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(size_t size) {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
oxTrace("ox::NodeBuffer::constructor") << m_header.firstItem;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::copy") << "other.m_header.firstItem:" << other.m_header.firstItem;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + sizeof(*this);
|
||||
ox_memset(data, 0, size - sizeof(*this));
|
||||
ox_memcpy(this, &other, size);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
const typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() const {
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::iterator::size") << m_header.size;
|
||||
return Iterator(this, firstItem());
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::firstItem() {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::firstItem") << m_header.firstItem;
|
||||
return ptr(m_header.firstItem);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::lastItem() {
|
||||
auto first = ptr(m_header.firstItem);
|
||||
if (first.valid()) {
|
||||
return prev(first);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename T>
|
||||
Ptr<T, size_t, sizeof(Item)> NodeBuffer<size_t, Item>::dataOf(ItemPtr ip) {
|
||||
auto out = ip.template subPtr<T>(sizeof(Item));
|
||||
oxAssert(out.size() == ip.size() - sizeof(Item), "Sub Ptr has invalid size.");
|
||||
return out;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::prev(Item *item) {
|
||||
return ptr(item->prev);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::next(Item *item) {
|
||||
return ptr(item->next);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::uninitializedPtr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item)) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, itemSpace);
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::ptr(size_t itemOffset) {
|
||||
// make sure this can be read as an Item, and then use Item::size for the size
|
||||
std::size_t itemSpace = m_header.size - itemOffset;
|
||||
auto item = reinterpret_cast<Item*>(reinterpret_cast<uint8_t*>(this) + itemOffset);
|
||||
if (itemOffset >= sizeof(Header) &&
|
||||
itemOffset + itemSpace <= size() &&
|
||||
itemSpace >= sizeof(Item) &&
|
||||
itemSpace >= item->fullSize()) {
|
||||
return ItemPtr(this, m_header.size, itemOffset, item->fullSize());
|
||||
} else {
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset:" << itemOffset;
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemOffset >= sizeof(Header):" << (itemOffset >= sizeof(Header));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= sizeof(Item):" << (itemSpace >= sizeof(Item));
|
||||
//oxTrace("ox::ptrarith::NodeBuffer::ptr::null") << "itemSpace >= item->fullSize():" << (itemSpace >= item->fullSize());
|
||||
return ItemPtr(this, m_header.size, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::malloc(size_t size) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Size:" << size;
|
||||
size_t fullSize = size + sizeof(Item);
|
||||
if (m_header.size - m_header.bytesUsed >= fullSize) {
|
||||
auto last = lastItem();
|
||||
size_t addr;
|
||||
if (last.valid()) {
|
||||
addr = last.offset() + last.size();
|
||||
} else {
|
||||
// there is no first item, so this must be the first item
|
||||
if (!m_header.firstItem) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "No first item, initializing.";
|
||||
m_header.firstItem = sizeof(m_header);
|
||||
addr = m_header.firstItem;
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer is in invalid state.";
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
oxTracef("ox::ptrarith::NodeBuffer::malloc", "buffer size: {}; addr: {}; fullSize: {}", m_header.size.get(), addr, fullSize);
|
||||
auto out = ItemPtr(this, m_header.size, addr, fullSize);
|
||||
if (!out.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Unknown";
|
||||
return nullptr;
|
||||
}
|
||||
ox_memset(out, 0, fullSize);
|
||||
new (out) Item;
|
||||
out->setSize(size);
|
||||
|
||||
auto first = firstItem();
|
||||
auto oldLast = last;
|
||||
out->next = first.offset();
|
||||
if (first.valid()) {
|
||||
first->prev = out.offset();
|
||||
} else {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid first element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
if (oldLast.valid()) {
|
||||
out->prev = oldLast.offset();
|
||||
oldLast->next = out.offset();
|
||||
} else { // check to see if this is the first allocation
|
||||
if (out.offset() != first.offset()) {
|
||||
// if this is not the first allocation, there should be an oldLast
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "NodeBuffer malloc failed due to invalid last element pointer.";
|
||||
return nullptr;
|
||||
}
|
||||
out->prev = out.offset();
|
||||
}
|
||||
m_header.bytesUsed += out.size();
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc") << "Offset:" << out.offset();
|
||||
return out;
|
||||
}
|
||||
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail") << "Insufficient space:" << fullSize << "needed," << available() << "available";
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::free(ItemPtr item) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "offset:" << item.offset();
|
||||
auto prev = this->prev(item);
|
||||
auto next = this->next(item);
|
||||
if (prev.valid() && next.valid()) {
|
||||
if (next != item) {
|
||||
prev->next = next;
|
||||
next->prev = prev;
|
||||
if (item.offset() == m_header.firstItem) {
|
||||
m_header.firstItem = next;
|
||||
}
|
||||
} else {
|
||||
// only one item, null out first
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free") << "Nulling out firstItem.";
|
||||
m_header.firstItem = 0;
|
||||
}
|
||||
} else {
|
||||
if (!prev.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid prev element pointer:" << prev.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
if (!next.valid()) {
|
||||
oxTrace("ox::ptrarith::NodeBuffer::free::fail") << "NodeBuffer free failed due to invalid next element pointer:" << next.offset();
|
||||
return OxError(1);
|
||||
}
|
||||
}
|
||||
m_header.bytesUsed -= item.size();
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
Error NodeBuffer<size_t, Item>::setSize(size_t size) {
|
||||
oxTracef("ox::ptrarith::NodeBuffer::setSize", "{} to {}", m_header.size.get(), size);
|
||||
auto last = lastItem();
|
||||
auto end = last.valid() ? last.end() : sizeof(m_header);
|
||||
oxTracef("ox::ptrarith::NodeBuffer::setSize", "end: {}", end);
|
||||
if (end > size) {
|
||||
// resizing to less than buffer size
|
||||
return OxError(1);
|
||||
} else {
|
||||
m_header.size = size;
|
||||
auto data = reinterpret_cast<uint8_t*>(this) + end;
|
||||
ox_memset(data, 0, size - end);
|
||||
return OxError(0);
|
||||
}
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::size() {
|
||||
return m_header.size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
bool NodeBuffer<size_t, Item>::valid(size_t maxSize) {
|
||||
return m_header.size <= maxSize;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::available() {
|
||||
return m_header.size - m_header.bytesUsed;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) {
|
||||
return sizeof(Item) + size;
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
template<typename F>
|
||||
Error NodeBuffer<size_t, Item>::compact(F cb) {
|
||||
auto src = firstItem();
|
||||
auto dest = ptr(sizeof(*this));
|
||||
while (dest.offset() <= src.offset()) {
|
||||
if (!src.valid()) {
|
||||
return OxError(1);
|
||||
}
|
||||
if (!dest.valid()) {
|
||||
return OxError(2);
|
||||
}
|
||||
// move node
|
||||
ox_memcpy(dest, src, src->fullSize());
|
||||
oxReturnError(cb(src, dest));
|
||||
// update surrounding nodes
|
||||
auto prev = ptr(dest->prev);
|
||||
if (prev.valid()) {
|
||||
prev->next = dest;
|
||||
}
|
||||
auto next = ptr(dest->next);
|
||||
if (next.valid()) {
|
||||
next->prev = dest;
|
||||
}
|
||||
// update iterators
|
||||
src = ptr(dest->next);
|
||||
dest = uninitializedPtr(dest.offset() + dest->fullSize());
|
||||
}
|
||||
return OxError(0);
|
||||
}
|
||||
|
||||
template<typename size_t, typename Item>
|
||||
uint8_t *NodeBuffer<size_t, Item>::data() {
|
||||
return reinterpret_cast<uint8_t*>(ptr(sizeof(*this)).get());
|
||||
}
|
||||
|
||||
|
||||
template<typename size_t>
|
||||
struct OX_PACKED Item {
|
||||
public:
|
||||
ox::LittleEndian<size_t> prev = 0;
|
||||
ox::LittleEndian<size_t> next = 0;
|
||||
|
||||
private:
|
||||
ox::LittleEndian<size_t> m_size = sizeof(Item);
|
||||
|
||||
public:
|
||||
size_t size() const {
|
||||
return m_size;
|
||||
}
|
||||
|
||||
void setSize(size_t size) {
|
||||
m_size = size;
|
||||
}
|
||||
};
|
||||
|
||||
}
|
230
deps/ox/src/ox/fs/ptrarith/ptr.hpp
vendored
Normal file
230
deps/ox/src/ox/fs/ptrarith/ptr.hpp
vendored
Normal file
@@ -0,0 +1,230 @@
|
||||
/*
|
||||
* Copyright 2015 - 2021 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
namespace ox::ptrarith {
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset = 1>
|
||||
class Ptr {
|
||||
|
||||
private:
|
||||
uint8_t *m_dataStart = nullptr;
|
||||
size_t m_dataSize = 0;
|
||||
size_t m_itemOffset = 0;
|
||||
size_t m_itemSize = 0;
|
||||
// this should be removed later on, but the excessive validation is
|
||||
// desirable during during heavy development
|
||||
mutable uint8_t m_validated = false;
|
||||
|
||||
public:
|
||||
inline Ptr() = default;
|
||||
|
||||
inline Ptr(std::nullptr_t);
|
||||
|
||||
inline Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T), size_t itemTypeSize = sizeof(T));
|
||||
|
||||
[[nodiscard]] inline bool valid() const;
|
||||
|
||||
inline size_t size() const;
|
||||
|
||||
inline size_t offset() const;
|
||||
|
||||
inline size_t end();
|
||||
|
||||
inline const T *get() const;
|
||||
|
||||
inline T *get();
|
||||
|
||||
inline const T *operator->() const;
|
||||
|
||||
inline T *operator->();
|
||||
|
||||
inline operator const T*() const;
|
||||
|
||||
inline operator T*();
|
||||
|
||||
inline const T &operator*() const;
|
||||
|
||||
inline T &operator*();
|
||||
|
||||
inline operator size_t() const;
|
||||
|
||||
inline bool operator==(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
inline bool operator!=(const Ptr<T, size_t, minOffset> &other) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset) const;
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset, size_t size);
|
||||
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> subPtr(size_t offset);
|
||||
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> to() const;
|
||||
|
||||
};
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(std::nullptr_t) {
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize, size_t itemTypeSize) {
|
||||
// do some sanity checks before assuming this is valid
|
||||
if (itemSize >= itemTypeSize &&
|
||||
dataStart &&
|
||||
itemStart >= minOffset &&
|
||||
itemStart + itemSize <= dataSize) {
|
||||
m_dataStart = reinterpret_cast<uint8_t*>(dataStart);
|
||||
m_dataSize = dataSize;
|
||||
m_itemOffset = itemStart;
|
||||
m_itemSize = itemSize;
|
||||
}
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::valid() const {
|
||||
m_validated = m_dataStart != nullptr;
|
||||
return m_validated;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::size() const {
|
||||
return m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::offset() const {
|
||||
return m_itemOffset;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline size_t Ptr<T, size_t, minOffset>::end() {
|
||||
return m_itemOffset + m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::get() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::get() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::get())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::get())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T *Ptr<T, size_t, minOffset>::operator->() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T *Ptr<T, size_t, minOffset>::operator->() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator->())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator->())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator const T*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator const T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator T*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer access. (ox::fs::Ptr::operator T*())");
|
||||
oxAssert(valid(), "Invalid pointer access. (ox::fs::Ptr::operator T*())");
|
||||
return reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline const T &Ptr<T, size_t, minOffset>::operator*() const {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline T &Ptr<T, size_t, minOffset>::operator*() {
|
||||
oxAssert(m_validated, "Unvalidated pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
oxAssert(valid(), "Invalid pointer dereference. (ox::fs::Ptr::operator*())");
|
||||
return *reinterpret_cast<T*>(m_dataStart + m_itemOffset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline Ptr<T, size_t, minOffset>::operator size_t() const {
|
||||
if (m_dataStart && m_itemOffset) {
|
||||
return m_itemOffset;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator==(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart == other.m_dataStart &&
|
||||
m_itemOffset == other.m_itemOffset &&
|
||||
m_itemSize == other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
inline bool Ptr<T, size_t, minOffset>::operator!=(const Ptr<T, size_t, minOffset> &other) const {
|
||||
return m_dataStart != other.m_dataStart ||
|
||||
m_itemOffset != other.m_itemOffset ||
|
||||
m_itemSize != other.m_itemSize;
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) const {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset, size_t size) {
|
||||
return Ptr<SubT, size_t, sizeof(T)>(get(), this->size(), offset, size);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) {
|
||||
oxTrace("ox::fs::Ptr::subPtr") << m_itemOffset << this->size() << offset << m_itemSize << (m_itemSize - offset);
|
||||
return subPtr<SubT>(offset, m_itemSize - offset);
|
||||
}
|
||||
|
||||
template<typename T, typename size_t, size_t minOffset>
|
||||
template<typename SubT>
|
||||
inline const Ptr<SubT, size_t, minOffset> Ptr<T, size_t, minOffset>::to() const {
|
||||
return Ptr<SubT, size_t, minOffset>(m_dataStart, m_dataSize, m_itemOffset, m_itemSize);
|
||||
}
|
||||
|
||||
}
|
11
deps/ox/src/ox/fs/ptrarith/test/CMakeLists.txt
vendored
Normal file
11
deps/ox/src/ox/fs/ptrarith/test/CMakeLists.txt
vendored
Normal file
@@ -0,0 +1,11 @@
|
||||
add_executable(
|
||||
PtrArithTests
|
||||
tests.cpp
|
||||
)
|
||||
|
||||
target_link_libraries(
|
||||
PtrArithTests
|
||||
OxStd
|
||||
)
|
||||
|
||||
add_test("Test PtrArith::setSize" PtrArithTests PtrArith::setSize)
|
72
deps/ox/src/ox/fs/ptrarith/test/tests.cpp
vendored
Normal file
72
deps/ox/src/ox/fs/ptrarith/test/tests.cpp
vendored
Normal file
@@ -0,0 +1,72 @@
|
||||
/*
|
||||
* Copyright 2015 - 2021 gary@drinkingtea.net
|
||||
*
|
||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
*/
|
||||
|
||||
// make sure asserts are enabled for the test file
|
||||
#undef NDEBUG
|
||||
|
||||
#include <assert.h>
|
||||
#include <array>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <ox/fs/ptrarith/nodebuffer.hpp>
|
||||
#include <ox/std/std.hpp>
|
||||
|
||||
using namespace std;
|
||||
using namespace ox;
|
||||
|
||||
template<typename T>
|
||||
struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
|
||||
public:
|
||||
size_t fullSize() const {
|
||||
return this->size() + sizeof(*this);
|
||||
}
|
||||
};
|
||||
|
||||
map<string, int(*)(string)> tests = {
|
||||
{
|
||||
{
|
||||
"PtrArith::setSize",
|
||||
[](string) {
|
||||
using BuffPtr_t = uint32_t;
|
||||
std::vector<char> buff(5 * ox::units::MB);
|
||||
auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
|
||||
using String = BString<6>;
|
||||
auto a1 = buffer->malloc(sizeof(String));
|
||||
auto a2 = buffer->malloc(sizeof(String));
|
||||
oxAssert(a1.valid(), "Allocation 1 failed.");
|
||||
oxAssert(a2.valid(), "Allocation 2 failed.");
|
||||
auto &s1 = *new (buffer->dataOf<String>(a1)) String("asdf");
|
||||
auto &s2 = *new (buffer->dataOf<String>(a2)) String("aoeu");
|
||||
oxTrace("test") << "s1: " << s1.c_str();
|
||||
oxTrace("test") << "s2: " << s2.c_str();
|
||||
oxAssert(s1 == "asdf", "Allocation 1 not as expected.");
|
||||
oxAssert(s2 == "aoeu", "Allocation 2 not as expected.");
|
||||
oxAssert(buffer->free(a1), "Free failed.");
|
||||
oxAssert(buffer->free(a2), "Free failed.");
|
||||
oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
|
||||
return 0;
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
int main(int argc, const char **args) {
|
||||
int retval = -1;
|
||||
if (argc > 1) {
|
||||
auto testName = args[1];
|
||||
string testArg = "";
|
||||
if (args[2]) {
|
||||
testArg = args[2];
|
||||
}
|
||||
if (tests.find(testName) != tests.end()) {
|
||||
retval = tests[testName](testArg);
|
||||
}
|
||||
}
|
||||
return retval;
|
||||
}
|
Reference in New Issue
Block a user