Technischer Artikel

Alcinoe-Komponentenbibliothek und Kompatibilität mit Delphi 11.1 Alexandria

Alcinoe ist eine Open-Source-Komponentenbibliothek für Delphi und C++Builder, die von Zeus64 auf GitHub gepflegt wird. Sie deckt Bereiche ab, die VCL und FireMonkey RTL Dritten überlassen: einen GPU-beschleunigten Videoplayer, einen WebRTC-Wrapper, native iOS- und Android-Bearbeitungssteuerelemente, einen Dual-Mode-JSON/BSON-Parser, einen MongoDB-Client mit Verbindungspooling, einen ImageMagick-Wrapper und eine Sammlung von FireMonkey-Steuerelementen, die die Standard-Rendering-Pipeline vollständig umgehen. Die Bibliothek baute ihren Ruf auf Rio (10.3.3) und Sydney (10.4.2) auf und hat seitdem jede Veröffentlichung von Embarcadero verfolgt. Zum Zeitpunkt der Erstellung dieses Dokuments ist es vollständig mit Delphi 11.1 Alexandria und Delphi Athens 12.3 kompatibel

Alcinoe in ein Projekt integrieren

Die Installation hängt von einer Frage ab: Benötigen Sie Unterstützung zur Entwurfszeit für die visuellen Steuerelemente von Alcinoe? Wenn nicht, überspringen Sie das BPL vollständig. Fügen Sie {alcinoe_rootdir}\source zum Suchpfad für Bibliotheken des Projekts hinzu, und Sie sind fertig. Jede nicht visuelle Komponente, einschließlich der Parser, Datenbankclients und Zeichenfolgen-Dienstprogramme, wird aus dem Quellcode kompiliert, ohne etwas zu registrieren

