1 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 2 /* */ 3 /* This file is part of the program and library */ 4 /* SCIP --- Solving Constraint Integer Programs */ 5 /* */ 6 /* Copyright (c) 2002-2023 Zuse Institute Berlin (ZIB) */ 7 /* */ 8 /* Licensed under the Apache License, Version 2.0 (the "License"); */ 9 /* you may not use this file except in compliance with the License. */ 10 /* You may obtain a copy of the License at */ 11 /* */ 12 /* http://www.apache.org/licenses/LICENSE-2.0 */ 13 /* */ 14 /* Unless required by applicable law or agreed to in writing, software */ 15 /* distributed under the License is distributed on an "AS IS" BASIS, */ 16 /* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. */ 17 /* See the License for the specific language governing permissions and */ 18 /* limitations under the License. */ 19 /* */ 20 /* You should have received a copy of the Apache-2.0 license */ 21 /* along with SCIP; see the file LICENSE. If not visit scipopt.org. */ 22 /* */ 23 /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */ 24 25 /**@file event.h 26 * @brief internal methods for managing events 27 * @author Tobias Achterberg 28 */ 29 30 /*---+----1----+----2----+----3----+----4----+----5----+----6----+----7----+----8----+----9----+----0----+----1----+----2*/ 31 32 #ifndef __SCIP_EVENT_H__ 33 #define __SCIP_EVENT_H__ 34 35 36 #include "scip/def.h" 37 #include "blockmemshell/memory.h" 38 #include "scip/type_retcode.h" 39 #include "scip/type_set.h" 40 #include "scip/type_event.h" 41 #include "scip/type_lp.h" 42 #include "scip/type_var.h" 43 #include "scip/type_sol.h" 44 #include "scip/type_primal.h" 45 #include "scip/type_branch.h" 46 #include "scip/pub_event.h" 47 48 /* In optimized mode, some function calls are overwritten by defines to reduce the number of function calls and 49 * speed up the algorithms. For this, we need to include struct_event.h. 50 */ 51 #ifdef NDEBUG 52 #include "scip/struct_event.h" 53 #endif 54 55 #ifdef __cplusplus 56 extern "C" { 57 #endif 58 59 /* 60 * Event handler methods 61 */ 62 63 /** copies the given event handler to a new scip */ 64 SCIP_RETCODE SCIPeventhdlrCopyInclude( 65 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 66 SCIP_SET* set /**< SCIP_SET of SCIP to copy to */ 67 ); 68 69 /** creates an event handler */ 70 SCIP_RETCODE SCIPeventhdlrCreate( 71 SCIP_EVENTHDLR** eventhdlr, /**< pointer to event handler data structure */ 72 SCIP_SET* set, /**< global SCIP settings */ 73 const char* name, /**< name of event handler */ 74 const char* desc, /**< description of event handler */ 75 SCIP_DECL_EVENTCOPY ((*eventcopy)), /**< copy method of event handler or NULL if you don't want to copy your plugin into sub-SCIPs */ 76 SCIP_DECL_EVENTFREE ((*eventfree)), /**< destructor of event handler */ 77 SCIP_DECL_EVENTINIT ((*eventinit)), /**< initialize event handler */ 78 SCIP_DECL_EVENTEXIT ((*eventexit)), /**< deinitialize event handler */ 79 SCIP_DECL_EVENTINITSOL((*eventinitsol)), /**< solving process initialization method of event handler */ 80 SCIP_DECL_EVENTEXITSOL((*eventexitsol)), /**< solving process deinitialization method of event handler */ 81 SCIP_DECL_EVENTDELETE ((*eventdelete)), /**< free specific event data */ 82 SCIP_DECL_EVENTEXEC ((*eventexec)), /**< execute event handler */ 83 SCIP_EVENTHDLRDATA* eventhdlrdata /**< event handler data */ 84 ); 85 86 /** calls destructor and frees memory of event handler */ 87 SCIP_RETCODE SCIPeventhdlrFree( 88 SCIP_EVENTHDLR** eventhdlr, /**< pointer to event handler data structure */ 89 SCIP_SET* set /**< global SCIP settings */ 90 ); 91 92 /** initializes event handler */ 93 SCIP_RETCODE SCIPeventhdlrInit( 94 SCIP_EVENTHDLR* eventhdlr, /**< event handler for this event */ 95 SCIP_SET* set /**< global SCIP settings */ 96 ); 97 98 /** calls exit method of event handler */ 99 SCIP_RETCODE SCIPeventhdlrExit( 100 SCIP_EVENTHDLR* eventhdlr, /**< event handler for this event */ 101 SCIP_SET* set /**< global SCIP settings */ 102 ); 103 104 /** informs event handler that the branch and bound process is being started */ 105 SCIP_RETCODE SCIPeventhdlrInitsol( 106 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 107 SCIP_SET* set /**< global SCIP settings */ 108 ); 109 110 /** informs event handler that the branch and bound process data is being freed */ 111 SCIP_RETCODE SCIPeventhdlrExitsol( 112 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 113 SCIP_SET* set /**< global SCIP settings */ 114 ); 115 116 /** calls execution method of event handler */ 117 SCIP_RETCODE SCIPeventhdlrExec( 118 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 119 SCIP_SET* set, /**< global SCIP settings */ 120 SCIP_EVENT* event, /**< event to call event handler with */ 121 SCIP_EVENTDATA* eventdata /**< user data for the issued event */ 122 ); 123 124 /** 125 * callback setter methods of event handlers 126 */ 127 /** sets copy callback for all events of this event handler */ 128 void SCIPeventhdlrSetCopy( 129 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 130 SCIP_DECL_EVENTCOPY ((*eventcopy)) /**< copy callback for events */ 131 ); 132 133 /** sets destructor callback of this event handler */ 134 void SCIPeventhdlrSetFree( 135 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 136 SCIP_DECL_EVENTFREE ((*eventfree)) /**< destructor callback of event handler */ 137 ); 138 139 /** sets initialization callback of this event handler */ 140 void SCIPeventhdlrSetInit( 141 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 142 SCIP_DECL_EVENTINIT ((*eventinit)) /**< initialization callback of event handler */ 143 ); 144 145 /** sets deinitialization callback of this event handler */ 146 void SCIPeventhdlrSetExit( 147 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 148 SCIP_DECL_EVENTEXIT ((*eventexit)) /**< deinitialization callback of event handler */ 149 ); 150 151 /** sets solving process initialization callback of this event handler */ 152 void SCIPeventhdlrSetInitsol( 153 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 154 SCIP_DECL_EVENTINITSOL((*eventinitsol)) /**< solving process initialization callback of event handler */ 155 ); 156 157 /** sets solving process deinitialization callback of this event handler */ 158 void SCIPeventhdlrSetExitsol( 159 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 160 SCIP_DECL_EVENTEXITSOL((*eventexitsol)) /**< solving process deinitialization callback of event handler */ 161 ); 162 163 /** sets callback to free specific event data */ 164 void SCIPeventhdlrSetDelete( 165 SCIP_EVENTHDLR* eventhdlr, /**< event handler */ 166 SCIP_DECL_EVENTDELETE ((*eventdelete)) /**< callback to free specific event data */ 167 ); 168 169 /** enables or disables all clocks of \p eventhdlr, depending on the value of the flag */ 170 void SCIPeventhdlrEnableOrDisableClocks( 171 SCIP_EVENTHDLR* eventhdlr, /**< the event handler for which all clocks should be enabled or disabled */ 172 SCIP_Bool enable /**< should the clocks of the event handler be enabled? */ 173 ); 174 175 /* 176 * Event methods 177 */ 178 179 /** creates a synchronization event */ 180 SCIP_RETCODE SCIPeventCreateSync( 181 SCIP_EVENT** event, /**< pointer to store the event */ 182 BMS_BLKMEM* blkmem /**< block memory */ 183 ); 184 185 /** creates an event for an addition of a variable to the problem */ 186 SCIP_RETCODE SCIPeventCreateVarAdded( 187 SCIP_EVENT** event, /**< pointer to store the event */ 188 BMS_BLKMEM* blkmem, /**< block memory */ 189 SCIP_VAR* var /**< variable that was added to the problem */ 190 ); 191 192 /** creates an event for a deletion of a variable from the problem */ 193 SCIP_RETCODE SCIPeventCreateVarDeleted( 194 SCIP_EVENT** event, /**< pointer to store the event */ 195 BMS_BLKMEM* blkmem, /**< block memory */ 196 SCIP_VAR* var /**< variable that is to be deleted from the problem */ 197 ); 198 199 /** creates an event for a fixing of a variable */ 200 SCIP_RETCODE SCIPeventCreateVarFixed( 201 SCIP_EVENT** event, /**< pointer to store the event */ 202 BMS_BLKMEM* blkmem, /**< block memory */ 203 SCIP_VAR* var /**< variable that was fixed */ 204 ); 205 206 /** creates an event for a change in the number of locks of a variable down to zero or one */ 207 SCIP_RETCODE SCIPeventCreateVarUnlocked( 208 SCIP_EVENT** event, /**< pointer to store the event */ 209 BMS_BLKMEM* blkmem, /**< block memory */ 210 SCIP_VAR* var /**< variable that changed the number of locks */ 211 ); 212 213 /** creates an event for a change in the objective value of a variable */ 214 SCIP_RETCODE SCIPeventCreateObjChanged( 215 SCIP_EVENT** event, /**< pointer to store the event */ 216 BMS_BLKMEM* blkmem, /**< block memory */ 217 SCIP_VAR* var, /**< variable whose objective value changed */ 218 SCIP_Real oldobj, /**< old objective value before value changed */ 219 SCIP_Real newobj /**< new objective value after value changed */ 220 ); 221 222 /** creates an event for a change in the global lower bound of a variable */ 223 SCIP_RETCODE SCIPeventCreateGlbChanged( 224 SCIP_EVENT** event, /**< pointer to store the event */ 225 BMS_BLKMEM* blkmem, /**< block memory */ 226 SCIP_VAR* var, /**< variable whose bound changed */ 227 SCIP_Real oldbound, /**< old bound before bound changed */ 228 SCIP_Real newbound /**< new bound after bound changed */ 229 ); 230 231 /** creates an event for a change in the global upper bound of a variable */ 232 SCIP_RETCODE SCIPeventCreateGubChanged( 233 SCIP_EVENT** event, /**< pointer to store the event */ 234 BMS_BLKMEM* blkmem, /**< block memory */ 235 SCIP_VAR* var, /**< variable whose bound changed */ 236 SCIP_Real oldbound, /**< old bound before bound changed */ 237 SCIP_Real newbound /**< new bound after bound changed */ 238 ); 239 240 /** creates an event for a change in the lower bound of a variable */ 241 SCIP_RETCODE SCIPeventCreateLbChanged( 242 SCIP_EVENT** event, /**< pointer to store the event */ 243 BMS_BLKMEM* blkmem, /**< block memory */ 244 SCIP_VAR* var, /**< variable whose bound changed */ 245 SCIP_Real oldbound, /**< old bound before bound changed */ 246 SCIP_Real newbound /**< new bound after bound changed */ 247 ); 248 249 /** creates an event for a change in the upper bound of a variable */ 250 SCIP_RETCODE SCIPeventCreateUbChanged( 251 SCIP_EVENT** event, /**< pointer to store the event */ 252 BMS_BLKMEM* blkmem, /**< block memory */ 253 SCIP_VAR* var, /**< variable whose bound changed */ 254 SCIP_Real oldbound, /**< old bound before bound changed */ 255 SCIP_Real newbound /**< new bound after bound changed */ 256 ); 257 258 /** creates an event for an addition of a global domain hole to a variable */ 259 SCIP_RETCODE SCIPeventCreateGholeAdded( 260 SCIP_EVENT** event, /**< pointer to store the event */ 261 BMS_BLKMEM* blkmem, /**< block memory */ 262 SCIP_VAR* var, /**< variable whose bound changed */ 263 SCIP_Real left, /**< left bound of open interval in new hole */ 264 SCIP_Real right /**< right bound of open interval in new hole */ 265 ); 266 267 /** creates an event for removing a global domain hole of a variable */ 268 SCIP_RETCODE SCIPeventCreateGholeRemoved( 269 SCIP_EVENT** event, /**< pointer to store the event */ 270 BMS_BLKMEM* blkmem, /**< block memory */ 271 SCIP_VAR* var, /**< variable whose bound changed */ 272 SCIP_Real left, /**< left bound of open interval in hole */ 273 SCIP_Real right /**< right bound of open interval in hole */ 274 ); 275 276 /** creates an event for an addition of a local domain hole to a variable */ 277 SCIP_RETCODE SCIPeventCreateLholeAdded( 278 SCIP_EVENT** event, /**< pointer to store the event */ 279 BMS_BLKMEM* blkmem, /**< block memory */ 280 SCIP_VAR* var, /**< variable whose bound changed */ 281 SCIP_Real left, /**< left bound of open interval in new hole */ 282 SCIP_Real right /**< right bound of open interval in new hole */ 283 ); 284 285 /** creates an event for removing a local domain hole of a variable */ 286 SCIP_RETCODE SCIPeventCreateLholeRemoved( 287 SCIP_EVENT** event, /**< pointer to store the event */ 288 BMS_BLKMEM* blkmem, /**< block memory */ 289 SCIP_VAR* var, /**< variable whose bound changed */ 290 SCIP_Real left, /**< left bound of open interval in hole */ 291 SCIP_Real right /**< right bound of open interval in hole */ 292 ); 293 294 /** creates an event for an addition to the variable's implications list, clique or variable bounds information */ 295 SCIP_RETCODE SCIPeventCreateImplAdded( 296 SCIP_EVENT** event, /**< pointer to store the event */ 297 BMS_BLKMEM* blkmem, /**< block memory */ 298 SCIP_VAR* var /**< variable that was fixed */ 299 ); 300 301 /** creates an event for a changeing the type of a variable */ 302 SCIP_RETCODE SCIPeventCreateTypeChanged( 303 SCIP_EVENT** event, /**< pointer to store the event */ 304 BMS_BLKMEM* blkmem, /**< block memory */ 305 SCIP_VAR* var, /**< variable whose objective value changed */ 306 SCIP_VARTYPE oldtype, /**< old variable type */ 307 SCIP_VARTYPE newtype /**< new variable type */ 308 ); 309 310 /** creates an event for the addition of a linear row to the separation storage */ 311 SCIP_RETCODE SCIPeventCreateRowAddedSepa( 312 SCIP_EVENT** event, /**< pointer to store the event */ 313 BMS_BLKMEM* blkmem, /**< block memory */ 314 SCIP_ROW* row /**< row that was added to the separation storage*/ 315 ); 316 317 /** creates an event for the deletion of a linear row from the separation storage */ 318 SCIP_RETCODE SCIPeventCreateRowDeletedSepa( 319 SCIP_EVENT** event, /**< pointer to store the event */ 320 BMS_BLKMEM* blkmem, /**< block memory */ 321 SCIP_ROW* row /**< row that was deleted from the separation storage */ 322 ); 323 324 /** creates an event for the addition of a linear row to the LP */ 325 SCIP_RETCODE SCIPeventCreateRowAddedLP( 326 SCIP_EVENT** event, /**< pointer to store the event */ 327 BMS_BLKMEM* blkmem, /**< block memory */ 328 SCIP_ROW* row /**< row that was added to the LP */ 329 ); 330 331 /** creates an event for the deletion of a linear row from the LP */ 332 SCIP_RETCODE SCIPeventCreateRowDeletedLP( 333 SCIP_EVENT** event, /**< pointer to store the event */ 334 BMS_BLKMEM* blkmem, /**< block memory */ 335 SCIP_ROW* row /**< row that was deleted from the LP */ 336 ); 337 338 /** creates an event for the change of a coefficient in a linear row */ 339 SCIP_RETCODE SCIPeventCreateRowCoefChanged( 340 SCIP_EVENT** event, /**< pointer to store the event */ 341 BMS_BLKMEM* blkmem, /**< block memory */ 342 SCIP_ROW* row, /**< row in which a coefficient changed */ 343 SCIP_COL* col, /**< column which coefficient changed */ 344 SCIP_Real oldval, /**< old value of coefficient */ 345 SCIP_Real newval /**< new value of coefficient */ 346 ); 347 348 /** creates an event for the change of a constant in a linear row */ 349 SCIP_RETCODE SCIPeventCreateRowConstChanged( 350 SCIP_EVENT** event, /**< pointer to store the event */ 351 BMS_BLKMEM* blkmem, /**< block memory */ 352 SCIP_ROW* row, /**< row in which the constant changed */ 353 SCIP_Real oldval, /**< old value of constant */ 354 SCIP_Real newval /**< new value of constant */ 355 ); 356 357 /** creates an event for the change of a side of a linear row */ 358 SCIP_RETCODE SCIPeventCreateRowSideChanged( 359 SCIP_EVENT** event, /**< pointer to store the event */ 360 BMS_BLKMEM* blkmem, /**< block memory */ 361 SCIP_ROW* row, /**< row which side has changed */ 362 SCIP_SIDETYPE side, /**< which side has changed */ 363 SCIP_Real oldval, /**< old value of side */ 364 SCIP_Real newval /**< new value of side */ 365 ); 366 367 /** frees an event */ 368 SCIP_RETCODE SCIPeventFree( 369 SCIP_EVENT** event, /**< event to free */ 370 BMS_BLKMEM* blkmem /**< block memory buffer */ 371 ); 372 373 /** sets type of event */ 374 SCIP_RETCODE SCIPeventChgType( 375 SCIP_EVENT* event, /**< event */ 376 SCIP_EVENTTYPE eventtype /**< new event type */ 377 ); 378 379 /** sets variable for a variable event */ 380 SCIP_RETCODE SCIPeventChgVar( 381 SCIP_EVENT* event, /**< event */ 382 SCIP_VAR* var /**< new variable */ 383 ); 384 385 /** sets node for a node or LP event */ 386 SCIP_RETCODE SCIPeventChgNode( 387 SCIP_EVENT* event, /**< event */ 388 SCIP_NODE* node /**< new node */ 389 ); 390 391 /** sets solution for a primal solution event */ 392 SCIP_RETCODE SCIPeventChgSol( 393 SCIP_EVENT* event, /**< event */ 394 SCIP_SOL* sol /**< new primal solution */ 395 ); 396 397 /** processes event by calling the appropriate event handlers */ 398 SCIP_RETCODE SCIPeventProcess( 399 SCIP_EVENT* event, /**< event */ 400 SCIP_SET* set, /**< global SCIP settings */ 401 SCIP_PRIMAL* primal, /**< primal data; only needed for objchanged events, or NULL */ 402 SCIP_LP* lp, /**< current LP data; only needed for obj/boundchanged events, or NULL */ 403 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage; only needed for bound change events, or NULL */ 404 SCIP_EVENTFILTER* eventfilter /**< event filter for global events; not needed for variable specific events */ 405 ); 406 407 408 409 /* 410 * Event filter methods 411 */ 412 413 /** creates an event filter */ 414 SCIP_RETCODE SCIPeventfilterCreate( 415 SCIP_EVENTFILTER** eventfilter, /**< pointer to store the event filter */ 416 BMS_BLKMEM* blkmem /**< block memory buffer */ 417 ); 418 419 /** frees an event filter and the associated event data entries */ 420 SCIP_RETCODE SCIPeventfilterFree( 421 SCIP_EVENTFILTER** eventfilter, /**< pointer to store the event filter */ 422 BMS_BLKMEM* blkmem, /**< block memory buffer */ 423 SCIP_SET* set /**< global SCIP settings */ 424 ); 425 426 /** adds element to event filter */ 427 SCIP_RETCODE SCIPeventfilterAdd( 428 SCIP_EVENTFILTER* eventfilter, /**< event filter */ 429 BMS_BLKMEM* blkmem, /**< block memory buffer */ 430 SCIP_SET* set, /**< global SCIP settings */ 431 SCIP_EVENTTYPE eventtype, /**< event type to catch */ 432 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 433 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */ 434 int* filterpos /**< pointer to store position of event filter entry, or NULL */ 435 ); 436 437 /** deletes element from event filter */ 438 SCIP_RETCODE SCIPeventfilterDel( 439 SCIP_EVENTFILTER* eventfilter, /**< event filter */ 440 BMS_BLKMEM* blkmem, /**< block memory buffer */ 441 SCIP_SET* set, /**< global SCIP settings */ 442 SCIP_EVENTTYPE eventtype, /**< event type */ 443 SCIP_EVENTHDLR* eventhdlr, /**< event handler to call for the event processing */ 444 SCIP_EVENTDATA* eventdata, /**< event data to pass to the event handler for the event processing */ 445 int filterpos /**< position of event filter entry, or -1 if unknown */ 446 ); 447 448 /** processes the event with all event handlers with matching filter setting */ 449 SCIP_RETCODE SCIPeventfilterProcess( 450 SCIP_EVENTFILTER* eventfilter, /**< event filter */ 451 SCIP_SET* set, /**< global SCIP settings */ 452 SCIP_EVENT* event /**< event to process */ 453 ); 454 455 456 457 /* 458 * Event queue methods 459 */ 460 461 /** creates an event queue */ 462 SCIP_RETCODE SCIPeventqueueCreate( 463 SCIP_EVENTQUEUE** eventqueue /**< pointer to store the event queue */ 464 ); 465 466 /** frees event queue; there must not be any unprocessed events in the queue! */ 467 SCIP_RETCODE SCIPeventqueueFree( 468 SCIP_EVENTQUEUE** eventqueue /**< pointer to the event queue */ 469 ); 470 471 /** processes event or adds event to the event queue */ 472 SCIP_RETCODE SCIPeventqueueAdd( 473 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 474 BMS_BLKMEM* blkmem, /**< block memory buffer */ 475 SCIP_SET* set, /**< global SCIP settings */ 476 SCIP_PRIMAL* primal, /**< primal data; only needed for objchanged events, or NULL */ 477 SCIP_LP* lp, /**< current LP data; only needed for obj/boundchanged events, or NULL */ 478 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage; only needed for bound change events, or NULL */ 479 SCIP_EVENTFILTER* eventfilter, /**< event filter for global events; not needed for variable specific events */ 480 SCIP_EVENT** event /**< pointer to event to add to the queue; will be NULL after queue addition */ 481 ); 482 483 /** marks queue to delay incoming events until a call to SCIPeventqueueProcess() */ 484 SCIP_RETCODE SCIPeventqueueDelay( 485 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 486 ); 487 488 /** processes all events in the queue */ 489 SCIP_RETCODE SCIPeventqueueProcess( 490 SCIP_EVENTQUEUE* eventqueue, /**< event queue */ 491 BMS_BLKMEM* blkmem, /**< block memory buffer */ 492 SCIP_SET* set, /**< global SCIP settings */ 493 SCIP_PRIMAL* primal, /**< primal data */ 494 SCIP_LP* lp, /**< current LP data */ 495 SCIP_BRANCHCAND* branchcand, /**< branching candidate storage */ 496 SCIP_EVENTFILTER* eventfilter /**< event filter for global (not variable dependent) events */ 497 ); 498 499 /** returns TRUE iff events of the queue are delayed until the next SCIPeventqueueProcess() call */ 500 SCIP_Bool SCIPeventqueueIsDelayed( 501 SCIP_EVENTQUEUE* eventqueue /**< event queue */ 502 ); 503 504 #ifdef NDEBUG 505 506 /* In optimized mode, the function calls are overwritten by defines to reduce the number of function calls and 507 * speed up the algorithms. 508 */ 509 510 #define SCIPeventqueueIsDelayed(eventqueue) ((eventqueue)->delayevents) 511 512 #endif 513 514 #ifdef __cplusplus 515 } 516 #endif 517 518 #endif 519