//#define _GNU_SOURCE #include #include #include #include #include "../include/opaque.hh" static void s_puts(const auto& string) { std::string_view str{string}; #ifdef DIRECT_WRITE write(1, str.data(), str.size()); #else printf("%.*s", (int)str.size(), str.data()); #endif } static void print_view(std::string_view ptr) { //std::string_view ptr{string}; size_t sz; #ifdef DIRECT_WRITE // Bypass all caching of the output and immediately invoke `write()` for everything if(__builtin_expect((sz = ptr.size()) > 0, true)) { write(1, "> ", 2); write(1, ptr.data(), sz); } else write(1, "! \n", 8); write(1, "\n", 1); #else // All the output from the program is cached and `write()` is only called once at the end. if(__builtin_expect((sz = ptr.size()) > 0, true)) { printf("> %.*s\n", (int)sz, ptr.data()); } else puts("! \n"); #endif } static inline void print(const std::string& string) { std::string_view sv{string}; return print_view(sv); } enum class moh_hck { Template, Ref, Owned, }; /// Example using `make_opaque_handle`, like would be done for a C interface template static void use_moh() { std::string* str = new std::string(__PRETTY_FUNCTION__); constexpr auto v_print = [](const opaque_handle& v) { print(*v); { auto copied = v; s_puts("(copied)"); print(*copied); s_puts("(moved)"); print(*std::move(copied)); } }; if constexpr(Create != moh_hck::Owned) { constexpr auto _h = [](std::string* ptr, auto op) noexcept { if(ptr) { switch(op) { case opaque_handle_operation::Clone: return new std::string(std::as_const(*ptr)); case opaque_handle_operation::Delete: delete ptr; break; } } return static_cast(nullptr); }; if constexpr(Create == moh_hck::Template) { const opaque_handle v{make_opaque_handle(str)}; v_print(v); } else /*if constexpr(Create == moh_hck::Ref)*/ { const opaque_handle v{make_opaque_handle(str, _h)}; v_print(v); } } else { const opaque_handle v{make_opaque_handle(str, [](std::string* ptr, auto op) noexcept { if(ptr) { switch(op) { case opaque_handle_operation::Clone: return new std::string(std::as_const(*ptr)); case opaque_handle_operation::Delete: delete ptr; break; } } return static_cast(nullptr); })}; v_print(v); } s_puts("---\n"); } // Testing a hypothetical C interface extern "C" { struct c_struct_example; struct opaque; void black_box(const opaque* __restrict__){} c_struct_example* cs_create(const c_struct_example* __restrict__ from); void cs_free(c_struct_example* p); void cs_print(const c_struct_example* p); } static void use_c_struct() { using type = c_struct_example; auto* allocp = cs_create(nullptr); opaque_handle impossible{make_opaque_handle>(nullptr)}; black_box(impossible); const opaque_handle v{make_opaque_handle(allocp, [](auto* ptr, auto op) noexcept { if(ptr) { switch(op) { case opaque_handle_operation::Clone: return cs_create(ptr); case opaque_handle_operation::Delete: cs_free(ptr); break; } } return static_cast(nullptr); })}; s_puts("> "); cs_print(v); { auto copied = v; s_puts("(copied)> "); cs_print(copied); s_puts("(moved)> "); cs_print(std::move(copied)); } } int main() { const opaque_handle v{make_opaque_object_handle("Hello world")}; puts("Auto-downcasting to `const std::string&`:"); print(*v); #if 1 s_puts("\nAttempting invalid safe cast... "); try { print_view(*v); // Try to cast to std::string_view, not the correct type... s_puts(" FAILED\n"); return 1; } catch(opaque_bad_cast&) { // Expected this exception to be thrown s_puts(" OK\n"); } catch(opaque_exception& other) { s_puts(" UNEXPECTED ("); s_puts(other.what()); s_puts(")\n"); return 2; } #endif puts("\nConverting view directly:"); print_view(std::string_view{v.cast()}); // Explicit cast needed, *v will choose the wrong type if not. puts("\nUsing opaque_make_handle():"); use_moh(); use_moh(); use_moh(); puts("\nUsing a C interface struct:"); use_c_struct(); return 0; } extern "C" { struct c_struct_example { int i,j; size_t sz; char buf[256]; }; c_struct_example* cs_create(const c_struct_example* __restrict__ from) { auto* ptr = reinterpret_cast(aligned_alloc(alignof(c_struct_example), sizeof(c_struct_example))); //memset(ptr, 0, sizeof(c_struct_example); if(!from) { ptr->i = 10; ptr->j = 11; snprintf(ptr->buf, 256, "Hello from C interface"); } else { //memcpy(ptr, from, sizeof(c_struct_example)); *ptr = *from; ptr->i +=1; ptr->j -=1; snprintf(ptr->buf, 256, "Hello from copied C interface (from %p)", from); } return ptr; } void cs_print(const c_struct_example* p) { #ifdef DIRECT_WRITE char ibuf[512]; size_t n = snprintf(ibuf, 512, "%s: (%d, %d)", p->buf, p->i, p->j); write(1, ibuf, n < sizeof(ibuf) ? n : 511); write(1, "\n", 1); #else printf("%s: (%d, %d)\n", p->buf, p->i, p->j); #endif } void cs_free(c_struct_example* p) { free(p); } }