Mercurial > projects > qtd
comparison qt/d2/qt/Signal.d @ 282:256ab6cb8e85
Signals look-up andNew syntax for connect. The old one will not work from now on. This will allow for the signals overload. Although changes are done for both D1 and D2 versions, D1 won't work because of compiler bugs. I am tired of waiting for fixes.
author | eldar |
---|---|
date | Fri, 16 Oct 2009 02:43:59 +0000 |
parents | 519befd5a5d1 |
children | 1f6923c8cba0 |
comparison
equal
deleted
inserted
replaced
281:7f2e3ffa1c33 | 282:256ab6cb8e85 |
---|---|
785 public struct SignalOps(int sigId, A...) | 785 public struct SignalOps(int sigId, A...) |
786 { | 786 { |
787 private SignalHandler sh; | 787 private SignalHandler sh; |
788 enum { signalId = sigId } | 788 enum { signalId = sigId } |
789 | 789 |
790 void connect(R, B...)(R function(B) fn, ConnectionFlags flags = ConnectionFlags.None) | |
791 { | |
792 alias CheckSlot!(typeof(fn), A) check; | |
793 auto invoker = Dg(&sh.invokeSlot!(typeof(fn), Fn, A)); | |
794 sh.connect(signalId, Fn(fn), invoker, flags); | |
795 } | |
796 | |
797 void connect(R, B...)(R delegate(B) dg, ConnectionFlags flags = ConnectionFlags.None) | |
798 { | |
799 alias CheckSlot!(typeof(dg), A) check; | |
800 auto invoker = Dg(&sh.invokeSlot!(typeof(dg), Dg, A)); | |
801 sh.connect(signalId, Dg(dg), invoker, flags); | |
802 } | |
803 | |
804 void disconnect(R, B...)(R function(B) fn) | |
805 { | |
806 sh.disconnect(signalId, Fn(fn)); | |
807 } | |
808 | |
809 void disconnect(R, B...)(R delegate(B) dg) | |
810 { | |
811 sh.disconnect(signalId, Dg(dg)); | |
812 } | |
813 | |
814 void emit(A args) | 790 void emit(A args) |
815 { | 791 { |
816 sh.emit(signalId, args); | 792 sh.emit(signalId, args); |
817 } | 793 } |
818 | 794 |
819 debug size_t slotCount() | 795 debug size_t slotCount() |
820 { | 796 { |
821 return sh.slotCount(signalId); | 797 return sh.slotCount(signalId); |
822 } | |
823 } | |
824 | |
825 template CheckSlot(Slot, A...) | |
826 { | |
827 static assert(ParameterTypeTuple!(Slot).length <= A.length, "Slot " ~ ParameterTypeTuple!(Slot).stringof ~ | |
828 " has more prameters than signal " ~ A.stringof); | |
829 alias CheckSlotImpl!(Slot, 0, A) check; | |
830 } | |
831 | |
832 template CheckSlotImpl(Slot, int i, A...) | |
833 { | |
834 alias ParameterTypeTuple!(Slot) SlotArgs; | |
835 static if (i < SlotArgs.length) | |
836 { | |
837 static assert (is(SlotArgs[i] : A[i]), "Argument " ~ ToString!(i) ~ | |
838 ":" ~ A[i].stringof ~ " of signal " ~ A.stringof ~ " is not implicitly convertible to parameter " | |
839 ~ SlotArgs[i].stringof ~ " of slot " ~ SlotArgs.stringof); | |
840 alias CheckSlotImpl!(Slot, i + 1, A) next; | |
841 } | 798 } |
842 } | 799 } |
843 | 800 |
844 public template SignalHandlerOps() | 801 public template SignalHandlerOps() |
845 { | 802 { |
872 final void unblockSignals() | 829 final void unblockSignals() |
873 { | 830 { |
874 signalHandler.unblockSignals(); | 831 signalHandler.unblockSignals(); |
875 } | 832 } |
876 | 833 |
877 void connect(string signalName, this T, R, B...)(R function(B) dg, ConnectionFlags flags = ConnectionFlags.None) | 834 template connect(string signalName, A...) |
878 { | 835 { |
879 alias findSymbol!(SignalQualifier, T, signalName) sig; | 836 static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None) |
880 alias CheckSlot!(typeof(fn), sig[2].at) check; | 837 if (isFnOrDg!(Func)) |
881 auto sh = signalHandler(); | 838 { |
882 auto invoker = Dg(&sh.invokeSlot!(typeof(fn), Fn, sig[2].at)); | 839 alias findSignal!(T, signalName, Func, A).result sig; |
883 sh.connect(sig[1], Fn(fn), invoker, flags); | 840 auto sh = sender.signalHandler(); |
884 } | 841 static if (isFn!(Func)) |
885 | 842 alias Fn Callable; |
886 void connect(string signalName, this T, R, B...)(R delegate(B) dg, ConnectionFlags flags = ConnectionFlags.None) | 843 else |
887 { | 844 alias Dg Callable; |
888 alias findSymbol!(SignalQualifier, T, signalName) sig; | 845 auto invoker = Dg(&sh.invokeSlot!(typeof(func), Callable, sig[2..$])); |
889 alias CheckSlot!(typeof(dg), sig[2].at) check; | 846 sh.connect(sig[1], Callable(func), invoker, flags); |
890 auto sh = signalHandler(); | 847 } |
891 auto invoker = Dg(&sh.invokeSlot!(typeof(dg), Dg, sig[2].at)); | 848 } |
892 sh.connect(sig[1], Dg(dg), invoker, flags); | 849 |
893 } | 850 template disconnect(string signalName, A...) |
894 | 851 { |
895 void disconnect(string signalName, this T, R, B...)(R function(B) fn) | 852 static void connect(T, Func)(T sender, Func func, ConnectionFlags flags = ConnectionFlags.None) |
896 { | 853 if (isFnOrDg!(Func)) |
897 alias findSymbol!(SignalQualifier, T, signalName) sig; | 854 { |
898 auto sh = signalHandler(); | 855 alias findSignal!(T, signalName, Func, A).result sig; |
899 sh.disconnect(sig[1], Fn(fn)); | 856 auto sh = sender.signalHandler(); |
900 } | 857 static if (isFn!(Func)) |
901 | 858 alias Fn Callable; |
902 void disconnect(string signalName, this T, R, B...)(R delegate(B) dg) | 859 else |
903 { | 860 alias Dg Callable; |
904 alias findSymbol!(SignalQualifier, T, signalName) sig; | 861 sh.disconnect(sig[1], Callable(func)); |
905 auto sh = signalHandler(); | 862 } |
906 sh.disconnect(sig[1], Dg(dg)); | 863 } |
907 } | 864 /* |
908 | 865 template slotCount(string signalName, A...) |
909 debug size_t slotCount(string signalName, this T)() | 866 { |
910 { | 867 debug static void slotCount(T)(T sender) |
911 alias findSymbol!(SignalQualifier, T, signalName) sig; | 868 { |
912 auto sh = signalHandler(); | 869 alias findSignal!(T, signalName, Func, A).result sig; |
913 return sh.slotCount(sig[1]); | 870 auto sh = sender.signalHandler(); |
914 } | 871 return sh.slotCount(sig[1]); |
872 } | |
873 } | |
874 */ | |
915 } | 875 } |
916 | 876 |
917 /** | 877 /** |
918 New implementation. | 878 New implementation. |
919 */ | 879 */ |
920 | 880 |
921 public bool startsWith(T)(T[] source, T[] pattern) | 881 const string signalPrefix = "__signal"; |
922 { | |
923 return source.length >= pattern.length && source[0 .. pattern.length] == pattern[]; | |
924 } | |
925 | 882 |
926 template TupleWrapper(A...) { alias A at; } | 883 template TupleWrapper(A...) { alias A at; } |
884 | |
885 template isDg(Dg) | |
886 { | |
887 enum isDg = is(Dg == delegate); | |
888 } | |
889 | |
890 template isFn(Fn) | |
891 { | |
892 enum isFn = is(typeof(*Fn.init) == function); | |
893 } | |
894 | |
895 template isFnOrDg(Dg) | |
896 { | |
897 enum isFnOrDg = isFn!(Dg) || isDg!(Dg); | |
898 } | |
927 | 899 |
928 string joinArgs(A...)() | 900 string joinArgs(A...)() |
929 { | 901 { |
930 string res = ""; | 902 string res = ""; |
931 static if(A.length) | 903 static if(A.length) |
935 res ~= "," ~ k.stringof; | 907 res ~= "," ~ k.stringof; |
936 } | 908 } |
937 return res; | 909 return res; |
938 } | 910 } |
939 | 911 |
940 struct SignalQualifier | 912 template SlotPred(T1, T2) |
941 { | 913 { |
942 const string staticSymbolPrefix = "__signal"; | 914 enum SlotPred = is(T1 : T2); |
943 const string name = "signal"; | 915 } |
944 | 916 |
945 static bool matches(alias source, string sigName)() | 917 template CheckSlot(alias Needle, alias Source) |
946 { | 918 { |
947 return startsWith(source.at[0], sigName); | 919 static if(Needle.at.length <= Source.at.length) |
948 } | 920 enum CheckSlot = CheckArgs!(Needle, Source, SlotPred, 0).value; |
949 } | 921 else |
950 | 922 enum CheckSlot = false; |
951 template staticSymbolName(Qualifier, int id) | 923 } |
952 { | 924 |
953 const string staticSymbolName = Qualifier.staticSymbolPrefix ~ ToString!(id); | 925 template SignalPred(T1, T2) |
926 { | |
927 enum SignalPred = is(T1 == T2); | |
928 } | |
929 | |
930 template CheckSignal(alias Needle, alias Source) | |
931 { | |
932 static if(Needle.at.length == Source.at.length) | |
933 enum CheckSignal = CheckArgs!(Needle, Source, SignalPred, 0).value; | |
934 else | |
935 enum CheckSignal = false; | |
936 } | |
937 | |
938 template CheckArgs(alias Needle, alias Source, alias pred, int i) | |
939 { | |
940 static if (i < Needle.at.length) | |
941 { | |
942 static if (pred!(Needle.at[i], Source.at[i])) | |
943 enum value = CheckArgs!(Needle, Source, pred, i + 1).value; | |
944 else | |
945 enum value = false; | |
946 } | |
947 else | |
948 { | |
949 enum value = true; | |
950 } | |
951 } | |
952 | |
953 template SigByNamePred(string name, SlotArgs...) | |
954 { | |
955 template SigByNamePred(source...) | |
956 { | |
957 static if (source[0] == name) // only instantiate CheckSlot if names match | |
958 enum SigByNamePred = CheckSlot!(TupleWrapper!(SlotArgs), TupleWrapper!(source[2 .. $])); | |
959 else | |
960 enum SigByNamePred = false; | |
961 } | |
962 } | |
963 | |
964 template SigBySignPred(string name, SigArgs...) | |
965 { | |
966 template SigBySignPred(source...) | |
967 { | |
968 static if (source[0] == name) // only instantiate CheckSignal if names match | |
969 enum SigBySignPred = CheckSignal!(TupleWrapper!(SigArgs), TupleWrapper!(source[2 .. $])); | |
970 else | |
971 enum SigBySignPred = false; | |
972 } | |
973 } | |
974 | |
975 template staticSymbolName(string prefix, int id) | |
976 { | |
977 const string staticSymbolName = prefix ~ ToString!(id); | |
954 } | 978 } |
955 | 979 |
956 template signatureString(string name, A...) | 980 template signatureString(string name, A...) |
957 { | 981 { |
958 const string signatureString = name ~ "(" ~ joinArgs!(A) ~ ")"; | 982 const string signatureString = name ~ "(" ~ joinArgs!(A) ~ ")"; |
959 } | 983 } |
960 | 984 |
961 template findSymbolImpl(Qualifier, C, int id, string key) | 985 template findSymbolImpl(string prefix, C, int id, alias pred) |
962 { | 986 { |
963 static if ( is(typeof(mixin("C." ~ staticSymbolName!(Qualifier, id)))) ) | 987 static if ( is(typeof(mixin("C." ~ staticSymbolName!(prefix, id)))) ) |
964 { | 988 { |
965 mixin ("alias C." ~ staticSymbolName!(Qualifier, id) ~ " current;"); | 989 mixin ("alias C." ~ staticSymbolName!(prefix, id) ~ " current;"); |
966 static if ( Qualifier.matches!(TupleWrapper!(current), key)() ) { | 990 static if (pred!current) |
967 alias current result; | 991 alias current result; |
968 } | |
969 else | 992 else |
970 alias findSymbolImpl!(Qualifier, C, id + 1, key).result result; | 993 alias findSymbolImpl!(prefix, C, id + 1, pred).result result; |
971 } | 994 } |
972 else | 995 else |
973 { | 996 { |
974 static assert(0, Qualifier.name ~ " " ~ key ~ " not found."); | 997 alias void result; |
975 } | 998 } |
976 } | 999 } |
977 | 1000 |
978 template findSymbol(Qualifier, C, string key) | 1001 template findSymbol(string prefix, C, alias pred) |
979 { | 1002 { |
980 alias findSymbolImpl!(Qualifier, C, 0, key).result findSymbol; | 1003 alias findSymbolImpl!(prefix, C, 0, pred).result findSymbol; |
1004 } | |
1005 | |
1006 template findSignal(C, string name, Receiver, SigArgs...) | |
1007 { | |
1008 alias TupleWrapper!(ParameterTypeTuple!Receiver) SlotArgsWr; | |
1009 static if (SigArgs.length > 0) | |
1010 { | |
1011 alias findSymbol!(signalPrefix, C, SigBySignPred!(name, SigArgs)) result; | |
1012 static if (is(result == void)) | |
1013 static assert(0, "Signal " ~ name ~ "(" ~ joinArgs!SigArgs() ~ ") was not found."); | |
1014 else | |
1015 static if (!CheckSlot!(SlotArgsWr, TupleWrapper!(result[2 .. $]))) | |
1016 static assert(0, "Signature of slot is incompatible with signal " ~ name ~ "."); | |
1017 } | |
1018 else | |
1019 { | |
1020 alias findSymbol!(signalPrefix, C, SigByNamePred!(name, SlotArgsWr.at)) result; | |
1021 static if (is(result == void)) | |
1022 static assert(0, "Signal " ~ name ~ " was not found."); | |
1023 } | |
981 } | 1024 } |
982 | 1025 |
983 /** ---------------- */ | 1026 /** ---------------- */ |
984 | 1027 |
985 | 1028 |
1020 mixin SignalImpl!(0, name, A); | 1063 mixin SignalImpl!(0, name, A); |
1021 } | 1064 } |
1022 | 1065 |
1023 template SignalImpl(int index, string name, A...) | 1066 template SignalImpl(int index, string name, A...) |
1024 { | 1067 { |
1025 static if (is(typeof(mixin(typeof(this).stringof ~ ".__sig" ~ ToString!(index))))) | 1068 static if (is(typeof(mixin(typeof(this).stringof ~ ".__signal" ~ ToString!(index))))) |
1026 mixin SignalImpl!(index + 1, name, A); | 1069 mixin SignalImpl!(index + 1, name, A); |
1027 else | 1070 else |
1028 { | 1071 { |
1029 // mixed-in once | 1072 // mixed-in once |
1030 static if (!is(typeof(this.signalHandler))) | 1073 static if (!is(typeof(this.signalHandler))) |
1031 { | 1074 { |
1032 mixin SignalHandlerOps; | 1075 mixin SignalHandlerOps; |
1033 } | 1076 } |
1034 /* deprecated */ mixin("private static const int __sig" ~ ToString!(index) ~ " = " ~ ToString!(index) ~ ";"); | 1077 mixin("public alias TypeTuple!(\"" ~ name ~ "\", index, A) __signal" ~ ToString!(index) ~ ";"); |
1035 // mixin("public alias TypeTuple!(\"" ~ signatureString!(name, A) ~ "\", index, TupleWrapper!(A)) __signal" ~ ToString!(index) ~ ";"); | |
1036 mixin("SignalOps!(" ~ ToString!(index) ~ ", A) " ~ name ~ "(){ return SignalOps!(" | 1078 mixin("SignalOps!(" ~ ToString!(index) ~ ", A) " ~ name ~ "(){ return SignalOps!(" |
1037 ~ ToString!(index) ~ ", A)(signalHandler); }"); | 1079 ~ ToString!(index) ~ ", A)(signalHandler); }"); |
1038 } | 1080 } |
1039 } | 1081 } |
1040 | 1082 |