Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit 69b91ab

Browse filesBrowse files
committed
Enhancements to MultiDelegate: event multiplexer mode no longer has auto-remove. Invoke returns result of last Delegate call.
Caveat: breaks use of event multiplexer with auto-remove; WIP: add iterators.
1 parent dd9bd9f commit 69b91ab
Copy full SHA for 69b91ab

File tree

Expand file treeCollapse file tree

1 file changed

+157
-91
lines changed
Filter options
Expand file treeCollapse file tree

1 file changed

+157
-91
lines changed

‎cores/esp8266/MultiDelegate.h

Copy file name to clipboardExpand all lines: cores/esp8266/MultiDelegate.h
+157-91Lines changed: 157 additions & 91 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
MultiDelegate.h - A queue or event multiplexer based on the efficient Delegate
33
class
4-
Copyright (c) 2019 Dirk O. Kaar. All rights reserved.
4+
Copyright (c) 2019-2020 Dirk O. Kaar. All rights reserved.
55
66
This library is free software; you can redistribute it and/or
77
modify it under the terms of the GNU Lesser General Public
@@ -52,7 +52,7 @@ namespace
5252
{
5353
static R execute(Delegate& del, P... args)
5454
{
55-
return del(std::forward<P...>(args...)) ? !ISQUEUE : ISQUEUE;
55+
return del(std::forward<P...>(args...));
5656
}
5757
};
5858

@@ -62,7 +62,7 @@ namespace
6262
static bool execute(Delegate& del, P... args)
6363
{
6464
del(std::forward<P...>(args...));
65-
return !ISQUEUE;
65+
return true;
6666
}
6767
};
6868

@@ -71,7 +71,7 @@ namespace
7171
{
7272
static R execute(Delegate& del)
7373
{
74-
return del() ? !ISQUEUE : ISQUEUE;
74+
return del();
7575
}
7676
};
7777

@@ -81,7 +81,7 @@ namespace
8181
static bool execute(Delegate& del)
8282
{
8383
del();
84-
return !ISQUEUE;
84+
return true;
8585
}
8686
};
8787

@@ -92,7 +92,7 @@ namespace delegate
9292
namespace detail
9393
{
9494

95-
template< typename Delegate, typename R = void, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P>
95+
template< typename Delegate, typename R, bool ISQUEUE = false, size_t QUEUE_CAPACITY = 32, typename... P>
9696
class MultiDelegatePImpl
9797
{
9898
public:
@@ -216,6 +216,42 @@ namespace delegate
216216
unused = node;
217217
}
218218

219+
void traverse(Node_t*& prev, Node_t*& current, bool remove = true)
220+
{
221+
if (remove && ISQUEUE)
222+
{
223+
// remove callback from stack
224+
#ifdef ARDUINO
225+
InterruptLock lockAllInterruptsInThisScope;
226+
#else
227+
std::lock_guard<std::mutex> lock(mutex_unused);
228+
#endif
229+
230+
auto to_recycle = current;
231+
232+
// removing last
233+
if (last == current)
234+
last = prev;
235+
236+
current = current->mNext;
237+
if (prev)
238+
{
239+
prev->mNext = current;
240+
}
241+
else
242+
{
243+
first = current;
244+
}
245+
246+
recycle_node_unsafe(to_recycle);
247+
}
248+
else
249+
{
250+
prev = current;
251+
current = current->mNext;
252+
}
253+
}
254+
219255
#ifndef ARDUINO
220256
std::mutex mutex_unused;
221257
#endif
@@ -277,7 +313,7 @@ namespace delegate
277313

278314
auto to_recycle = current;
279315

280-
// removing rLast
316+
// removing last
281317
if (last == current)
282318
last = prev;
283319

@@ -306,72 +342,45 @@ namespace delegate
306342
return false;
307343
}
308344

