offset-based cow_size_unsafe defined, dubiously...

cpp
Avril 4 years ago
parent b8699c78db
commit 0c5865e00f
Signed by: flanchan
GPG Key ID: 284488987C31F630

@ -24,6 +24,14 @@ cow_t* cow_clone(const cow_t* cow);
int cow_is_fake(const cow_t* cow); int cow_is_fake(const cow_t* cow);
/// Get the size of this cow area. /// Get the size of this cow area.
size_t cow_size(const cow_t* cow); size_t cow_size(const cow_t* cow);
/// Get the size of this cow area by assuming layout. This should work assuming "cow_t.h"'s build assertions didn't fail and avoids an extra call.
#ifdef _COW_NO_ASSUME_ABI
#define cow_size_unsafe(v) cow_size(v)
#else
// XXX: This macro is *VERY* ABI sensitive. This shouldn't be used if the ABI has changed since the build of libcow's `cow_t.h` passed its static assertions in *both* the C and C++ implementations.
// The C++ API uses this by default for its `Cow::size()` function.
#define cow_size_unsafe(v) *(((size_t*)(v))+1)
#endif
/// Get the `void*` pointer to the start of the area. /// Get the `void*` pointer to the start of the area.
#define cow_ptr(v) (*((void**)(v))) #define cow_ptr(v) (*((void**)(v)))

@ -4,6 +4,7 @@
#include <memory> #include <memory>
struct Cow { struct Cow {
struct Fake; struct Fake;
Cow() = delete; Cow() = delete;
@ -16,13 +17,29 @@ struct Cow {
inline void* area() { return cow_ptr(get_raw()); } inline void* area() { return cow_ptr(get_raw()); }
inline const void* area() const { return cow_ptr_of(const void, get_raw()); } inline const void* area() const { return cow_ptr_of(const void, get_raw()); }
inline size_t size() const { return cow_size(get_raw()); }
/// Get the size of the mapped area.
///
/// Note: This calls into `_inner`'s internals. To skip the call on non-LTO builds, use `size_unsafe()`.
size_t size() const;
/// Get the size by assuming the ABI layout of cow_t to be correct. Potentially faster but ABI sensitive.
/// This shouldn't be a problem if all build static assertions passed.
///
/// Note: This behaviour can be diabled by building with `-DCOW_NO_ASSUME_ABI`. In this case, this function calls out to the C API to determine the size.
/// There is also likely no benefit using this over `size()` in LTO enabled builds.
inline size_t size_unsafe() const { return cow_size_unsafe(get_raw()); }
inline unsigned char* as_bytes() { return (unsigned char*)area(); } inline unsigned char* as_bytes() { return (unsigned char*)area(); }
inline const unsigned char* as_bytes() const { return (const unsigned char*)area(); } inline const unsigned char* as_bytes() const { return (const unsigned char*)area(); }
unsigned char& operator[](size_t index); inline unsigned char& operator[](size_t index) {
const unsigned char& operator[](size_t index) const; if(index >= size()) throw "Size too large";
return as_bytes()[index];
}
inline const unsigned char& operator[](size_t index) const {
if(index >= size()) throw "Size too large";
return as_bytes()[index];
}
static Cow from_raw(cow_t* owned); static Cow from_raw(cow_t* owned);

@ -39,6 +39,8 @@ Cow Cow::from_raw(cow_t* owned) { if(cow_is_fake(owned)) throw "Trying to create
Cow::Fake Cow::clone() const { return Fake::from_real(*this); } Cow::Fake Cow::clone() const { return Fake::from_real(*this); }
cow_t* Cow::get_raw() const { return super->ptr(); } cow_t* Cow::get_raw() const { return super->ptr(); }
size_t Cow::size() const { return super->cow.size; }
Cow::Fake::Fake(const Cow& copy) : Cow(copy), fake(cow_clone(copy.super->ptr())){} Cow::Fake::Fake(const Cow& copy) : Cow(copy), fake(cow_clone(copy.super->ptr())){}
Cow::Fake::Fake(const Fake& copy) : Cow(copy), fake(cow_clone(copy.fake)){}//Fake(*static_cast<const Cow*>(&copy)){} Cow::Fake::Fake(const Fake& copy) : Cow(copy), fake(cow_clone(copy.fake)){}//Fake(*static_cast<const Cow*>(&copy)){}
Cow::Fake::Fake(Fake&& move) : Cow(std::move(move)), fake(move.fake) Cow::Fake::Fake(Fake&& move) : Cow(std::move(move)), fake(move.fake)
@ -54,11 +56,3 @@ cow_t* Cow::Fake::get_raw() const { return fake; }
// Operators // Operators
unsigned char& Cow::operator[](size_t index) {
if(index >= size()) throw "Size too large";
return as_bytes()[index];
}
const unsigned char& Cow::operator[](size_t index) const {
if(index >= size()) throw "Size too large";
return as_bytes()[index];
}

@ -16,8 +16,8 @@ extern "C" {
struct cow_mapped_slice { struct cow_mapped_slice {
void* origin; // ptr to mapped memory. This *MUST* be the first field and have an offset of 0. void* origin; // ptr to mapped memory. This *MUST* be the first field and have an offset of 0.
size_t size; // Should be at this offset.
int fd; // Will be ORd with ~INT_MAX if it's a clone. Will be >0 if it's the original. int fd; // Will be ORd with ~INT_MAX if it's a clone. Will be >0 if it's the original.
size_t size;
}; // cow_t, *cow }; // cow_t, *cow
#ifdef __cplusplus #ifdef __cplusplus
@ -27,6 +27,15 @@ _Static_assert
#endif #endif
(offsetof(cow_t, origin) == 0, "`cow_t.origin` must have an offset of 0."); (offsetof(cow_t, origin) == 0, "`cow_t.origin` must have an offset of 0.");
#ifndef _COW_NO_ASSUME_ABI
#ifdef __cplusplus
static_assert
#else
_Static_assert
#endif
(offsetof(cow_t, size) == sizeof(void*), "`cow_t.size` should have an offset equal to `sizeof(void*)` or cow_size_unsafe() becomes UB.");
#endif
cow_t _cow_create_unboxed(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;

@ -1,9 +1,13 @@
#include <cow.hpp> #include <cow.hpp>
#include <cstdio>
int main() int main()
{ {
Cow real(4096); Cow real(4096);
printf("Fast size: %lu, slow size: %lu\n", real.size_unsafe(), real.size());
Cow::Fake clone = real; Cow::Fake clone = real;
{ {
Cow::Fake clone2 = clone; Cow::Fake clone2 = clone;

Loading…
Cancel
Save