February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 10:14:41 UTC, Виталий Фадеев wrote:
> On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås wrote:
>> On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote:
>>> [...]
>>
>> So let's create a template for that:
>>
>> [...]
>
> Cool!
Think!
I writing code generation. Like this:
void On( T, alias M )( T o )
{
// generate code in dispatcher
// get AllMembers()
// filter OnABC (ex: OnWM_KEYUP)
// on each
// writeCode(
// q{
// if ( message == WM_KEYUP )
// o.OnWM_KEYUP();
// }
// );
static ... foreach( ) ...
{
CB_MESSAGE = ...
CB_METHOD = ...
mixin (
"if ( message == CB_MESSAGE ) " ~ "o." ~ CB_METHOD ~ "();"
);
}
}
|
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 10:20:03 UTC, Виталий Фадеев wrote:
> On Friday, 28 February 2020 at 10:14:41 UTC, Виталий Фадеев wrote:
>> On Friday, 28 February 2020 at 09:49:53 UTC, Simen Kjærås wrote:
>>> On Friday, 28 February 2020 at 09:25:58 UTC, Виталий Фадеев wrote:
>>>> [...]
>>>
>>> So let's create a template for that:
>>>
>>> [...]
>>
>> Cool!
>
> Think!
> I writing code generation. Like this:
>
> void On( T, alias M )( T o )
> {
> // generate code in dispatcher
> // get AllMembers()
> // filter OnABC (ex: OnWM_KEYUP)
> // on each
> // writeCode(
> // q{
> // if ( message == WM_KEYUP )
> // o.OnWM_KEYUP();
> // }
> // );
>
> static ... foreach( ) ...
> {
> CB_MESSAGE = ...
> CB_METHOD = ...
>
> mixin (
> "if ( message == CB_MESSAGE ) " ~ "o." ~ CB_METHOD ~ "();"
> );
> }
> }
Thanks all !
I happy !
Check this one:
import core.sys.windows.windows;
import std.stdio;
import std.traits;
import std.algorithm.searching;
void On( T, M )( T o, M message )
{
// generate code in dispatcher
// get AllMembers()
// filter OnABC (ex: OnWM_KEYUP)
// on each
// writeCode(
// q{
// if ( message == WM_KEYUP )
// o.OnWM_KEYUP();
// }
// );
foreach( methodName; __traits( allMembers, T ) )
{
static if ( methodName.startsWith( "On" ) && methodName.length >= 3 )
{
mixin (
"if ( message == " ~ methodName[2..$] ~ " ) " ~ "o." ~ methodName ~ "();"
);
}
}
}
class Base
{
void Send( T, M )( T o, M message )
{
o.On!( T, M )( message );
}
}
class A : Base
{
void OnWM_KEYUP()
{
writeln( "A.OnWM_KEYUP()" );
}
void OnWM_KEYDOWN()
{
writeln( "A.OnWM_KEYDOWN()" );
}
}
void main()
{
auto a = new A();
a.Send( a, WM_KEYUP );
a.Send( a, WM_KEYDOWN );
}
|
February 28, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев wrote: > Thanks all ! > I happy ! > Check this one: > void On( T, M )( T o, M message ) > { [snip] > void main() > { > auto a = new A(); > a.Send( a, WM_KEYUP ); > a.Send( a, WM_KEYDOWN ); > } That does mostly work, but fails for this code: void main() { Base a = new A(); a.send( a, WM_KEYUP ); } Basically, whenever you assign a derived to a base, this solution doesn't work, because T will be Base, not A. I enjoyed with the previous code, so I wrote the code necessary to handle any WM_ message: import core.sys.windows.windows; import std.stdio; import std.meta; template startsWith(string prefix) { enum startsWith(string s) = s.length >= prefix.length && s[0..prefix.length] == prefix; } enum getMessageValue(string s) = __traits(getMember, core.sys.windows.winuser, s); // Get the all the WM_ messages alias messageNames = Filter!(startsWith!"WM_", __traits(allMembers, core.sys.windows.winuser)); alias messageValues = NoDuplicates!(staticMap!(getMessageValue, messageNames)); class Base { LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) { switch (message) { foreach (msg; messageValues) { case msg: if (auto that = cast(IMessageHandler!msg)this) { return that.handle(wParam, lParam); } break; } default: } return 0; } } interface IMessageHandler(alias msg) { mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);"); alias handle = mixin("On"~__traits(identifier, msg)); } class Button : Base, IMessageHandler!WM_KEYDOWN, IMessageHandler!WM_SETTINGCHANGE { LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) { writeln("WM_KEYDOWN"); return 0; } LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) { writeln("WM_SETTINGCHANGE"); return 0; } } unittest { Base b1 = new Base(); Base b2 = new Button(); writeln("Base:"); // None of these will print anything, as Base doesn't handle them b1.On(WM_KEYDOWN, 0, 0); b1.On(WM_SETTINGCHANGE, 0, 0); b1.On(WM_DRAWITEM, 0, 0); writeln("Button:"); b2.On(WM_KEYDOWN, 0, 0); b2.On(WM_SETTINGCHANGE, 0, 0); // This will print nothing, as Button doesn't handle that message. b2.On(WM_DRAWITEM, 0, 0); } -- Simen |
February 29, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Simen Kjærås | On Friday, 28 February 2020 at 12:21:41 UTC, Simen Kjærås wrote:
> On Friday, 28 February 2020 at 10:33:11 UTC, Виталий Фадеев wrote:
>> Thanks all !
>> I happy !
>> Check this one:
>> void On( T, M )( T o, M message )
>> {
> [snip]
>> void main()
>> {
>> auto a = new A();
>> a.Send( a, WM_KEYUP );
>> a.Send( a, WM_KEYDOWN );
>> }
>
> That does mostly work, but fails for this code:
>
> void main()
> {
> Base a = new A();
> a.send( a, WM_KEYUP );
> }
>
> Basically, whenever you assign a derived to a base, this solution doesn't work, because T will be Base, not A.
>
> I enjoyed with the previous code, so I wrote the code necessary to handle any WM_ message:
>
> import core.sys.windows.windows;
> import std.stdio;
> import std.meta;
>
> template startsWith(string prefix) {
> enum startsWith(string s) = s.length >= prefix.length && s[0..prefix.length] == prefix;
> }
>
> enum getMessageValue(string s) = __traits(getMember, core.sys.windows.winuser, s);
>
> // Get the all the WM_ messages
> alias messageNames = Filter!(startsWith!"WM_", __traits(allMembers, core.sys.windows.winuser));
> alias messageValues = NoDuplicates!(staticMap!(getMessageValue, messageNames));
>
> class Base {
> LRESULT On(UINT message, WPARAM wParam, LPARAM lParam) {
> switch (message) {
> foreach (msg; messageValues) {
> case msg:
> if (auto that = cast(IMessageHandler!msg)this) {
> return that.handle(wParam, lParam);
> }
> break;
> }
> default:
> }
> return 0;
> }
> }
>
> interface IMessageHandler(alias msg) {
> mixin("LRESULT On"~__traits(identifier, msg)~"(WPARAM wParam, LPARAM lParam);");
> alias handle = mixin("On"~__traits(identifier, msg));
> }
>
> class Button : Base, IMessageHandler!WM_KEYDOWN, IMessageHandler!WM_SETTINGCHANGE {
> LRESULT OnWM_KEYDOWN(WPARAM wParam, LPARAM lParam) {
> writeln("WM_KEYDOWN");
> return 0;
> }
> LRESULT OnWM_SETTINGCHANGE(WPARAM wParam, LPARAM lParam) {
> writeln("WM_SETTINGCHANGE");
> return 0;
> }
> }
>
> unittest {
> Base b1 = new Base();
> Base b2 = new Button();
>
> writeln("Base:");
> // None of these will print anything, as Base doesn't handle them
> b1.On(WM_KEYDOWN, 0, 0);
> b1.On(WM_SETTINGCHANGE, 0, 0);
> b1.On(WM_DRAWITEM, 0, 0);
> writeln("Button:");
> b2.On(WM_KEYDOWN, 0, 0);
> b2.On(WM_SETTINGCHANGE, 0, 0);
> // This will print nothing, as Button doesn't handle that message.
> b2.On(WM_DRAWITEM, 0, 0);
> }
>
> --
> Simen
Thank!
Today version is:
import core.sys.windows.windows;
import std.stdio;
import std.traits;
import std.conv : to;
import std.algorithm.searching : startsWith;
mixin template Eventable()
{
override
void On( UINT message )
{
// generate code in dispatcher
// get AllMembers()
// filter OnABC (ex: OnWM_KEYUP)
// on each
// writeCode(
// if ( message == WM_KEYUP ) this.OnWM_KEYUP();
// );
foreach( methodName; __traits( allMembers, typeof( this ) ) )
{
static if ( methodName.startsWith( "On" ) && methodName.length >= 3 )
{
mixin (
"if ( message == " ~ methodName[2..$] ~ " ) " ~ "this." ~ methodName ~ "();"
);
}
}
}
}
void Send( T, M )( T o, M message )
{
o.On( message );
}
class Base
{
void On( UINT message )
{
writeln( "Base.On() // default" );
};
}
class A : Base
{
mixin Eventable;
void OnWM_KEYUP()
{
writeln( "A.OnWM_KEYUP()" );
}
void OnWM_KEYDOWN()
{
writeln( "A.OnWM_KEYDOWN()" );
}
}
void main()
{
auto a = new A();
a.Send( WM_KEYUP ); // A
auto c = cast(Base)a; // Base
c.Send( WM_KEYUP );
}
// output:
// A.OnWM_KEYUP()
// A.OnWM_KEYUP()
|
March 01, 2020 Re: Call method if declared only | ||||
---|---|---|---|---|
| ||||
Posted in reply to Виталий Фадеев | On Friday, 28 February 2020 at 06:12:37 UTC, Виталий Фадеев wrote:
> How to implement ?
I would go for a template mixin that implements send operation in each subclass. Sine template mixin's content is declared in scope of declaration not template's module, the code inside it is aware of concrete implementation of your base class, and could introspect all methods available in it, and generate your switch statement (in send operation) for all supported messages.
This would be just one line of code in each class with no complication whatsoever.
Best regards,
Alexandru.
|
Copyright © 1999-2021 by the D Language Foundation