0001:
0002:
0003:
0004:
0005:
0006:
0007:
0008:
0009:
0010:
0011:
0012:
0013:
0014:
0015:
0016:
0017:
0018:
0019:
0020:
0021:
0022:
0023:
0024:
0025:
0026:
0027:
0028:
0029:
0030:
0031:
0032:
0033:
0034:
0035:
0036:
0037:
0038:
0039:
0040:
0041:
0042:
0043:
0044:
0045:
0046:
0047:
0048:
0049:
0050:
0051:
0052:
0053:
0054:
0055:
0056:
0057:
0058:
0059:
0060:
0061:
0062:
0063:
0064:
0065:
0066:
0067:
0068:
0069:
0070:
0071:
0072:
0073:
0074:
0075:
0076:
0077:
0078:
0079:
0080:
0081:
0082:
0083:
0084:
0085:
0086:
0087:
0088:
0089:
0090:
0091:
0092:
0093:
0094:
0095:
0096:
0097:
0098:
0099:
0100:
0101:
0102:
0103:
0104:
0105:
0106:
0107:
0108:
0109:
0110:
0111:
0112:
0113:
0114:
0115:
0116:
0117:
0118:
0119:
0120:
0121:
0122:
0123:
0124:
0125:
0126:
0127:
0128:
0129:
0130:
0131:
0132:
0133:
0134:
0135:
0136:
0137:
0138:
0139:
0140:
0141:
0142:
0143:
0144:
0145:
0146:
0147:
0148:
0149:
0150:
0151:
0152:
0153:
0154:
0155:
0156:
0157:
0158:
0159:
0160:
0161:
0162:
0163:
0164:
0165:
0166:
0167:
0168:
0169:
0170:
0171:
0172:
0173:
0174:
0175:
0176:
0177:
0178:
0179:
0180:
0181:
0182:
0183:
0184:
0185:
0186:
0187:
0188:
0189:
0190:
0191:
0192:
0193:
0194:
0195:
0196:
0197:
0198:
0199:
0200:
0201:
0202:
0203:
0204:
0205:
0206:
0207:
0208:
0209:
0210:
0211:
0212:
0213:
0214:
0215:
0216:
0217:
0218:
0219:
0220:
0221:
0222:
0223:
0224:
0225:
0226:
0227:
0228:
0229:
0230:
0231:
0232:
0233:
0234:
0235:
0236:
0237:
0238:
0239:
0240:
0241:
0242:
0243:
0244:
0245:
0246:
0247:
0248:
0249:
0250:
0251:
0252:
0253:
0254:
0255:
0256:
0257:
0258:
0259:
0260:
0261:
0262:
0263:
0264:
0265:
0266:
0267:
0268:
0269:
0270:
0271:
0272:
0273:
0274:
0275:
0276:
0277:
0278:
0279:
0280:
0281:
0282:
0283:
0284:
0285:
0286:
0287:
0288:
0289:
0290:
0291:
0292:
0293:
0294:
0295:
0296:
0297:
0298:
0299:
0300:
0301:
0302:
0303:
0304:
0305:
0306:
0307:
0308:
0309:
0310:
0311:
0312:
0313:
0314:
0315:
0316:
0317:
0318:
0319:
0320:
0321:
0322:
0323:
0324:
0325:
0326:
0327:
0328:
0329:
0330:
0331:
0332:
0333:
0334:
0335:
0336:
0337:
0338:
0339:
0340:
0341:
0342:
0343:
0344:
0345:
0346:
0347:
0348:
0349:
0350:
0351:
0352:
0353:
0354:
0355:
0356:
0357:
0358:
0359:
0360:
0361:
0362:
0363:
0364:
0365:
0366:
0367:
0368:
0369:
0370:
0371:
0372:
0373:
0374:
0375:
0376:
0377:
0378:
0379:
0380:
0381:
0382:
0383:
0384:
0385:
0386:
0387:
0388:
0389:
0390:
0391:
0392:
0393:
0394:
0395:
0396:
0397:
0398:
0399:
0400:
0401:
0402:
0403:
0404:
0405:
0406:
0407:
0408:
0409:
0410:
0411:
0412:
0413:
0414:
0415:
0416:
0417:
0418:
0419:
0420:
0421:
0422:
0423:
0424:
0425:
0426:
0427:
0428:
0429:
0430:
0431:
0432:
0433:
0434:
0435:
0436:
0437:
0438:
0439:
0440:
0441:
0442:
0443:
0444:
0445:
0446:
0447:
0448:
0449:
0450:
0451:
0452:
0453:
0454:
0455:
0456:
0457:
0458:
0459:
0460:
0461:
0462:
0463:
0464:
0465:
0466:
0467:
0468:
0469:
0470:
0471:
0472:
0473:
0474:
0475:
0476:
0477:
0478:
0479:
0480:
0481:
0482:
0483:
0484:
0485:
0486:
0487:
0488:
0489:
0490:
0491:
0492:
0493:
0494:
0495:
0496:
0497:
0498:
0499:
0500:
0501:
0502:
0503:
0504:
0505:
0506:
0507:
0508:
0509:
0510:
0511:
0512:
0513:
0514:
0515:
0516:
0517:
0518:
0519:
0520:
0521:
0522:
0523:
0524:
0525:
0526:
0527:
0528:
0529:
0530:
0531:
0532:
0533:
0534:
0535:
0536:
0537:
0538:
0539:
0540:
0541:
0542:
0543:
0544:
0545:
0546:
0547:
0548:
0549:
0550:
0551:
0552:
0553:
0554:
0555:
0556:
0557:
0558:
0559:
0560:
0561:
0562:
0563:
0564:
0565:
0566:
0567:
0568:
0569:
0570:
0571:
0572:
0573:
0574:
0575:
0576:
0577:
0578:
0579:
0580:
0581:
0582:
0583:
0584:
0585:
0586:
0587:
0588:
0589:
0590:
0591:
0592:
0593:
0594:
0595:
0596:
0597:
0598:
0599:
0600:
0601:
0602:
0603:
0604:
0605:
0606:
0607:
0608:
0609:
0610:
0611:
0612:
0613:
0614:
0615:
0616:
0617:
0618:
0619:
0620:
0621:
0622:
0623:
0624:
0625:
0626:
0627:
0628:
0629:
0630:
0631:
0632:
0633:
0634:
0635:
0636:
0637:
0638:
0639:
0640:
0641:
0642:
0643:
0644:
0645:
0646:
0647:
0648:
0649:
0650:
0651:
0652:
0653:
0654:
0655:
0656:
0657:
0658:
0659:
0660:
0661:
0662:
0663:
0664:
0665:
0666:
0667:
0668:
0669:
0670:
0671:
0672:
0673:
0674:
0675:
0676:
0677:
0678:
0679:
0680:
0681:
0682:
0683:
0684:
0685:
0686:
0687:
0688:
0689:
0690:
0691:
0692:
0693:
0694:
0695:
0696:
0697:
0698:
0699:
0700:
0701:
0702:
0703:
0704:
0705:
0706:
0707:
0708:
0709:
0710:
0711:
0712:
0713:
0714:
0715:
0716:
0717:
0718:
0719:
0720:
0721:
0722:
0723:
0724:
0725:
0726:
0727:
0728:
0729:
0730:
0731:
0732:
0733:
0734:
0735:
0736:
0737:
0738:
0739:
0740:
0741:
0742:
0743:
0744:
0745:
0746:
0747:
0748:
0749:
0750:
0751:
0752:
0753:
0754:
0755:
0756:
0757:
0758:
0759:
0760:
0761:
0762:
0763:
0764:
0765:
0766:
0767:
0768:
0769:
0770:
0771:
0772:
0773:
0774:
0775:
0776:
0777:
0778:
0779:
0780:
0781:
0782:
0783:
0784:
0785:
0786:
0787:
0788:
0789:
0790:
0791:
0792:
0793:
0794:
0795:
0796:
0797:
0798:
0799:
0800:
0801:
0802:
0803:
0804:
0805:
0806:
0807:
0808:
0809:
0810:
0811:
0812:
0813:
0814:
0815:
0816:
0817:
0818:
0819:
0820:
0821:
0822:
0823:
0824:
0825:
0826:
0827:
0828:
0829:
0830:
0831:
0832:
0833:
0834:
0835:
0836:
0837:
0838:
0839:
0840:
0841:
0842:
0843:
0844:
0845:
0846:
0847:
0848:
0849:
0850:
0851:
0852:
0853:
0854:
0855:
0856:
0857:
0858:
0859:
0860:
0861:
0862:
0863:
0864:
0865:
0866:
0867:
0868:
0869:
0870:
0871:
0872:
0873:
0874:
0875:
0876:
0877:
0878:
0879:
0880:
0881:
0882:
0883:
0884:
0885:
0886:
0887:
0888:
0889:
0890:
0891:
0892:
0893:
0894:
0895:
0896:
0897:
0898:
0899:
0900:
0901:
0902:
0903:
0904:
0905:
0906:
0907:
0908:
0909:
0910:
0911:
0912:
0913:
0914:
0915:
0916:
0917:
0918:
0919:
0920:
0921:
0922:
0923:
0924:
0925:
0926:
0927:
0928:
0929:
0930:
0931:
0932:
0933:
0934:
0935:
0936:
0937:
0938:
0939:
0940:
0941:
0942:
0943:
0944:
0945:
0946:
0947:
0948:
0949:
0950:
0951:
0952:
0953:
0954:
0955:
0956:
0957:
0958:
0959:
0960:
0961:
0962:
0963:
0964:
0965:
0966:
0967:
0968:
0969:
0970:
0971:
0972:
0973:
0974:
0975:
0976:
0977:
0978:
0979:
0980:
0981:
0982:
0983:
0984:
0985:
0986:
0987:
0988:
0989:
0990:
0991:
0992:
0993:
0994:
0995:
0996:
0997:
0998:
0999:
1000:
1001:
1002:
1003:
1004:
1005:
1006:
1007:
1008:
1009:
1010:
1011:
1012:
1013:
1014:
1015:
1016:
1017:
1018:
1019:
1020:
1021:
1022:
1023:
1024:
1025:
1026:
1027:
1028:
1029:
1030:
1031:
1032:
1033:
1034:
1035:
1036:
1037:
1038:
1039:
1040:
1041:
1042:
1043:
1044:
1045:
1046:
1047:
1048:
1049:
1050:
1051:
1052:
1053:
1054:
1055:
1056:
1057:
1058:
1059:
1060:
1061:
1062:
1063:
1064:
1065:
1066:
1067:
1068:
1069:
1070:
1071:
1072:
1073:
1074:
1075:
1076:
1077:
1078:
1079:
1080:
1081:
1082:
1083:
1084:
1085:
1086:
1087:
1088:
1089:
1090:
1091:
1092:
1093:
1094:
1095:
1096:
1097:
1098:
1099:
1100:
1101:
1102:
1103:
1104:
1105:
1106:
1107:
1108:
1109:
1110:
1111:
1112:
1113:
1114:
1115:
1116:
1117:
1118:
1119:
1120:
1121:
1122:
1123:
1124:
1125:
1126:
1127:
1128:
1129:
1130:
1131:
1132:
1133:
1134:
1135:
1136:
1137:
1138:
1139:
1140:
1141:
1142:
1143:
1144:
1145:
1146:
1147:
1148:
1149:
1150:
1151:
1152:
1153:
1154:
1155:
1156:
1157:
1158:
1159:
1160:
1161:
1162:
1163:
1164:
1165:
1166:
1167:
1168:
1169:
1170:
1171:
1172:
1173:
1174:
1175:
1176:
1177:
1178:
1179:
1180:
1181:
1182:
1183:
1184:
1185:
1186:
1187:
1188:
1189:
1190:
1191:
1192:
1193:
1194:
1195:
1196:
1197:
1198:
1199:
1200:
1201:
1202:
1203:
1204:
1205:
1206:
1207:
1208:
1209:
1210:
1211:
1212:
1213:
1214:
1215:
1216:
1217:
1218:
1219:
1220:
1221:
1222:
1223:
1224:
1225:
1226:
1227:
1228:
1229:
1230:
1231:
1232:
1233:
1234:
1235:
1236:
1237:
1238:
1239:
1240:
1241:
1242:
1243:
1244:
1245:
1246:
1247:
1248:
1249:
1250:
1251:
1252:
1253:
1254:
1255:
1256:
1257:
1258:
1259:
1260:
1261:
1262:
1263:
1264:
1265:
1266:
1267:
1268:
1269:
1270:
1271:
1272:
1273:
1274:
1275:
1276:
1277:
1278:
1279:
1280:
1281:
1282:
1283:
1284:
1285:
1286:
1287:
1288:
1289:
1290:
1291:
1292:
1293:
1294:
1295:
1296:
1297:
1298:
1299:
1300:
1301:
1302:
1303:
1304:
1305:
1306:
1307:
1308:
1309:
1310:
1311:
1312:
1313:
1314:
1315:
1316:
1317:
1318:
1319:
1320:
1321:
1322:










































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































































