自作プラグイン更新のお知らせ。
今更で申し訳ないですが><
10.2 Tokyoに新規対応したもの
10.2 Tokyoでもそのまま動いたもの
- 16進数表示プラグイン for Delphi Ver.1.0
- Lock on Load plugin
- 無名メソッド入力補完プラグイン Ver.0.0.2
- New Edit Window for Embedded Designer plugin Ver.0.0.1
- Lock Toolbar Ver.0.0.1
- May the bevel be with you Ver.1.0 (旧凹ンパイルプラグイン)
- DLight Ver.0.0.7
- Open standard libraries as read-only by default Ver.0.0.1
- Quick "Quick Edit" Ver.0.0.1
- Component Tray Ver.1.1.0
- Clipboard History Disabler Ver.0.0.1
- Style Selector for TFrame Ver.0.0.1
macOSでDockメニューに独自項目を追加する。
サンプルコード
uses ..., System.Messaging, Macapi.ObjCRuntime, Macapi.ObjectiveC, Macapi.AppKit, Macapi.Helpers, FMX.Helpers.Mac; procedure TForm1.FormCreate(Sender: TObject); begin TMessageManager.DefaultManager.SubscribeToMessage(TApplicationDockMenuMessage, procedure(const Sender: TObject; const M: TMessageBase) var menu: NSMenu; item: NSMenuItem; begin menu := TNSMenu.Create; TNSAutoreleasePool.OCClass.addObject((menu as ILocalObject).GetObjectID); item := menu.addItemWithTitle(StrToNSStr('AAA'), sel_getUid('onMenuClicked:'), StrToNSStr('')); item.setTag(1); item := menu.addItemWithTitle(StrToNSStr('BBB'), sel_getUid('onMenuClicked:'), StrToNSStr('')); item.setTag(2); TApplicationDockMenuMessage(M).Value.ReturnValue := menu; end); TMessageManager.DefaultManager.SubscribeToMessage(TApplicationMenuClickedMessage, procedure(const Sender: TObject; const M: TMessageBase) var item: NSMenuItem; begin item := TApplicationMenuClickedMessage(M).Value.Sender as NSMenuItem; case item.tag of 1: ... // AAA 2: ... // BBB end; end); end;
class or class = ???
サンプルコード
https://gist.github.com/lynatan/673e574faa8343fa01d7a91e75065c54
type TObjectHelper = class helper for TObject public class function &&op_LogicalOr<T: class>(A, B: T): T; static; end; class function TObjectHelper.&&op_LogicalOr<T>(A, B: T): T; begin if A <> nil then Result := A else Result := B; end; procedure Test; var sl1, sl2, sl3: TStringList; begin sl1 := nil; sl2 := TStringList.Create; sl3 := sl1 or sl2; // -> sl3 = sl2 end;
Use operator overloading for classes with non-ARC compiler
はじめに
演算子オーバーロードはDelphi 2006で導入された機能で、自分が定義したレコードに+や-といった演算子の動作を実装できます。この機能はARC対応コンパイラであればレコードだけでなくクラスでも使えるんですが、非ARCコンパイラ、つまりx86向けのようなコンパイラでは使うことができませんでした。
ところが何気なくコードを書いていたところ、ちょっと違う書き方をするだけで演算子オーバーロードがクラスでも使えることを発見しました。また、同じ記述方法でクラスヘルパーやレコードヘルパーで演算子オーバーロードを後付けするという従来では完全に不可能だったことまでできるようになり、コーディングの幅が広がる可能性があります。
使い方
https://gist.github.com/lynatan/886ed984d230ac1b42dd89ed42ab2214
type TStringListEx = class(TStringList) public // class operator In(const A: string; B: TStringListEx): Boolean; class function &&op_In(const A: string; B: TStringListEx): Boolean; static; end; TPointHelper = record helper for TPoint // Possible in class helper! public // class operator Equal(const A: TPoint; const B: string) : Boolean; class function &&op_Equality(const A: TPoint; const B: string): Boolean; static; end; class function TStringListEx.&&op_In(const A: string; B: TStringListEx): Boolean; begin Result := B.IndexOf(A) >= 0; end; class function TPointHelper.&&op_Equality(const A: TPoint; const B: string): Boolean; begin Result := Format('%d,%d', [A.X, A.Y]) = B; end; var sl: TStringListEx; pt: TPoint; ret: Boolean; begin sl := TStringListEx.Create; sl.Add('AAA'); sl.Add('BBB'); ret := 'AAA' in sl; Writeln(BoolToStr(ret, True)); // -> 'True' pt := Point(123, 456); ret := pt = '123,456'; Writeln(BoolToStr(ret, True)); // -> 'True' ... end;
対応表
class operator | class function |
---|---|
Implicit | &&op_Implicit |
Explicit | &&op_Explicit |
Negative | &&op_UnaryNegation |
Positive | &&op_UnaryPlus |
Inc | &&op_Increment |
Dec | &&op_Decrement |
LogicalNot | &&op_LogicalNot |
Trunc | &&op_Trunc |
Round | &&op_Round |
In | &&op_In |
Equal | &&op_Equality |
NotEqual | &&op_Inequality |
GreaterThan | &&op_GreaterThan |
GreaterThanOrEqual | &&op_GreaterThanOrEqual |
LessThan | &&op_LessThan |
LessThanOrEqual | &&op_LessThanOrEqual |
Add | &&op_Addition |
Subtract | &&op_Subtraction |
Multiply | &&op_Multiply |
Divide | &&op_Division |
IntDivide | &&op_IntDivide |
Modulus | &&op_Modulus |
LeftShift | &&op_LeftShift |
RightShift | &&op_RightShift |
LogicalAnd | &&op_LogicalAnd |
LogicalOr | &&op_LogicalOr |
LogicalXor | &&op_ExclusiveOr |
BitwiseAnd | &&op_BitwiseAnd |
BitwiseOr | &&op_BitwiseOr |
BitwiseXor | &&op_BitwiseXOR |
Include | &&op_Include |
Exclude | &&op_Exclude |
Starterでフォームデザイナオプションが表示されないバグの修正プラグイン作った。
VM上で検証してたら原因が分かったので直しました。
ダウンロード
https://github.com/lynatan/StarterFix
「Clone or Download -> Download ZIP」でダウンロードできます。
Delphinusにも対応しているので、インストールしている方はそちらから導入した方が簡単です。
Delphinusパッケージマネージャの紹介。
パッケージマネージャとはなんぞや
Delphiは数多くのパッケージの集合で成り立っています。パッケージには製品本体に元々付属しているもの以外に企業や個人が作った追加パッケージがあり、この追加パッケージを簡単に導入できるようにするのがパッケージマネージャです。
Delphinusとはなんぞや
Delphinusはパッケージマネージャのひとつで、Embarcadero公式のGetItパッケージマネージャと違い、申請不要で誰でも自作のパッケージを公開することができます。というのも、Delphinusは自前のサーバを持たず、ファイルの管理は全てGitHubに任せています。そのGitHubの検索APIを使い、特定の条件に合致したプロジェクトをパッケージとしてリストアップし、インストールできるようになっています。そのため、GitHubでソースコードを公開すれば誰でもパッケージを公開することができるというわけです。
ちなみに対応バージョンはXE以降となっています。
Delphinusのインストール方法
Gitが統合されているバージョンの場合(XE7以降)
Delphiを起動し、「ファイル→バージョン管理リポジトリから開く」を選択、バージョン管理システムとしてGitを選び、ソース欄にDelphinusのプロジェクトページのURLを、保存先には任意のフォルダを選んでください。
OKを押すとダウンロードが開始し、それが終わると開くプロジェクトを選択する画面が出るので、リストの中からDelphiXE6フォルダ内のDelphinus.dprojを選択してOKを押します。
プロジェクトを開いたらプロジェクトマネージャの「Delphinus.bpl」上で右クリックし、「インストール」を選択してください。「ツール→Delphinus」というメニューが追加されていればインストール成功です。
Gitが統合されていないバージョンの場合(XE6以前)
Delphinusのプロジェクトページにアクセスし、緑色の「Clone or download」というボタンを押して「Download ZIP」を選択し、ソースコード一式をダウンロードします。
次に、ダウンロードしたファイルを任意のフォルダに展開し、Delphiを起動してXE-XE5はDelphiXEフォルダ内の、XE6以降はDelphiXE6フォルダ内のDelphinus.dprojを開いてください。
プロジェクトを開いたらプロジェクトマネージャの「Delphinus.bpl」上で右クリックし、「インストール」を選択してください。「ツール→Delphinus」というメニューが追加されていればインストール成功です。
Delphinusでのパッケージのインストール
「ツール→Delphinus」メニューを選択すると、Delphinus Packagemanagerが起動します。左上の緑の更新ボタンを押すとパッケージ一覧が表示されるので、好きなパッケージを選択し、インストールボタン(下向き矢印の付いたアイコン)を押すことでパッケージがインストールできます。
アクセストークンの設定
これは任意の設定項目ですが、歯車アイコンを押すことでアクセストークンが設定できます。これはDelphinusがバックエンドとしてGitHub APIを利用して検索していることから、APIの利用制限を緩和するために設定するもので、無くても利用自体は可能です。
アクセストークンはGitHubにサインインし、メニューのSettingsからPersonal access tokensを選び、Generate new tokenを押すことで生成できます。付与する権限は最小限でいいとのことなので、特にチェックは付けないまま生成してOKです。トークンの文字列が入手できたら、歯車アイコンを押して表示されたエディットに貼り付け、Testボタンを押して成功すれば登録されます。
Delphinusでのパッケージの公開
Delphinusでは誰でも自作のパッケージを公開できます。パッケージはGitHub上でパブリックリポジトリとして公開されていて、かつoriginalであるもの(forkではないもの)である必要があります。
パッケージの登録に必要な手順はPublishing your Project for Delphinusにまとめられていますが、大きく言えば「Delphinus.Info.jsonをリポジトリのルートに置く」「Delphinus.Install.jsonをリポジトリのルートに置く」「readmeに『Delphinus-Support』という文字列を加える」の3点です。
詳しい説明は省きますが、Delphinusに登録されているパッケージは全てGitHub上に公開されているので、これらの設定は各パッケージのソースコードが参考になります。
DelphiとFreePascalの最適化比較。
検証用コード
Wikipediaより拝借したコードをPascalに書き直した以下のコードを使用、それぞれのコンパイラでどの程度最適化がかかるか調べる。ともにx86ターゲットで、Delphiは10.1 BerlinのO+、FreePascalは3.0.0の-O4で検証した。
function GetValue: Integer; inline; var a, b, c: Integer; begin a := 30; b := 9 - a div 5; c := b * 4; if c > 10 then c := c - 10; Result := c * (60 div a); end; var a: Integer; begin a := GetValue; Random(a); // aが無効化されないように end;
ちなみに変数を展開していけば分かりますが、最終的に4になります。
FreePascalの場合
mov eax,$0000001e mov eax,$00000003 mov eax,$0000000c mov eax,$00000002 mov eax,$00000004
最終的に4が導き出されてはいるものの、途中の不要な定数が残ってしまっているのが残念。
Delphiの場合
mov ebx,$0000001e mov eax,ebx mov ecx,$00000005 cdq idiv ecx push eax mov eax,$00000009 pop edx sub eax,edx mov ecx,eax add ecx,ecx add ecx,ecx cmp ecx,$0a jle @@1 sub ecx,$0a @@1: mov eax,$0000003c cdq idiv ebx imul ecx
ザ・ウンコ。FreePascalの足元にも及ばないまさかの最適化ゼロ。あまりにも酷いので、最適化オンにしてもデバッグ実行しちゃうとオフになるバグでもあるのでは?と思い、Releaseビルドした上で別のデバッガで逆アセンブルかけてみましたが結果は同じでした…。ちなみに「x64ターゲットだとマシ」という話もあったんで念のためx64でも試したところ、ほぼ同じコードが生成されて膝から崩れ落ちましたw