Wenn Sie Unterstützung zur Entwurfszeit benötigen, ist der Weg etwas länger. Öffnen Sie in der Delphi-IDE Komponente > Pakete installieren, navigieren Sie zum BPL, das Ihrer Version entspricht (z. B. {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl), installieren Sie es und fügen Sie dann immer noch {alcinoe_rootdir}\source zum Suchpfad hinzu. Das BPL registriert die Komponenten; das Quellverzeichnis ist das, was der Compiler findet, wenn er Ihr Projekt kompiliert

Alcinoe liefert optionale Patches für die Embarcadero-RTL-Quellen. Wenn Sie diese möchten, navigieren Sie zu {alcinoe_rootdir}\embarcadero\, wählen Sie das Unterverzeichnis für Ihre Version und führen Sie update.bat aus. Das Skript erwartet GIT im Pfad und geht von einem Standard-Installationsort für Embarcadero aus. Es ruft den originalen RTL-Quellcode ab und wendet die Patches an. Fügen Sie anschließend dieses gepatchte Quellverzeichnis zu Ihrem Projektsuchpfad hinzu, damit der Compiler es vor der schreibgeschützten Kopie in der Embarcadero-Installationsstruktur abruft. Nichts davon ist für den Einstieg erforderlich; es ist nur wichtig, wenn Sie auf Fehler stoßen, die von den Patches behoben werden

Android und der D8-Desugaring-Proxy

Einige Alcinoe-Komponenten (WebRTC, ExoPlayer-gestütztes Video) hängen von Java-Bibliotheken ab, die Sprachfunktionen von Java 8 verwenden. Die mit älteren Delphi-Versionen ausgelieferte Android-Toolchain verwendet dx.bat für die DEX-Konvertierung, die diese Bytecodes auf API-Ebenen unter 26 nicht verarbeiten kann. Die Lösung ist das Desugaring, das D8 automatisch ausführt, wenn es direkt aufgerufen wird. Alcinoe bietet ein Proxy-Skript unter {alcinoe_rootdir}\tools\D8Proxy\dx.bat an, das Aufrufe vom Delphi-Buildsystem an D8 weiterleitet und das Desugaring transparent macht. Ersetzen Sie die ursprüngliche dx.bat in Ihrem Android SDK-Verzeichnis für Build-Tools (normalerweise C:\SDKs\android\build-tools\30.0.3\) durch diesen Proxy. Embarcadero verfolgte das zugrunde liegende Problem unter RSP-24155; neuere Versionen der SDK-Tools haben es direkt behoben. Überprüfen Sie daher, ob Ihre aktuelle Toolchain diesen Workaround noch benötigt

Das Rendering-Problem von FireMonkey und die Antwort von Alcinoe

Der Standard-Malzyklus von FireMonkey wird in scroll-lastigen Benutzeroberflächen zum Engpass. Ein einzelnes TRectangle mit abgerundeten Ecken kann zum Neuzeichnen etwa 3 ms benötigen, da die Standardimplementierung den Pfad bei jedem Frame neu berechnet. Bei 20 sichtbaren derartigen Steuerelementen summiert sich dies auf 60 ms pro Frame-Durchlauf, was die effektive Bildrate deutlich unter den Schwellenwert für flüssiges Scrollen drückt

Alcinoe behebt dies mit einem GPU-resistenten Puffer pro Steuerelement. Der erste Malvorgang rendert das Steuerelement auf eine TTexture, die im GPU-Speicher gespeichert ist. Nachfolgende Neuzeichnungsvorgänge blitten diese Textur, anstatt den Malalgorithmus erneut auszuführen. Das gemessene Ergebnis auf demselben abgerundeten Rechteck fällt von etwa 3 ms auf etwa 0,1 ms. Über die Pufferung hinaus ersetzt Alcinoe das Zeichnen von OpenGL-Pfaden für Grundformen durch native Android- und iOS-Zeichen-APIs und umgeht so den Kompromiss zwischen Qualität und Leistung, der an Form.Quality gebunden ist. Die relevanten Steuerelemente sind TALRectangle, TALCircle und ein Satz verbesserter Layoutcontainer, einschließlich einer ScrollBox und eines TabControl

TALJsonDocument: DOM und SAX in einem Typ

TALJsonDocument ist Alcinoes JSON- und BSON-Parser. Er unterstützt zwei Durchlaufmodi. Der DOM-Modus erstellt einen In-Memory-Objektbaum, der wahlfreien Zugriff auf jeden Knoten auf Kosten des proportional zur Dokumentgröße stehenden Speichers bietet. Der SAX-Modus löst Ereignisse aus, während der Parser jedes Token liest, ohne einen Baum beizubehalten, was die richtige Wahl ist, wenn Sie ein großes Dokument filtern und nur eine Handvoll Werte behalten müssen. DOM-Parser in Delphi (DBXJSON, SuperObject und die anderen) sind für denselben Inhalt in der Regel drei- bis fünfmal langsamer als ein SAX-Ansatz, da jede Knotenzuweisung zusätzlich zur eigentlichen Parsingarbeit einen Aufwand für die Objekterstellung mit sich bringt

Der Typ folgt demselben Knoten-Navigationsmuster wie TALXMLDocument. Ein minimales DOM-Lesen sieht so aus:

MyJsonDoc.LoadFromJSON(AJsonStr, False {dom mode});
MyJsonDoc.ParseOptions := [poAllowComments];

// read scalar values
ShowMessage(MyJsonDoc.ChildNodes[‘name’].ChildNodes[‘first’].Text);
ShowMessage(IntToStr(MyJsonDoc.ChildNodes[‘_id’].Int32));

// iterate an array
for I := 0 to MyJsonDoc.ChildNodes[‘contribs’].ChildNodes.Count - 1 do
  Writeln(MyJsonDoc.ChildNodes[‘contribs’].ChildNodes[I].Text);

Weisen Sie für den SAX-Modus vor dem Aufruf von LoadFromJSON eine anonyme Prozedur zu OnParseText zu, wobei das zweite Argument auf True gesetzt ist. Der Rückruf erhält den Knotenpfad, den Namen, den Wert und einen TALJSONNodeSubType, der den JSON-Typ identifiziert (Zeichenfolge, Ganzzahl, Gleitkommazahl, Boolescher Wert usw.). Dieser Modus erzeugt keine Heap-Zuordnungen für Knoten und skaliert daher auf beliebig große Dokumente, ohne das Speicherbudget zu sprengen

TALJsonDocument liest und schreibt auch BSON nativ; übergeben Sie True als BSON-Flag an LoadFromFile oder SaveToFile. Eine zweite Variante, TALJsonDocumentU, verwendet intern UnicodeString (UTF-16) anstelle von AnsiString (UTF-8) für Kontexte, in denen der umgebende Code durchgehend in Unicode arbeitet

MongoDB-Client und Verbindungspooling

Der MongoDB-Treiber von Alcinoe deckt die üblichen Abfrageoperationen ab und verarbeitet Verbindungspooling nativ. Der einfache Client, TAlMongoDBClient, öffnet und schließt eine einzelne Verbindung pro Operation. Die gepoolte Variante, TAlMongoDBConnectionPoolClient, verwaltet eine Reihe aktiver Verbindungen und übergibt jedem aufrufenden Thread eine aus dem Pool und gibt sie zurück, wenn der Aufruf abgeschlossen ist. Dieses Modell verhindert, dass sich mehrere Threads beim Verbindungsaufbau gegenseitig blockieren, was wichtig ist, wenn Hintergrund-Worker dieselbe Datenbank gleichzeitig abfragen. Bei folgbaren Cursorn für begrenzte Sammlungen überwacht TAlMongoDBTailMonitoringThread neue Dokumente und löst bei ihrem Eintreffen einen Rückruf aus, was das Standardmuster für Log-Streaming oder Änderungsbenachrichtigungen ohne Polling ist

Weitere wissenswerte Komponenten

ALVideoPlayer rendert Videos auf eine TTexture und nicht auf ein Overlay-Fenster, sodass andere FireMonkey-Steuerelemente in Z-Reihenfolge darüber platziert werden können. Das Android-Backend verwendet ExoPlayer, was die Unterstützung für DASH, HLS und SmoothStreaming über das hinaus hinzufügt, was der integrierte MediaPlayer von Android verarbeitet. Das iOS-Backend verwendet AVPlayer mit äquivalenter HLS-Unterstützung

TALWebRTC umschließt den WebRTC-Stack für Peer-to-Peer-Audio und -Video. Er erfordert keinen Browser oder ein Plugin, und die Verbindung durchquert NAT durch die standardmäßige ICE/STUN/TURN-Aushandlung, die von der zugrunde liegenden Bibliothek verarbeitet wird

TALStringList ersetzt die auf AnsiCompareText basierende Sortierung von TStringList durch einen gebietsschemaunabhängigen ordinalen Vergleich und einen Quicksort, der bei großen Listen bis zu 10-mal schneller ist. Die gehashte Variante, TALHashedStringList, fügt eine interne Hash-Tabelle für O(1)-Lookups auf Kosten eines etwas höheren Overheads bei kleinen Listen hinzu. Beachten Sie, dass TALStringList eine 8-Bit-AnsiString-Liste und keine Unicode-Liste ist. Es eignet sich gut für serverseitigen Code, bei dem UTF-8 die funktionierende Codierung ist und der rohe Durchsatz wichtiger ist als ein gebietsschemabezogener Vergleich

Unter 64-Bit-Windows überträgt sich das FastCode-Erbe, das vielen Zeichenfolgenroutinen von Alcinoe ihren Geschwindigkeitsvorteil verschaffte (hauptsächlich handgeschriebenes x86-Assembly), nicht. Die Win64-Builds greifen auf die Pascal-Implementierungen zurück, die bei zeichenfolgenintensiven Workloads merklich langsamer ausgeführt werden. Das demo\ALStringBenchMark-Projekt lässt Sie die Lücke auf Ihrer Hardware messen, bevor Sie sich für einen 64-Bit-Build entscheiden, bei dem der Zeichenfolgengdurchsatz einen Engpass darstellt

Der vollständige Quellcode befindet sich unter github.com/Zeus64/alcinoe