309-
void operator()(P... args)
345+
operator bool() const
346+
{
347+
return first;
348+
}
349+
350+
R operator()(P... args)
310351
{
311352
auto current = first;
312353
if (!current)
313-
return;
354+
return {};
314355

315356
static std::atomic<bool> fence(false);
316357
// prevent recursive calls
317358
#if defined(ARDUINO) && !defined(ESP32)
318-
if (fence.load()) return;
359+
if (fence.load()) return {};
319360
fence.store(true);
320361
#else
321-
if (fence.exchange(true)) return;
362+
if (fence.exchange(true)) return {};
322363
#endif
323364

324365
Node_t* prev = nullptr;
325366
// prevent execution of new callbacks during this run
326367
auto stop = last;
327368

369+
R result;
328370
bool done;
329371
do
330372
{
331373
done = current == stop;
332-
if (!CallP<Delegate, R, ISQUEUE, P...>::execute(current->mDelegate, args...))
333-
{
334-
// remove callback from stack
335-
#ifdef ARDUINO
336-
InterruptLock lockAllInterruptsInThisScope;
337-
#else
338-
std::lock_guard<std::mutex> lock(mutex_unused);
339-
#endif
340-
341-
auto to_recycle = current;
342-
343-
// removing rLast
344-
if (last == current)
345-
last = prev;
346-
347-
current = current->mNext;
348-
if (prev)
349-
{
350-
prev->mNext = current;
351-
}
352-
else
353-
{
354-
first = current;
355-
}
356-
357-
if (ISQUEUE)
358-
recycle_node_unsafe(to_recycle);
359-
else
360-
delete to_recycle;
361-
}
362-
else
363-
{
364-
prev = current;
365-
current = current->mNext;
366-
}
367-
374+
result = CallP<Delegate, R, ISQUEUE, P...>::execute(current->mDelegate, args...);
375+
traverse(prev, current, result);
368376
#if defined(ESP8266) || defined(ESP32)
369377
// running callbacks might last too long for watchdog etc.
370378
optimistic_yield(10000);
371379
#endif
372380
} while (current && !done);
373381

374382
fence.store(false);
383+
return result;
375384
}
376385
};
377386

@@ -392,72 +401,40 @@ namespace delegate
392401
public:
393402
using MultiDelegatePImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::MultiDelegatePImpl;
394403

395-
void operator()()
404+
R operator()()
396405
{
397406
auto current = first;
398407
if (!current)
399-
return;
408+
return {};
400409

401410
static std::atomic<bool> fence(false);
402411
// prevent recursive calls
403412
#if defined(ARDUINO) && !defined(ESP32)
404-
if (fence.load()) return;
413+
if (fence.load()) return {};
405414
fence.store(true);
406415
#else
407-
if (fence.exchange(true)) return;
416+
if (fence.exchange(true)) return {};
408417
#endif
409418

410419
Node_t* prev = nullptr;
411420
// prevent execution of new callbacks during this run
412421
auto stop = last;
413422

423+
R result;
414424
bool done;
415425
do
416426
{
417427
done = current == stop;
418-
if (!Call<Delegate, R, ISQUEUE>::execute(current->mDelegate))
419-
{
420-
// remove callback from stack
421-
#ifdef ARDUINO
422-
InterruptLock lockAllInterruptsInThisScope;
423-
#else
424-
std::lock_guard<std::mutex> lock(mutex_unused);
425-
#endif
426-
427-
auto to_recycle = current;
428-
429-
// removing rLast
430-
if (last == current)
431-
last = prev;
432-
433-
current = current->mNext;
434-
if (prev)
435-
{
436-
prev->mNext = current;
437-
}
438-
else
439-
{
440-
first = current;
441-
}
442-
443-
if (ISQUEUE)
444-
recycle_node_unsafe(to_recycle);
445-
else
446-
delete to_recycle;
447-
}
448-
else
449-
{
450-
prev = current;
451-
current = current->mNext;
452-
}
453-
428+
result = Call<Delegate, R, ISQUEUE>::execute(current->mDelegate);
429+
this->traverse(prev, current, result);
454430
#if defined(ESP8266) || defined(ESP32)
455431
// running callbacks might last too long for watchdog etc.
456432
optimistic_yield(10000);
457433
#endif
458434
} while (current && !done);
459435

460436
fence.store(false);
437+
return result;
461438
}
462439
};
463440

@@ -477,7 +454,96 @@ namespace delegate
477454
using MultiDelegateImpl<Delegate, R, ISQUEUE, QUEUE_CAPACITY>::MultiDelegateImpl;
478455
};
479456

