2.5.6.4 Sample PlBlob code
Here is minimal sample code for creating a blob that owns a
connection to a database. It has a single field (connection)
and defines compare_fields() and write_fields().
struct MyBlob;
static PL_blob_t my_blob = PL_BLOB_DEFINITION(MyBlob, "my_blob");
struct MyBlob : public PlBlob
{ std::unique_ptr<MyConnection> connection;
std::string name_; // Used for error terms
explicit MyBlob()
: PlBlob(&my_blob) { }
explicit MyBlob(const std::string& connection_name)
: PlBlob(&my_blob),
connection(std::make_unique<MyConnection>(connection_name)),
name_(connection_name)
{ if ( !connection->open() )
throw MyBlobError("my_blob_open_error");
}
PL_BLOB_SIZE
~MyBlob() noexcept
{ if ( !close() )
Sdprintf("Close MyBlob failed: %s", name_.c_str()); // Can't use PL_warning()
}
bool close() noexcept
{ if ( !connection )
return true;
bool rc = connection->close();
connection.reset(); // Can be omitted, leaving deletion to ~MyBlob()
return rc;
}
PlException MyBlobError(const char* error) const
{ return PlGeneralError(PlCompound(error, PlTermv(symbol_term())));
}
int compare_fields(const PlBlob* _b_data) const override
{ auto b_data = static_cast<const MyBlob*>(_b_data); // See note about cast
return name_.compare(b_data->name_);
}
bool write_fields(IOSTREAM *s, int flags) const override
{ if ( !Sfprintf(s, ",name=%s", name_.c_str()) )
return false;
if ( !connection )
return Sfprintf(s, ",closed");
return true;
}
};
// %! create_my_blob(+Name: atom, -MyBlob) is semidet.
PREDICATE(create_my_blob, 2)
{ // Allocating the blob uses std::unique_ptr<MyBlob> so that it'll be
// deleted if an error happens - the auto-deletion is disabled by
// ref.release() before returning success.
auto ref = std::unique_ptr<PlBlob>(new MyBlob(A1.as_atom().as_string()));
return A2.unify_blob(&ref);
}
// %! close_my_blob(+MyBlob) is det.
// % Close the connection, silently succeeding if is already
// % closed; throw an exception if something goes wrong.
PREDICATE(close_my_blob, 1)
{ auto ref = PlBlobV<MyBlob>::cast_ex(A1, my_blob);
if ( !ref->close() )
throw ref->MyBlobError("my_blob_close_error");
return true;
}