|
|
|
@ -5,18 +5,101 @@
|
|
|
|
|
|
|
|
|
|
#include <unistd.h>
|
|
|
|
|
|
|
|
|
|
#include <cxxabi.h>
|
|
|
|
|
|
|
|
|
|
#include "../include/opaque.hh"
|
|
|
|
|
|
|
|
|
|
static void s_puts(const auto& string)
|
|
|
|
|
struct demangle_failed : std::exception {
|
|
|
|
|
virtual int status() const noexcept = 0;
|
|
|
|
|
const char* what() const noexcept override {
|
|
|
|
|
auto s = status();
|
|
|
|
|
switch(s) {
|
|
|
|
|
case -1: return "A memory allocation failure occurred";
|
|
|
|
|
case -2: return "`mangled` was not a valid name under the C++ ABI mangling rules";
|
|
|
|
|
case -3: return "One of the arguments was invalid";
|
|
|
|
|
default: return "Unknown error";
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
protected:
|
|
|
|
|
inline demangle_failed() : std::exception(){}
|
|
|
|
|
};
|
|
|
|
|
static std::string demangle_name(const char* mangled)
|
|
|
|
|
{
|
|
|
|
|
struct demangle_error final : public demangle_failed
|
|
|
|
|
{
|
|
|
|
|
inline demangle_error(int s) : demangle_failed(), _status(s) {}
|
|
|
|
|
|
|
|
|
|
inline int status() const noexcept override final { return _status; }
|
|
|
|
|
|
|
|
|
|
int _status;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
size_t len;
|
|
|
|
|
int status;
|
|
|
|
|
char * demangled = abi::__cxa_demangle(mangled, nullptr, &len, &status);
|
|
|
|
|
|
|
|
|
|
const auto c_str_to_string = [len](char* str)
|
|
|
|
|
noexcept(std::is_nothrow_constructible_v<std::string, const char*, size_t>)
|
|
|
|
|
{
|
|
|
|
|
const auto _free = [&]() { free(static_cast<void*>(str)); };
|
|
|
|
|
|
|
|
|
|
if constexpr(std::is_nothrow_constructible_v<std::string, const char*, size_t>) {
|
|
|
|
|
std::string v{str, len};
|
|
|
|
|
_free();
|
|
|
|
|
return v;
|
|
|
|
|
} else {
|
|
|
|
|
try {
|
|
|
|
|
std::string v{str, len};
|
|
|
|
|
_free();
|
|
|
|
|
return v;
|
|
|
|
|
} catch(...) {
|
|
|
|
|
_free();
|
|
|
|
|
throw;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
if(demangled)
|
|
|
|
|
return c_str_to_string(demangled);
|
|
|
|
|
else
|
|
|
|
|
throw demangle_error(status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
inline static std::string demangle_name(const std::string& mangled)
|
|
|
|
|
{
|
|
|
|
|
return demangle_name(mangled.c_str());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void s_puts(const auto& string, FILE* to = nullptr)
|
|
|
|
|
{
|
|
|
|
|
std::string_view str{string};
|
|
|
|
|
to = to ?: stdout;
|
|
|
|
|
|
|
|
|
|
#ifdef DIRECT_WRITE
|
|
|
|
|
write(1, str.data(), str.size());
|
|
|
|
|
write(fileno(to), str.data(), str.size());
|
|
|
|
|
#else
|
|
|
|
|
printf("%.*s", (int)str.size(), str.data());
|
|
|
|
|
fprintf(to, "%.*s", (int)str.size(), str.data());
|
|
|
|
|
#endif
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_name(const std::type_info& type)
|
|
|
|
|
{
|
|
|
|
|
const char* name = type.name();
|
|
|
|
|
s_puts("type holds: ");
|
|
|
|
|
try {
|
|
|
|
|
s_puts(demangle_name(name));
|
|
|
|
|
s_puts("\n");
|
|
|
|
|
} catch(demangle_failed& err) {
|
|
|
|
|
s_puts("<mangled> ");
|
|
|
|
|
s_puts(name);
|
|
|
|
|
s_puts("\n");
|
|
|
|
|
|
|
|
|
|
s_puts("Failed to demangle name: ", stderr);
|
|
|
|
|
s_puts(err.what(), stderr);
|
|
|
|
|
s_puts("\n", stderr);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void print_view(std::string_view ptr)
|
|
|
|
|
{
|
|
|
|
|
//std::string_view ptr{string};
|
|
|
|
@ -55,6 +138,10 @@ static void use_moh()
|
|
|
|
|
std::string* str = new std::string(__PRETTY_FUNCTION__);
|
|
|
|
|
|
|
|
|
|
constexpr auto v_print = [](const opaque_handle& v) {
|
|
|
|
|
try {
|
|
|
|
|
print_name(v.get_type());
|
|
|
|
|
} catch(const opaque_unknown_type&) { s_puts("type holds: <unknown>\n"); }
|
|
|
|
|
|
|
|
|
|
print(*v);
|
|
|
|
|
{
|
|
|
|
|
auto copied = v;
|
|
|
|
@ -119,6 +206,15 @@ static void use_c_struct()
|
|
|
|
|
opaque_handle impossible{make_opaque_handle<opaque, opaque_empty_handler<opaque>>(nullptr)};
|
|
|
|
|
black_box(impossible);
|
|
|
|
|
|
|
|
|
|
s_puts("Testing <incomplete>.get_type() throwing... ");
|
|
|
|
|
try {
|
|
|
|
|
print_name(impossible.get_type());
|
|
|
|
|
s_puts(" FAILED (expected `opaque_unknown_type` exception)\n");
|
|
|
|
|
std::terminate();
|
|
|
|
|
} catch(const opaque_unknown_type&) {
|
|
|
|
|
s_puts(" OK\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
const opaque_handle v{make_opaque_handle<type>(allocp, [](auto* ptr, auto op) noexcept {
|
|
|
|
|
if(ptr) {
|
|
|
|
|
switch(op) {
|
|
|
|
@ -129,6 +225,10 @@ static void use_c_struct()
|
|
|
|
|
return static_cast<type*>(nullptr);
|
|
|
|
|
})};
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
print_name(v.get_type());
|
|
|
|
|
} catch(const opaque_unknown_type&) { s_puts("type holds: <unknown at this point>\n"); }
|
|
|
|
|
|
|
|
|
|
s_puts("> ");
|
|
|
|
|
cs_print(v);
|
|
|
|
|
{
|
|
|
|
@ -144,8 +244,28 @@ int main()
|
|
|
|
|
{
|
|
|
|
|
const
|
|
|
|
|
opaque_handle v{make_opaque_object_handle<std::string>("Hello world")};
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
using prim_t = int;
|
|
|
|
|
struct never_t{};
|
|
|
|
|
auto prim = make_opaque_object_handle<prim_t>(-115);
|
|
|
|
|
puts("Primitive type handling");
|
|
|
|
|
s_puts("(pre-mutation)");
|
|
|
|
|
{
|
|
|
|
|
prim_t& vref = prim.cast<prim_t>();
|
|
|
|
|
print(std::to_string(std::as_const(vref)));
|
|
|
|
|
vref *= -1;
|
|
|
|
|
}
|
|
|
|
|
s_puts("(post-mutation)");
|
|
|
|
|
print(std::to_string(std::as_const(prim).cast<prim_t>()));
|
|
|
|
|
print_name(prim.get_type());
|
|
|
|
|
s_puts(prim.is_type<prim_t>() ? "\t-> +v: yes, " : "\t-> +v: no, ");
|
|
|
|
|
s_puts(prim.is_type<never_t>() ? "!v: yes\n" : "!v: no\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
puts("\nAuto-downcasting to `const std::string&`:");
|
|
|
|
|
print_name(v.get_type());
|
|
|
|
|
|
|
|
|
|
puts("Auto-downcasting to `const std::string&`:");
|
|
|
|
|
print(*v);
|
|
|
|
|
#if 1
|
|
|
|
|
s_puts("\nAttempting invalid safe cast... ");
|
|
|
|
|