457+
template< typename Delegate, bool ISQUEUE, size_t QUEUE_CAPACITY, typename... P>
458+
class MultiDelegate<Delegate, void(P...), ISQUEUE, QUEUE_CAPACITY> : public MultiDelegatePImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY, P...>
459+
{
460+
public:
461+
using MultiDelegatePImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY, P...>::MultiDelegatePImpl;
462+
using typename MultiDelegatePImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY, P...>::Node_t;
463+
using MultiDelegatePImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY, P...>::first;
464+
using MultiDelegatePImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY, P...>::last;
465+
466+
void operator()(P... args)
467+
{
468+
auto current = first;
469+
if (!current)
470+
return;
471+
472+
static std::atomic<bool> fence(false);
473+
// prevent recursive calls
474+
#if defined(ARDUINO) && !defined(ESP32)
475+
if (fence.load()) return;
476+
fence.store(true);
477+
#else
478+
if (fence.exchange(true)) return;
479+
#endif
480+
481+
Node_t* prev = nullptr;
482+
// prevent execution of new callbacks during this run
483+
auto stop = last;
484+
485+
bool done;
486+
do
487+
{
488+
done = current == stop;
489+
CallP<Delegate, void, ISQUEUE, P...>::execute(current->mDelegate, args...);
490+
this->traverse(prev, current);
491+
#if defined(ESP8266) || defined(ESP32)
492+
// running callbacks might last too long for watchdog etc.
493+
optimistic_yield(10000);
494+
#endif
495+
} while (current && !done);
496+
497+
fence.store(false);
498+
}
499+
};
500+
501+
template< typename Delegate, bool ISQUEUE, size_t QUEUE_CAPACITY>
502+
class MultiDelegate<Delegate, void(), ISQUEUE, QUEUE_CAPACITY> : public MultiDelegateImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY>
503+
{
504+
public:
505+
using MultiDelegateImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY>::MultiDelegateImpl;
506+
using typename MultiDelegateImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY>::Node_t;
507+
using MultiDelegateImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY>::first;
508+
using MultiDelegateImpl<Delegate, void, ISQUEUE, QUEUE_CAPACITY>::last;
509+
510+
void operator()()
511+
{
512+
auto current = first;
513+
if (!current)
514+
return;
515+
516+
static std::atomic<bool> fence(false);
517+
// prevent recursive calls
518+
#if defined(ARDUINO) && !defined(ESP32)
519+
if (fence.load()) return;
520+
fence.store(true);
521+
#else
522+
if (fence.exchange(true)) return;
523+
#endif
524+
525+
Node_t* prev = nullptr;
526+
// prevent execution of new callbacks during this run
527+
auto stop = last;
528+
529+
bool done;
530+
do
531+
{
532+
done = current == stop;
533+
Call<Delegate, void, ISQUEUE>::execute(current->mDelegate);
534+
this->traverse(prev, current);
535+
#if defined(ESP8266) || defined(ESP32)
536+
// running callbacks might last too long for watchdog etc.
537+
optimistic_yield(10000);
538+
#endif
539+
} while (current && !done);
540+
541+
fence.store(false);
542+
}
543+
};
544+
480545
}
546+
481547
}
482548

483549
/**
@@ -492,10 +558,10 @@ It is designed to be used with Delegate, the efficient runtime wrapper for C fun
492558
If the result type of the function call operator of Delegate is void, calling a MultiDelegate queue
493559
removes each item after calling it; a Multidelegate event multiplexer keeps event handlers until
494560
explicitly removed.
495-
If the result type of the function call operator of Delegate is non-void, the type-conversion to bool
496-
of that result determines if the item is immediately removed or kept after each call: a Multidelegate
497-
queue removes an item only if true is returned, but a Multidelegate event multiplexer removes event
498-
handlers that return false.
561+
If the result type of the function call operator of Delegate is non-void, in a MultiDelegate queue
562+
the type-conversion to bool of that result determines if the item is immediately removed or kept
563+
after each call: if true is returned, the item is removed. A Multidelegate event multiplexer keeps event
564+
handlers until they are explicitly removed.
499565
@tparam QUEUE_CAPACITY is only used if ISQUEUE == true. Then, it sets the maximum capacity that the queue dynamically
500566
allocates from the heap. Unused items are not returned to the heap, but are managed by the MultiDelegate
501567
instance during its own lifetime for efficiency.

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.