/*
* This file is part of the Omni C++ framework
*
* Copyright (c) 2016, Zeriph Enterprises, LLC
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* - Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* - Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* - Neither the name of Zeriph, Zeriph Enterprises, LLC, nor the names
* of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY ZERIPH AND CONTRIBUTORS "AS IS" AND ANY
* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL ZERIPH AND CONTRIBUTORS BE LIABLE FOR ANY
* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#if !defined(OMNI_DELEGATE3_HPP)
#define OMNI_DELEGATE3_HPP 1
#include <omni/defs/delegate_def.hpp>
#include <omni/types/invoke_t.hpp>

namespace omni {
    /**
     * The delegate is a powerful function pointer object that
     * encapsulates both an object instance and a method. The delegate is
     * agnostic to the type or method it encapsulates; all that matters is that
     * the method be signature compatible with the delegate. This allows for
     * 'anonymous' invocation by users of the delegate.
     *
     * @tparam Ret     Specifies the return type of the function the delegate is to attach to
     * @tparam PT1     Specifies the 1st parameter type passed to the function delegate
     * @tparam PT2     Specifies the 2nd parameter type passed to the function delegate
     * @tparam PT3     Specifies the 3rd parameter type passed to the function delegate
     */
    template < typename Ret, typename PT1, typename PT2, typename PT3 >
    class delegate3
    {
        public:
            /** Defines the return type this delegate will represent */
            typedef Ret ret_t;
            /** Defines the 1st function parameter type of this delegate */
            typedef PT1 p1_t;
            /** Defines the 2nd function parameter type of this delegate */
            typedef PT2 p2_t;
            /** Defines the 3rd function parameter type of this delegate */
            typedef PT3 p3_t;

            /** Defines the functor signature this delegate will represent */
            typedef ret_t (*functor)(void* extObj, p1_t val1, p2_t val2, p3_t val3);
            /** Defines the function pointer signature this delegate will represent */
            typedef ret_t (*function_ptr)(p1_t val1, p2_t val2, p3_t val3);
            
            /**
             * The default constructor; constructs a default delegate
             * object with no function or member attached.
             */
            delegate3() :
                OMNI_SAFE_DGATE_MILST_FW
                m_method(OMNI_NULL),
                m_target(OMNI_NULL)
            {
                OMNI_SAFE_DGATE_INIT_FW
                OMNI_D5_FW("created delegate");
            }
            
            /**
             * The copy constructor; copies another delegates target and method.
             * The delegate being copied must be of the same signature.
             *
             * @param cp    The other delegate to copy
             */
            delegate3(const delegate3< Ret, PT1, PT2, PT3 >& cp) :
                OMNI_SAFE_DGATE_MILST_FW
                m_method(cp.m_method),
                m_target(cp.m_target)
            {
                OMNI_SAFE_DGATE_INIT_FW
                OMNI_D5_FW("copied delegate");
            }
            
            /**
             * Creates a new instance from a non-member or static member function pointer.
             *
             * @param fnptr The function pointer to attach
             */
            delegate3(function_ptr fnptr) :
                OMNI_SAFE_DGATE_MILST_FW
                m_method(reinterpret_cast<functor>(fnptr)),
                m_target(OMNI_NULL)
            {
                OMNI_SAFE_DGATE_INIT_FW
                OMNI_D5_FW("created delegate with function pointer");
            }
            
            /**
             * Creates a new instance from a functor and object.
             *
             * @param obj The instance of the object to use with this delegate
             * @param mthd The functor of the object to attach to this delegate for invocation
             */
            delegate3(void* obj, functor mthd) :
                OMNI_SAFE_DGATE_MILST_FW
                m_method(mthd),
                m_target(obj)
            {
                OMNI_SAFE_DGATE_INIT_FW
                OMNI_D5_FW("created delegate with target and method");
            }
            
            /** The default destructor, detaches this instance from its target and method */
            ~delegate3()
            {
                OMNI_TRY_FW
                this->unbind();
                OMNI_SAFE_DGATE_DTOR_FW
                OMNI_CATCH_FW
                OMNI_D5_FW("destroyed");
            }

            /**
             * Attach a static member or non-member function to this delegate.
             *
             * @param fnptr The function taking 3 parameters to attach to the delegate
             */
            inline void bond(function_ptr fnptr)
            {
                this->_bind(OMNI_NULL, reinterpret_cast<functor>(fnptr));
            }
            
            /**
             * Attach a static member or non-member function to this delegate.
             *
             * @tparam fnptr The function taking 3 parameters to attach to the delegate
             */
            template < ret_t (*fnptr)(p1_t, p2_t, p3_t) >
            inline void bond()
            {
                this->_bind(OMNI_NULL, &_anon_param_fn<fnptr>);
            }
            
            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            inline void bond(T& obj)
            {
                this->_bind(static_cast<void*>(&obj), &_member_param_fn<T, fnptr>);
            }

            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            inline void bond(const T& obj)
            {
                this->_bind(static_cast<void*>(const_cast<T*>(&obj)), &_member_param_fn<T, fnptr>);
            }
            
            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            inline void bond(const T *const obj)
            {
                this->_bind(static_cast<void*>(const_cast<T *const>(obj)), &_member_param_fn<T, fnptr>);
            }

            /**
             * Attach a const member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The const function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) const >
            inline void bond_const(const T& obj)
            {
                this->_bind(static_cast<void*>(const_cast<T*>(&obj)), &_member_param_fn_const<T, fnptr>);
            }
            
            /**
             * Attach a const member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) const >
            inline void bond_const(const T *const obj)
            {
                this->_bind(static_cast<void*>(const_cast<T *const>(obj)), &_member_param_fn_const<T, fnptr>);
            }
            
            /**
             * Attach a static member or non-member function to this delegate.
             *
             * @tparam fnptr The function taking 3 parameters to attach to the delegate
             */
            template < ret_t (*fnptr)(p1_t, p2_t, p3_t) >
            static delegate3 bind()
            {
                return delegate3(OMNI_NULL, &_anon_param_fn<fnptr>);
            }
            
            /**
             * Attach a parametrized member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The parametrized function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            static delegate3 bind(T& obj)
            {
                return delegate3(&obj, &_member_param_fn<T, fnptr>);
            }
            
            /**
             * Attach a parametrized member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The parametrized function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            static delegate3 bind(const T& obj)
            {
                return delegate3(const_cast<T *const>(&obj), &_member_param_fn<T, fnptr>);
            }
            
            /**
             * Attach a parametrized member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The parametrized function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            static delegate3 bind(const T *const obj)
            {
                return delegate3(const_cast<T *const>(obj), &_member_param_fn<T, fnptr>);
            }

            /**
             * Attach a const parametrized member function to this delegate.
             *
             * @tparam T         The type of class to associate with this delegate
             * @tparam fnptr     The parametrized function to attach to the delegate
             * @param obj         The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) const >
            static delegate3 bind_const(const T& obj)
            {
                return delegate3(const_cast<T *const>(&obj), &_member_param_fn_const<T, fnptr>);
            }
            
            /**
             * Attach a parametrized member function to this delegate.
             *
             * @tparam T         The type of class to associate with this delegate
             * @tparam fnptr     The parametrized function to attach to the delegate
             * @param obj         The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) const >
            static delegate3 bind_const(const T *const obj)
            {
                return delegate3(const_cast<T *const>(obj), &_member_param_fn_const<T, fnptr>);
            }
            
            /**
             * Gets if this instance is bound to a method
             *
             * @return True if this instance is currently bound
             */
            bool is_bound() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return (this->m_method != OMNI_NULL);
            }
            
            /**
             * Gets if this instance is bound to a member method
             *
             * @return True if this instance is currently bound to a target and method
             */
            bool is_member_bound() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return (this->m_method != OMNI_NULL && this->m_target != OMNI_NULL);
            }
            
            /**
             * Invoke the function bound to this delegate instance
             *
             * @return This function returns whatever is returned
             *         (if anything) from the invoked function
             */
            ret_t invoke(p1_t val1, p2_t val2, p3_t val3) const
            {
                #if defined(OMNI_SAFE_DELEGATES)
                    omni::sync::mutex_lock(this->m_mtx);
                    if (this->m_method != OMNI_NULL) {
                        if (this->m_target == OMNI_NULL) {
                            function_ptr fp = reinterpret_cast<function_ptr>(this->m_method);
                            omni::sync::mutex_unlock(this->m_mtx);
                            return (*fp)(val1, val2, val3);
                        } else {
                            functor m = this->m_method;
                            void* t = this->m_target;
                            omni::sync::mutex_unlock(this->m_mtx);
                            return (*m)(t, val1, val2, val3);
                        }
                    }
                    omni::sync::mutex_unlock(this->m_mtx);
                #else
                    return (this->m_target == OMNI_NULL ?
                            (*reinterpret_cast<function_ptr>(this->m_method))(val1, val2, val3) :
                            (*this->m_method)(this->m_target, val1, val2, val3));
                #endif
                OMNI_ERR_RETV_FW("No valid function has been assigned to the delegate", omni::invalid_delegate(), ret_t())
            }
            
            /**
             * Invoke the function bound to this delegate instance.
             * This method does not preform any safety checks on the
             * method or object instance and directly calls the method
             * for invocation (if bound).
             *
             * @return This function returns whatever is returned
             *         (if anything) from the invoked function
             */
            ret_t invoke_direct(p1_t val1, p2_t val2, p3_t val3) const
            {
                return (this->m_target == OMNI_NULL ?
                        (*reinterpret_cast<function_ptr>(this->m_method))(val1, val2, val3) :
                        (*this->m_method)(this->m_target, val1, val2, val3));
            }
            
            /**
             * Gets the invocation type this delegate represents
             *
             * @return The delegates omni::invoke_type::enum_t
             */
            omni::invoke_t invoke_type() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                if (this->m_method == OMNI_NULL) { return omni::invoke_type::NONE; }
                return (this->m_target == OMNI_NULL ?
                        omni::invoke_type::ANONYMOUS :
                        omni::invoke_type::MEMBER_FUNC);
            }
            
            /**
             * Gets the underlying functor called when this method is invoked.
             *
             * @return The underlying functor method
             */
            const functor method() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return this->m_method;
            }
            
            /**
             * Gets the underlying function pointer called when this method is invoked.
             *
             * @return The underlying function pointer, or an OMNI_NULL value if the
             * object instance is null;
             */
            const function_ptr function() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return ((this->m_target == OMNI_NULL) ?
                        reinterpret_cast<function_ptr>(this->m_method) : OMNI_NULL);
            }
            
            /**
             * Swaps the invocation method and target of 2 delegates
             */
            void swap(delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                #if defined(OMNI_SAFE_DELEGATES)
                    omni::sync::mutex_lock(d.m_mtx);
                #endif
                std::swap(this->m_target, d.m_target);
                std::swap(this->m_method, d.m_method);
                #if defined(OMNI_SAFE_DELEGATES)
                    omni::sync::mutex_unlock(d.m_mtx);
                #endif
            }
            
            /**
             * Gets the underlying target (if any) used when invoking this method.
             *
             * @return A pointer to the underlying target object (if any)
             */
            void *const target() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return this->m_target;
            }
            
            /**
             * Detaches the target and method from this instance
             */
            inline void unbind()
            {
                this->_bind(OMNI_NULL, OMNI_NULL);
                OMNI_D4_FW("instance unbound");
            }
            
            /**
             * Checks if the current delegate instance is valid
             *
             * @return True if the instance has a method attached, false if not
             */
            bool valid() const
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                return (this->m_method != OMNI_NULL);
            }
            
            /**
             * Has the same effect as calling the invoke method.
             * Overloading this operator makes it such that you can
             * use the delegate as if it were a function.
             *
             * delegate<int> d = &some_func;
             * printf("value = %d", d());
             *
             * @return The return type specified at compile time
             */
            inline ret_t operator()(p1_t val1, p2_t val2, p3_t val3) const
            {
                return this->invoke(val1, val2, val3);
            }
            
            /**
             * The boolean operator allows you to check for validity as if
             * the delegate were a function pointer, example:
             * delegate<int> d;
             * if (d) { d(); } // fails check because d is not attached
             * d = &some_func;
             * if (d) { d(); } // success because d is bound
             *
             * @return True if the delegate is attached
             */
            inline operator bool() const
            {
                return this->valid();
            }
            
            /**
             * The negated boolean () operator is used to check negation of the boolean () operator
             */
            inline bool operator!() const
            {
                return !(this->operator bool());
            }
            
            /**
             * The assignment operator is used to set the target and method
             * of another delegate to this one.
             *
             * @param d        The right most operand which to assign to
             *
             * @return A reference to the current instance
             */
            delegate3< Ret, PT1, PT2, PT3 >& operator=(const delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                if (this != &d) {
                    #if defined(OMNI_SAFE_DELEGATES)
                        omni::sync::mutex_lock(d.m_mtx);
                    #endif
                    this->_bind(d.m_target, d.m_method);
                    #if defined(OMNI_SAFE_DELEGATES)
                        omni::sync::mutex_unlock(d.m_mtx);
                    #endif
                }
                return *this;
            }
            
            /**
             * Allows for assignment to anonymous (non-member) functions
             * by saying = &func_name
             *
             * @param fp The function pointer to assign
             *
             * @return A reference to the current instance
             */
            delegate3< Ret, PT1, PT2, PT3 >& operator=(function_ptr fnptr)
            {
                this->_bind(OMNI_NULL, reinterpret_cast<functor>(fnptr));
                return *this;
            }
            
            /**
             * The equality operator test the target and method against the other
             *
             * @param d        The right most operand which to compare to
             *
             * @return     True if the two instance are equal
             */
            bool operator==(const delegate3< Ret, PT1, PT2, PT3 >& d) const
            {
                if (this == &d) { return true; }
                OMNI_SAFE_DGATE_ALOCK_FW
                return
                (
                    this->m_target == d.m_target &&
                    this->m_method == d.m_method
                );
            }
            
            /**
             * The != operator is used for comparison results (negates the == operator)
             *
             * @param d        The right most operand which to compare to
             *
             * @return True if the instances are not equal
             */
            bool operator!=(const delegate3< Ret, PT1, PT2, PT3 >& d) const
            {
                return !(*this == d);
            }
            
        private:
            OMNI_SAFE_DGATE_MTX_FW
            /** The 3 parameter member function to be called */
            functor m_method;
            /** The instance of the object set when attaching to the delegate */
            void* m_target;
            
            /**
             * The internal binding function that sets the underlying method and target
             *
             * @param obj The target to set
             * @param mthd The method to set
             * @param type The type to set
             */
            void _bind(void* obj, functor mthd)
            {
                OMNI_SAFE_DGATE_ALOCK_FW
                this->m_target = obj;
                this->m_method = mthd;
            }
            
            /**
             * Gets the parametrized non member (static/anonymous) function to use
             *
             * @tparam fnptr         The method to assign
             */
            template < ret_t (*fnptr)(p1_t, p2_t, p3_t) >
            static ret_t _anon_param_fn(void*, p1_t val1, p2_t val2, p3_t val3)
            {
                return (fnptr)(val1, val2, val3);
            }
            
            /**
             * Get the parametrized member function to use
             *
             * @tparam T         The class type
             * @tparam fnptr     The parametrized member method to use
             * @param obj         The instance object associated with the member method
             *
             * @return             The functor
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) >
            static ret_t _member_param_fn(void* obj, p1_t val1, p2_t val2, p3_t val3)
            {
                return ((static_cast<T*>(obj))->*reinterpret_cast<ret_t (T::*)(p1_t, p2_t, p3_t, void*)>(fnptr))(val1, val2, val3, obj);
            }
            
            /**
             * Get the const parametrized member function to use
             *
             * @tparam T         The class type
             * @tparam fnptr     The parametrized member method to use
             * @param obj         The instance object associated with the member method
             *
             * @return             The functor
             */
            template < class T, ret_t (T::*fnptr)(p1_t, p2_t, p3_t) const >
            static ret_t _member_param_fn_const(void* obj, p1_t val1, p2_t val2, p3_t val3)
            {
                return ((static_cast<T*>(obj))->*reinterpret_cast<ret_t (T::*)(p1_t, p2_t, p3_t, void*) const>(fnptr))(val1, val2, val3, obj);
            }
    };
    
    /** A generic delegate that has 3 parameters and does not return a value. */
    typedef omni::delegate3<void, void*, void*, void*> callback3;
    
    /**
     * The templated event allows client code to attach multiple delegates
     * and invoke them, providing notification to attached code (i.e. event handlers).
     *
     * Invoking an event will invoke each attached handler (delegate) in the order
     * they have been attached.
     *
     * @tparam Ret     Specifies the return type of the delegates to be attached
     * @tparam 3     Specifies the parameter types passed to the delegate
     */
    template < typename Ret, typename PT1, typename PT2, typename PT3 >
    class event3
    {
        public:
            /** Defines the return type this event will represent */
            typedef Ret ret_t;
            /** Defines the delegate signature this event represents */
            typedef omni::delegate3< Ret, PT1, PT2, PT3 > delegate_t;
            /** Defines the container type used by this event class */
            typedef typename std::deque< omni::delegate3< Ret, PT1, PT2, PT3 > > container_t;
            /** Defines an iterator type to the underlying types */
            typedef typename std::deque< omni::delegate3< Ret, PT1, PT2, PT3 > >::iterator iterator_t;
            /** Defines a const iterator type to the underlying types */
            typedef typename std::deque< omni::delegate3< Ret, PT1, PT2, PT3 > >::const_iterator const_iterator_t;
            /** Defines a reverse iterator type to the underlying types */
            typedef typename std::reverse_iterator< iterator_t > reverse_iterator_t;
            /** Defines a const reverse iterator type to the underlying types */
            typedef typename std::reverse_iterator< const_iterator_t > const_reverse_iterator_t;
            /** Defines the 1st function parameter type of this delegate */
            typedef PT1 p1_t;
            /** Defines the 2nd function parameter type of this delegate */
            typedef PT2 p2_t;
            /** Defines the 3rd function parameter type of this delegate */
            typedef PT3 p3_t;


            /** The default constructor */
            event3() :
                OMNI_SAFE_EVENT_MILST_FW
                m_list()
            {
                OMNI_SAFE_EVENT_INIT_FW
                OMNI_D5_FW("created event");
            }
            
            /**
             * The copy constructor copies the elements from the
             * event passed in.
             *
             * @param cp    The event to copy
             */
            event3(const event3< Ret, PT1, PT2, PT3 >& cp) :
                OMNI_SAFE_EVENT_MILST_FW
                m_list(cp.m_list)
            {
                OMNI_SAFE_EVENT_INIT_FW
                OMNI_D5_FW("created event");
            }
            
            /**
             * Creates an event with a signature compatible delegate attached
             *
             * @param d     The signature compatible delegate to add to the invocation list
             */
            explicit event3(const omni::delegate3< Ret, PT1, PT2, PT3 >& d) :
                OMNI_SAFE_EVENT_MILST_FW
                m_list()
            {
                OMNI_SAFE_EVENT_INIT_FW
                this->attach(d);
                OMNI_D5_FW("created event");
            }

            /**
             * The default destructor; clears the underlying list,
             * calling the destructor for each attached delegate
             */
            ~event3()
            {
                OMNI_TRY_FW
                this->clear();
                OMNI_SAFE_EVENT_DTOR_FW
                OMNI_CATCH_FW
                OMNI_D5_FW("destroyed");
            }
            
            /**
             * Add (attach) a member delegate to this event instance
             *
             * @param d        The member delegate to attach
             */
            void attach(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                /* DEV_NOTE: don't check if 'd' doesn't have a valid function reference
                since on invoke 'd' would fail if it didn't have a valid fnptr */
                OMNI_SAFE_EVENT_ALOCK_FW
                this->m_list.push_back(d);
            }
            
            /**
             * Add (attach) another events invocation list to this instance
             *    
             * @param e        The other event to add invocation list
             */
            void attach(const event3< Ret, PT1, PT2, PT3 >& e)
            {
                if (this != &e) {
                    OMNI_SAFE_EVENT_ALOCK_FW
                    container_t tmp = e.invocation_list();
                    for (iterator_t it = tmp.begin(); it != tmp.end(); it++) {
                        this->m_list.push_back(*it);
                    }
                }
            }
            
            /**
             * Add (attach) a range of delegates to this event instance
             *
             * @param begin     The input iterator pointing to the initial position in the sequence to add
             * @param end     The input iterator pointing to the last position in the sequence to add
             */
            template < class InputIterator >
            void attach(InputIterator begin, InputIterator end)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                while (begin != end) {
                    this->m_list.push_back(*begin);
                    ++begin;
                }
            }
            
            /**
             * Attach a an anonymous/non-member or static member function to this delegate.
             *
             * @tparam fnptr         The function to attach to the delegate
             */
            template < ret_t (*fnptr)(PT1, PT2, PT3) >
            void attach()
            {
                this->attach( fnptr );
            }
            
            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void attach(T& obj)
            {
                this->attach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void attach(const T& obj)
            {
                this->attach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Attach a member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void attach(const T *const obj)
            {
                this->attach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Attach a const member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            void attach_const(const T& obj)
            {
                this->attach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Attach a const member function to this delegate.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            void attach_const(const T *const obj)
            {
                this->attach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Clears the underlying invocation list
             */
            void clear()
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                // clear the list container, calling the items destructors
                this->m_list.clear();
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @param d        The member delegate to search for
             *
             * @return True if the delegate is found, false otherwise
             */
            bool contains(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                return (this->_find(d) != this->m_list.end());
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam fnptr         The function to attach to the delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < ret_t (*fnptr)(PT1, PT2, PT3) >
            bool contains()
            {
                return this->contains( fnptr );
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            bool contains(T& obj)
            {
                return this->contains( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            bool contains(const T& obj)
            {
                return this->contains( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            bool contains(const T *const obj)
            {
                return this->contains( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            bool contains_const(const T& obj)
            {
                return this->contains( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Tests if a specified member delegate is in this event instance.
             *
             * @tparam T             The type of class to associate with this delegate
             * @tparam fnptr         The function to attach to the delegate
             * @param obj            The instance of the class to reference in this delegate
             *
             * @return True if the delegate is found, false otherwise
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            bool contains_const(const T *const obj)
            {
                return this->contains( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Detach a member delegate to this event instance
             *
             * @param d        The member delegate to detach
             */
            void detach(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                iterator_t found;
                while ((found = this->_find(d)) != this->m_list.end()) {
                    this->m_list.erase(found);
                }
            }
            
            /**
             * Detaches another events invocation list from this instance
             *
             * @param e        The event to detach invocation list of
             */
            void detach(const event3< Ret, PT1, PT2, PT3 >& e)
            {
                if (this != &e) {
                    OMNI_SAFE_EVENT_ALOCK_FW
                    iterator_t found = this->m_list.end();
                    container_t tmp = e.invocation_list();
                    for (iterator_t it = tmp.begin(); it != tmp.end(); ++it) {
                        while ((found = this->_find(*it)) != this->m_list.end()) {
                            this->m_list.erase(found);
                        }
                    }
                }
            }
            
            /**
             * Detach a range of delegates from this event instance
             *
             * @param begin     The input iterator pointing to the initial position in the sequence to remove
             * @param end     The input iterator pointing to the last position in the sequence to remove
             */
            template < class InputIterator >
            void detach(InputIterator begin, InputIterator end)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                iterator_t found = this->m_list.end();
                while (begin != end) {
                    while ((found = this->_find(*begin)) != this->m_list.end()) {
                        this->m_list.erase(found);
                    }
                    ++begin;
                }
            }
            
            /**
             * Detach an anonymous/non-member or static member function from this event.
             *
             * @tparam fnptr         The function to detach
             */
            template < ret_t (*fnptr)(PT1, PT2, PT3) >
            void detach()
            {
                this->detach( fnptr );
            }
            
            /**
             * Detach a member function from this event.
             *
             * @tparam T             The type of class to associate with the delegate
             * @tparam fnptr         The function to detach
             * @param obj            The instance of the class to reference
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void detach(T& obj)
            {
                this->detach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Detach a member function from this event.
             *
             * @tparam T             The type of class to associate with the delegate
             * @tparam fnptr         The function to detach
             * @param obj            The instance of the class to reference
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void detach(const T& obj)
            {
                this->detach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Detach a member function from this event.
             *
             * @tparam T             The type of class to associate with the delegate
             * @tparam fnptr         The function to detach
             * @param obj            The instance of the class to reference
             */
            template < class T, Ret (T::*fnptr)(PT1, PT2, PT3) >
            void detach(const T *const obj)
            {
                this->detach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind< T, fnptr >(obj) );
            }
            
            /**
             * Detach a const member function from this event.
             *
             * @tparam T             The type of class to associate with the delegate
             * @tparam fnptr         The function to detach
             * @param obj            The instance of the class to reference
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            void detach_const(const T& obj)
            {
                this->detach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Detach a const member function from this event.
             *
             * @tparam T             The type of class to associate with the delegate
             * @tparam fnptr         The function to detach
             * @param obj            The instance of the class to reference
             */
            template < class T, ret_t (T::*fnptr)(PT1, PT2, PT3) const >
            void detach_const(const T *const obj)
            {
                this->detach( omni::delegate3< Ret, PT1, PT2, PT3 >::template bind_const< T, fnptr >(obj) );
            }
            
            /**
             * Checks if the current event instance has any attached methods
             *
             * @return True if the instance has a method or methods attached, false if not
             */
            bool empty() const
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                return this->m_list.empty();
            }
            
            /**
             * Gets the invocation list used to call the delegate objects on event invocation
             *
             * @return The underlying container variable
             */
            container_t invocation_list() const
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                return this->m_list;
            }
            
            /**
             * Calls the functions bound to this event instance in a non-safe manner.
             * delegate::invoke_direct does not perform certain checks.
             *
             * @return The return type specified at compile time
             */
            ret_t invoke_direct(p1_t val1, p2_t val2, p3_t val3) const
            {
                OMNI_SAFE_EVENT_LOCK_FW
                const_iterator_t cur = this->m_list.begin();
                const_iterator_t tmp = this->m_list.begin();
                const_iterator_t end = this->m_list.end();
                while (cur != end) {
                    if ((++tmp) == end) {
                        OMNI_SAFE_EVENT_UNLOCK_FW
                        return cur->invoke_direct(val1, val2, val3);
                    }
                    OMNI_SAFE_EVENT_UNLOCK_FW
                    cur->invoke_direct(val1, val2, val3);
                    OMNI_SAFE_EVENT_LOCK_FW
                    tmp = (++cur);
                }
                OMNI_SAFE_EVENT_UNLOCK_FW
            }
            
            void swap(event3< Ret, PT1, PT2, PT3 >& e)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                #if defined(OMNI_SAFE_EVENTS)
                    omni::sync::mutex_lock(e.m_mtx);
                #endif
                std::swap(this->m_list, e.m_list);
                #if defined(OMNI_SAFE_EVENTS)
                    omni::sync::mutex_unlock(e.m_mtx);
                #endif
            }
            
            /**
             * The () operator can be used to call the functions bound to this event instance
             *
             * @return The return type specified at compile time
             */
            ret_t operator()(p1_t val1, p2_t val2, p3_t val3) const
            {
                OMNI_SAFE_EVENT_LOCK_FW
                const_iterator_t cur = this->m_list.begin();
                const_iterator_t tmp = this->m_list.begin();
                const_iterator_t end = this->m_list.end();
                while (cur != end) {
                    if ((++tmp) == end) {
                        OMNI_SAFE_EVENT_UNLOCK_FW
                        return cur->invoke(val1, val2, val3);
                    }
                    OMNI_SAFE_EVENT_UNLOCK_FW
                    cur->invoke(val1, val2, val3);
                    OMNI_SAFE_EVENT_LOCK_FW
                    tmp = (++cur);
                }
                OMNI_SAFE_EVENT_UNLOCK_FW
            }
            
            /**
             * The boolean () operator can be used to check if this delegate is valid (has a valid function assigned)
             */
            operator bool() const
            {
                return !this->empty();
            }
            
            /**
             * The negated boolean () operator is used to check negation of the boolean () operator
             */
            bool operator!() const
            {
                return (!operator bool());
            }

            /**
             * The = operator is used to assign one event invocation to another
             *
             * @param e        The right most operand event to assign
             */
            event3< Ret, PT1, PT2, PT3 >& operator=(const event3< Ret, PT1, PT2, PT3 >& e)
            {
                if (this != &e) {
                    OMNI_SAFE_EVENT_ALOCK_FW
                    this->m_list.clear();
                    #if defined(OMNI_SAFE_EVENTS)
                        omni::sync::mutex_lock(e.m_mtx);
                    #endif
                    this->m_list = e.m_list;
                    #if defined(OMNI_SAFE_EVENTS)
                        omni::sync::mutex_unlock(e.m_mtx);
                    #endif
                }
                return *this;
            }
            
            /**
             * The [int] operator can be used to access a specific delegate in the
             * invocation list directly.
             *
             * @return A reference to the delegate instance at the specified index
             */
            omni::delegate3< Ret, PT1, PT2, PT3 >& operator[](std::size_t idx)
            {
                OMNI_SAFE_EVENT_ALOCK_FW
                if (this->m_list.empty() || (idx > (this->m_list.size() - 1))) {
                    OMNI_ERR_RETV_FW("Index out of range", omni::index_out_of_range(), NULL)
                }
                return *(this->m_list[idx]);
            }
            
            /**
             * The += operator is used to add delegates to this event instance
             *
             * @param d        The right most operand delegate to add
             */
            event3< Ret, PT1, PT2, PT3 >& operator+=(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                this->attach(d);
                return *this;
            }
            
            /**
             * The += operator is used to add delegates to this event instance
             *
             * @param e        The right most operand event to add
             */
            event3< Ret, PT1, PT2, PT3 >& operator+=(const event3< Ret, PT1, PT2, PT3 >& e)
            {
                this->attach(e);
                return *this;
            }
            
            /**
             * The -= operator is used to remove delegates from this event instance
             *
             * @param d        The right most operand delegate to remove
             */
            event3< Ret, PT1, PT2, PT3 >& operator-=(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                this->detach(d);
                return *this;
            }
            
            /**
             * The -= operator is used to remove delegates from this event instance
             *
             * @param e        The right most operand event to remove
             */
            event3< Ret, PT1, PT2, PT3 >& operator-=(const event3< Ret, PT1, PT2, PT3 >& e)
            {
                this->detach(e);
                return *this;
            }

            /**
             * The == operator is used for comparison results
             *
             * @param d        The right most operand which to compare to
             */
            bool operator==(const event3< Ret, PT1, PT2, PT3 >& e) const
            {
                if (this == &e) { return true; }
                OMNI_SAFE_EVENT_ALOCK_FW
                container_t l = e.invocation_list();
                bool ret = (l.size() == this->m_list.size());
                if (ret) {
                    const_iterator_t a = this->m_list.begin();
                    const_iterator_t b = l.begin();
                    while ((a != this->m_list.end()) && (b != l.end())) {
                        if (*a != *b) { ret = false; break; }
                        ++a; ++b;
                    }
                }
                return ret;
            }
            
            /**
             * The != operator is used for comparison results (negates the == operator)
             *
             * @param d        The right most operand which to compare to
             */
            bool operator!=(const event3< Ret, PT1, PT2, PT3 >& e) const
            {
                return !(*this == e);
            }
            
        private:
            OMNI_SAFE_EVENT_MTX_FW
            /** The collection of member methods */
            container_t m_list;

            /**
             * Find a specified member delegate in this event instance.
             *
             * @param d        The member delegate to search for
             *
             * @return An iterator to the found delegate, list.end() if not found
             */
            iterator_t _find(const omni::delegate3< Ret, PT1, PT2, PT3 >& d)
            {
                // don't use any locks here as calling code does the lock
                if (this->m_list.empty()) { return this->m_list.end(); }
                iterator_t itr = this->m_list.end();
                while (itr != this->m_list.begin()) {
                    if (*(--itr) == d) { return itr; }
                }
                return this->m_list.end();
            }
    };
    
    /** A generic event that has 3 parameters and does not return a value. */
    typedef omni::event3<void, void*, void*, void*> action3;
} // namespace omni

#define OMNI_BIND3(Ret, PT1, PT2, PT3, Class, Function, Obj) omni::delegate3<Ret, PT1, PT2, PT3>::bind<Class, &Class::Function>(Obj)
#define OMNI_BIND3_CONST(Ret, PT1, PT2, PT3, Class, Function, Obj) omni::delegate3<Ret, PT1, PT2, PT3>::bind_const<Class, &Class::Function>(Obj)

namespace std {
    template < typename Ret, typename PT1, typename PT2, typename PT3 >
    inline void swap(omni::delegate3<Ret, void*, void*, void*>& d1, omni::delegate3<Ret, void*, void*, void*>& d2)
    {
        d1.swap(d2);
    }
    
    template < typename Ret, typename PT1, typename PT2, typename PT3 >
    inline void swap(omni::event3<Ret, void*, void*, void*>& e1, omni::event3<Ret, void*, void*, void*>& e2)
    {
        e1.swap(e2);
    }
}

#endif // OMNI_DELEGATE3_HPP