IVersioned class
Basic interface, from which all specialized interfaces descend.
For more information about using the OO API to access Firebird databases, please refer to the doc/Using_OO_API.html document in the official Firebird installation.
Technical notes.
All interfaces in the OO API extend (directly or indirectly) the IVersioned interface. Both IDisposable and IReferenceCounted base interfaces also extend IVersioned, therefore IVersioned's memory layout implies the inner layout of all interface objects.
The IVersioned native interface in libfbclient consists of a dummy CLOOP field (a single pointer to be ignored) and a pointer to the VTable, i.e. an array of method pointers. The VTable is the heart of an interface, because it is the only way to access the interface's functionality (its methods).
Note: this philosophy resembles somewhat the Windows COM model.
A pointer to an interface returned by any libfbclient routine, which is declared as returning an interface object, should be treated (as long as the interface extends IVersioned) as an array of two consecutive pointers, from which only the second pointer is actually of any value, because it points to the VTable of the interface:
((uintptr_t*) IVersioned)[0]
- ignore: CLOOP dummy pointer
((uintptr_t*) IVersioned)[1]
- points to the VTable of the interface
The relevant snippet from the IVersioned
C++ implementation
(include/firebird/IdlFbInterfaces.h):
class IVersioned
{
public:
struct VTable
{
void* cloopDummy[1];
uintptr_t version;
};
void* cloopDummy[1];
VTable* cloopVTable;
However, the original pointer to the interface has to be retained, because methods of the interface require the interface pointer (and not the interface's VTable pointer) to be passed as the first argument. In other words, we invoke functions, which come from the VTable, but the functions receive (as their first argument) not the VTable as such, but an interface pointer, from which VTable can be further obtained (as the second pointer counting from the beginning of the interface).
Every interface extending IVersioned (which at this moment means every interface from libfbclient OO API) on the Dart side is constructed in the following way. The Dart class, wrapping the Firebird interface, has the following attrbutes:
startIndex
- defines the first index (slot) in the VTable, which contains a method of this particular interface (all slots with lower indices contain methods of ancestor interfaces); this attribute is calculated asstartIndex
+metodCount
of the parent interface (except ofIVersioned
, for which those are constant, because it's the ancestor of all other versioned interfaces),methodCount
- defines the number of VTable slots, which this particular interface occupies.
Therefore, if we have an interface hierarchy: A <- B <- C (B extends A, and C extends B), their attributes are defined as:
A.startIndex
andA.methodCount
are constant (A.startIndex
is most likely 0),B.startIndex = A.startIndex + A.methodCount
,B.methodCount
is constant (specific to interface B),C.startIndex = B.startIndex + B.methodCount
,C.methodCount
is constant (specific to interface C).
The calculation of startIndex
in terms of the superclass' attributes
and the definition of methodCount
are both placed in the class
constructor.
That's because fbclient is supposed to support different versions of
the Firebird interfaces, and in the future the values of
methodCount
will depend on the version of the interface.
Additionally, each interface defines (overrides) the method
minSupportedVersion
, which return the minimal required interface
version number. If a Dart object, created around a native Firebird
interface pointer, detects that the native interface has a version
lower than the minimum required (which can mean not all methods,
which the Dart class constructor will attempt to map, may be present
in the interface's VTable), an exception is thrown.
Note, that receiving a higher interface version should be safe
(as long as there are no descendant interfaces), the worst that can
happen is that some new methods from the VTable won't be available
in the Dart class.
The VTable layout of an example interface (IMetadataBuilder version 4, extending IReferenceCounted, which extends IVersioned):
[0]: IVersioned.CLOOP dummy pointer (to be ignored)
[1]: IVersioned.version number (from IVersioned)
[2]: IReferenceCounted.addRef method pointer
[3]: IReferenceCounted.release method pointer
[4]: IMetadataBuilder.setType method pointer
...
[17]: IMetadataBuilder.setAlias method pointer
In version 4, IMetadataBuilder has 14 methods (VTable[4]
... VTable[17]
).
Constructors
- IVersioned(FbInterface self)
Properties
- hashCode → int
-
The hash code for this object.
no setterinherited
- methodCount ↔ int
-
The number of entries in the VTable the interface occupies.
getter/setter pair
- runtimeType → Type
-
A representation of the runtime type of the object.
no setterinherited
- self ↔ FbInterface
-
The raw pointer to the native interface.
getter/setter pair
- startIndex ↔ int
-
The first entry in the VTable the interface uses.
getter/setter pair
- version ↔ int
-
The interface version. Copied from the VTable for convenience.
getter/setter pair
- vtable ↔ FbInterface
-
The pointer to the interface's VTable.
getter/setter pair
Methods
-
minSupportedVersion(
) → int - Defines the minimum native interface version supported by this class in fbclient.
-
noSuchMethod(
Invocation invocation) → dynamic -
Invoked when a nonexistent method or property is accessed.
inherited
-
toString(
) → String -
A string representation of this object.
inherited
Operators
-
operator ==(
Object other) → bool -
The equality operator.
inherited