• Places
    • Home
    • Graphs
    • Prefixes
  • Admin
    • Users
    • Settings
    • Plugins
    • Statistics
  • CPACK
    • Home
    • List packs
    • Submit pack
  • Repository
    • Load local file
    • Load from HTTP
    • Load from library
    • Remove triples
    • Clear repository
  • Query
    • YASGUI SPARQL Editor
    • Simple Form
    • SWISH Prolog shell
  • Help
    • Documentation
    • Tutorial
    • Roadmap
    • HTTP Services
  • Login

1.6.8 Blobs
All Application Manual Name SummaryHelp

  • Documentation
    • Reference manual
    • Packages
      • A C++ interface to SWI-Prolog
        • A C++ interface to SWI-Prolog
          • Overview
            • Blobs
              • A review of C++ features used by the API
              • How to define a blob using C++
              • The life of a PlBlob
              • C++ exceptions and blobs
              • Sample PlBlob code (connection to database)
              • Discussion of the sample PlBlob code
              • Sample PlBlob code (wrapping a pointer)
              • Discussion of the sample PlBlob code (wrapping a pointer)
              • Identifying blobs by atoms

1.6.8.5 Sample PlBlob code (connection to database)

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().

A second sample code shows how to wrap a system pointer - section 1.6.8.7

struct MyConnection
{ std::string name;

  explicit MyConnection();
  explicit MyConnection(const std::string& _name);
  bool open();
  bool close() noexcept;
  void portray(PlStream& strm) const;
};

struct MyBlob;

static PL_blob_t my_blob = PL_BLOB_DEFINITION(MyBlob, "my_blob");

struct MyBlob : public PlBlob
{ std::unique_ptr<MyConnection> connection;

  explicit MyBlob()
    : PlBlob(&my_blob) { }

  explicit MyBlob(const std::string& connection_name)
    : PlBlob(&my_blob),
      connection(std::make_unique<MyConnection>(connection_name))
  { if ( !connection->open() )
      throw MyBlobError("my_blob_open_error");
  }

  PL_BLOB_SIZE

  ~MyBlob() noexcept
  { if ( !close() )
      Sdprintf("***ERROR: Close MyBlob failed: %s\n", name().c_str()); // Can't use PL_warning()
  }

  inline std::string
  name() const
  { return connection ? connection->name : "";
  }

  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
  { PlStream strm(s);
    strm.printf(",");
    return write_fields_only(strm);
  }

  bool write_fields_only(PlStream& strm) const
  { if ( connection )
      connection->portray(strm);
    else
      strm.printf("closed");
    return true;
  }

  bool portray(PlStream& strm) const
  { strm.printf("MyBlob(");
    write_fields_only(strm);
    strm.printf(")");
    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() inside unify_blob() 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;
}

// %! portray_my_blob(+Stream, +MyBlob) is det.
// % Hook predicate for
// %   user:portray(MyBlob) :-
// %     blob(MyBlob, my_blob), !,
// %     portray_my_blob(current_output, MyBlob).
PREDICATE(portray_my_blob, 2)
{ auto ref = PlBlobV<MyBlob>::cast_ex(A2, my_blob);
  PlStream strm(A1, 0);
  return ref->portray(strm);
}

ClioPatria (version V3.1.1-51-ga0b30a5)