Compare commits

..

No commits in common. 'master' and 'error_handling' have entirely different histories.

2
.gitignore vendored

@ -4,5 +4,3 @@ cow-*
obj/ obj/
*~ *~
vgcore.* vgcore.*
target/
!cowslice/*.a

@ -5,7 +5,7 @@ PROJECT=cow
AUTHOR=Avril (Flanchan) <flanchan@cumallover.me> AUTHOR=Avril (Flanchan) <flanchan@cumallover.me>
VERSION_MAJOR=0 VERSION_MAJOR=0
VERSION_MINOR=3.0 VERSION_MINOR=2.0r1
VERSION=$(VERSION_MAJOR).$(VERSION_MINOR) VERSION=$(VERSION_MAJOR).$(VERSION_MINOR)
ifeq ($(PREFIX),) ifeq ($(PREFIX),)

@ -35,13 +35,6 @@ typedef struct cow_mapped_slice cow_t;
/// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory. /// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory.
/// Writes to any cloned instances do not propagate to this instance. /// Writes to any cloned instances do not propagate to this instance.
cow_t* cow_create(size_t size); cow_t* cow_create(size_t size);
/// Create a new copy-on-write area of `size` bytes from file `fd`.
/// Writes to this instance pointer (`cow_ptr()`) are written to the allocated memory.
/// Writes to any cloned instances do not propagate to this instance.
///
/// The resulting object does not own `fd`, but does own a duplicate of it.
cow_t* cow_create_fd(int fd, size_t size);
/// Free a cow area. This should be called on all clones before the parent of those clones is freed. /// Free a cow area. This should be called on all clones before the parent of those clones is freed.
void cow_free(cow_t* restrict cow); void cow_free(cow_t* restrict cow);
/// Create a clone of this instance. Any writes to the returned pointer will not be propagated to the input one. /// Create a clone of this instance. Any writes to the returned pointer will not be propagated to the input one.

@ -21,15 +21,12 @@ struct Cow : public _cow_util::Span<unsigned char> {
struct Fake; struct Fake;
Cow() = delete; Cow() = delete;
Cow(int fd, size_t size);
explicit Cow(size_t size); explicit Cow(size_t size);
Cow(Cow&& m); Cow(Cow&& m);
virtual ~Cow(); virtual ~Cow();
virtual Fake clone() const; virtual Fake clone() const;
protected:
inline void* area() override { inline void* area() override {
auto raw = get_raw(); auto raw = get_raw();
return raw ? cow_ptr(raw) : nullptr; return raw ? cow_ptr(raw) : nullptr;
@ -38,7 +35,6 @@ struct Cow : public _cow_util::Span<unsigned char> {
auto raw = get_raw(); auto raw = get_raw();
return raw ? cow_ptr_of(const void, raw) : nullptr; return raw ? cow_ptr_of(const void, raw) : nullptr;
} }
public:
/// Get the size of the mapped area. /// Get the size of the mapped area.
/// ///
@ -63,8 +59,6 @@ struct Cow : public _cow_util::Span<unsigned char> {
protected: protected:
Cow(const Cow& c); Cow(const Cow& c);
explicit inline Cow(std::shared_ptr<_inner>&& super) : super(std::move(super)){}
const std::shared_ptr<_inner> super; const std::shared_ptr<_inner> super;
virtual cow_t* get_raw() const; virtual cow_t* get_raw() const;
@ -90,3 +84,9 @@ struct Cow::Fake : public Cow {
cow_t* const fake; cow_t* const fake;
}; };
//TODO
template<typename T>
struct TypedCow : private Cow, public _cow_util::Span<T> {
struct Fake : private Cow::Fake, public _cow_util::Span<T>{};
};

@ -5,10 +5,9 @@
#include <utility> #include <utility>
#include <cow.hpp> #include <cow.hpp>
#include "slice.hpp"
namespace _cow_util { namespace _cow_util {
struct Area : public Span<unsigned char> { struct Area {
Area() = delete; Area() = delete;
explicit Area(size_t sz); explicit Area(size_t sz);
@ -31,13 +30,7 @@ namespace _cow_util {
inline cow_t* raw() const { return _area->raw(); } inline cow_t* raw() const { return _area->raw(); }
inline size_t size() const override { return _area->size(); }
~Area(); ~Area();
protected:
inline void* area() override { return _area->ptr(); }
inline const void* area() const override { return _area->ptr(); }
private: private:
const std::unique_ptr<Cow> _area; const std::unique_ptr<Cow> _area;
}; };

@ -4,19 +4,17 @@ namespace _cow_util {
/// A type that spans a sized region of memory /// A type that spans a sized region of memory
template<typename T> template<typename T>
struct Span { struct Span {
protected:
virtual const void* area() const =0; virtual const void* area() const =0;
virtual void* area() = 0; virtual void* area() = 0;
public:
virtual size_t size() const = 0; virtual size_t size() const = 0;
inline T* ptr() { return reinterpret_cast<T*>(area()); } inline T* ptr() { return (T*)area(); }
inline const T* ptr() const { return reinterpret_cast<const T*>(area()); } inline const T* ptr() const { return (const T*)area(); }
inline size_t size_bytes() const { return size() * sizeof(T); } inline size_t size_bytes() const { return size() * sizeof(T); }
inline unsigned char* as_bytes() { return area_as<unsigned char>(); } inline unsigned char* as_bytes() { return (unsigned char*)area(); }
inline const unsigned char* as_bytes() const { return area_as<unsigned char>(); } inline const unsigned char* as_bytes() const { return (const unsigned char*)area(); }
inline T& operator[](size_t index) { inline T& operator[](size_t index) {
if(index >= size()) throw "index out of range"; if(index >= size()) throw "index out of range";
@ -40,9 +38,9 @@ namespace _cow_util {
inline operator T*() { return &(*this)[0]; } inline operator T*() { return &(*this)[0]; }
template<typename U> template<typename U>
inline U* area_as() requires(sizeof(T) % sizeof(U) == 0) { return reinterpret_cast<U*>(area()); } inline U* area_as() requires(sizeof(T) % sizeof(U) == 0) { return (U*)area(); }
template<typename U> template<typename U>
inline const U* area_as() const requires(sizeof(T) % sizeof(U) == 0) { return reinterpret_cast<const U*>(area()); } inline const U* area_as() const requires(sizeof(T) % sizeof(U) == 0) { return (U*)area(); }
template<typename U> template<typename U>
size_t size_as() const requires(sizeof(T) % sizeof(U) == 0) { return size_bytes() / sizeof(U); } size_t size_as() const requires(sizeof(T) % sizeof(U) == 0) { return size_bytes() / sizeof(U); }
@ -91,24 +89,23 @@ namespace _cow_util {
inline const Slice slice_wrap(ssize_t len) const { return slice_abs((size_t)wrap_len(len)); } inline const Slice slice_wrap(ssize_t len) const { return slice_abs((size_t)wrap_len(len)); }
template<typename U> template<typename U>
inline Span<U>::Slice reinterpret() { return typename Span<U>::Slice(area_as<U>(), size_bytes() / sizeof(U)); } inline Span<U>::Slice reinterpret() { return typename Span<U>::Slice((U*)area(), size_bytes() / sizeof(U)); }
template<typename U> template<typename U>
inline Span<const U>::Slice reinterpret() const { return typename Span<const U>::Slice(area_as<U>(), size_bytes() / sizeof(U)); } inline Span<const U>::Slice reinterpret() const { return typename Span<const U>::Slice((const U*)area(), size_bytes() / sizeof(U)); }
}; };
/// A slice of memory with a backing pointer and size. /// A slice of memory with a backing pointer and size.
template<typename T> template<typename T>
struct Span<T>::Slice : public Span<T> { struct Span<T>::Slice : public Span<T> {
inline Slice(T* ptr, size_t sz) : _area(reinterpret_cast<void*>(ptr)), _size(sz){} inline Slice(T* ptr, size_t sz) : _area((void*)ptr), _size(sz){}
inline Slice(const Span<T>& slice) : _area(const_cast<void*>(slice.area())), _size(slice.size()){} inline Slice(const Span<T>& slice) : _area(const_cast<void*>(slice.area())), _size(slice.size()){}
inline Slice(const Slice& copy) = default; inline Slice(const Slice& copy) = default;
inline Slice(Slice&& copy) : _area(copy._area), _size(copy._size){ *const_cast<size_t*>(&copy._size) = 0; } inline Slice(Slice&& copy) : _area(copy._area), _size(copy._size){ *const_cast<size_t*>(&copy._size) = 0; }
Slice() = delete; Slice() = delete;
inline size_t size() const override { return _size; }
protected:
inline const void* area() const override { return _area; } inline const void* area() const override { return _area; }
inline void* area() override { return _area; } inline void* area() override { return _area; }
inline size_t size() const override { return _size; }
private: private:
void* const _area; void* const _area;

@ -1,121 +0,0 @@
#pragma once
#include <cow.hpp>
#include <utility>
template<typename T>
struct TypedCow : public _cow_util::Span<T> {
struct Fake;
template<typename... Args>
inline TypedCow(size_t sz, Args&&... args) : real(Cow(sz * sizeof(T))) { init_copy( T(std::forward<Args>(args)...) ); }
inline TypedCow(size_t sz, const T& copy) : real(Cow(sz * sizeof(T))) { init_copy(copy); }
inline TypedCow(size_t sz) : TypedCow(sz, T()){}
inline virtual ~TypedCow() { uninit(); }
inline virtual Fake clone() const { return Fake(*this); }
inline virtual cow_t* raw() const { return real.raw(); }
inline size_t size() const { return real.size() / sizeof(T); }
protected:
//inline explicit TypedCow(const TypedCow<T>& unsafeCopy) : real(Cow(unsafeCopy.real)){}
inline virtual void* area() override { return reinterpret_cast<void*>( real.ptr() ); }
inline virtual const void* area() const override { return reinterpret_cast<const void*>( real.ptr() ); }
inline void init_copy(const T& copy_from) {
T* ptr = this->ptr();
for(size_t i=0;i<size();i++)
new ((void*)(ptr+i)) T(copy_from);
}
// UNSAFE: Explicitly calls destructors of each element in this instance.
inline void uninit() {
T* ptr = this->ptr();
if(!ptr) return;
for(size_t i=0;i<size();i++)
(ptr+i)->~T();
}
private:
Cow real;
};
template<typename T>
struct TypedCow<T>::Fake : public TypedCow<T> {
//XXX: How THE FUCK do we initialise base's `real` here?????
Fake() = delete;
inline Fake(const Fake& copy) : fake(cow_clone(copy.fake)){}
inline Fake(Fake&& move) : fake(move.fake) { *const_cast<cow_t**>(&move.fake) = nullptr; }
inline Fake(const TypedCow<T>& clone) : fake(cow_clone(clone.raw())){}
inline cow_t* raw() const override { return fake; }
inline Fake clone() const override { return Fake(*this); }
inline ~Fake(){}
inline size_t size() const override { return fake ? cow_size(fake) : 0; }
protected:
inline void* area() override { return fake ? cow_ptr(fake) : nullptr; }
inline const void* area() const override { return fake ? cow_ptr_of(const void, fake) : nullptr; }
private:
cow_t* const fake;
};
#if 0
struct Fake;
friend class Fake;
TypedCow() = delete;
inline TypedCow(TypedCow<T>&& move) : Cow(std::move(move.super)) { /* Moves the shared_ptr. No need to move the elements. */ }
// protected: copy
inline TypedCow(size_t sz) : Cow(sz * sizeof(T)) { init_copy(T()); }
inline TypedCow(size_t sz, const T& copy_from) : TypedCow(sz) { init_copy(copy_from); }
//template<typename... Args>
//inline TypedCow(size_t sz, Args&&... args) : TypedCow(sz) { init_copy( T(std::forward<Args>(args)...) ); }
virtual inline ~TypedCow() { uninit(); }
inline Cow::Fake clone() const override { return Cow::clone(); }
inline Fake clone() const { return Fake(Cow::clone()); }
inline size_t size() const override { return Cow::size() / sizeof(T); }
protected:
inline void* area() override { return Cow::area(); }
inline const void* area() const override { return Cow::area(); }
//// Should only be used for creating Fakes. Copies the refcounted pointer.
//inline TypedCow(const TypedCow<T>& copy) : Cow(copy.super) {}
// UNSAFE: Placement-new's copys of `copy_from` into `0..size()` of this instance.
inline void init_copy(const T& copy_from) {
T* ptr = _cow_util::Span<T>::ptr();
for(size_t i=0;i<size();i++)
new ((void*)(ptr+i)) T(copy_from);
}
// UNSAFE: Explicitly calls destructors of each element in this instance.
inline void uninit() {
T* ptr = _cow_util::Span<T>::ptr();
for(size_t i=0;i<size();i++)
(ptr+i)->~T();
}
};
template<typename T>
struct TypedCow<T>::Fake : private Cow::Fake, public _cow_util::Span<T> {
Fake() = delete;
explicit inline Fake(Cow::Fake&& untyped) : Cow::Fake(untyped){}
inline Fake(const Fake& copy) : Fake(copy.Cow::Fake::clone()){}
inline Fake(Fake&& move) : Cow::Fake(std::move(move)) {}
inline ~Fake(){}
inline size_t size() const override { return Cow::Fake::size(); }
protected:
inline const void* area() const override { return Cow::Fake::area(); }
inline void* area() override { return Cow::Fake::area(); }
};
#endif

