Alcinoe è una libreria di componenti open source per Delphi e C++Builder, mantenuta su GitHub da Zeus64. Copre un terreno che la RTL di VCL e FireMonkey lascia a terze parti: un lettore video accelerato via GPU, un wrapper WebRTC, controlli di editing nativi per iOS e Android, un parser JSON/BSON a doppia modalità, un client MongoDB con connection pooling, un wrapper per ImageMagick e una raccolta di controlli FireMonkey che aggirano del tutto la pipeline di rendering standard. La libreria si è costruita la reputazione su Rio (10.3.3) e Sydney (10.4.2), e da allora ha seguito ogni rilascio di Embarcadero. Al momento in cui scriviamo è pienamente compatibile con Delphi 11.1 Alexandria e Delphi Athens 12.3
Portare Alcinoe dentro un progetto
L'installazione si divide su una domanda: vi serve il supporto in fase di progettazione per i controlli visuali di Alcinoe? Se no, saltate del tutto il BPL. Aggiungete {alcinoe_rootdir}\source al percorso di ricerca delle librerie del progetto e avete finito. Ogni componente non visuale, compresi i parser, i client di database e le utility per le stringhe, si compila dal sorgente senza registrare nulla
Quando il supporto in fase di progettazione vi serve davvero, il percorso è un po' più lungo. Aprite Component > Install Packages nell'IDE Delphi, individuate il BPL corrispondente alla vostra versione (per esempio {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl), installatelo e poi aggiungete comunque {alcinoe_rootdir}\source al percorso di ricerca. Il BPL registra i componenti; la directory dei sorgenti è ciò che il compilatore trova quando compila il vostro progetto
Alcinoe distribuisce patch opzionali per i sorgenti della RTL di Embarcadero. Se le volete, andate in {alcinoe_rootdir}\embarcadero\, scegliete la sottodirectory della vostra versione ed eseguite update.bat. Lo script si aspetta GIT nel PATH e presuppone una posizione di installazione Embarcadero predefinita. Recupera i sorgenti RTL originali e applica le patch. Fatto questo, aggiungete quella directory di sorgenti corretti al percorso di ricerca del progetto così che il compilatore la trovi prima della copia in sola lettura presente nell'albero di installazione di Embarcadero. Nulla di tutto ciò è necessario per iniziare; conta solo se incappate nei bug che le patch risolvono
Android e il proxy di desugaring D8
Diversi componenti di Alcinoe (WebRTC, video basato su ExoPlayer) dipendono da librerie Java che usano funzionalità del linguaggio Java 8. La toolchain Android distribuita con le versioni più vecchie di Delphi usa dx.bat per la conversione DEX, e quel programma non sa gestire quei bytecode sui livelli di API inferiori a 26. Il rimedio è il desugaring, che D8 esegue automaticamente quando viene invocato direttamente. Alcinoe fornisce uno script proxy in {alcinoe_rootdir}\tools\D8Proxy\dx.bat che inoltra le chiamate dal sistema di build Delphi a D8, rendendo il desugaring trasparente. Sostituite il dx.bat originale nella directory build-tools del vostro Android SDK (di solito C:\SDKs\android\build-tools\30.0.3\) con questo proxy. Embarcadero ha tracciato il problema di fondo con RSP-24155; le versioni successive degli strumenti dell'SDK lo hanno affrontato direttamente, quindi verificate se la vostra toolchain attuale abbia ancora bisogno dell'espediente
Il problema di rendering di FireMonkey e la risposta di Alcinoe
Il ciclo di disegno predefinito di FireMonkey diventa un collo di bottiglia nelle interfacce con molto scorrimento. Un singolo TRectangle con angoli arrotondati può richiedere circa 3 ms per essere ridisegnato, perché l'implementazione standard ricalcola il percorso a ogni fotogramma. Con 20 controlli simili visibili, si arriva a 60 ms per passata di fotogramma, il che tiene il frame rate effettivo ben sotto la soglia di uno scorrimento fluido
Alcinoe affronta la cosa con un buffer residente in GPU per ciascun controllo. Il primo disegno renderizza il controllo in una TTexture conservata nella memoria della GPU. I ridisegni successivi eseguono il blit di quella texture anziché rieseguire l'algoritmo di disegno. Il risultato misurato sullo stesso rettangolo arrotondato scende da circa 3 ms a circa 0,1 ms. Oltre alla bufferizzazione, Alcinoe sostituisce il disegno di percorsi OpenGL per le forme di base con le API di disegno native di Android e iOS, aggirando il compromesso tra qualità e prestazioni legato a Form.Quality. I controlli rilevanti sono TALRectangle, TALCircle e un insieme di contenitori di layout migliorati, tra cui uno ScrollBox e un TabControl
TALJsonDocument: DOM e SAX in un solo tipo
TALJsonDocument è il parser JSON e BSON di Alcinoe. Supporta due modalità di attraversamento. La modalità DOM costruisce un albero di oggetti in memoria, offrendo accesso casuale a qualsiasi nodo al prezzo di una memoria proporzionale alla dimensione del documento. La modalità SAX solleva eventi mentre il parser legge ogni token, senza conservare alcun albero, ed è la scelta giusta quando dovete filtrare un documento grande e trattenere solo una manciata di valori. I parser DOM in Delphi (DBXJSON, SuperObject e gli altri) sono tipicamente da tre a cinque volte più lenti di un approccio SAX sullo stesso contenuto, perché ogni allocazione di nodo porta con sé il costo di creazione dell'oggetto oltre al lavoro di parsing vero e proprio
Il tipo segue lo stesso schema di navigazione per nodi di TALXMLDocument. Una lettura DOM minima si presenta così:
MyJsonDoc.LoadFromJSON(AJsonStr, False {modalità dom});
MyJsonDoc.ParseOptions := [poAllowComments];
// leggete i valori scalari
ShowMessage(MyJsonDoc.ChildNodes['name'].ChildNodes['first'].Text);
ShowMessage(IntToStr(MyJsonDoc.ChildNodes['_id'].Int32));
// scorrete un array
for I := 0 to MyJsonDoc.ChildNodes['contribs'].ChildNodes.Count - 1 do
Writeln(MyJsonDoc.ChildNodes['contribs'].ChildNodes[I].Text);
Per la modalità SAX, assegnate una procedura anonima a OnParseText prima di chiamare LoadFromJSON con il secondo argomento impostato a True. La callback riceve il percorso del nodo, il nome, il valore e un TALJSONNodeSubType che identifica il tipo JSON (stringa, intero, float, booleano e così via). Quella modalità non produce alcuna allocazione su heap per i nodi, quindi scala a documenti arbitrariamente grandi senza far saltare il budget di memoria
TALJsonDocument legge e scrive nativamente anche BSON; passate True come flag BSON a LoadFromFile o SaveToFile. Una seconda variante, TALJsonDocumentU, usa internamente UnicodeString (UTF-16) anziché AnsiString (UTF-8), per contesti in cui il codice circostante lavora in Unicode dall'inizio alla fine
Client MongoDB e connection pooling
Il driver MongoDB di Alcinoe copre le operazioni di query più comuni e gestisce nativamente il connection pooling. Il client semplice, TAlMongoDBClient, apre e chiude una singola connessione per operazione. La variante con pool, TAlMongoDBConnectionPoolClient, mantiene un insieme di connessioni vive e ne consegna una dal pool a ciascun thread chiamante, riprendendola al termine della chiamata. Quel modello evita che più thread si blocchino a vicenda sull'apertura della connessione, cosa che conta ogni volta che dei worker in background interrogano contemporaneamente lo stesso database. Per i cursori tailable su collezioni capped, TAlMongoDBTailMonitoringThread sorveglia l'arrivo di nuovi documenti e richiama una callback quando arrivano, che è lo schema standard per lo streaming di log o le notifiche di cambiamento senza polling
Altri componenti che vale la pena conoscere
ALVideoPlayer renderizza il video in una TTexture anziché in una finestra sovrapposta, così altri controlli FireMonkey possono stargli sopra nell'ordine Z. Il backend Android usa ExoPlayer, che aggiunge il supporto per DASH, HLS e SmoothStreaming oltre a ciò che il MediaPlayer integrato di Android gestisce. Il backend iOS usa AVPlayer con un supporto HLS equivalente
TALWebRTC avvolge lo stack WebRTC per audio e video peer-to-peer. Non richiede un browser né un plugin, e la connessione attraversa il NAT tramite la consueta negoziazione ICE/STUN/TURN che la libreria sottostante gestisce
TALStringList sostituisce l'ordinamento basato su AnsiCompareText di TStringList con un confronto ordinale indipendente dalla locale e un quicksort fino a 10 volte più veloce su liste grandi. La variante con hash, TALHashedStringList, aggiunge una tabella hash interna per ricerche O(1) al prezzo di un costo leggermente più alto sulle liste piccole. Notate che TALStringList è una lista AnsiString a 8 bit, non Unicode; si adatta bene al codice lato server dove UTF-8 è la codifica di lavoro e il throughput grezzo conta più del confronto sensibile alla locale
Su Windows a 64 bit, l'eredità FastCode che ha dato a molte routine di stringa di Alcinoe il loro vantaggio di velocità (soprattutto assembly x86 scritto a mano) non si trasferisce. Le build Win64 ripiegano sulle implementazioni Pascal, che risultano sensibilmente più lente sui carichi di lavoro intensivi sulle stringhe. Il progetto demo\ALStringBenchMark vi permette di misurare il divario sul vostro hardware prima di impegnarvi in una build a 64 bit dove il throughput sulle stringhe è un collo di bottiglia
I sorgenti completi si trovano su github.com/Zeus64/alcinoe