Alcinoeは、Zeus64によってGitHubで保守されているDelphiおよびC++Builder用のオープンソースコンポーネントライブラリです。これは、VCLおよびFireMonkey RTLがサードパーティに任せている領域をカバーしています。GPUアクセラレーションによるビデオプレーヤー、WebRTCラッパー、ネイティブのiOSおよびAndroidの編集コントロール、デュアルモードのJSON/BSONパーサー、接続プーリングを備えたMongoDBクライアント、ImageMagickラッパー、および標準のレンダリングパイプラインを完全に回避するFireMonkeyコントロールのコレクションなどです。このライブラリは、Rio(10.3.3)およびSydney(10.4.2)で評判を築き、それ以降はEmbarcaderoの各リリースを追跡しています。執筆時点では、Delphi 11.1 AlexandriaおよびDelphi Athens 12.3と完全に互換性があります
Alcinoeをプロジェクトに導入する
インストールは、1つの質問によって分かれます。Alcinoeのビジュアルコントロールに対する設計時(デザインタイム)のサポートが必要ですか?必要ない場合は、BPLを完全にスキップしてください。プロジェクトのライブラリ検索パスに {alcinoe_rootdir}\source を追加するだけで完了です。パーサー、データベースクライアント、文字列ユーティリティを含むすべての非ビジュアルコンポーネントは、何も登録せずにソースからコンパイルされます
設計時のサポートが必要な場合は、パスが少し長くなります。Delphi IDEで コンポーネント > パッケージのインストール を開き、バージョンに一致するBPL(たとえば {alcinoe_rootdir}\lib\bpl\alcinoe\Win32\alexandria\Alcinoe_alexandria.bpl)を参照してインストールし、次に検索パスに {alcinoe_rootdir}\source を追加します。BPLはコンポーネントを登録します。ソースディレクトリは、コンパイラがプロジェクトをコンパイルするときに見つける場所です
Alcinoeには、Embarcadero RTLソースへのオプションのパッチが同梱されています。これらが必要な場合は、{alcinoe_rootdir}\embarcadero\ に移動し、バージョンのサブディレクトリを選択して、update.bat を実行します。スクリプトはPATHにGITがあることを期待し、デフォルトのEmbarcaderoインストール場所を想定しています。元のRTLソースを取得し、パッチを適用します。完了したら、そのパッチが適用されたソースディレクトリをプロジェクトの検索パスに追加して、コンパイラがEmbarcaderoインストールツリー内の読み取り専用コピーよりも先にそれを取得するようにします。これらはどれも開始するために必要なことではありません。パッチが対処するバグに遭遇した場合にのみ重要になります
AndroidとD8脱糖(desugaring)プロキシ
Alcinoeのいくつかのコンポーネント(WebRTC、ExoPlayerをバックエンドとするビデオ)は、Java 8の言語機能を使用するJavaライブラリに依存しています。古いDelphiバージョンに同梱されているAndroidツールチェーンは、DEX変換に dx.bat を使用しますが、APIレベル26未満のそれらのバイトコードを処理できません。解決策は脱糖(desugaring)であり、D8を直接呼び出すと自動的に処理されます。Alcinoeは {alcinoe_rootdir}\tools\D8Proxy\dx.bat にプロキシスクリプトを提供しており、Delphiビルドシステムからの呼び出しをD8に転送し、脱糖を透過的に行います。Android SDKのbuild-toolsディレクトリ(通常は C:\SDKs\android\build-tools\30.0.3\)にある元の dx.bat をこのプロキシに置き換えてください。EmbarcaderoはRSP-24155で根本的な問題を追跡しました。SDKツールの新しいバージョンはこれに直接対処したため、現在のツールチェーンがまだその回避策を必要としているかどうかを確認してください
FireMonkeyのレンダリング問題とAlcinoeの回答
FireMonkeyのデフォルトのペイントサイクルは、スクロールの多いUIでボトルネックになります。角の丸い単一の TRectangle の再描画には、標準の実装ではフレームごとにパスを再計算するため、約3ミリ秒かかる場合があります。このようなコントロールが20個表示されていると、フレームのパスあたり合計60ミリ秒になり、有効なフレームレートが滑らかなスクロールのしきい値をはるかに下回るように制限されてしまいます
Alcinoeは、コントロールごとのGPU常駐バッファでこれに対処します。最初のペイントは、GPUメモリに保存された TTexture にコントロールをレンダリングします。その後の再描画は、ペイントアルゴリズムを再実行する代わりに、そのテクスチャをBLITします。同じ角丸長方形の測定結果は、約3ミリ秒から約0.1ミリ秒に低下します。バッファリングを超えて、Alcinoeは基本図形のOpenGLパス描画をネイティブのAndroidおよびiOSの描画APIに置き換え、Form.Quality に結びついた品質/パフォーマンスのトレードオフを回避します。関連するコントロールは、TALRectangle、TALCircle、および ScrollBox や TabControl を含む改善された一連のレイアウトコンテナです
TALJsonDocument:1つのタイプのDOMとSAX
TALJsonDocument は、AlcinoeのJSONおよびBSONパーサーです。これは2つのトラバーサルモードをサポートしています。DOMモードはインメモリオブジェクトツリーを構築し、ドキュメントのサイズに比例したメモリを犠牲にして、任意のノードへのランダムアクセスを提供します。SAXモードは、ツリーを保持せずにパーサーが各トークンを読み取るときにイベントを発生させます。これは、大きなドキュメントをフィルタリングして、ほんの一握りの値のみを保持する必要がある場合の正しい選択です。DelphiのDOMパーサー(DBXJSON、SuperObjectなど)は、通常、同じコンテンツに対するSAXアプローチの3〜5倍遅くなります。これは、各ノードの割り当てが、解析作業自体に加えてオブジェクト作成のオーバーヘッドを伴うためです
このタイプは TALXMLDocument と同じノードナビゲーションパターンに従います。最小限のDOM読み取りは次のようになります
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);
SAXモードの場合は、2番目の引数を True に設定して LoadFromJSON を呼び出す前に、匿名プロシージャを OnParseText に割り当てます。コールバックは、ノードパス、名前、値、およびJSONタイプ(文字列、整数、浮動小数点、ブール値など)を識別する TALJSONNodeSubType を受け取ります。そのモードはノードのヒープ割り当てを生成しないため、メモリ予算を吹き飛ばすことなく、任意の大きさのドキュメントにスケーリングします
TALJsonDocument はBSONもネイティブに読み書きします。LoadFromFile または SaveToFile へのBSONフラグとして True を渡します。2つ目のバリアントである TALJsonDocumentU は、周囲のコードが全体にわたってUnicodeで機能するコンテキストのために、AnsiString(UTF-8)の代わりに内部で UnicodeString(UTF-16)を使用します
MongoDBクライアントと接続プーリング
AlcinoeのMongoDBドライバーは、一般的なクエリ操作をカバーし、ネイティブで接続プーリングを処理します。単純なクライアント TAlMongoDBClient は、操作ごとに単一の接続を開閉します。プーリングされたバリアントである TAlMongoDBConnectionPoolClient は、一連のライブ接続を維持し、プールから各呼び出しスレッドに接続を渡し、呼び出しが完了するとそれを返します。このモデルは、接続のセットアップで複数のスレッドが互いにブロックするのを防ぎます。これは、バックグラウンドワーカーが同じデータベースに同時にクエリを実行するたびに重要になります。上限付きコレクション(capped collections)の追随可能なカーソル(tailable cursors)については、TAlMongoDBTailMonitoringThread が新しいドキュメントを監視し、ドキュメントが到着したときにコールバックを発生させます。これは、ポーリングなしのログストリーミングや変更通知の標準的なパターンです
知っておく価値のあるその他のコンポーネント
ALVideoPlayer はオーバーレイウィンドウではなく TTexture にビデオをレンダリングするため、他のFireMonkeyコントロールをZオーダーでその上に配置できます。AndroidバックエンドはExoPlayerを使用します。これにより、Androidに組み込まれている MediaPlayer が処理するもの以外に、DASH、HLS、およびSmoothStreamingのサポートが追加されます。iOSバックエンドは、同等のHLSサポートを備えた AVPlayer を使用します
TALWebRTC はピアツーピアのオーディオおよびビデオのためにWebRTCスタックをラップします。ブラウザやプラグインは必要なく、接続は基盤となるライブラリが処理する標準のICE/STUN/TURNネゴシエーションを通じてNATをトラバースします
TALStringList は、TStringList の AnsiCompareText ベースのソートを、ロケールに依存しない序数比較(ordinal comparison)と、大規模なリストで最大10倍高速なクイックソートに置き換えます。ハッシュ化されたバリアントである TALHashedStringList は、小さなリストでのわずかなオーバーヘッドの代わりに、O(1) ルックアップ用の内部ハッシュテーブルを追加します。TALStringList はUnicodeリストではなく8ビットのAnsiStringリストであることに注意してください。これは、UTF-8がワーキングエンコーディングであり、ロケールを意識した比較よりも生のスループットが重要となるサーバー側コードによく適合します
64ビットWindowsでは、Alcinoeの多くの文字列ルーチンに速度の優位性を与えたFastCodeの遺産(主に手書きのx86アセンブリ)は引き継がれません。Win64ビルドはPascalの実装にフォールバックしますが、これは文字列を集中的に使用するワークロードでは著しく遅く動作します。demo\ALStringBenchMark プロジェクトを使用すると、文字列のスループットがボトルネックになる64ビットビルドにコミットする前に、ハードウェアでのギャップを測定できます
完全なソースは github.com/Zeus64/alcinoe にあります