@ -76,13 +76,13 @@ size_t cow_size(const cow_t* cow)
return cow->size; return cow->size;
} }
inline internal cow_t _cow_create_unboxed(int _fd, size_t size) inline internal cow_t _cow_create_unboxed(size_t size)
{ {
cow_t ret; cow_t ret;
ret.size = size; ret.size = size;
if( (ret.poisoned = if( (ret.poisoned =
((ret.fd = _fd < 0 ? shm_fd(size) : _fd) == -1)) ((ret.fd = shm_fd(size)) == -1))
) { ) {
ret.origin = NULL; ret.origin = NULL;
return ret; return ret;
@ -96,14 +96,7 @@ inline internal cow_t _cow_create_unboxed(int _fd, size_t size)
} }
cow_t* cow_create(size_t size) cow_t* cow_create(size_t size)
{ {
return box_value(_cow_create_unboxed(-1, size)); return box_value(_cow_create_unboxed(size));
}
cow_t* cow_create_fd(int fd, size_t size)
{
fd = dup(fd);
if(__builtin_expect(fd < 0, false)) return NULL;
return box_value(_cow_create_unboxed(fd, size));
} }
inline internal void _cow_free_unboxed(const cow_t* cow) inline internal void _cow_free_unboxed(const cow_t* cow)

@ -15,7 +15,6 @@ struct Cow::_inner {
~_inner(); ~_inner();
_inner(size_t sz); _inner(size_t sz);
_inner(int fd, size_t sz);
_inner(cow_t* ptr); _inner(cow_t* ptr);
_inner(const _inner& copy) = delete; _inner(const _inner& copy) = delete;
@ -28,12 +27,10 @@ Cow::_inner::~_inner() {
_cow_free_unboxed(ptr()); _cow_free_unboxed(ptr());
cow.poisoned=true; cow.poisoned=true;
} }
Cow::_inner::_inner(int fd, size_t sz) : cow(_cow_create_unboxed(fd, sz)){ Cow::_inner::_inner(size_t sz) : cow(_cow_create_unboxed(sz)){
if(UNLIKELY(cow.poisoned)) throw CowException(cow_err()); if(UNLIKELY(cow.poisoned)) throw CowException(cow_err());
} }
Cow::_inner::_inner(size_t sz) : _inner(-1, sz) {}
Cow::_inner::_inner(cow_t* ptr) : cow(*ptr) Cow::_inner::_inner(cow_t* ptr) : cow(*ptr)
{ {
free(ptr); free(ptr);
@ -41,7 +38,6 @@ Cow::_inner::_inner(cow_t* ptr) : cow(*ptr)
} }
Cow::Cow(size_t size) : super(std::make_shared<_inner>(size)){} Cow::Cow(size_t size) : super(std::make_shared<_inner>(size)){}
Cow::Cow(int fd, size_t size) : super(std::make_shared<_inner>(fd, size)){}
Cow::Cow(cow_t* raw) : super(std::make_shared<_inner>(raw)){} Cow::Cow(cow_t* raw) : super(std::make_shared<_inner>(raw)){}
Cow::Cow(Cow&& m) : super(std::move(*const_cast<std::shared_ptr<_inner>*>(&m.super))){} Cow::Cow(Cow&& m) : super(std::move(*const_cast<std::shared_ptr<_inner>*>(&m.super))){}

@ -44,7 +44,7 @@ _Static_assert
(offsetof(cow_t, size) == sizeof(void*), "`cow_t.size` should have an offset equal to `sizeof(void*)` or cow_size_unsafe() becomes UB."); (offsetof(cow_t, size) == sizeof(void*), "`cow_t.size` should have an offset equal to `sizeof(void*)` or cow_size_unsafe() becomes UB.");
#endif #endif
cow_t _cow_create_unboxed(int rfd, size_t size) internal; cow_t _cow_create_unboxed(size_t size) internal;
void _cow_free_unboxed(const cow_t* cow) internal; void _cow_free_unboxed(const cow_t* cow) internal;
#ifdef __cplusplus #ifdef __cplusplus

@ -8,7 +8,6 @@
#include <vector> #include <vector>
#include <cow/area.hpp> #include <cow/area.hpp>
#include <cow/typed.hpp>
using namespace _cow_util; using namespace _cow_util;
@ -147,7 +146,7 @@ namespace Tiling {
template<typename T = unsigned char> template<typename T = unsigned char>
void print_slice(Slice<T> memory) void print_slice(Slice<T> memory)
{ {
printf("slice: { %p, %lu (%lu bytes) }\n", memory.ptr(), memory.size(), memory.size_bytes()); printf("slice: { %p, %lu (%lu bytes) }\n", memory.area(), memory.size(), memory.size_bytes());
} }
@ -169,12 +168,6 @@ void moving_cow(Cow moved)
read_fake(moved); read_fake(moved);
} }
void typed_cow()
{
TypedCow<int> tc(1024);
}
int main() int main()
{ {
Cow _area(4000); Cow _area(4000);
@ -210,7 +203,7 @@ int main()
Cow::Fake clone = real; Cow::Fake clone = real;
printf("Fake size: %lu\n", clone.size()); printf("Fake size: %lu\n", clone.size());
printf("Fake ptr: %p\n", clone.ptr()); printf("Fake ptr: %p\n", clone.area());
read_fake(clone); read_fake(clone);
write_fake(clone, "hello fake!"); write_fake(clone, "hello fake!");
@ -223,7 +216,6 @@ int main()
printf("First byte of: fake = %x\n", clone[0]); printf("First byte of: fake = %x\n", clone[0]);
read_fake(clone); //clone still functions because of refcount on origin. read_fake(clone); //clone still functions because of refcount on origin.
typed_cow();
printf("Last error: %d, %s\n", cow_err(), *cow_err_msg(cow_err())); printf("Last error: %d, %s\n", cow_err(), *cow_err_msg(cow_err()));
try { try {
Cow should_fail(SIZE_MAX); Cow should_fail(SIZE_MAX);

Loading…
Cancel
Save