FastArduino v1.10
C++ library to build fast but small Arduino/AVR projects
Loading...
Searching...
No Matches
future.h
Go to the documentation of this file.
1// Copyright 2016-2023 Jean-Francois Poilpret
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
16
23#ifndef FUTURE_HH
24#define FUTURE_HH
25
26#include <string.h>
27#include "flash.h"
28#include "interrupts.h"
29#include "iterator.h"
30#include "errors.h"
31#include "time.h"
32
62#define REGISTER_FUTURE_STATUS_LISTENERS(ABSTRACT_TYPE, HANDLER1, ...) \
63 namespace future \
64 { \
65 void future_on_status_change_dispatch(const AbstractFuture& future, FutureStatus status) \
66 { \
67 dispatch_handler<ABSTRACT_TYPE, AbstractFuture>::future_on_status_change< \
68 HANDLER1, ##__VA_ARGS__>(future, status); \
69 } \
70 void future_on_status_change_dispatch(const AbstractFakeFuture& future, FutureStatus status)\
71 { \
72 dispatch_handler<ABSTRACT_TYPE, AbstractFakeFuture>::future_on_status_change< \
73 HANDLER1, ##__VA_ARGS__>(future, status); \
74 } \
75 } \
76
90#define REGISTER_FUTURE_STATUS_NO_LISTENERS() \
91 void future::future_on_status_change_dispatch(const AbstractFuture&, FutureStatus) {} \
92 void future::future_on_status_change_dispatch(const AbstractFakeFuture&, FutureStatus) {}
93
123#define REGISTER_FUTURE_OUTPUT_LISTENERS(ABSTRACT_TYPE, HANDLER1, ...) \
124 namespace future \
125 { \
126 void future_on_output_change_dispatch(const AbstractFuture& future) \
127 { \
128 dispatch_handler<ABSTRACT_TYPE, AbstractFuture>::future_on_output_change< \
129 HANDLER1, ##__VA_ARGS__>(future); \
130 } \
131 void future_on_output_change_dispatch(const AbstractFakeFuture& future) \
132 { \
133 dispatch_handler<ABSTRACT_TYPE, AbstractFakeFuture>::future_on_output_change< \
134 HANDLER1, ##__VA_ARGS__>(future); \
135 } \
136 } \
137
150#define REGISTER_FUTURE_OUTPUT_NO_LISTENERS() \
151 void future::future_on_output_change_dispatch(const AbstractFuture&) {} \
152 void future::future_on_output_change_dispatch(const AbstractFakeFuture&) {}
153
166#define REGISTER_FUTURE_NO_LISTENERS() \
167 REGISTER_FUTURE_STATUS_NO_LISTENERS() \
168 REGISTER_FUTURE_OUTPUT_NO_LISTENERS()
169
178#define DECL_FUTURE_LISTENERS_FRIEND \
179 template<typename> friend struct future::dispatch_handler_impl;
180
311namespace future
312{
320 enum class FutureStatus : uint8_t
321 {
334 NOT_READY = 0,
335
344 READY,
345
353 ERROR,
354
359 INVALID
360 };
361
363 template<typename OSTREAM> OSTREAM& operator<<(OSTREAM& out, FutureStatus status)
364 {
365 // Conversion lambda for local usage
366 auto convert = [](FutureStatus s)
367 {
368 switch (s)
369 {
371 return F("NOT_READY");
372
374 return F("READY");
375
377 return F("ERROR");
378
380 return F("INVALID");
381
382 default:
383 return F("");
384 }
385 };
386 return out << convert(status);
387 }
389
391 class AbstractFuture;
392 extern void future_on_status_change_dispatch(const AbstractFuture&, FutureStatus);
393 extern void future_on_output_change_dispatch(const AbstractFuture&);
394 class AbstractFakeFuture;
395 extern void future_on_status_change_dispatch(const AbstractFakeFuture&, FutureStatus);
396 extern void future_on_output_change_dispatch(const AbstractFakeFuture&);
398
404 enum class FutureNotification : uint8_t
405 {
407 NONE = 0,
409 STATUS = 1,
411 OUTPUT = 2,
416 BOTH = 3
417 };
418
426 {
427 public:
434 {
435 return status_;
436 }
437
448 {
449 while (status_ == FutureStatus::NOT_READY)
450 time::yield();
451 return status_;
452 }
453
465 int error() const
466 {
467 switch (await())
468 {
470 return error_;
471
473 return 0;
474
475 default:
476 // This should never happen
477 return errors::EINVAL;
478 }
479 }
480
481 // Methods called by a Future consumer
482 //=====================================
483
498 {
499 return input_size_;
500 }
501
526 bool get_storage_value_(uint8_t& chunk)
527 {
528 // Check all bytes have not been transferred yet
529 if (input_size_ == 0)
530 return false;
531 chunk = *input_current_++;
532 --input_size_;
533 return true;
534 }
535
562 bool get_storage_value_(uint8_t* chunk, uint8_t size)
563 {
564 // Check size does not go beyond transferrable size
565 if (size > input_size_)
566 return false;
567 memcpy(chunk, input_current_, size);
568 input_current_ += size;
569 input_size_ -= size;
570 return true;
571 }
572
573 // Methods called by a Future supplier
574 //=====================================
575
592 {
593 return output_size_;
594 }
595
617 {
618 // Check this future is waiting for data
619 if (status_ != FutureStatus::NOT_READY)
620 return false;
621 if (output_size_ == 0)
622 {
623 status_ = FutureStatus::READY;
624 callback_status();
625 }
626 return true;
627 }
628
653 bool set_future_value_(uint8_t chunk)
654 {
655 // Check this future is waiting for data
656 if (status_ != FutureStatus::NOT_READY)
657 return false;
658 // Update Future value chunk
659 *output_current_++ = chunk;
660 // Is that the last chunk?
661 --output_size_;
662 callback_output();
663 if (output_size_ == 0)
664 {
665 status_ = FutureStatus::READY;
666 callback_status();
667 }
668 return true;
669 }
670
698 bool set_future_value_(const uint8_t* chunk, uint8_t size)
699 {
700 // Check size does not go beyond expected size
701 if (size > output_size_)
702 {
703 // Store error
705 return false;
706 }
707 while (size--)
708 {
709 if (!set_future_value_(*chunk++)) return false;
710 }
711 return true;
712 }
713
739 template<typename T> bool set_future_value_(const T& value)
740 {
741 return set_future_value_(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
742 }
743
762 {
763 // Check this future is waiting for data
764 if ((error == 0) || (status_ != FutureStatus::NOT_READY))
765 return false;
766 error_ = error;
767 status_ = FutureStatus::ERROR;
768 callback_status();
769 return true;
770 }
771
772 protected:
774 // "default" constructor
775 AbstractFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
777 : output_data_{output_data}, output_current_{output_data}, output_size_{output_size},
778 input_data_{input_data}, input_current_{input_data}, input_size_{input_size},
779 notifications_{notifications} {}
780
781 // these constructors are forbidden (subclass ctors shall call above move/copy ctor instead)
782 AbstractFuture(const AbstractFuture&) = delete;
783 AbstractFuture& operator=(const AbstractFuture&) = delete;
784 AbstractFuture(AbstractFuture&&) = delete;
785 AbstractFuture& operator=(AbstractFuture&&) = delete;
786
787 ~AbstractFuture() = default;
788
789 // This method is called by subclasses to completely reset this future (for reuse from scratch)
790 void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
791 {
792 status_ = FutureStatus::NOT_READY;
793 error_ = 0;
794 output_data_ = output_current_ = output_data;
795 output_size_ = output_size;
796 input_data_ = input_current_ = input_data;
797 input_size_ = input_size;
798 }
799
800 // This method is called by subclass to check if input is replaceable,
801 // i.e. it has not been read yet
802 bool can_replace_input_() const
803 {
804 return (input_current_ == input_data_);
805 }
807
808 private:
809 void callback_status()
810 {
811 if (uint8_t(notifications_) & uint8_t(FutureNotification::STATUS))
812 future_on_status_change_dispatch(*this, status_);
813 }
814
815 void callback_output()
816 {
817 if (uint8_t(notifications_) & uint8_t(FutureNotification::OUTPUT))
818 future_on_output_change_dispatch(*this);
819 }
820
821 volatile FutureStatus status_ = FutureStatus::NOT_READY;
822 int error_ = 0;
823
824 uint8_t* output_data_ = nullptr;
825 uint8_t* output_current_ = nullptr;
826 uint8_t output_size_ = 0;
827
828 uint8_t* input_data_ = nullptr;
829 uint8_t* input_current_ = nullptr;
830 uint8_t input_size_ = 0;
831
832 FutureNotification notifications_;
833
834 template<typename F> friend class AbstractFuturesGroup;
835 };
836
865 template<typename OUT_ = void, typename IN_ = void>
866 class Future : public AbstractFuture
867 {
868 static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
869 static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
870
871 public:
873 using OUT = OUT_;
875 using IN = IN_;
876
878 static constexpr uint8_t OUT_SIZE = sizeof(OUT);
880 static constexpr uint8_t IN_SIZE = sizeof(IN);
881
898 explicit Future(const IN& input = IN{}, FutureNotification notifications = FutureNotification::NONE)
899 : AbstractFuture{output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN),
900 notifications}, input_{input} {}
901
903 ~Future() = default;
905
914 void reset_(const IN& input = IN{})
915 {
916 AbstractFuture::reset_(output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN));
917 input_ = input;
918 }
919
934 bool reset_input_(const IN& input)
935 {
936 if (!can_replace_input_()) return false;
937 input_ = input;
938 return true;
939 }
940
961 bool get(OUT& result)
962 {
963 if (await() != FutureStatus::READY)
964 return false;
965 result = output_;
966 return true;
967 }
968
969 protected:
975 const IN& get_input() const
976 {
977 return input_;
978 }
979
986 {
987 return input_;
988 }
989
990 private:
991 union
992 {
993 OUT output_;
994 uint8_t output_buffer_[sizeof(OUT)];
995 };
996 union
997 {
998 IN input_;
999 uint8_t input_buffer_[sizeof(IN)];
1000 };
1001 };
1002
1003 // Future template specializations for void types
1004 //================================================
1006 template<typename OUT_>
1007 class Future<OUT_, void> : public AbstractFuture
1008 {
1009 static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
1010
1011 public:
1012 using OUT = OUT_;
1013 using IN = void;
1014
1015 static constexpr uint8_t OUT_SIZE = sizeof(OUT);
1016 static constexpr uint8_t IN_SIZE = 0;
1017
1018 explicit Future(FutureNotification notifications = FutureNotification::NONE)
1019 : AbstractFuture{output_buffer_, sizeof(OUT), nullptr, 0, notifications} {}
1020 ~Future() = default;
1021
1022 // This method completely resets this future (for reuse from scratch)
1023 void reset_()
1024 {
1025 AbstractFuture::reset_(output_buffer_, sizeof(OUT), nullptr, 0);
1026 }
1027
1028 // The following method is blocking until this Future is ready
1029 bool get(OUT& result)
1030 {
1031 if (await() != FutureStatus::READY)
1032 return false;
1033 result = output_;
1034 return true;
1035 }
1036
1037 private:
1038 union
1039 {
1040 OUT output_;
1041 uint8_t output_buffer_[sizeof(OUT)];
1042 };
1043 };
1045
1047 template<typename IN_>
1048 class Future<void, IN_> : public AbstractFuture
1049 {
1050 static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
1051
1052 public:
1053 using OUT = void;
1054 using IN = IN_;
1055
1056 static constexpr uint8_t OUT_SIZE = 0;
1057 static constexpr uint8_t IN_SIZE = sizeof(IN);
1058
1059 explicit Future(const IN& input = IN{}, FutureNotification notifications = FutureNotification::NONE)
1060 : AbstractFuture{nullptr, 0, input_buffer_, sizeof(IN), notifications}, input_{input} {}
1061 ~Future() = default;
1062
1063 // This method completely resets this future (for reuse from scratch)
1064 void reset_(const IN& input = IN{})
1065 {
1066 AbstractFuture::reset_(nullptr, 0, input_buffer_, sizeof(IN));
1067 input_ = input;
1068 }
1069
1070 bool reset_input_(const IN& input)
1071 {
1072 if (!can_replace_input_()) return false;
1073 input_ = input;
1074 return true;
1075 }
1076
1077 // The following method is blocking until this Future is ready
1078 bool get()
1079 {
1080 return (await() == FutureStatus::READY);
1081 }
1082
1083 protected:
1084 const IN& get_input() const
1085 {
1086 return input_;
1087 }
1088 IN& get_input()
1089 {
1090 return input_;
1091 }
1092
1093 private:
1094 union
1095 {
1096 IN input_;
1097 uint8_t input_buffer_[sizeof(IN)];
1098 };
1099 };
1101
1103 template<>
1104 class Future<void, void> : public AbstractFuture
1105 {
1106 public:
1107 using OUT = void;
1108 using IN = void;
1109
1110 static constexpr uint8_t OUT_SIZE = 0;
1111 static constexpr uint8_t IN_SIZE = 0;
1112
1113 explicit Future(FutureNotification notifications = FutureNotification::NONE)
1114 : AbstractFuture{nullptr, 0,nullptr, 0, notifications} {}
1115 ~Future() = default;
1116
1117 // This method completely resets this future (for reuse from scratch)
1118 void reset_()
1119 {
1120 AbstractFuture::reset_(nullptr, 0, nullptr, 0);
1121 }
1122
1123 // The following method is blocking until this Future is ready
1124 bool get()
1125 {
1126 return (await() == FutureStatus::READY);
1127 }
1128 };
1130
1142 {
1143 public:
1145 FutureStatus status() const
1146 {
1147 return (error_ == 0 ? FutureStatus::READY : FutureStatus::ERROR);
1148 }
1149
1150 FutureStatus await() const
1151 {
1152 return status();
1153 }
1154
1155 int error() const
1156 {
1157 return error_;
1158 }
1159
1160 // Methods called by a Future consumer
1161 //=====================================
1162
1163 uint8_t get_storage_value_size_() const
1164 {
1165 return input_size_;
1166 }
1167
1168 bool get_storage_value_(uint8_t& chunk)
1169 {
1170 // Check all bytes have not been transferred yet
1171 chunk = *input_current_++;
1172 --input_size_;
1173 return true;
1174 }
1175
1176 bool get_storage_value_(uint8_t* chunk, uint8_t size)
1177 {
1178 memcpy(chunk, input_current_, size);
1179 input_current_ += size;
1180 input_size_ -= size;
1181 return true;
1182 }
1183
1184 // Methods called by a Future supplier
1185 //=====================================
1186
1187 uint8_t get_future_value_size_() const
1188 {
1189 return output_size_;
1190 }
1191
1192 bool set_future_finish_()
1193 {
1194 callback_status();
1195 return true;
1196 }
1197
1198 bool set_future_value_(uint8_t chunk)
1199 {
1200 // Update Future value chunk
1201 *output_current_++ = chunk;
1202 --output_size_;
1203 callback_output();
1204 return true;
1205 }
1206
1207 bool set_future_value_(const uint8_t* chunk, uint8_t size)
1208 {
1209 while (size--)
1210 {
1211 set_future_value_(*chunk++);
1212 }
1213 return true;
1214 }
1215
1216 template<typename T> bool set_future_value_(const T& value)
1217 {
1218 return set_future_value_(reinterpret_cast<const uint8_t*>(&value), sizeof(T));
1219 }
1220
1221 bool set_future_error_(int error)
1222 {
1223 error_ = error;
1224 callback_status();
1225 return true;
1226 }
1227
1229
1230 protected:
1232 // "default" constructor
1233 AbstractFakeFuture(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size,
1235 : output_current_{output_data}, output_size_{output_size},
1236 input_current_{input_data}, input_size_{input_size},
1237 notifications_{notifications} {}
1238
1239 // these constructors are forbidden (subclass ctors shall call above move/copy ctor instead)
1240 AbstractFakeFuture(const AbstractFakeFuture&) = delete;
1241 AbstractFakeFuture& operator=(const AbstractFakeFuture&) = delete;
1243 AbstractFakeFuture& operator=(AbstractFakeFuture&&) = delete;
1244
1245 ~AbstractFakeFuture() = default;
1246
1247 // This method is called by subclasses to completely reset this future (for reuse from scratch)
1248 void reset_(uint8_t* output_data, uint8_t output_size, uint8_t* input_data, uint8_t input_size)
1249 {
1250 error_ = 0;
1251 output_current_ = output_data;
1252 output_size_ = output_size;
1253 input_current_ = input_data;
1254 input_size_ = input_size;
1255 }
1256
1257 // This method is called by subclass to check if input is replaceable,
1258 // i.e. it has not been read yet
1259 bool can_replace_input_() const
1260 {
1261 return true;
1262 }
1264
1265 private:
1266 void callback_status()
1267 {
1268 if (uint8_t(notifications_) & uint8_t(FutureNotification::STATUS))
1269 future_on_status_change_dispatch(*this, status());
1270 }
1271
1272 void callback_output()
1273 {
1274 if (uint8_t(notifications_) & uint8_t(FutureNotification::OUTPUT))
1275 future_on_output_change_dispatch(*this);
1276 }
1277
1278 int error_ = 0;
1279
1280 uint8_t* output_current_ = nullptr;
1281 uint8_t output_size_ = 0;
1282
1283 uint8_t* input_current_ = nullptr;
1284 uint8_t input_size_ = 0;
1285
1286 FutureNotification notifications_;
1287
1288 template<typename F> friend class AbstractFuturesGroup;
1289 };
1290
1298 template<typename OUT_ = void, typename IN_ = void>
1300 {
1301 static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
1302 static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
1303
1304 public:
1306 using OUT = OUT_;
1307 using IN = IN_;
1308
1309 static constexpr uint8_t OUT_SIZE = sizeof(OUT);
1310 static constexpr uint8_t IN_SIZE = sizeof(IN);
1311
1312 explicit FakeFuture(const IN& input = IN{},
1314 : AbstractFakeFuture{output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN),
1315 notifications}, input_{input} {}
1316
1317 ~FakeFuture() = default;
1318
1319 // This method completely resets this future (for reuse from scratch)
1320 void reset_(const IN& input = IN{})
1321 {
1322 AbstractFakeFuture::reset_(output_buffer_, sizeof(OUT), input_buffer_, sizeof(IN));
1323 input_ = input;
1324 }
1325
1326 bool reset_input_(const IN& input)
1327 {
1328 input_ = input;
1329 return true;
1330 }
1331
1332 bool get(OUT& result)
1333 {
1334 result = output_;
1335 return true;
1336 }
1337
1338 protected:
1339 const IN& get_input() const
1340 {
1341 return input_;
1342 }
1343 IN& get_input()
1344 {
1345 return input_;
1346 }
1348
1349 private:
1350 union
1351 {
1352 OUT output_;
1353 uint8_t output_buffer_[sizeof(OUT)];
1354 };
1355 union
1356 {
1357 IN input_;
1358 uint8_t input_buffer_[sizeof(IN)];
1359 };
1360 };
1361
1363 template<typename OUT_>
1364 class FakeFuture<OUT_, void> : public AbstractFakeFuture
1365 {
1366 static_assert(sizeof(OUT_) <= UINT8_MAX, "OUT type must be strictly smaller than 256 bytes");
1367
1368 public:
1369 using OUT = OUT_;
1370 using IN = void;
1371
1372 static constexpr uint8_t OUT_SIZE = sizeof(OUT);
1373 static constexpr uint8_t IN_SIZE = 0;
1374
1376 : AbstractFakeFuture{output_buffer_, sizeof(OUT), nullptr, 0,
1377 notifications} {}
1378
1379 ~FakeFuture() = default;
1380
1381 // This method completely resets this future (for reuse from scratch)
1382 void reset_()
1383 {
1384 AbstractFakeFuture::reset_(output_buffer_, sizeof(OUT), nullptr, 0);
1385 }
1386
1387 bool get(OUT& result)
1388 {
1389 result = output_;
1390 return true;
1391 }
1392
1393 private:
1394 union
1395 {
1396 OUT output_;
1397 uint8_t output_buffer_[sizeof(OUT)];
1398 };
1399 };
1401
1403 template<typename IN_>
1404 class FakeFuture<void, IN_> : public AbstractFakeFuture
1405 {
1406 static_assert(sizeof(IN_) <= UINT8_MAX, "IN type must be strictly smaller than 256 bytes");
1407
1408 public:
1409 using OUT = void;
1410 using IN = IN_;
1411
1412 static constexpr uint8_t OUT_SIZE = 0;
1413 static constexpr uint8_t IN_SIZE = sizeof(IN);
1414
1415 explicit FakeFuture(const IN& input = IN{}, FutureNotification notifications = FutureNotification::NONE)
1416 : AbstractFakeFuture{nullptr, 0, input_buffer_, sizeof(IN), notifications}, input_{input} {}
1417
1418 ~FakeFuture() = default;
1419
1420 // This method completely resets this future (for reuse from scratch)
1421 void reset_(const IN& input = IN{})
1422 {
1423 AbstractFakeFuture::reset_(nullptr, 0, input_buffer_, sizeof(IN));
1424 input_ = input;
1425 }
1426
1427 bool reset_input_(const IN& input)
1428 {
1429 input_ = input;
1430 return true;
1431 }
1432
1433 bool get()
1434 {
1435 return true;
1436 }
1437
1438 protected:
1439 const IN& get_input() const
1440 {
1441 return input_;
1442 }
1443 IN& get_input()
1444 {
1445 return input_;
1446 }
1447
1448 private:
1449 union
1450 {
1451 IN input_;
1452 uint8_t input_buffer_[sizeof(IN)];
1453 };
1454 };
1456
1458 template<>
1459 class FakeFuture<void, void> : public AbstractFakeFuture
1460 {
1461 public:
1462 using OUT = void;
1463 using IN = void;
1464
1465 static constexpr uint8_t OUT_SIZE = 0;
1466 static constexpr uint8_t IN_SIZE = 0;
1467
1468 explicit FakeFuture(FutureNotification notifications = FutureNotification::NONE)
1469 : AbstractFakeFuture{nullptr, 0, nullptr, 0, notifications} {}
1470
1471 ~FakeFuture() = default;
1472
1473 void reset_()
1474 {
1475 AbstractFakeFuture::reset_(nullptr, 0, nullptr, 0);
1476 }
1477
1478 bool get()
1479 {
1480 return true;
1481 }
1482 };
1484
1486 // Specific traits for futures
1487 template<typename F> struct Future_trait
1488 {
1489 static constexpr const bool IS_FUTURE = false;
1490 static constexpr const bool IS_ABSTRACT = false;
1491 static constexpr const bool IS_FAKE = false;
1492 };
1493 template<> struct Future_trait<AbstractFuture>
1494 {
1495 static constexpr const bool IS_FUTURE = true;
1496 static constexpr const bool IS_ABSTRACT = true;
1497 static constexpr const bool IS_FAKE = false;
1498 };
1499 template<typename OUT, typename IN> struct Future_trait<Future<OUT, IN>>
1500 {
1501 static constexpr const bool IS_FUTURE = true;
1502 static constexpr const bool IS_ABSTRACT = false;
1503 static constexpr const bool IS_FAKE = false;
1504 };
1505 template<> struct Future_trait<AbstractFakeFuture>
1506 {
1507 static constexpr const bool IS_FUTURE = true;
1508 static constexpr const bool IS_ABSTRACT = true;
1509 static constexpr const bool IS_FAKE = true;
1510 };
1511 template<typename OUT, typename IN> struct Future_trait<FakeFuture<OUT, IN>>
1512 {
1513 static constexpr const bool IS_FUTURE = true;
1514 static constexpr const bool IS_ABSTRACT = false;
1515 static constexpr const bool IS_FAKE = true;
1516 };
1518
1575 template<typename F> class AbstractFuturesGroup : public F
1576 {
1577 static_assert(Future_trait<F>::IS_FUTURE, "F must be a Future");
1578 static_assert(Future_trait<F>::IS_ABSTRACT, "F must be an abstract Future");
1579
1580 protected:
1586 static constexpr const uint16_t NO_LIMIT = 0xFFFFU;
1587
1604 : F{nullptr, 0, nullptr, 0, notifications} {}
1605
1620 void init(utils::range<F*> futures, uint16_t actual_size = 0)
1621 {
1622 num_ready_ = (actual_size != 0 ? actual_size : futures.size());
1623 for (F* future: futures)
1624 future->notifications_ = FutureNotification::STATUS;
1625 }
1626
1636 {
1637 switch (status)
1638 {
1640 this->set_future_error_(future.error());
1641 break;
1642
1644 this->set_future_error_(errors::EINVAL);
1645 break;
1646
1648 if (--num_ready_ == 0)
1649 this->set_future_finish_();
1650 break;
1651
1652 default:
1653 break;
1654 }
1655 }
1656
1657 private:
1658 uint16_t num_ready_ = 0;
1659 };
1660
1662 template<typename F>
1663 struct dispatch_handler_impl
1664 {
1665 template<bool DUMMY> static void future_on_status_change_helper(const F&, FutureStatus)
1666 {
1667 // Intentionally blank (last recursive call)
1668 }
1669
1670 template<bool DUMMY, typename HANDLER1_, typename... HANDLERS_>
1671 static void future_on_status_change_helper(const F& future, FutureStatus status)
1672 {
1673 HANDLER1_* handler = interrupt::HandlerHolder<HANDLER1_>::handler();
1674 if (handler != nullptr)
1675 handler->on_status_change(future, status);
1676 // handle other handlers
1677 future_on_status_change_helper<true, HANDLERS_...>(future, status);
1678 }
1679
1680 template<typename... HANDLERS_>
1681 static void future_on_status_change(const F& future, FutureStatus status)
1682 {
1683 // Ask each registered listener to handle on_status_change() if concerned
1684 future_on_status_change_helper<true, HANDLERS_...>(future, status);
1685 }
1686
1687 template<bool DUMMY> static void future_on_output_change_helper(const F&)
1688 {
1689 // Intentionally blank (last recursive call)
1690 }
1691
1692 template<bool DUMMY, typename HANDLER1_, typename... HANDLERS_>
1693 static void future_on_output_change_helper(const F& future)
1694 {
1695 HANDLER1_* handler = interrupt::HandlerHolder<HANDLER1_>::handler();
1696 if (handler != nullptr)
1697 handler->on_output_change(future);
1698 // handle other handlers
1699 future_on_output_change_helper<true, HANDLERS_...>(future);
1700 }
1701
1702 template<typename... HANDLERS_>
1703 static void future_on_output_change(const F& future)
1704 {
1705 // Ask each registered listener to handle on_output_change() if concerned
1706 future_on_output_change_helper<true, HANDLERS_...>(future);
1707 }
1708 };
1709
1710 template<typename F1, typename F2>
1711 struct dispatch_handler
1712 {
1713 template<typename... HANDLERS_>
1714 static void future_on_status_change(const F2&, FutureStatus)
1715 {
1716 // Intentionally blank (tasks performed only on template specialization for actual futures)
1717 }
1718 template<typename... HANDLERS_>
1719 static void future_on_output_change(const F2&)
1720 {
1721 // Intentionally blank (tasks performed only on template specialization for actual futures)
1722 }
1723 };
1724
1725 template<>
1726 struct dispatch_handler<AbstractFuture, AbstractFuture>
1727 {
1728 template<typename... HANDLERS_>
1729 static void future_on_status_change(const AbstractFuture& future, FutureStatus status)
1730 {
1731 dispatch_handler_impl<AbstractFuture>::future_on_status_change<HANDLERS_...>(
1732 future, status);
1733 }
1734 template<typename... HANDLERS_>
1735 static void future_on_output_change(const AbstractFuture& future)
1736 {
1737 dispatch_handler_impl<AbstractFuture>::future_on_output_change<HANDLERS_...>(future);
1738 }
1739 };
1740
1741 template<>
1742 struct dispatch_handler<AbstractFakeFuture, AbstractFakeFuture>
1743 {
1744 template<typename... HANDLERS_>
1745 static void future_on_status_change(const AbstractFakeFuture& future, FutureStatus status)
1746 {
1747 dispatch_handler_impl<AbstractFakeFuture>::future_on_status_change<HANDLERS_...>(
1748 future, status);
1749 }
1750 template<typename... HANDLERS_>
1751 static void future_on_output_change(const AbstractFakeFuture& future)
1752 {
1753 dispatch_handler_impl<AbstractFakeFuture>::future_on_output_change<HANDLERS_...>(future);
1754 }
1755 };
1757}
1758
1759#endif /* FUTURE_HH */
Base class for all FakeFutures.
Definition: future.h:1142
Base class for all Futures.
Definition: future.h:426
bool set_future_value_(uint8_t chunk)
Add one byte to the output value content of this Future.
Definition: future.h:653
bool get_storage_value_(uint8_t *chunk, uint8_t size)
Get size bytes from the input storage value of this Future.
Definition: future.h:562
bool set_future_value_(const T &value)
Set the output value content of this Future.
Definition: future.h:739
uint8_t get_future_value_size_() const
Check the number of bytes remaining to write to the output value of this Future.
Definition: future.h:591
bool set_future_error_(int error)
Mark this Future as FutureStatus::ERROR.
Definition: future.h:761
bool set_future_finish_()
Mark this Future as FutureStatus::READY.
Definition: future.h:616
bool get_storage_value_(uint8_t &chunk)
Get one byte from the input storage value of this Future.
Definition: future.h:526
FutureStatus status() const
The current status of this Future.
Definition: future.h:433
FutureStatus await() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error.
Definition: future.h:447
int error() const
Wait until this Future becomes "ready", that is when it holds either an output value or an error,...
Definition: future.h:465
uint8_t get_storage_value_size_() const
Check the number of bytes remaining to read from this Future.
Definition: future.h:497
bool set_future_value_(const uint8_t *chunk, uint8_t size)
Add several bytes to the output value content of this Future.
Definition: future.h:698
Abstract class to allow aggregation of several futures.
Definition: future.h:1576
static constexpr const uint16_t NO_LIMIT
Specific size value indicating this group has an unlimited (and unknown at construction time) number ...
Definition: future.h:1586
void on_status_change_pre_step(const F &future, FutureStatus status)
This must be called by subclasses on_status_change() method, after checking that future is one of the...
Definition: future.h:1635
AbstractFuturesGroup(FutureNotification notifications=FutureNotification::NONE)
Construct a new AbstractFuturesGroup.
Definition: future.h:1603
void init(utils::range< F * > futures, uint16_t actual_size=0)
Called from constructors of subclasses, this method allows this group to listen for the status of all...
Definition: future.h:1620
Actual FakeFuture, it has the exact same API as Future and can be used in lieu of Future.
Definition: future.h:1300
Represent a value to be obtained, in some asynchronous way, in the future.
Definition: future.h:867
IN & get_input()
Return the input storage value as it was initially set (or reset through reset_input_()),...
Definition: future.h:985
IN_ IN
Type of the input value of this Future.
Definition: future.h:875
bool reset_input_(const IN &input)
Reset the input storage value held by this Future with a new value.
Definition: future.h:934
const IN & get_input() const
Return the input storage value as it was initially set (or reset through reset_input_()),...
Definition: future.h:975
OUT_ OUT
Type of the output value of this Future.
Definition: future.h:873
static constexpr uint8_t IN_SIZE
Size of the input value of this Future.
Definition: future.h:880
static constexpr uint8_t OUT_SIZE
Size of the output value of this Future.
Definition: future.h:878
bool get(OUT &result)
Wait until an output value has been completely filled in this Future and return that value to the cal...
Definition: future.h:961
void reset_(const IN &input=IN{})
This method completely resets this future (for reuse from scratch), as if it was just constructed.
Definition: future.h:914
Future(const IN &input=IN{}, FutureNotification notifications=FutureNotification::NONE)
Construct a new Future.
Definition: future.h:898
Iterable class that can embed arrays or initializer lists through implicit conversion.
Definition: iterator.h:51
Common errors definition.
Flash memory utilities.
#define F(ptr)
Force string constant to be stored as flash storage.
Definition: flash.h:150
General API for handling AVR interrupt vectors.
Utilities to convert arrays into an iterable (usable if for x: list construct).
constexpr const int EINVAL
Invalid argument or invalid Future.
Definition: errors.h:49
constexpr const int EMSGSIZE
Message too long.
Definition: errors.h:68
Contains the API around Future implementation.
Definition: future.h:312
FutureStatus
Status of a Future.
Definition: future.h:321
@ READY
The status of a Future once its output value has been fully set by a provider.
@ NOT_READY
The status of a Future immediately after it has been constructed.
@ ERROR
The status of a Future once a value provider has reported an error to it.
@ INVALID
The status of a Future that has been moved, if it was NOT_READY before moving.
FutureNotification
Notification(s) dispatched by a Future.
Definition: future.h:405
@ OUTPUT
Notification is dispatched whenever the Future output buffer gets filled, even partly.
@ STATUS
Notification is dispatched whenever the Future status changes.
@ BOTH
Notification is dispatched whenever the Future status changes or the Future output buffer gets filled...
@ NONE
No notification is dispatched by the Future.
void yield()
Utility method used by many FastArduino API in order to "yield" some processor time; concretely it ju...
Definition: time.cpp:22
Simple time utilities.