Compare commits

...

321 Commits

Author SHA1 Message Date
Robert Bendun
205868a868 0.5.0 2023-03-05 01:34:36 +01:00
Robert Bendun
1632ef74af Remove bestline from project 2023-03-05 01:31:32 +01:00
Robert Bendun
ee9cd987e7 Use new command line parameter syntax in test runner 2023-03-05 01:24:09 +01:00
Robert Bendun
4ef724041b Merge branch 'repl' into staged-0.5 2023-03-05 01:18:41 +01:00
Robert Bendun
943b065626 Merge branch 'integrated-documentation' into staged-0.5 2023-03-05 01:13:15 +01:00
Robert Bendun
719e8d4f26 Report similar names for builtins that user is searching for 2023-03-05 01:10:43 +01:00
Robert Bendun
92e5c3169c Started musique man implementation: structure of a page implemented 2023-03-04 21:23:13 +01:00
Robert Bendun
a2d8f28cd1 More colorfull error messages 2023-03-04 20:15:58 +01:00
Robert Bendun
20a6779e2f Usage generated from parameters short descriptions
Additionally printing short descriptions with list of proposed commands
2023-03-04 20:09:58 +01:00
Robert Bendun
c0f021e57f Introduce internal parameters; better condition for enabling repl 2023-03-04 19:00:15 +01:00
Robert Bendun
d351b49148 cleared mess in platform.hh 2023-03-04 18:35:46 +01:00
Robert Bendun
4dccde7830 Save history between command invocations 2023-03-04 17:59:33 +01:00
Robert Bendun
ff58e6506d Fix CTRL-C one time use on Windows 2023-03-04 16:39:16 +01:00
Robert Bendun
2d61896824 C++ standard only interrupts implementation 2023-02-22 19:34:24 +01:00
Robert Bendun
e26474a2d7 Replxx integration; Linux CTRL-C handler 2023-02-22 02:38:46 +01:00
Robert Bendun
280d6bda3c Remove unused Catch2 library 2023-02-20 18:55:37 +01:00
Robert Bendun
a7ed7a0d65 Proper usage message 2023-02-20 18:33:32 +01:00
Robert Bendun
83ede4ef81 Support complex syntax for command line arguments
Support parameters prefixed by '-' or '--'.
Support parameters in form 'key=value'
2023-02-20 18:16:20 +01:00
Robert Bendun
aaf6e6ec0c New parameter passing convention
With suggestions on wrong parameter names
2023-02-20 17:38:17 +01:00
Robert Bendun
deabd1865a Introduced integrated documentation for builtin functions 2023-01-30 14:59:14 +01:00
Robert Bendun
25b446a5cc v0.4.0 2023-01-15 02:28:39 +01:00
Robert Bendun
253e9f9700 fix compilation warnings 2023-01-15 01:39:42 +01:00
Robert Bendun
ddad9eafba Fix nested arithmetic expressions with undefined operator 2023-01-15 01:23:42 +01:00
Robert Bendun
a03d22ce8d Documentation for new builtins: peers, ports and start 2023-01-15 01:14:27 +01:00
Robert Bendun
a2149aa4ce Dockerfile forwards version parameter 2023-01-15 01:11:10 +01:00
Robert Bendun
9f57bbaecd Dockerfile builds Windows and Linux releases 2023-01-15 00:37:11 +01:00
Robert Bendun
243c49234f changed readme from pl to en 2023-01-14 23:11:45 +01:00
Robert Bendun
588e15a8b6 Merge branch 'port-in-context' 2023-01-14 23:05:42 +01:00
Robert Bendun
88f8fa7d75 remove unnesesary commandline params; :ports command 2023-01-14 23:01:51 +01:00
Robert Bendun
2b10ef61d0 credit ableton/link authors 2023-01-14 22:53:22 +01:00
Robert Bendun
860a302219 Move from std::stop_token to std::atomic<bool>
clang on macOS doesn't support <stop_token> now
2023-01-14 22:52:50 +01:00
Robert Bendun
23fe33abce peers builtin; fixed stop request issuing in starter 2023-01-14 22:52:50 +01:00
Mateusz Piątkowski
8d86dde405 Implemented start synchronization 2023-01-14 22:52:50 +01:00
Robert Bendun
99f89c2e8b Integrated Ableton/link library 2023-01-14 22:52:45 +01:00
Robert Bendun
4178308e96 make version info available 2023-01-14 22:48:15 +01:00
Robert Bendun
e008a45cf7 overalocate strings to ensure correctness; diagnostic for assigment to undefined variable 2023-01-12 20:51:15 +01:00
Robert Bendun
8c4aecf6e0 Error message for using assigment as comparison operator (#38) 2023-01-12 20:25:45 +01:00
Robert Bendun
87cea02b45 negative numbers; fixed duration builtin 2023-01-10 06:41:08 +01:00
Robert Bendun
8fbeaea80d introduced multiple port connections 2023-01-09 21:29:33 +01:00
Robert Bendun
0b8fd86680 more documentation for builtin call 2023-01-09 19:30:02 +01:00
Mateusz Piątkowski
f33627d05a minor fixes in documentation 2023-01-09 10:29:32 +01:00
Mateusz Piątkowski
dcf160f017 minor fixes in documentation 2023-01-09 10:29:01 +01:00
Robert Bendun
ef80bd0c5f builtin rotate: fix no arguments other then shift (#39) 2023-01-09 10:05:50 +01:00
Mateusz Piątkowski
aec2f3f496 add example 2023-01-09 10:03:39 +01:00
Robert Bendun
b39e1c4a0f builtin try: should be switched to macro with if or for 2023-01-09 09:58:31 +01:00
Mateusz Piątkowski
d85c29427d apply changes from commit 986545b2ec and 0b14f0c563 2023-01-08 14:20:52 +01:00
Mateusz Piątkowski
c8b8adca5d function documentation part 2 2023-01-08 14:14:47 +01:00
Robert Bendun
986545b2ec builtins note_{on,off}: error was reported even when function completed successfully (#37) 2023-01-08 09:56:44 +01:00
Robert Bendun
ad95299a7e fixed builtins ceil, floor, round (#37) 2023-01-08 09:41:30 +01:00
Robert Bendun
93a15a3cf8 test runner: support adding and updating specific test cases 2023-01-08 08:50:53 +01:00
Robert Bendun
c61b5c7e93 cleanup things that should never got here 2023-01-08 08:11:02 +01:00
Robert Bendun
0b14f0c563 builtin duration: fill note length from context (#37) 2023-01-08 08:09:42 +01:00
Mateusz Piątkowski
fc95405a06 functions documentation part 1 2023-01-07 19:37:41 +01:00
Robert Bendun
d7c26e5858 digits builtin 2022-12-30 15:31:39 +01:00
Robert Bendun
bda1e503c7 Builtin function documentation generates from implementation 2022-12-01 00:52:53 +01:00
Robert Bendun
b51088a9f0 Fixed for elise 2022-11-28 12:58:14 +01:00
Robert Bendun
2630dff5ac Sending proper Program Change MIDI message 2022-11-28 02:13:40 +01:00
Robert Bendun
7f73f3dcad Made context stack a tree; fixed function name in error printing 2022-11-21 17:03:14 +01:00
Robert Bendun
a32bfa24d3 Try to enable ANSI escape codes in Windows terminal 2022-11-21 01:52:26 +01:00
Robert Bendun
a6b54d231d Renamed targets in release archive 2022-11-20 16:16:36 +01:00
Robert Bendun
4fc3ef5208 Added Catch2 library 2022-11-20 16:14:12 +01:00
a92cffd150 Poprawki literówek i nomenklatury muzycznej 2022-11-16 21:17:30 +01:00
Mateusz Piątkowski
b94c7465c6 literówki 2022-11-14 19:58:24 +01:00
Mateusz Piątkowski
21431af191 Translation to polish 2022-11-14 19:55:09 +01:00
Robert Bendun
de210b571d By default connect to existing MIDI port in repl 2022-11-13 23:26:06 +01:00
Robert Bendun
e101d362b9 Basic polish tutorial 2022-11-12 01:25:16 +01:00
Robert Bendun
e46a41d2ff Array repetition using multiplication 2022-11-11 21:55:31 +01:00
Robert Bendun
a262a643e9 Removed h note literal 2022-11-11 19:35:07 +01:00
Robert Bendun
268455532b Early text-based snapshot system 2022-11-11 19:24:45 +01:00
Robert Bendun
89b3519c24 Updated changelog 2022-10-31 22:29:43 +01:00
Robert Bendun
7aecf2ea19 Release build system partially moved to Docker
Change to Docker forced by need of supporting older Ubuntu releases with
older glibc without building them on host
2022-10-31 22:28:18 +01:00
Robert Bendun
609ddf1854 Updated changelog 2022-10-31 19:12:56 +01:00
Robert Bendun
1a7fdf06cc comparison cheatsheet with new syntax 2022-10-31 18:02:46 +01:00
Robert Bendun
79da98e058 Merge branch 'main' into new-block-syntax 2022-10-31 17:36:21 +01:00
Robert Bendun
e4b211b21a added language-cmp-cheatsheet to Makefile 2022-10-31 17:33:53 +01:00
Robert Bendun
fa853e000f regression test updates 2022-10-31 00:39:56 +01:00
Robert Bendun
bfbc82d6a5 switched index operation from 'a.n' to 'a[n]' 2022-10-31 00:31:47 +01:00
Robert Bendun
0e515c727b removed out-of-date documentation 2022-10-31 00:27:14 +01:00
Robert Bendun
4990e4ff1f new example 2022-10-28 16:25:48 +02:00
Robert Bendun
b38db9fdaa new builtins: set_oct, pick 2022-10-28 16:01:34 +02:00
Robert Bendun
6a3308fc46 check if block is a collection at runtime; operators pretty printing 2022-10-28 00:56:11 +02:00
Robert Bendun
d4c3dbb280 moved from ';' to ',' as expression separator 2022-10-27 22:32:20 +02:00
Robert Bendun
e4797d08e1 changed chord invocation arguments 2022-10-27 21:09:46 +02:00
Robert Bendun
02740d5865 removed old chord notation; intoroduced chord-octave notation 2022-10-27 21:03:37 +02:00
Robert Bendun
baabdd2655 if works properly now 2022-10-27 20:59:27 +02:00
f57fc87673 rozszerzenie sekcji muzyka 2022-10-27 20:11:11 +02:00
Robert Bendun
5f0f511066 new builtins: while, map, duration, set_len 2022-10-27 00:27:41 +02:00
Robert Bendun
b612209914 Added macros; if is now macro and not a function 2022-10-26 16:50:40 +02:00
Robert Bendun
0529a84fb7 Test suite works with new syntax 2022-10-25 16:20:24 +02:00
Robert Bendun
8cda4f4d8e Removed [] block notation in favour of unification with () 2022-10-25 16:10:34 +02:00
Robert Bendun
fe6c1e3bd0 Blocks can accept now more parameters then they capture 2022-10-23 12:24:32 +02:00
Robert Bendun
b924f7dff2 fixed index operation; unified builtin operators naming convention 2022-10-23 00:08:06 +02:00
Robert Bendun
f10eb5c2ad instruments.mq using new definition syntax; fixed windows builds 2022-10-21 17:50:25 +02:00
Robert Bendun
7621e6e3ff VSCode extension 2022-10-21 13:14:12 +02:00
Robert Bendun
2a3bfa14ae If all sources are considered deffered enter interactive mode 2022-10-20 16:46:52 +02:00
Robert Bendun
6c631dc075 Added file as function commandline switch 2022-10-20 16:42:05 +02:00
Robert Bendun
346c66a8f4 First iteration of build instructions 2022-10-20 14:37:50 +02:00
Robert Bendun
2ac95e3b14 Remove previous VSCode extension 2022-10-18 14:29:36 +02:00
480de4182c Merge pull request 'Adding support for MacOS' (#36) from macos into main 2022-10-14 16:55:45 +02:00
Robert Bendun
8348a857f3 Finalizing build scripts 2022-10-14 16:45:47 +02:00
Robert Bendun
e9d67178da Added virtual port creation as default action. Restored port connection
Removed input ports support
2022-10-14 16:26:08 +02:00
Robert Bendun
0d7f4b1eb5 Build system supports both MacOS and Linux now 2022-10-14 15:56:36 +02:00
Robert Bendun
b93a236e37 Conforming to clang's standard library on MacOS 2022-10-14 14:42:37 +02:00
Robert Bendun
78b1e7d703 new REPL command parsing & handling system 2022-10-11 11:01:01 +02:00
Robert Bendun
cfa0513226 :load command inside interactive mode 2022-10-11 10:06:42 +02:00
Robert Bendun
d784da1e8d Mention windows binary in realase package 2022-10-08 20:41:04 +02:00
Robert Bendun
145441cead Merge branch 'windows-support' 2022-10-08 20:35:03 +02:00
Robert Bendun
5866278340 Bringed back old build system 2022-10-08 20:34:29 +02:00
Robert Bendun
e8ef207ec9 Windows support 2022-10-08 20:32:41 +02:00
Robert Bendun
ecabf885f3 Compiling with mingw 2022-10-08 17:18:55 +02:00
Robert Bendun
0ee52951c1 Moved from written by hand Makefiles to Premake 2022-10-08 15:05:05 +02:00
Robert Bendun
32f2183136 Recognizing rtmidi creators contributions 2022-10-08 13:09:11 +02:00
Robert Bendun
57ac46cf9b Moved from custom ALSA adapter to RtMidi
This should allow for easy support for other operating systems and other
Linux sound systems like Jack in the future
2022-10-08 12:48:42 +02:00
Robert Bendun
6389535443 integrated libmidi into Musique codebase 2022-10-07 18:17:25 +02:00
Robert Bendun
b6b1209014 scan builtin; Value and Array conviniance constructors made explicit 2022-10-07 17:33:38 +02:00
Robert Bendun
20bf379332 Added changelog 2022-09-25 23:09:48 +02:00
Mateusz Piątkowski
95c296a332 Add call func description 2022-09-25 20:21:08 +02:00
Robert Bendun
68f5298e39 testing builtins: uniq, unique, typeof 2022-09-25 12:01:19 +02:00
Robert Bendun
225befb22b Removed unused files 2022-09-25 11:59:50 +02:00
Robert Bendun
bc5736bf35 Started builtins refactoring and testing 2022-09-25 10:40:36 +02:00
Robert Bendun
548b29d897 New edition of testing script 2022-09-25 03:19:00 +02:00
Robert Bendun
5a7c204ceb Moved from Value::from constructor to Value constructor 2022-09-25 00:40:49 +02:00
Robert Bendun
6a98178690 Moved Value from beeing bodged sum type to proper one
This allowed for simpler type checking approach, disallowed using
non-initialized members and hopefully will allow further code
simplification and reliability
2022-09-25 00:10:42 +02:00
Robert Bendun
ceeb25ea82 Created better hierarchy of source files 2022-09-23 18:55:25 +02:00
Robert Bendun
6a71614cab Project restructuring
include/musique.hh was getting large and musique_internal.hh emerged to
help with that. Header file separation become a huge mess.

The chosen approach is one hierarchy containing both header and
implementation files
2022-09-23 16:42:33 +02:00
Robert Bendun
038de0fc27 Moved from Result<void> to std::optional<Error> 2022-09-23 13:59:35 +02:00
Robert Bendun
d9c0468729 Value printing improved 2022-09-23 13:59:07 +02:00
Robert Bendun
857f8f3b52 [cheatsheet] Started working on Music section 2022-09-23 11:54:59 +02:00
Robert Bendun
973fbd62f7 Vectorized note creation 2022-09-22 18:12:17 +02:00
Robert Bendun
9fb1815e01 [cheatsheet] Argumentless function calls 2022-09-21 19:52:26 +02:00
Robert Bendun
9a978d8984 [cheatsheet] Splitted into sections, added navigation 2022-09-21 19:32:31 +02:00
Robert Bendun
e7ec8229e1 More array examples in doc/ 2022-09-21 16:54:17 +02:00
Robert Bendun
f42e700747 Musique vs other programming languages cheatsheet 2022-09-21 16:42:18 +02:00
Robert Bendun
34eb56ac50 Removed unused tests 2022-09-21 16:40:40 +02:00
Robert Bendun
1384e5f96e Eliminated unimplemented() that ware missing error reporting 2022-09-21 13:37:06 +02:00
Mateusz Piątkowski
3ed11fd33b operators.md fix3 2022-09-19 23:42:20 +02:00
Mateusz Piątkowski
8f46d49bac operators.md fix2 2022-09-19 23:41:21 +02:00
Mateusz Piątkowski
5ad87f4a91 operators.md fix 2022-09-19 23:39:23 +02:00
Mateusz Piątkowski
57e3ee06dd Include vector aspect of operators 2022-09-19 23:35:31 +02:00
Mateusz Piątkowski
f900647c76 Include vector aspect of operators 2022-09-19 23:34:25 +02:00
Robert Bendun
bd116d8810 Improved factorial example 2022-09-19 22:16:38 +02:00
Mateusz Piątkowski
691d4d84ac Add category for other operators 2022-09-19 21:16:11 +02:00
Mateusz Piątkowski
a8ee488010 Operators reference 2022-09-19 21:14:12 +02:00
Mateusz Piątkowski
ae5a9294eb Operators reference 2022-09-19 21:13:58 +02:00
Mateusz Piątkowski
5589094034 Fix install script 2022-09-18 21:40:44 +02:00
Mateusz Piątkowski
07317e19eb Merge remote-tracking branch 'refs/remotes/origin/main' 2022-09-18 21:26:48 +02:00
Mateusz Piątkowski
1b88afa283 Install within release 2022-09-18 21:25:42 +02:00
Robert Bendun
4c592091da Mention commandline parameters 2022-09-18 21:23:11 +02:00
Mateusz Piątkowski
5612b7256a Install instructions in README 2022-09-18 19:26:48 +02:00
Mateusz Piątkowski
c6061d07bc Install instructions in README 2022-09-18 19:20:45 +02:00
Mateusz Piątkowski
893d20cee1 Installation script 2022-09-18 19:15:38 +02:00
Robert Bendun
a217a09aec Recognize creators of used libraries 2022-09-18 16:52:44 +02:00
Robert Bendun
829243f059 statically linking libstdc++; recursive cloninng 2022-09-18 16:42:46 +02:00
Robert Bendun
2f101fdccf call builtin; release builder; documentation from docs repo 2022-09-18 16:34:43 +02:00
Robert Bendun
ddf9cc8f8c New declaration syntax x := foo instead of var x = foo
Additionaly moving into multiparameter binary operations
2022-09-18 14:50:20 +02:00
Robert Bendun
e57a60c36f Started working of For Elise example 2022-09-17 18:30:59 +02:00
Robert Bendun
7665ea0b53 sim builtin & proper chord notation behaviour 2022-09-17 17:47:14 +02:00
Robert Bendun
676f41909f Overhaul of chord call semantics to support easy sequencing 2022-09-17 13:10:24 +02:00
Robert Bendun
98a88c3acc ";" input does not raise an error anymore. Missing '=' precedanse 2022-09-17 11:49:09 +02:00
Robert Bendun
cb13dc9591 Refactored operators, loosing binary requirements due to them
Due to addition of turning binary operators into functions, they can now
be called with more or less then 2 arguments, which would trigger
assertions. Not all were converted to support new call syntax though
2022-09-17 00:34:41 +02:00
Mateusz Piątkowski
fefde2f12e Play ref change 2022-09-11 20:45:53 +02:00
Mateusz Piątkowski
eb4bf1c270 Fold ref + fixes 2022-09-11 20:41:42 +02:00
Robert Bendun
96c96ef2b0 fold buultin. Operators can be quoted
By prepending ' to operator you can use it as function
2022-09-11 20:10:44 +02:00
Mateusz Piątkowski
9b846d8115 Function reference 2022-09-11 20:05:29 +02:00
Mateusz Piątkowski
b4984d5c61 minor fixes 2022-09-11 18:02:27 +02:00
Mateusz Piątkowski
9956cf8993 more functions 2022-09-11 17:27:16 +02:00
Mateusz Piątkowski
b1bed2c7da instrument function description 2022-09-11 17:04:42 +02:00
Mateusz Piątkowski
4209a495ea Documentation on builtin functions 2022-09-11 16:59:51 +02:00
Robert Bendun
9213d5219a All stuff from this file is builtin 2022-09-11 16:30:27 +02:00
Robert Bendun
0743a9b7c4 Added pause
It's faking to be a note, but does not play anything when played
2022-09-11 16:19:10 +02:00
Robert Bendun
91f401a13a builtin mix; fixed vectorized equality 2022-09-05 23:52:26 +02:00
Robert Bendun
d77f844c81 Hashing functions; builtins hash, uniq and unique 2022-09-05 23:17:40 +02:00
Robert Bendun
ab0ba8d4c8 Algorithms like min don't flatten all the way
To restore previous behaviour one can use `min (flat x)`
2022-09-05 22:30:11 +02:00
Robert Bendun
eb822a4a6e '&' operator can merge arrays; 'down' builtin works 2022-09-05 20:47:15 +02:00
Robert Bendun
de92564cc1 Error reporting improvement for number operations; added power operator 2022-09-04 19:44:33 +02:00
Robert Bendun
497a4bcc6a Improvement of builtin functions; added try builtin
Including moving functions from lambdas into global scope, adding
documentation, improvement of error reporting
2022-09-04 17:46:04 +02:00
Robert Bendun
421f8111f0 builtin_for now reports nice error message when given wrong arguments 2022-09-04 14:11:06 +02:00
Robert Bendun
aabcc42625 Error reporting when too many closing parens at the end 2022-09-04 13:48:06 +02:00
Robert Bendun
f2a78cd331 Index operator now reports when given unindexable lhs 2022-09-04 13:25:55 +02:00
Robert Bendun
1597b678e1 Report error when index is too large 2022-09-04 13:16:40 +02:00
Robert Bendun
3b1500313c Operators associate to the left now
This should be default behaviour but somehow we missed it.
2022-09-04 12:04:19 +02:00
Robert Bendun
00b11087b4 When playing empty chord user gets pause with default length 2022-08-29 21:48:35 +02:00
Robert Bendun
c0af952fc6 Improved rhythm of primes example 2022-08-29 21:45:17 +02:00
Robert Bendun
7b5e43293a For as builtin and new example that plays primes 2022-08-29 21:38:15 +02:00
Robert Bendun
1fa2ec6b76 Vectorized equality and index operations 2022-08-29 21:22:46 +02:00
Robert Bendun
2b29522293 New operator: modulo operator '%' 2022-08-29 20:37:11 +02:00
Robert Bendun
b8feb4043e New builtin: n primes generator 2022-08-29 20:29:45 +02:00
Robert Bendun
5c53bb9e9f Nicer undefiend operator message 2022-08-21 20:39:35 +02:00
Robert Bendun
43555cbc1c Improved interactive mode interaction with errors 2022-08-21 20:24:49 +02:00
Robert Bendun
cb5eedb2a5 Unexpected empty source error improved 2022-08-21 20:01:59 +02:00
Robert Bendun
183907a0ed Improved error location reporting 2022-08-21 19:24:33 +02:00
Robert Bendun
99482d4c7c Improved examples; multiplication = repeat operator 2022-08-21 17:34:03 +02:00
Robert Bendun
b9eb3f957d play as evaluation operator 2022-08-21 16:49:54 +02:00
Robert Bendun
5c47b7b808 par improvement: allow actions like octave changes inside
This is implemented with default action idea. During evaluation of
expresions sequence all but return expressions is passed to
default_action. Par sets default action to `action_play` which plays
given value if it's musical value.
2022-08-21 15:52:54 +02:00
Robert Bendun
2452b95a90 Par now accepts arrays 2022-08-21 14:49:39 +02:00
Robert Bendun
e3164395de Range function for Musique language 2022-08-21 13:45:34 +02:00
Robert Bendun
da1ac0dcf7 {floor, ceil, round} available in Musique language 2022-08-21 13:19:16 +02:00
Robert Bendun
617fbac98f Unified rounding implementation 2022-08-21 12:26:45 +02:00
Robert Bendun
eb36ad2c93 Implemented Number::{ceil, floor, round, pow, inverse}
Except that pow only accepts integer exponents, since nth root is not
that quick to implement and simple blind implementation may have
performance issues.
2022-08-21 00:43:04 +02:00
Robert Bendun
ab6ed8f45c Report nice error when without MIDI connection 2022-08-19 16:06:33 +02:00
Robert Bendun
b06ad84514 File hierarchy cleanup by removing etc folder
And moving it's content into scripts and editor directories.
2022-08-18 23:03:21 +02:00
Robert Bendun
e16a28dfdc Separated makefile into smaller scripts to improve readability 2022-08-18 22:58:41 +02:00
Robert Bendun
7fb6df219c Successfully separated small portion of include/musique.hh 2022-08-18 22:48:11 +02:00
Robert Bendun
0b3dc2bb57 Move src/musique.hh to include/musique.hh
This is preparation for separation of public musique interface and
implementation details shared across files.
2022-08-18 22:44:04 +02:00
Robert Bendun
81f512d69d Builtin function handlers definition now in separate file
Same as in commit before, we try to cleanup src/interpreter.cc from all
of builtin function noise.
2022-08-18 22:37:40 +02:00
Robert Bendun
831de5abe5 Builtin operator handlers definiton now in separate file
Interpreter constructor and file in general is very unreadable
and busy now. To limit noise separate builtin operators from
src/interpreter.cc into their own file src/builtin_operators.cc

This also allows to see which functions are used as implementation
detail of which operations.
2022-08-18 22:21:04 +02:00
Robert Bendun
a3d0a942e4 Ensure when adding new operators we add them right
Operators not only are needed to be defined by their implementation in
Interpreter constructor, but also are needed to be included in
precedense resolution.

To prevent partial definition we predefine number of builtin operators
as numeric constant and test against it in all relevant places.
2022-08-18 22:07:13 +02:00
Robert Bendun
e090778db9 Added '&' operator that joins chords together.
For example 'c & g' makes chord 'chord c g'
2022-08-18 22:07:13 +02:00
Robert Bendun
881dc8975a Missing variable error implementation 2022-08-18 22:07:13 +02:00
Robert Bendun
75c9eefd50 Ignoring new LSP 2022-08-18 22:07:13 +02:00
Robert Bendun
d8f8214556 Tests now compile again 2022-07-30 13:45:23 +02:00
Robert Bendun
0e796d5efc Minor cleanup 2022-07-30 13:40:59 +02:00
2ea507dde2 Par accepts arrays of notes 2022-06-23 07:49:38 +02:00
4a844a319e Handle incoming note on messages 2022-06-23 07:41:06 +02:00
4d272723c7 Elegant exit (not aborting due to thread issues) 2022-06-23 07:36:28 +02:00
Mateusz Piątkowski
7b572e2a1f ode to joy final_master_full 2022-06-22 18:46:24 +02:00
Mateusz Piątkowski
24b1a71e55 more examples WIP 2022-06-22 18:39:23 +02:00
Mateusz Piątkowski
742b48e1ce better ode to joy 2022-06-22 17:44:04 +02:00
772686a2fc Better error reporting of not mached parens 2022-06-20 13:21:37 +02:00
21bf18bbdd Error reporting in builtins producing midi messages 2022-06-20 12:59:36 +02:00
d60e2dfb38 Preserving sequences 2022-06-20 06:20:24 +02:00
ea1dddaf26 Precedense aware parser 2022-06-20 05:45:28 +02:00
854b72cf35 Unit testing builtins 2022-06-19 17:44:42 +02:00
29f9a4467c Skipping tests that require not implemented functionality 2022-06-19 16:15:41 +02:00
2dd97709a0 Better unit test response messages when unrecoverable state reached
Instead of `exit` we throw `std::runtime_error` in Debug mode assertions
and unreachable functions, to have better response from unit test runner.
2022-06-19 16:09:39 +02:00
ed3b2006e9 Symbol quoting and user defined incoming MIDI message processing 2022-06-19 15:45:14 +02:00
387835a155 Number -> Note translation for Note{on,off} incoming messages 2022-06-19 00:40:04 +02:00
7a3d211d09 Infrastructure for incoming MIDI messages ready 2022-06-19 00:27:02 +02:00
bf3f388acb User-defined input and port numbers of ALSA MIDI connection 2022-06-18 00:28:48 +02:00
09f736bf83 Updated to newer version of lib/midi 2022-06-18 00:13:21 +02:00
16d1a5e0d6 Introduced first iteration of typechecking errors 2022-06-14 13:24:15 +02:00
910792e383 rotate function 2022-06-14 11:39:04 +02:00
55554606a1 partition function 2022-06-14 11:21:37 +02:00
5ab750b93b Array modification functions 2022-06-14 10:30:52 +02:00
7d0f732a57 GNU Readline replace with bestline 2022-06-11 19:57:56 +02:00
e6aed50fe9 Support for midi program change message 2022-06-11 19:00:36 +02:00
b930ef4e6e Index operator binds more tightly then function call 2022-06-11 17:55:52 +02:00
b7d879bf70 Relevant code printing when error reporting 2022-06-09 01:48:02 +02:00
d16f6de53c Compound assigments 2022-06-06 04:22:59 +02:00
91eaa0ceea Assigments, array updating function. Test runner update 2022-06-06 04:03:40 +02:00
118837f6d8 Fixed multiline comment bug
We forgot to skip '-' when parsing multiline comment begining
2022-06-06 03:08:34 +02:00
e528fd9e83 In-language comparison operators made holistic 2022-06-06 00:20:25 +02:00
7c5f3e2170 Small refactoring & more testing 2022-06-05 23:54:42 +02:00
c1e1acd6e2 Removing test from the past 2022-06-03 00:58:53 +02:00
4d88ca7e40 Logical short-circuting operators 2022-06-03 00:52:55 +02:00
946d4b96b1 Permutations! 2022-06-02 23:17:02 +02:00
45a3710626 function implementation 2022-06-02 21:50:44 +02:00
1e1d9b0cb6 Error reporting of use of non-symbols in indentifier context 2022-06-02 21:39:22 +02:00
0a00080d2d Implemented many missing test cases 2022-05-31 13:43:14 +02:00
23a230c9d3 Instruments list 2022-05-30 16:56:57 +02:00
31dfcc37ca Note on & note off explicit midi calls 2022-05-30 15:35:37 +02:00
43d7aeac1d New intrinsic implementation primitives 2022-05-30 15:10:03 +02:00
ada8e17d1b Added documentation mostly for error reporting structures 2022-05-30 00:18:48 +02:00
2eee11e476 Removed unused errors 2022-05-30 00:02:50 +02:00
25e730c8d3 Missing semicolon error! 2022-05-29 23:54:05 +02:00
016e48570e Optionally colorful errors part 2; repl dont exit on errors 2022-05-29 23:34:20 +02:00
3c4da4a226 Optionally colorful errors 2022-05-29 23:29:37 +02:00
96378a16c1 Not callable testing restored 2022-05-29 22:53:09 +02:00
9c4b57f217 Human readable token type names for error reporting 2022-05-29 22:46:20 +02:00
605533de32 Error reporting system improvement 2022-05-29 22:39:46 +02:00
df236b13c8 New chord notation in cheatsheet 2022-05-29 03:11:26 +02:00
4985843f8f More tests for note resolution 2022-05-29 03:01:17 +02:00
a665d95692 Extended chord literal syntax with flats 2022-05-29 02:57:36 +02:00
dc1322e4ea Major documentation of source code improvement 2022-05-29 02:28:51 +02:00
563786312c Documentation for programmers 2022-05-29 01:00:13 +02:00
26521be98d Removed Sphinx documentation system 2022-05-29 00:19:58 +02:00
fd63beab86 Invalid example in cheatsheet 2022-05-26 18:32:59 +02:00
3caa5b80cb Ode To Joy, par function, context management 2022-05-25 17:03:46 +02:00
7cc61e30e4 REPL 2022-05-25 15:53:09 +02:00
ad79c17551 removed tests that ware testing old chord literals 2022-05-25 04:41:40 +02:00
741eb7f576 Result of evaluation is only printed when it's not nil 2022-05-25 04:36:16 +02:00
e2142d9dbd Added each to prelude 2022-05-25 04:34:37 +02:00
70e1431f05 Begining of support of array programming 2022-05-25 04:30:24 +02:00
5d410a1ffd Makefile produces less noise 2022-05-25 03:14:29 +02:00
4421acebd6 Halftones moving operator 2022-05-25 03:14:08 +02:00
611007a888 chord function 2022-05-25 02:13:35 +02:00
80bc4c039c Chords! 2022-05-25 00:08:48 +02:00
6611512b1f Working arrays, flat function 2022-05-24 19:09:37 +02:00
64417bf187 changed shape of Value constructors; added Array type 2022-05-24 17:39:07 +02:00
d549d23f0a Overloadable index operation 2022-05-24 16:38:18 +02:00
15f5e66e0b updated cheatsheet 2022-05-24 15:48:11 +02:00
fd6009bb02 Euterpea like octave and duration setting 2022-05-24 15:45:31 +02:00
fe2cd9f1ef Euterpea like duration notation. Cheatsheet 2022-05-24 15:34:38 +02:00
6652a08f42 VSCode syntax highlighting extension 2022-05-24 14:13:45 +02:00
d1366aee74 vim supports multiline comments 2022-05-24 14:13:45 +02:00
b422ca8677 License 2022-05-24 12:11:50 +00:00
1c6db5e7b7 Removed say from default builtins, moved to src/main.cc
The reason is that `say` requires text output to work, which is platform
specific. Interpreter should only register platform independent
functions like operations on arrays or math library
2022-05-24 03:48:10 +02:00
2c19db7354 Playing MIDI! 2022-05-24 03:35:15 +02:00
5560549c7c Separated building bin/unit-test into several objects 2022-05-24 03:00:51 +02:00
ba463139d6 Note duration calculation in current BPM context 2022-05-24 02:58:15 +02:00
2e2c34ce21 Note parsing & printing 2022-05-24 01:58:17 +02:00
142680ab77 Working note resolution 2022-05-24 01:40:16 +02:00
7d2ba379f7 Infrastructure for note parsing 2022-05-24 00:48:15 +02:00
3c476d4629 Disabled CI due to inablity to configure it correctly
Main reason is compiling with submodules; secondary is python test suite
2022-05-23 17:47:33 +02:00
0a024430e8 Enable recursive submodules loading in CI 2022-05-23 15:39:11 +00:00
61cf0559b1 lib/midi in CI 2022-05-23 15:30:36 +00:00
8853451cb5 Added Midi dependency 2022-05-23 17:27:06 +02:00
f28cb10669 Block indexing and len builtin 2022-05-22 16:43:36 +02:00
23b9d901ac Vim syntax highlighting 2022-05-22 15:53:39 +02:00
045150938c Removed python installing from CI 2022-05-22 15:03:32 +02:00
Mateusz Piątkowski
201f4c4cf8 Update .gitlab-ci.yml file 2022-05-22 09:53:07 +00:00
Mateusz Piątkowski
f39296ae22 Update .gitlab-ci.yml file 2022-05-22 09:52:05 +00:00
Mateusz Piątkowski
d249386030 trying python tests 2022-05-22 09:50:22 +00:00
Mateusz Piątkowski
da5964a778 updating repos befor attempt to install python3 2022-05-22 09:48:45 +00:00
Mateusz Piątkowski
873941110a Adding python3 to gitlab-ci image 2022-05-22 09:42:19 +00:00
0ce1b59757 make test subcommand 2022-05-22 06:33:33 +02:00
b193ca1213 Removed problematic examples testing from CI 2022-05-22 06:26:29 +02:00
9ed25cc32c Maybe this would work? 2022-05-22 06:25:17 +02:00
2c9792d6b8 Explicit python reference 2022-05-22 06:23:37 +02:00
601659399c Forgot to specify mode 2022-05-22 06:21:23 +02:00
794502188b Proper CI file 2022-05-22 06:18:08 +02:00
9e2784f609 Added examples testing to CI 2022-05-22 06:16:15 +02:00
10d1223f9f Examples testing 2022-05-22 06:10:44 +02:00
bde30f5d99 Separated Musique functions and C++ intrinsics; blocks as delayed computations 2022-05-22 05:29:46 +02:00
de1ed62f6b Overloaded operators 2022-05-22 04:58:45 +02:00
5b3cfca2a8 More testing & keywords 2022-05-22 04:31:31 +02:00
c1493a75c2 Rewritten previous enviroment tests to new implementation 2022-05-22 03:44:15 +02:00
6bc2a1cd38 Context aware clojures
Moved from dynamic scoping to static scoping.
2022-05-22 03:44:15 +02:00
8ac9fc5929 Explicit test for bug that caused all this trouble 2022-05-22 03:44:14 +02:00
b9d87e1456 New environment implementation
It's a failure of locating precise source of the bug that would cause `var x =
[i|i] 0` to segfault. New implementation DOES NOT have this bug.
2022-05-22 03:44:10 +02:00
d542bbe696 Small refactoring 2022-05-21 23:12:50 +02:00
936 changed files with 213372 additions and 7476 deletions

8
.gitignore vendored
View File

@ -5,3 +5,11 @@ coverage
doc/musique
doc/build
doc/source/api
doc/*.html
doc/*.pdf
__pycache__
drafts.cc
.cache
release_*
*.zip
*.html

View File

@ -1,19 +0,0 @@
image: gcc
stages:
- build
- test
build:
stage: build
script:
- make
artifacts:
paths:
- main
stage: test
unit-testing:
stage: test
script:
- make unit-tests

144
CHANGELOG.md Normal file
View File

@ -0,0 +1,144 @@
# Changelog
All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
## [Unreleased]
## [0.5.0]
### Added
- Builtin documentation for builtin functions display from repl and command line (`musique doc <builtin>`)
- Man documentation for commandline interface builtin (`musique man`)
- Suggestions which command line parameters user may wanted to use
### Changed
- Moved from `bestline` to `replxx` Readline implementation due to lack of Windows support from bestline
- New parameter passing convention for command line invocation. `musique help` to learn how it changed
- `CTRL-C` handler that turns notes that are playing off
## [0.4.0]
### Added
- Builtin function documentation generation from C++ Musique implementation source code
- New builtins: digits
- Negative numbers!
- Version command via `:version` in REPL or `--version`, `-v` in command line.
- Introduced start synchronization with builtins: `peers` and `start`
- Connection with MIDI ports via parameters dropped in favour of function using context system: `port`
- Listing ports via REPL command: `:ports` instead of commandline parameter
- Building release with `make musique.zip` using Docker
### Changed
- Readme from Polish to English
### Removed
- Release script builder
### Fixed
- `ceil`, `round`, `floor` didn't behave well with negative numbers
- `duration` wasn't filling note length from context and summed all notes inside chord, when it should take max
- `try` evaluated arguments too quickly
- Nested arithmetic expression with undefined operator reports proper error and don't crash
## [0.3.1]
### Fixed
- release build script was producing executable with wrong path
- `examples/for-elise.mq` had bug in it
- in error reporting printing garbage instead of function name was fixed
- sending proper program change message
## [0.3.0]
### Added
- new builtins: map, while, set_len, set_oct, duration, pick
- `<note><octave>` notation like `c4` that mimics [scientific notation](https://en.wikipedia.org/wiki/Scientific_pitch_notation)
- operator pretty printing while printing values
- macros: builtin functions that takes AST and produces value
- early text-based snapshot system available via `:snap` command inside interactive session
- polish basic tutorial
### Changed
- Block can be called with more parameters then it requires
- reorganized fold argument order
- Moved from `(<note> <octave> <length>)` invocation to `(<note> <length>)`
- Moved from '[]' to '()' notation for blocks
- Moved from `a.n` index operator to `a[n]`
- Moved from ';' to ',' notation for expression separator
- Moved 'if', 'while' from beeing functions to macros - side effect of new notation
- Build system uses now Docker
- Array repetition using `number * array` like `3 * (c, e) == (c, e, c, e, c, e)`
### Fixed
- Index operation using booleans behaves like a mask and not fancy way of spelling 0 and 1
- Blocks are check against beeing a collection at runtime to prevent treating anonymous functions as collections and cousing assertions
- On Windows default terminal emulator ansi escape codes are conditionally supported. Review musique/pretty.cc for details
### Removed
- Removed `<note><absolute notes indexes>` chord notation like `c47` meaning c-major
- Removed obsolete documentation
- `h` as note literal
## [0.2.1] - 2022-10-21
### Fixed
- Windows build doesn't require pthread dll
## [0.2.0] - 2022-10-21
### Added
* Added `scan` builtin, which computes prefix sum of passed values when provided with addition operator
* Added [rtmidi](https://github.com/thestk/rtmidi/) dependency which should provide multiplatform MIDI support
* Support for Windows (with only basic REPL) (`make os=windows`)
* Support for MacOS (`make os=macos`)
* Release package now with compiled Windows binary
* `:load` REPL command to load Musique files inside Musique session. Allows for delayed file execution after a connection
* `:quit` REPL command that mirrors `:exit` command
* Virtual MIDI output port creation as default action (--output connects to existing one)
* Added build instructions
* `-f` commandline argument that will turn file into deffered function
### Changed
* Integrated libmidi library into Musique codebase
* Moved from custom ALSA interaction to using rtmidi for MIDI I/O operations
* VSCode extension has been re-created
### Removed
* Support for incoming MIDI messages handling due to poor implementation that didn't statisfy user needs
### Fixed
* Prevented accidental recursive construction of Arrays and Values by making convinience constructor `Value::Value(std::vector<Value>&&)` explicit
## [0.1.0] - 2022-09-25
### Added
* Musique programming language initial implementation that supports:
* Chord system
* Playing MIDI notes using par, sim and play
* Notes and chords as first-class citizens of Musique
* Bunch of builtins like math and array operations
* All numerical values as fractions (like in JavaScript but better)
* Primitive interactive mode
* Only ALSA MIDI Sequencer output
* Simple regression testing framework
* Basic documentation of builtin functions and operators

43
Dockerfile Normal file
View File

@ -0,0 +1,43 @@
FROM ubuntu:20.04 AS linux
ARG TZ=Europe/Warsaw
ARG VERSION
RUN ln -snf /usr/share/zoneinfo/$TZ /etc/localtime && echo $TZ > /etc/timezone
RUN apt update && apt install -y make software-properties-common zip unzip git
RUN add-apt-repository ppa:ubuntu-toolchain-r/test
RUN apt install -y gcc-11 g++-11 libasound2-dev
RUN mkdir -p /src/
WORKDIR /src/
COPY config.mk Makefile /src/
COPY .git /src/.git/
COPY musique /src/musique/
COPY lib /src/lib/
COPY scripts /src/scripts/
RUN make clean && make CC=gcc-11 CXX=g++-11 VERSION="$VERSION"
FROM ubuntu:22.04 AS windows
ARG VERSION
RUN apt update && apt install -y git make gcc-mingw-w64-x86-64 g++-mingw-w64-x86-64
RUN mkdir -p /src/
WORKDIR /src/
COPY config.mk Makefile /src/
COPY .git /src/.git/
COPY musique /src/musique/
COPY lib /src/lib/
COPY scripts /src/scripts/
RUN make clean && make os=windows CC=x86_64-w64-mingw32-gcc-posix CXX=x86_64-w64-mingw32-g++-posix VERSION="$VERSION"
FROM ubuntu:22.04 AS release
RUN apt update && apt install -y zip pandoc python3 python-is-python3 pandoc
COPY CHANGELOG.md LICENSE /musique/
COPY examples /musique/examples/
COPY --from=windows /src/bin/musique.exe /musique/musique-windows.exe
COPY --from=linux /src/bin/musique /musique/musique-linux
COPY doc /doc/
COPY scripts /scripts/
RUN python /scripts/language-cmp-cheatsheet.py /doc/musique-vs-languages-cheatsheet.template \
&& bash -c 'cp /{doc,musique}/musique-vs-languages-cheatsheet.html'
RUN pandoc -o /musique/wprowadzenie.html /doc/wprowadzenie.md -s --toc
RUN zip -r musique.zip /musique/

View File

@ -58,7 +58,7 @@ PROJECT_LOGO =
# entered, it will be relative to the location where doxygen was started. If
# left blank the current directory will be used.
OUTPUT_DIRECTORY = doc/build/doxygen/
OUTPUT_DIRECTORY = doc/build/
# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
# directories (in 2 levels) under the output directory of each output format and
@ -485,13 +485,13 @@ NUM_PROC_THREADS = 1
# normally produced when WARNINGS is set to YES.
# The default value is: NO.
EXTRACT_ALL = NO
EXTRACT_ALL = YES
# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
# be included in the documentation.
# The default value is: NO.
EXTRACT_PRIVATE = NO
EXTRACT_PRIVATE = YES
# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
# methods of a class will be included in the documentation.
@ -864,7 +864,7 @@ WARN_LOGFILE =
# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
# Note: If this tag is empty the current directory is searched.
INPUT = src
INPUT = musique doc/index.md
# This tag can be used to specify the character encoding of the source files
# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
@ -952,7 +952,7 @@ RECURSIVE = YES
# Note that relative paths are relative to the directory from which doxygen is
# run.
EXCLUDE = tests
EXCLUDE = tests src/main.cc
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
@ -1061,7 +1061,7 @@ FILTER_SOURCE_PATTERNS =
# (index.html). This can be useful if you have a project on for instance GitHub
# and want to reuse the introduction page also for the doxygen output.
USE_MDFILE_AS_MAINPAGE =
USE_MDFILE_AS_MAINPAGE = doc/index.md
#---------------------------------------------------------------------------
# Configuration options related to source browsing
@ -1213,7 +1213,7 @@ IGNORE_PREFIX =
# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
# The default value is: YES.
GENERATE_HTML = NO
GENERATE_HTML = YES
# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
@ -1582,7 +1582,7 @@ DISABLE_INDEX = NO
# The default value is: NO.
# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
GENERATE_TREEVIEW = YES
# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
# doxygen will group on one line in the generated HTML documentation.

661
LICENSE Normal file
View File

@ -0,0 +1,661 @@
GNU AFFERO GENERAL PUBLIC LICENSE
Version 3, 19 November 2007
Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/>
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The GNU Affero General Public License is a free, copyleft license for
software and other kinds of works, specifically designed to ensure
cooperation with the community in the case of network server software.
The licenses for most software and other practical works are designed
to take away your freedom to share and change the works. By contrast,
our General Public Licenses are intended to guarantee your freedom to
share and change all versions of a program--to make sure it remains free
software for all its users.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
them if you wish), that you receive source code or can get it if you
want it, that you can change the software or use pieces of it in new
free programs, and that you know you can do these things.
Developers that use our General Public Licenses protect your rights
with two steps: (1) assert copyright on the software, and (2) offer
you this License which gives you legal permission to copy, distribute
and/or modify the software.
A secondary benefit of defending all users' freedom is that
improvements made in alternate versions of the program, if they
receive widespread use, become available for other developers to
incorporate. Many developers of free software are heartened and
encouraged by the resulting cooperation. However, in the case of
software used on network servers, this result may fail to come about.
The GNU General Public License permits making a modified version and
letting the public access it on a server without ever releasing its
source code to the public.
The GNU Affero General Public License is designed specifically to
ensure that, in such cases, the modified source code becomes available
to the community. It requires the operator of a network server to
provide the source code of the modified version running there to the
users of that server. Therefore, public use of a modified version, on
a publicly accessible server, gives the public access to the source
code of the modified version.
An older license, called the Affero General Public License and
published by Affero, was designed to accomplish similar goals. This is
a different license, not a version of the Affero GPL, but Affero has
released a new version of the Affero GPL which permits relicensing under
this license.
The precise terms and conditions for copying, distribution and
modification follow.
TERMS AND CONDITIONS
0. Definitions.
"This License" refers to version 3 of the GNU Affero General Public License.
"Copyright" also means copyright-like laws that apply to other kinds of
works, such as semiconductor masks.
"The Program" refers to any copyrightable work licensed under this
License. Each licensee is addressed as "you". "Licensees" and
"recipients" may be individuals or organizations.
To "modify" a work means to copy from or adapt all or part of the work
in a fashion requiring copyright permission, other than the making of an
exact copy. The resulting work is called a "modified version" of the
earlier work or a work "based on" the earlier work.
A "covered work" means either the unmodified Program or a work based
on the Program.
To "propagate" a work means to do anything with it that, without
permission, would make you directly or secondarily liable for
infringement under applicable copyright law, except executing it on a
computer or modifying a private copy. Propagation includes copying,
distribution (with or without modification), making available to the
public, and in some countries other activities as well.
To "convey" a work means any kind of propagation that enables other
parties to make or receive copies. Mere interaction with a user through
a computer network, with no transfer of a copy, is not conveying.
An interactive user interface displays "Appropriate Legal Notices"
to the extent that it includes a convenient and prominently visible
feature that (1) displays an appropriate copyright notice, and (2)
tells the user that there is no warranty for the work (except to the
extent that warranties are provided), that licensees may convey the
work under this License, and how to view a copy of this License. If
the interface presents a list of user commands or options, such as a
menu, a prominent item in the list meets this criterion.
1. Source Code.
The "source code" for a work means the preferred form of the work
for making modifications to it. "Object code" means any non-source
form of a work.
A "Standard Interface" means an interface that either is an official
standard defined by a recognized standards body, or, in the case of
interfaces specified for a particular programming language, one that
is widely used among developers working in that language.
The "System Libraries" of an executable work include anything, other
than the work as a whole, that (a) is included in the normal form of
packaging a Major Component, but which is not part of that Major
Component, and (b) serves only to enable use of the work with that
Major Component, or to implement a Standard Interface for which an
implementation is available to the public in source code form. A
"Major Component", in this context, means a major essential component
(kernel, window system, and so on) of the specific operating system
(if any) on which the executable work runs, or a compiler used to
produce the work, or an object code interpreter used to run it.
The "Corresponding Source" for a work in object code form means all
the source code needed to generate, install, and (for an executable
work) run the object code and to modify the work, including scripts to
control those activities. However, it does not include the work's
System Libraries, or general-purpose tools or generally available free
programs which are used unmodified in performing those activities but
which are not part of the work. For example, Corresponding Source
includes interface definition files associated with source files for
the work, and the source code for shared libraries and dynamically
linked subprograms that the work is specifically designed to require,
such as by intimate data communication or control flow between those
subprograms and other parts of the work.
The Corresponding Source need not include anything that users
can regenerate automatically from other parts of the Corresponding
Source.
The Corresponding Source for a work in source code form is that
same work.
2. Basic Permissions.
All rights granted under this License are granted for the term of
copyright on the Program, and are irrevocable provided the stated
conditions are met. This License explicitly affirms your unlimited
permission to run the unmodified Program. The output from running a
covered work is covered by this License only if the output, given its
content, constitutes a covered work. This License acknowledges your
rights of fair use or other equivalent, as provided by copyright law.
You may make, run and propagate covered works that you do not
convey, without conditions so long as your license otherwise remains
in force. You may convey covered works to others for the sole purpose
of having them make modifications exclusively for you, or provide you
with facilities for running those works, provided that you comply with
the terms of this License in conveying all material for which you do
not control copyright. Those thus making or running the covered works
for you must do so exclusively on your behalf, under your direction
and control, on terms that prohibit them from making any copies of
your copyrighted material outside their relationship with you.
Conveying under any other circumstances is permitted solely under
the conditions stated below. Sublicensing is not allowed; section 10
makes it unnecessary.
3. Protecting Users' Legal Rights From Anti-Circumvention Law.
No covered work shall be deemed part of an effective technological
measure under any applicable law fulfilling obligations under article
11 of the WIPO copyright treaty adopted on 20 December 1996, or
similar laws prohibiting or restricting circumvention of such
measures.
When you convey a covered work, you waive any legal power to forbid
circumvention of technological measures to the extent such circumvention
is effected by exercising rights under this License with respect to
the covered work, and you disclaim any intention to limit operation or
modification of the work as a means of enforcing, against the work's
users, your or third parties' legal rights to forbid circumvention of
technological measures.
4. Conveying Verbatim Copies.
You may convey verbatim copies of the Program's source code as you
receive it, in any medium, provided that you conspicuously and
appropriately publish on each copy an appropriate copyright notice;
keep intact all notices stating that this License and any
non-permissive terms added in accord with section 7 apply to the code;
keep intact all notices of the absence of any warranty; and give all
recipients a copy of this License along with the Program.
You may charge any price or no price for each copy that you convey,
and you may offer support or warranty protection for a fee.
5. Conveying Modified Source Versions.
You may convey a work based on the Program, or the modifications to
produce it from the Program, in the form of source code under the
terms of section 4, provided that you also meet all of these conditions:
a) The work must carry prominent notices stating that you modified
it, and giving a relevant date.
b) The work must carry prominent notices stating that it is
released under this License and any conditions added under section
7. This requirement modifies the requirement in section 4 to
"keep intact all notices".
c) You must license the entire work, as a whole, under this
License to anyone who comes into possession of a copy. This
License will therefore apply, along with any applicable section 7
additional terms, to the whole of the work, and all its parts,
regardless of how they are packaged. This License gives no
permission to license the work in any other way, but it does not
invalidate such permission if you have separately received it.
d) If the work has interactive user interfaces, each must display
Appropriate Legal Notices; however, if the Program has interactive
interfaces that do not display Appropriate Legal Notices, your
work need not make them do so.
A compilation of a covered work with other separate and independent
works, which are not by their nature extensions of the covered work,
and which are not combined with it such as to form a larger program,
in or on a volume of a storage or distribution medium, is called an
"aggregate" if the compilation and its resulting copyright are not
used to limit the access or legal rights of the compilation's users
beyond what the individual works permit. Inclusion of a covered work
in an aggregate does not cause this License to apply to the other
parts of the aggregate.
6. Conveying Non-Source Forms.
You may convey a covered work in object code form under the terms
of sections 4 and 5, provided that you also convey the
machine-readable Corresponding Source under the terms of this License,
in one of these ways:
a) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by the
Corresponding Source fixed on a durable physical medium
customarily used for software interchange.
b) Convey the object code in, or embodied in, a physical product
(including a physical distribution medium), accompanied by a
written offer, valid for at least three years and valid for as
long as you offer spare parts or customer support for that product
model, to give anyone who possesses the object code either (1) a
copy of the Corresponding Source for all the software in the
product that is covered by this License, on a durable physical
medium customarily used for software interchange, for a price no
more than your reasonable cost of physically performing this
conveying of source, or (2) access to copy the
Corresponding Source from a network server at no charge.
c) Convey individual copies of the object code with a copy of the
written offer to provide the Corresponding Source. This
alternative is allowed only occasionally and noncommercially, and
only if you received the object code with such an offer, in accord
with subsection 6b.
d) Convey the object code by offering access from a designated
place (gratis or for a charge), and offer equivalent access to the
Corresponding Source in the same way through the same place at no
further charge. You need not require recipients to copy the
Corresponding Source along with the object code. If the place to
copy the object code is a network server, the Corresponding Source
may be on a different server (operated by you or a third party)
that supports equivalent copying facilities, provided you maintain
clear directions next to the object code saying where to find the
Corresponding Source. Regardless of what server hosts the
Corresponding Source, you remain obligated to ensure that it is
available for as long as needed to satisfy these requirements.
e) Convey the object code using peer-to-peer transmission, provided
you inform other peers where the object code and Corresponding
Source of the work are being offered to the general public at no
charge under subsection 6d.
A separable portion of the object code, whose source code is excluded
from the Corresponding Source as a System Library, need not be
included in conveying the object code work.
A "User Product" is either (1) a "consumer product", which means any
tangible personal property which is normally used for personal, family,
or household purposes, or (2) anything designed or sold for incorporation
into a dwelling. In determining whether a product is a consumer product,
doubtful cases shall be resolved in favor of coverage. For a particular
product received by a particular user, "normally used" refers to a
typical or common use of that class of product, regardless of the status
of the particular user or of the way in which the particular user
actually uses, or expects or is expected to use, the product. A product
is a consumer product regardless of whether the product has substantial
commercial, industrial or non-consumer uses, unless such uses represent
the only significant mode of use of the product.
"Installation Information" for a User Product means any methods,
procedures, authorization keys, or other information required to install
and execute modified versions of a covered work in that User Product from
a modified version of its Corresponding Source. The information must
suffice to ensure that the continued functioning of the modified object
code is in no case prevented or interfered with solely because
modification has been made.
If you convey an object code work under this section in, or with, or
specifically for use in, a User Product, and the conveying occurs as
part of a transaction in which the right of possession and use of the
User Product is transferred to the recipient in perpetuity or for a
fixed term (regardless of how the transaction is characterized), the
Corresponding Source conveyed under this section must be accompanied
by the Installation Information. But this requirement does not apply
if neither you nor any third party retains the ability to install
modified object code on the User Product (for example, the work has
been installed in ROM).
The requirement to provide Installation Information does not include a
requirement to continue to provide support service, warranty, or updates
for a work that has been modified or installed by the recipient, or for
the User Product in which it has been modified or installed. Access to a
network may be denied when the modification itself materially and
adversely affects the operation of the network or violates the rules and
protocols for communication across the network.
Corresponding Source conveyed, and Installation Information provided,
in accord with this section must be in a format that is publicly
documented (and with an implementation available to the public in
source code form), and must require no special password or key for
unpacking, reading or copying.
7. Additional Terms.
"Additional permissions" are terms that supplement the terms of this
License by making exceptions from one or more of its conditions.
Additional permissions that are applicable to the entire Program shall
be treated as though they were included in this License, to the extent
that they are valid under applicable law. If additional permissions
apply only to part of the Program, that part may be used separately
under those permissions, but the entire Program remains governed by
this License without regard to the additional permissions.
When you convey a copy of a covered work, you may at your option
remove any additional permissions from that copy, or from any part of
it. (Additional permissions may be written to require their own
removal in certain cases when you modify the work.) You may place
additional permissions on material, added by you to a covered work,
for which you have or can give appropriate copyright permission.
Notwithstanding any other provision of this License, for material you
add to a covered work, you may (if authorized by the copyright holders of
that material) supplement the terms of this License with terms:
a) Disclaiming warranty or limiting liability differently from the
terms of sections 15 and 16 of this License; or
b) Requiring preservation of specified reasonable legal notices or
author attributions in that material or in the Appropriate Legal
Notices displayed by works containing it; or
c) Prohibiting misrepresentation of the origin of that material, or
requiring that modified versions of such material be marked in
reasonable ways as different from the original version; or
d) Limiting the use for publicity purposes of names of licensors or
authors of the material; or
e) Declining to grant rights under trademark law for use of some
trade names, trademarks, or service marks; or
f) Requiring indemnification of licensors and authors of that
material by anyone who conveys the material (or modified versions of
it) with contractual assumptions of liability to the recipient, for
any liability that these contractual assumptions directly impose on
those licensors and authors.
All other non-permissive additional terms are considered "further
restrictions" within the meaning of section 10. If the Program as you
received it, or any part of it, contains a notice stating that it is
governed by this License along with a term that is a further
restriction, you may remove that term. If a license document contains
a further restriction but permits relicensing or conveying under this
License, you may add to a covered work material governed by the terms
of that license document, provided that the further restriction does
not survive such relicensing or conveying.
If you add terms to a covered work in accord with this section, you
must place, in the relevant source files, a statement of the
additional terms that apply to those files, or a notice indicating
where to find the applicable terms.
Additional terms, permissive or non-permissive, may be stated in the
form of a separately written license, or stated as exceptions;
the above requirements apply either way.
8. Termination.
You may not propagate or modify a covered work except as expressly
provided under this License. Any attempt otherwise to propagate or
modify it is void, and will automatically terminate your rights under
this License (including any patent licenses granted under the third
paragraph of section 11).
However, if you cease all violation of this License, then your
license from a particular copyright holder is reinstated (a)
provisionally, unless and until the copyright holder explicitly and
finally terminates your license, and (b) permanently, if the copyright
holder fails to notify you of the violation by some reasonable means
prior to 60 days after the cessation.
Moreover, your license from a particular copyright holder is
reinstated permanently if the copyright holder notifies you of the
violation by some reasonable means, this is the first time you have
received notice of violation of this License (for any work) from that
copyright holder, and you cure the violation prior to 30 days after
your receipt of the notice.
Termination of your rights under this section does not terminate the
licenses of parties who have received copies or rights from you under
this License. If your rights have been terminated and not permanently
reinstated, you do not qualify to receive new licenses for the same
material under section 10.
9. Acceptance Not Required for Having Copies.
You are not required to accept this License in order to receive or
run a copy of the Program. Ancillary propagation of a covered work
occurring solely as a consequence of using peer-to-peer transmission
to receive a copy likewise does not require acceptance. However,
nothing other than this License grants you permission to propagate or
modify any covered work. These actions infringe copyright if you do
not accept this License. Therefore, by modifying or propagating a
covered work, you indicate your acceptance of this License to do so.
10. Automatic Licensing of Downstream Recipients.
Each time you convey a covered work, the recipient automatically
receives a license from the original licensors, to run, modify and
propagate that work, subject to this License. You are not responsible
for enforcing compliance by third parties with this License.
An "entity transaction" is a transaction transferring control of an
organization, or substantially all assets of one, or subdividing an
organization, or merging organizations. If propagation of a covered
work results from an entity transaction, each party to that
transaction who receives a copy of the work also receives whatever
licenses to the work the party's predecessor in interest had or could
give under the previous paragraph, plus a right to possession of the
Corresponding Source of the work from the predecessor in interest, if
the predecessor has it or can get it with reasonable efforts.
You may not impose any further restrictions on the exercise of the
rights granted or affirmed under this License. For example, you may
not impose a license fee, royalty, or other charge for exercise of
rights granted under this License, and you may not initiate litigation
(including a cross-claim or counterclaim in a lawsuit) alleging that
any patent claim is infringed by making, using, selling, offering for
sale, or importing the Program or any portion of it.
11. Patents.
A "contributor" is a copyright holder who authorizes use under this
License of the Program or a work on which the Program is based. The
work thus licensed is called the contributor's "contributor version".
A contributor's "essential patent claims" are all patent claims
owned or controlled by the contributor, whether already acquired or
hereafter acquired, that would be infringed by some manner, permitted
by this License, of making, using, or selling its contributor version,
but do not include claims that would be infringed only as a
consequence of further modification of the contributor version. For
purposes of this definition, "control" includes the right to grant
patent sublicenses in a manner consistent with the requirements of
this License.
Each contributor grants you a non-exclusive, worldwide, royalty-free
patent license under the contributor's essential patent claims, to
make, use, sell, offer for sale, import and otherwise run, modify and
propagate the contents of its contributor version.
In the following three paragraphs, a "patent license" is any express
agreement or commitment, however denominated, not to enforce a patent
(such as an express permission to practice a patent or covenant not to
sue for patent infringement). To "grant" such a patent license to a
party means to make such an agreement or commitment not to enforce a
patent against the party.
If you convey a covered work, knowingly relying on a patent license,
and the Corresponding Source of the work is not available for anyone
to copy, free of charge and under the terms of this License, through a
publicly available network server or other readily accessible means,
then you must either (1) cause the Corresponding Source to be so
available, or (2) arrange to deprive yourself of the benefit of the
patent license for this particular work, or (3) arrange, in a manner
consistent with the requirements of this License, to extend the patent
license to downstream recipients. "Knowingly relying" means you have
actual knowledge that, but for the patent license, your conveying the
covered work in a country, or your recipient's use of the covered work
in a country, would infringe one or more identifiable patents in that
country that you have reason to believe are valid.
If, pursuant to or in connection with a single transaction or
arrangement, you convey, or propagate by procuring conveyance of, a
covered work, and grant a patent license to some of the parties
receiving the covered work authorizing them to use, propagate, modify
or convey a specific copy of the covered work, then the patent license
you grant is automatically extended to all recipients of the covered
work and works based on it.
A patent license is "discriminatory" if it does not include within
the scope of its coverage, prohibits the exercise of, or is
conditioned on the non-exercise of one or more of the rights that are
specifically granted under this License. You may not convey a covered
work if you are a party to an arrangement with a third party that is
in the business of distributing software, under which you make payment
to the third party based on the extent of your activity of conveying
the work, and under which the third party grants, to any of the
parties who would receive the covered work from you, a discriminatory
patent license (a) in connection with copies of the covered work
conveyed by you (or copies made from those copies), or (b) primarily
for and in connection with specific products or compilations that
contain the covered work, unless you entered into that arrangement,
or that patent license was granted, prior to 28 March 2007.
Nothing in this License shall be construed as excluding or limiting
any implied license or other defenses to infringement that may
otherwise be available to you under applicable patent law.
12. No Surrender of Others' Freedom.
If conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot convey a
covered work so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you may
not convey it at all. For example, if you agree to terms that obligate you
to collect a royalty for further conveying from those to whom you convey
the Program, the only way you could satisfy both those terms and this
License would be to refrain entirely from conveying the Program.
13. Remote Network Interaction; Use with the GNU General Public License.
Notwithstanding any other provision of this License, if you modify the
Program, your modified version must prominently offer all users
interacting with it remotely through a computer network (if your version
supports such interaction) an opportunity to receive the Corresponding
Source of your version by providing access to the Corresponding Source
from a network server at no charge, through some standard or customary
means of facilitating copying of software. This Corresponding Source
shall include the Corresponding Source for any work covered by version 3
of the GNU General Public License that is incorporated pursuant to the
following paragraph.
Notwithstanding any other provision of this License, you have
permission to link or combine any covered work with a work licensed
under version 3 of the GNU General Public License into a single
combined work, and to convey the resulting work. The terms of this
License will continue to apply to the part which is the covered work,
but the work with which it is combined will remain governed by version
3 of the GNU General Public License.
14. Revised Versions of this License.
The Free Software Foundation may publish revised and/or new versions of
the GNU Affero General Public License from time to time. Such new versions
will be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the
Program specifies that a certain numbered version of the GNU Affero General
Public License "or any later version" applies to it, you have the
option of following the terms and conditions either of that numbered
version or of any later version published by the Free Software
Foundation. If the Program does not specify a version number of the
GNU Affero General Public License, you may choose any version ever published
by the Free Software Foundation.
If the Program specifies that a proxy can decide which future
versions of the GNU Affero General Public License can be used, that proxy's
public statement of acceptance of a version permanently authorizes you
to choose that version for the Program.
Later license versions may give you additional or different
permissions. However, no additional obligations are imposed on any
author or copyright holder as a result of your choosing to follow a
later version.
15. Disclaimer of Warranty.
THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY
APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT
HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY
OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM
IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF
ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. Limitation of Liability.
IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY
GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE
USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF
DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD
PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),
EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF
SUCH DAMAGES.
17. Interpretation of Sections 15 and 16.
If the disclaimer of warranty and limitation of liability provided
above cannot be given local legal effect according to their terms,
reviewing courts shall apply local law that most closely approximates
an absolute waiver of all civil liability in connection with the
Program, unless a warranty or assumption of liability accompanies a
copy of the Program in return for a fee.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
state the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
Musique
Copyright (C) 2022 Projekt inżynierski
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Also add information on how to contact you by electronic and paper mail.
If your software can interact with users remotely through a computer
network, you should also make sure that it provides a way for users to
get its source. For example, if your program is a web application, its
interface could display a "Source" link that leads users to an archive
of the code. There are many ways you could offer source, and different
solutions will be better for different programs; see section 13 for the
specific requirements.
You should also get your employer (if you work as a programmer) or school,
if any, to sign a "copyright disclaimer" for the program, if necessary.
For more information on this, and how to apply and follow the GNU AGPL, see
<https://www.gnu.org/licenses/>.

View File

@ -1,71 +1,55 @@
MAKEFLAGS="-j $(grep -c ^processor /proc/cpuinfo)"
CXXFLAGS:=$(CXXFLAGS) -std=c++20 -Wall -Wextra -Werror=switch -Werror=return-type -Werror=unused-result
CPPFLAGS:=$(CPPFLAGS) -Ilib/expected/ -Ilib/ut/ -Isrc/
RELEASE_FLAGS=-O3
DEBUG_FLAGS=-O0 -ggdb
include config.mk
Obj= \
environment.o \
errors.o \
interpreter.o \
lexer.o \
location.o \
number.o \
parser.o \
unicode.o \
unicode_tables.o \
value.o
Sources := $(shell find musique/ -name '*.cc')
Obj := $(subst musique/,,$(Sources:%.cc=%.o))
Release_Obj=$(addprefix bin/,$(Obj))
Debug_Obj=$(addprefix bin/debug/,$(Obj))
ifeq ($(os),windows)
all: bin/musique.exe
debug: bin/windows/debug/musique.exe
else
all: bin/musique
debug: bin/$(os)/debug/musique
endif
all: bin/musique bin/unit-tests
include scripts/$(os).mk
include scripts/build.mk
include scripts/test.mk
debug: bin/debug/musique
bin/$(Target): bin/$(os)/$(Target)
ln -f $< $@
bin/%.o: src/%.cc src/*.hh
g++ $(CXXFLAGS) $(RELEASE_FLAGS) $(CPPFLAGS) -o $@ $< -c
bin/musique: $(Release_Obj) bin/main.o src/*.hh
g++ $(CXXFLAGS) $(RELEASE_FLAGS) $(CPPFLAGS) -o $@ $(Release_Obj) bin/main.o
bin/debug/musique: $(Debug_Obj) bin/debug/main.o src/*.hh
g++ $(CXXFLAGS) $(DEBUG_FLAGS) $(CPPFLAGS) -o $@ $(Debug_Obj) bin/debug/main.o
bin/debug/%.o: src/%.cc src/*.hh
g++ $(CXXFLAGS) $(DEBUG_FLAGS) $(CPPFLAGS) -o $@ $< -c
.PHONY: unit-tests
unit-tests: bin/unit-tests
./$<
.PHONY: unit-test-coverage
unit-test-coverage:
@which gcov >/dev/null || ( echo "[ERROR] gcov is required for test coverage report"; false )
@which gcovr >/dev/null || ( echo "[ERROR] gcovr is required for test coverage report"; false )
CXXFLAGS=--coverage $(MAKE) bin/unit-tests -B
bin/unit-tests
rm -rf coverage
mkdir coverage
gcovr -e '.*\.hpp' --html --html-details -o coverage/index.html
rm -rf bin
xdg-open coverage/index.html
.PHONY: doc
doc: Doxyfile src/*.cc src/*.hh
doc: Doxyfile musique/*.cc musique/*.hh
doxygen
cd doc; $(MAKE) html
.PHONY: doc-open
doc-open: doc
xdg-open ./doc/build/html/index.html
bin/unit-tests: src/tests/*.cc $(Release_Obj)
g++ $(CXXFLAGS) $(CPPFLAGS) -o $@ $^
clean:
rm -rf bin coverage
.PHONY: clean
release: bin/musique
scripts/release
$(shell mkdir -p bin/debug)
install: bin/musique
scripts/install
doc/musique-vs-languages-cheatsheet.html: doc/musique-vs-languages-cheatsheet.template
scripts/language-cmp-cheatsheet.py $<
doc/wprowadzenie.html: doc/wprowadzenie.md
pandoc -o $@ $< -s --toc
doc/functions.html: musique/interpreter/builtin_functions.cc scripts/document-builtin.py
scripts/document-builtin.py -o $@ $<
musique.zip:
docker build -t musique-builder --build-arg "VERSION=$(VERSION)" .
docker create --name musique musique-builder
docker cp musique:/musique.zip musique.zip
docker rm -f musique
.PHONY: clean doc doc-open all test unit-tests release install musique.zip
$(shell mkdir -p $(subst musique/,bin/$(os)/,$(shell find musique/* -type d)))
$(shell mkdir -p bin/$(os)/replxx/)
$(shell mkdir -p $(subst musique/,bin/$(os)/debug/,$(shell find musique/* -type d)))

View File

@ -1,37 +1,36 @@
# Musique interpreter
Interpreter języka Musique. Możliwy do wykorzystywania jako:
Reference implementation of Musique programming language.
- biblioteka interpretera języka dołączana do innego projektu (podobnie jak Lua);
- REPL działający w systemie GNU/Linux + ALSA wykonujący język Musique.
## Building
## Dostępne komendy
Reference [`build_instructions.md`](./build_instructions.md).
- `make` - Buduje interpreter `bin/musique` (tryb release)
- `make debug` - Buduje interpreter `bin/debug/musique` (tryb debug)
- `make clean` - Usuwa reprodukowalne elementy projektu (automatycznie stworzone pliki binarne czy raporty)
## Syntax highlighting
### Dokumentacja
### Vim / Neovim
- `make doc` - Tworzy `doc/build/html/` zawierający dokumentację projektu
### Testowanie
- `make unit-tests` - Uruchamia testy jednostkowe interpretera
- `make unit-test-coverage` - Uruchamia raport pokrycia kodu przez testy jednostkowe
## Budowa projektu
Copy [editor/musique.vim](editor/musique.vim) to `syntax` directory inside your Vim (Neovim) configuration.
```console
$ cp editor/musique.vim ~/.config/nvim/syntax/
```
.
├── bin Miejsce produkcji plików wykonywalnych
├── coverage
├── doc Dokumentacja języka, interpretera
│   ├── build Miejsce produkcji dokumentacji
│   └── source Źródła dokumentacji Sphinx
├── lib Zewnętrzne zależności projektu
│   ├── expected
│   └── ut
└── src Główny katalog z kodem źródłowym
└── tests Katalog z testami jednostkowymi
Next, you can add bindings for filetype:
```vim
au BufRead,BufNewFile *.mq set filetype=musique
```
### Visual Studio Code
Copy [editor/vscode-musique](editor/vscode-musique) directory to `<user home>/.vscode/extensions` and restart VS Code.
# Thanks to
- Creator of [tl::expected](https://github.com/TartanLlama/expected) - [Sy Brand](https://sybrand.ink/)
- Creator of [bestline](https://github.com/jart/bestline) - [Justine Tunney](https://justinetunney.com/)
- Creator of [rtmidi](https://github.com/thestk/rtmidi/) - [Gary P. Scavone](http://www.music.mcgill.ca/~gary/)
- Creators of [link](https://github.com/Ableton/link)
and all contributors that created libraries above.

27
build_instructions.md Normal file
View File

@ -0,0 +1,27 @@
# Musique build instructions
## Linux
Use your local C++ compiler (supporting C++20) and ALSA dev libraries or included Dockerfile.
## MacOS
Required system dependency is fairly new C++ compiler. The simplest way is to type `clang` in terminal, which should launch installation of C++ compiler. Next provided compiler version:
```
$ clang++ --version
```
Minimal supported version is __14__. On older editions of MacOS one can aquire new editions by [Homebrew](https://brew.sh/). After homebrew installation install clang via `brew install llvm`.
Next you should be able to build project by running `make` command inside main directory (in released zip file in `source_code` directory).
## Windows
Windows support is provided via cross compilation. Mingw GCC C++ compiler is required to produce Windows binaries.
```
$ make os=windows
```
will create `bin/musique.exe` that can be used on x86_64 Windows operating systems or use included Dockerfile

28
config.mk Normal file
View File

@ -0,0 +1,28 @@
MAKEFLAGS="-j $(grep -c ^processor /proc/cpuinfo)"
MAJOR := 5
MINOR := 0
PATCH := 0
COMMIT := gc$(shell git rev-parse --short HEAD 2>/dev/null)
ifeq ($(COMMIT),gc)
COMMIT = gcunknown
endif
VERSION := $(MAJOR).$(MINOR).$(PATCH)-dev+$(COMMIT)
CXXFLAGS:=$(CXXFLAGS) -std=c++20 -Wall -Wextra -Werror=switch -Werror=return-type -Werror=unused-result
CPPFLAGS:=$(CPPFLAGS) -DMusique_Version='"$(VERSION)"' \
-Ilib/expected/ -I. -Ilib/rtmidi/ -Ilib/link/include -Ilib/asio/include/ -Ilib/edit_distance.cc/ -Ilib/replxx/include -DREPLXX_STATIC
LDFLAGS=-flto
LDLIBS= -lpthread
RELEASE_FLAGS=-O2
DEBUG_FLAGS=-O0 -ggdb -fsanitize=undefined -DDebug
ifeq ($(shell uname),Darwin)
os=macos
else
os=linux
endif

View File

@ -1,20 +0,0 @@
# Minimal makefile for Sphinx documentation
#
# You can set these variables from the command line, and also
# from the environment for the first two.
SPHINXOPTS ?=
SPHINXBUILD ?= sphinx-build
SOURCEDIR = source
BUILDDIR = build
# Put it first so that "make" without argument is like "make help".
help:
@$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)
.PHONY: help Makefile
# Catch-all target: route all unknown targets to Sphinx using the new
# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS).
%: Makefile
@$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O)

55
doc/index.md Normal file
View File

@ -0,0 +1,55 @@
# Musique interpreter documentation
This documentation system contains information for programmers that will like to contribute or learn about Musique interpreter (and [REPL](https://en.wikipedia.org/wiki/Read%E2%80%93eval%E2%80%93print_loop)).
## Building
To build you need to have installed:
- Modern C++ compiler compatible with GNU compund expression extension and C++20 support;
- Following libraries when targetting GNU/Linux: `libreadline`, `libasound`.
Then all you have to do is run `make` in main source directory.
## Using interpreter as a library
Interpreter usage consist of three steps:
- creating chosen MIDI support for an Interpreter
- creating Interpreter instance
- parsing and evaluating source code
Parsing and evaluating may result in an error. For this case Result type offers `error()` method to get produced error and `has_value()` to check if computation was successfull.
### Simple example
We define `run` function that will do steps above, to execute provided string.
```cpp
void run(std::string_view source)
{
Interpreter interpreter;
// We don't want midi support so we ignore it
interpreter.midi_connection = nullptr;
// We set filename used in error reporting to "example"
auto ast = Parser::parse(source, "example");
// Check if file was properly parsed. If not print error message and exit
if (!ast.has_value()) {
std::cerr << ast.error() << '\n';
return;
}
// Evaluate program
auto result = interpreter.eval(std::move(ast));
if (result.has_value()) {
std::cout << *result << std::endl;
} else {
std::cerr << result.error() << '\n';
}
}
```
When in doubt see `src/main.cc` as example on library usage.

View File

@ -0,0 +1,285 @@
TITLE Porównanie Musique z typowymi językami programowania
BEGIN CSS
table, tr, td {
font-size: 12pt;
border: 1pt solid #DDDDDD;
border-collapse: collapse;
vertical-align: top;
tab-size: 2;
}
td, th {
padding: 2px;
}
END CSS
BEGIN INTRO
<h1>Ściągawka Musique, a Python i Ruby</h1>
Ponieważ Musique jest kierowany do osób posiadających doświadczenie z muzyką algorytmiczną, szybkim sposobem na podstawowe poznanie języka jest porównanie z innymi technologiami w tej dziedzinie. Ten dokument służy bardziej ukazaniu różnic niż omówieniu samego języka.
END INTRO
BEGIN TABLE
SECTION Podstawy
n Kategoria
m Musique
p Python
r Ruby (SonicPi)
c Komentarz
n Deklaracja zmiennej
m x := 0
p x = 0
r x = 0
c Zmienne należy zadeklarować by móc z nich korzystać
n Aktualizacja wartości zmiennej
m x = 1
r x = 1
p x = 1
n Operacje matematyczne
m x = 10 * 30 - 40 ** 2
p x = 10 * 30 - 40 ** 2
r x = 10 * 30 - 40 ** 2
c Zarówno Python, Ruby jak i Musique posiadają operator potęgi **
n Funkcja anonimowa
m add := (x y | x + y)
p add = lambda x, y: x + y
r add = ->(x, y) { x + y }
n Deklaracja funkcji
m add := (x y |
m say x y,
m x + y
m )
p def add(x, y):
p print(x, y)
p return x + y
r def add(x, y)
r puts x, y
r return x + y
r end
c Musique nie rozróżnia funkcji anonimowych i zadeklarowanych
n Wywoływanie funkcji
m add 1 3
p add(1, 3)
r add 1, 3
n Wywołanie funkcji
n nie przymujących argumentów
m constant := (say 42, 10),
m say (call foo)
p def constant():
p print(42)
p return 10
p print(constant())
r def constant()
r puts(42)
r return 10
r end
r puts constant
n Instrukcja warunkowa
m if (n == 42)
m (say 1)
m (say 2)
p if n == 42:
p print(1)
p else:
p print(2)
r if n == 42
r puts 1
r else
r puts 2
r end
n Wyrażenie warunkowe
m x := if (n == 42) 1 2
p x = 1 if n == 42 else 2
r x = n == 42 ? 1 : 2
SECTION Tablice
n Kategoria
m Musique
p Python
r Ruby (SonicPi)
c Komentarz
n Tablice
m x = (1, 2, 3, 4)
p x = [1, 2, 3, 4]
r x = [1, 2, 3, 4]
c W Musique funkcja anonimowa nie przyjmująca argumentów
c jak i tablica są tożsame.
n Nty element tablicy
m x[n]
p x[n]
r x[n]
n Aktualizacja ntego elementu tablicy
m x = update x n 10
p x[n] = 10
r x[n] = 10
n Tablica od 0 do 9 włącznie
m x = up 10
p x = list(range(10))
r x = [*0..9]
n Tablica od 1 do 10 włącznie
m x = 1 + up 10
m lub x = range 1 11
p x = list(range(1, 11))
r x = [*1..10]
n Tablica od 9 do 0 włącznie
m x = down 10
m lub x = reverse (up 10)
p x = list(range(9, -1, -1))
p lub x = list(reversed(range(10)))
r x = 9.downto(0).to_a
n Iloczyn elementów tablicy
m fold '* (1 + up 5)
p functools.reduce(
p operator.mul, range(1, 6), 1)
r [*1..5].inject(:*)
c Musique pozwala zmienić dowolny operator w funkcję
c poprzez zapis 'operator jak '* w przykładzie
n Iteracja po elementach tablicy
m for (up 5) (i | say i)
p for i in range(5):
p print(i)
r (0..4).each do |i|
r puts i
r end
n Sortowanie tablicy
m xs := sort (1, 5, 3, 3, 2)
p xs = sorted([1, 5, 3, 3, 2])
r xs = [1, 5, 3, 3, 2].sort
n Sortowanie wielu tablic w jedną
m xs := sort (1, 5, 3, 3, 2)
m (3, 4, 5) 1 2 3
p xs = sorted(itertools.chain(
p [1, 5, 3, 3, 2], [3, 4, 5],
p [1], [2], [3]
p ))
r [[1, 5, 3, 3, 2], [3, 4, 5],
r [1], [2], [3]
r ].flatten.sort
c Wiele operacji na tablicach może być wykonywane na dowolnej kombinacji
c tablic i pojedyńczych wartości. Tworzy to jedną tablicę wykoniową.
SECTION Muzyka
n Kategoria
m Musique
r SonicPi
c Komentarz
n Zmiana tempa na 90
m bpm 90
r use_bpm 90
n Zmiana domyślnej długości nuty na półnutę
m len 1/2
c w SonicPi nie ma domyślnej długości nuty;
c za każdym razem trzeba ją definiować
n Zmiana oktawy do 4tej
m oct 4,
c w SonicPi domyślna oktawa
c jest ustalona jako 4
n C w 4 oktawie
m play c4
r play 60
n Akord C-dur
m play (c & e & g)
m lub play (chord c e g)
r play :C4
r play :E4
r play :G4
r lub play chord(:C4, :major)
n Akord C-dur w 8 oktawie
m play (c8 & e8 & g8)
r play :C8
r play :E8
r play :G8
r lub play chord(:C8, :major)
n C w 4 oktawie, półnuta
m play (c4 hn)
m lub play (c4 (1/2))
m lub play (c4 0.5)
r play 60, sustain: 2
c w SonicPi możliwa jest kontrola obwiedni ADSR za pomocą
c parametrów attack, delay, sustain i release
n Sekwencja C, E i G w oktawie 4, półnuty, <br />zagrane jedna po drugiej
m play (len (1/2), c4 e4 g4)
r [:C4, :E4, :G4].each do |i|
r play i, sustain: 2
r sleep 2
r end
n Sekwencja C, D, E, F, G,<br/>z nutą A graną przez cały czas trwania sekwencji
m par a (c, d, e, f, g)
r in_thread do
r [:C4, :D4, :E4, :F4, :G4].each do |i|
r play i
r sleep 1
r end
r end
r in_thread do
r play :A4, sustain: 5
r end
n Dwie melodie grane współbieżnie
m sim (c 4 c 3 c 2) (e 4 e 3 e 2)
r in_thread do
r [:C4, :C3, :C2].each do |i|
r play i
r sleep 1
r end
r end
r in_thread do
r [:E4, :E3, :E2].each do |i|
r play i
r sleep 1
r end
r end
n Zagranie losowej nuty spośród C, E, G
m play (pick (c e g))
r play choose([:C, :E, :G])
n Zagranie sekwencji nut C, E, G w losowej kolejności
m play (shuffle (c e g))
r [:C, :E, :G].shuffle().each do |i|
r play i, sustain: 1
r sleep 1
r end
n Zagranie sekwencji C, E, G od tyłu
m play (reverse (c e g))
r [:C, :E, :G].reverse.each do |i|
r play i, sustain: 1
r sleep 1
r end
END TABLE

180
doc/operators.md Normal file
View File

@ -0,0 +1,180 @@
# Lista wbudowanych operatorów języka Musique
## Operatory arytmetyczne
- `+` operator:
- dodawania (liczby całkowite i ułamki):
```
> 2 + 3
5
> (1/3) + (1/4)
7/12
> 1 + (up 10)
[1; 2; 3; 4; 5; 6; 7; 8; 9; 10]
```
- inkrementacji zmiennej (liczby lub akordu, w tym w szczególności pojedynczeń nuty):
```
> c + 1
c#
c4 + 2
hord[d; f#]
```
- `-` operator odejmowania/dekrementacji analogicznie do operatora `+`;
- `*` operator:
- mnożenia (liczby całkowite i ułamki):
```
> 2 * 5
10
> (1/3) * (1/4)
1/12
> 2 * (up 10)
[0; 2; 4; 6; 8; 10; 12; 14; 16; 18]
```
- powtarzania zwraca określoną liczbę powtórzeń danego dźwięku:
```
> a * 4
[a; a; a; a]
> a3 * 4
[chord[a; c]; chord[a; c]; chord[a; c]; chord[a; c]]
```
- `/` operator dzielenia *wektor może być wyłącznie dzielną*:
```
> 4 / 2
2
> 5 / 7
5/7
> (2/3) / (3/5)
10/9
> (up 10) / 2
[0; 1/2; 1; 3/2; 2; 5/2; 3; 7/2; 4; 9/2]
```
- `%` operator działania modulo (wynikiem jest reszta z dzielenia) *nie działa dla ułamków*, *wektor może być wyłącznie dzielną*:
```
> 3 % 3
0
> 6 % 5
1
> (up 10) % 2
[0; 1; 0; 1; 0; 1; 0; 1; 0; 1]
```
- `**` operator potęgowania *wykładnikiem nie może być ułamek*:
```
> 2 ** 8
256
> (2/3) ** 3
8/27
> (up 10) ** 2
[0; 1; 4; 9; 16; 25; 36; 49; 64; 81]
> 2 ** (up 10)
[1; 2; 4; 8; 16; 32; 64; 128; 256; 512]
```
## Operatory porównawcze
- `!=` operator "nie równa się":
```
> 2 != 3
true
> a != a
false
> 3 != (up 5)
[true; true; true; false; true]
```
- `<` operator "mniejsze niż":
```
> 2 < 3
true
> a < a
false
> 3 < (up 5)
[true; true; true; false; false]
```
- `<=` operator "mniejsze lub równe":
```
> 2 <= 3
true
> a <= a
true
> 3 <= 2
false
> 3 <= (up 5)
[true; true; true; true; false]
```
- `==` operator "równe":
```
> 2 == 3
false
> a == a
true
> 3 == (up 5)
[false; false; false; true; false]
```
- `>` operator "większe niż":
```
> 2 > 3
false
> a > a
true
> 3 > (up 5)
[false; false; false; false; true]
```
- `>=` operator "większe lub równe":
```
> 2 >= 3
false
> a >= a
true
> 3 >= 2
true
> 3 >= (up 5)
[false; false; false; true; true]
```
## Pozostałe operatory
- `.` operator indeksu (zwraca wskazany element, liczone od 0):
```
> A:=[1; 3; 5]
> A . 1
3
> (up 7).4
3
```
- `&` operator łączenia:
```
> c & a
chord[c; a]
> [1;3;5] & [2;4;6]
[1; 3; 5; 2; 4; 6]
> (up 7) & (down 9)
[0; 1; 2; 3; 4; 5; 6; 8; 7; 6; 5; 4; 3; 2; 1; 0]
```

View File

@ -1,5 +0,0 @@
Sphinx==4.5.0
breathe==4.33.1
exhale==0.3.1
recommonmark==0.7.1
sphinx-rtd-theme==1.0.0

View File

@ -1,54 +0,0 @@
program = { expression, ws*, ";", { ws*, ";" }, ws* } ;
block = "[", program, "]" ;
(* At interpreter runtime it is determined which symbols pass as operators, and which not *)
expression = value, ws*, operator, ws*, expression
| operator, ws*, value
| value ;
value = note
| chord
| symbol
| block
| number
| ( "(", expression, ")" ) ;
symbol = ( valid-symbol-start-characters, { valid-symbol-characters } ) - note - chord;
valid-symbol-start-characters = uniletter | "_" | "@" | "$" | "#" ;
valid-symbol-characters = valid-symbol-start-characters | unidigit | "-" ;
operator = operator-symbols, { operator-symbols } ;
operator-symbols = "+" | "-" | "*" | "/" | "%" | "!"
| "<" | ">" | "v" | "^" | "=" | ":" ;
(********************************* Literały liczbowe *********************************)
number = floating-point | fraction ;
(* Dopuszcza następujące zapisy: 1/2, *)
fraction = digits+, ws*, "/", ws*, digits+ ;
(* Dopuszcza następujące zapisy: -123.456, 123.456, .456; Notacja naukowa nie jest wspierana *)
floating-point = ( ["-"], digits+, [ ".", digits+ ] ) | ( ".", digits+ );
(********************************* Literały muzyczne *********************************)
(* DSL do definiowania muzycznych wartości. Brakuje notacji dla akordów, przewrotów itd *)
note = note-letter, ["#"], [ws*, octave] ;
note-letter = "c" | "C" | "d" | "D" | "e" | "E" | "f" | "F" | "g" | "G" | "a" | "A" | "h" | "H" | "b" | "B" ;
octave = "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" ;
chord = note-letter, ["#"], [ ("1" | "2" | "5" | "7" ), [ "," | "'" ] ];
(********************************* Definicje pomocnicze *********************************)
(* Unicode helpers, based on Go's compiler source code *)
uniletter = ? all characters that are considered letters in unicode ?;
unidigit = ? all characters that are considered digits in unicode ?;
digits+ = digit, { digits } ;
digit = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9" ;
(* Whitespace helpers *)
ws* = { ws } ;
ws+ = ws, { ws } ;
ws = ? all characters that are considered ascii whitespace ? ;

View File

@ -1,55 +0,0 @@
# This file only contains a selection of the most common options. For a full
# list see the documentation:
# https://www.sphinx-doc.org/en/master/usage/configuration.html
# -- Project information -----------------------------------------------------
project = 'Musique'
copyright = '2022, Robert Bendun'
author = 'Robert Bendun'
# -- General configuration ---------------------------------------------------
extensions = [
"sphinx_rtd_theme",
"breathe",
"recommonmark",
"exhale"
]
breathe_projects = {
"musique": "../build/doxygen/xml"
}
breathe_default_project = "musique"
exhale_args = {
"containmentFolder": "./api",
"rootFileName": "musique-root.rst",
"createTreeView": True,
"doxygenStripFromPath": ".."
}
primary_domain = "cpp"
highlight_language = "cpp"
# Add any paths that contain templates here, relative to this directory.
templates_path = ['_templates']
# List of patterns, relative to source directory, that match files and
# directories to ignore when looking for source files.
# This pattern also affects html_static_path and html_extra_path.
exclude_patterns = []
# -- Options for HTML output -------------------------------------------------
# The theme to use for HTML and HTML Help pages. See the documentation for
# a list of builtin themes.
#
html_theme = 'sphinx_rtd_theme'
# Add any paths that contain custom static files (such as style sheets) here,
# relative to this directory. They are copied after the builtin static files,
# so a file named "default.css" will overwrite the builtin "default.css".
html_static_path = ['_static']

View File

@ -1,22 +0,0 @@
.. Musique documentation master file, created by
sphinx-quickstart on Sun May 8 17:37:28 2022.
You can adapt this file completely to your liking, but it should at least
contain the root `toctree` directive.
Welcome to Musique's documentation!
===================================
.. toctree::
:maxdepth: 2
:caption: Contents:
api/musique-root
Indices and tables
==================
* :ref:`genindex`
* :ref:`modindex`
* :ref:`search`

298
doc/wprowadzenie.md Normal file
View File

@ -0,0 +1,298 @@
---
title: Wprowadzenie do języka Musique
date: 2022-11-12
author: Robert Bendun <robben@st.amu.edu.pl>
---
# Wprowadzenie do języka Musique
W dalszej części tekstu przyjmujemy następujące konwencje:
`>` jest to [znak zachęty](https://pl.wikipedia.org/wiki/Znak_zach%C4%99ty) i wskazuje gotowość programu Musique do wprowadzania tekstu. Jeżeli widzisz taki znak, oznacza to, że jesteś w programie Musique.
Przykładowo:
```
> 3 + 4
7
>
```
W tym przykładzie wykonujemy `3 + 4` , zatwierdzając ENTEREM, w zwrocie otrzymując w tym konkretnym przypadku wynik operacji.
Przykłady w tym wprowadzeniu mogą rozpoczynać się od `>` oznacza to, że polecenia wprowadzono w sesji interaktywnej, lub bez tego znaku wtedy traktujemy przykład jako zapisany plik z poleceniami.
Nie ma różnic pomiędzy wykonywaniem poleceń języka Musique zawartych w pliku, a poleceniami wprowadzanymi w sesji interaktywnej wybór pozostawiamy użytkownikowi.
Można wykonać złożone polecenia (które w pliku zostałyby rozbite na kilka linii) w sesji interaktywnej - należy wtedy wpisać je w formie jednej linii.
## Nuty, pauzy, akordy
W tej sekcji zostanie omówione tworzenie prostych utworów z wykorzystaniem nut, akordów oraz prostych sekwencji.
### Nuty
Aby zagrać nutę C wpisz `play c` w uruchomionym programie Musique.
```
> play c
```
Możesz zagrać inną nutę jak E:
```
> play e
```
lub wiele nut po kolei należy umieścić je w nawiasach okrągłych, rozdzielone przecinkami:
```
> play (c, e, g)
```
Dostępne dźwięki bazowe to kolejno: `c`, `d`, `e`, `f`, `g`, `a`, `b`. Można je modyfikować poprzez znaki:
- `#` lub `s` podwyższający wysokość dźwięku o pół tonu (krzyżyk, **s**harp)
- `b` lub `f` obniżający wysokość dźwięku o pół tonu (**b**emol, **f**lat)
pozwala to przykładowo tworzyć:
- `c#` - dźwięk Cis
- `c##` - dźwięk D
- `eb` - dźwięk Dis
Aby dźwięk został odtworzony w wybranej oktawie można dołączyć do znaku dźwięku liczbową wartość oktawy - `c4` to dźwięk C w 4 oktawie, `c#8` to dźwięk Cis w 8 oktawie, itp.
```
> play (c4, c5, c6)
```
Aby dźwięk trwał określoną długość należy podać jako dodatkowy parametr pożądaną wartość, przykładowo:
Sekwencja złożona z dźwięku C w 4. oktawie trwającym ćwierćnutę, dźwięku D w 5. oktawie trwającym półnutę oraz dźwięku E w 4. oktawie trwającym całą nutę wygląda następująco:
```
> play (c4 (1/4), d5 (1/2), e4 1)
```
Można uprościć zapis korzystając z predefiniowanych czasów dźwięków:
| nazwa | czas trwania | liczbowo |
| :-: | :-: | :-: |
| `wn` | cała nuta | `1` |
| `dwn` | cała nuta z kropką | `3/2` |
| `hn` | półnuta | `1/2` |
| `dhn` | półnuta z kropką | `3/4` |
| `qn` | ćwierćnuta | `1/4` |
| `dqn` | ćwierćnuta z kropką | `3/8` |
| `en` | ósemka | `1/8` |
| `den` | ósemka z kropką | `3/16` |
| `sn` | szesnastka | `1/16` |
| `dsn` | szesnastka z kropką | `3/32` |
| `tn` | trzydziestkadwójka | `1/32` |
Korzystając z tych długości możemy powyższy przykład zapisać równoważnie w ten sposób:
```
> play (c4 qn, d5 hn, e4 1)
```
### Pauzy
Pauzy stosuje się poprzez użycie litery `p`:
```
> play (c4 hn, p qn, c4 hn, p qn, c4 hn)
```
Pauzy zachowują się identycznie jak nuty opisane powyżej.
### Akordy
Aby odegrać akord należy umieścić symbole dźwięków, z których miałby się składać, w wywołaniu funkcji `chord`:
```
> play (chord (c, e, g))
```
W utworze możemy chcieć częściej używać tych samych akordów czy sekwencji. Przypisanie ich do wybranej nazwy wyglądałoby tak:
```
> sekwencja := (c, e, g)
> sekwencja
(c, e, g)
```
Wpisanie samej nazwy pozwala zobaczyć co się pod nią znajduje.
Zapisaną sekwencję możemy przerobić na akord, ponownie wykorzystując funkcję `chord`:
```
> C := chord sekwencja
> C
chord (c, e, g)
```
i następnie go odtworzyć:
```
> play C
```
Należy zwrócić uwagę, że Musique rozróżnia wielkość liter. Ponadto nazw będących oznaczeniami dźwięków jak `c` bądź `cffff` nie można używać jako nazw dla zmiennych.
## Metody tworzenia sekwencji
### Wielokrotne powtarzanie tego samego dźwięku
Wielokrotne powtarzanie tego samego dźwięku można osiągnąć poprzez mnożenie dźwięku przez ilość powtórzeń:
```
> 3 * c
(c, c, c)
> c * 3
(c, c, c)
> 3 * (c, e)
(c, e, c, e, c, e)
```
Operacja ta zachowuje długości i oktawy:
```
> 3 * (e4 qn, f8 tn)
(e4 1/4, f8 1/32, e4 1/4, f8 1/32, e4 1/4, f8 1/32)
```
### Wybieranie losowego dźwięku z grupy
Funkcja `pick` pozwala na wybór losowego elementu z sekwencji. Można użyć jej np. do grania dźwięku o losowej długości:
```
> play (c4 (pick qn hn))
```
W powyższym przykładzie dźwięk C w oktawie 4. zostanie zagrany losowo z długością ćwierćnuty lub półnuty.
### Losowe ustawienie elementów sekwencji
Funkcja `shuffle` pozwala na tworzenie sekwencji z losową kolejnością elementów, np:
```
> shuffle (c, e, f, g)
(f, g, e, c)
```
### Generowanie sekwencji w oparciu o liczbę półtonów
`dźwięk + liczba` przesuwa dany dźwięk o daną liczbę półtonów. Pozwala to tworzyć następujące sekwencje:
```
> c4 + (0, 1, 2, 3)
(c4, c#4, d4, d#4)
```
Podobny efekt można uzyskać funkcję `up` jako generator wartości liczbowych:
```
> up 5
(0, 1, 2, 3, 4)
> c4 + up 4
(c4, c#4, d4, d#4, e4)
> play (c4 + up 4)
```
Analogicznie działa funkcja `down`, generująca wartości liczbowe w kierunku zera:
```
> down 5
(4, 3, 2, 1, 0)
> c4 + down 5
(e4, d#4, d4, c#4, c4)
> play (c4 + down 5)
```
Możemy złączyć sekwencje przy pomocy operatora `&`:
```
> up 5 & down 5
(0, 1, 2, 3, 4, 4, 3, 2, 1, 0)
> play (c4 + up 5 & down 5)
```
Jeśli przeszkadza nam podwójnie zagrana nuta `e4` możemy ją wyeliminować funkcją `uniq`, która usuwa sąsiadujące ze sobą powtórzenia:
```
> uniq (up 5 & down 5)
(0, 1, 2, 3, 4, 3, 2, 1, 0)
> play (c4 + uniq (up 5 & down 5))
```
## Metody odtwarzania sekwencji
Musique posiada trzy główne metody odtwarzania sekwencji:
- `play` które odtwarza dźwięki w kolejności
- `par` które odtwarza pierwszy dźwięk równocześnie z pozostałymi
- `sim` który odtwarza każdą podaną mu sekwencję równocześnie
Każda z nich w momencie napotkania dźwięku z nieokreśloną oktawą lub długością wypełni ją według wartości *domyślnej* (wartości domyślne to: 4. oktawa, 120 bpm, ćwierćnuta).
Wartości domyślne można ustawiać przy pomocy funkcji `oct`, `len` oraz `bpm`. Poniższy przykład ustawia domyślną oktawę na 5, domyślną długość na półnutę oraz domyślne tempo na 100 uderzeń na minutę:
```
> oct 5
> len hn
> bpm 100
```
### `play`
`play` przechodzi kolejno przez elementy sekwencji i kończy się po odtworzeniu wszystkich dźwięków.
Jeśli chcemy wykonać kilka `play` po sobie, możemy to osiągnąć rozdzielając je przecinkami analogicznie do wspomnianych wcześniej sekwencji:
```
play (c qn, e qn, g hn),
play (16 * (f sn)),
play (c qn, e qn, g hn),
```
Uwaga powyższy przykład reprezentuje polecenia zapisane w pliku (stosujemy konwencję rozszerzenia `.mq`) wskazuje na to brak znaku zachęty `>`.
Można ten zapis uprościć:
```
play (
(c qn, e qn, g hn),
(16 * (f sn)),
(c qn, e qn, g hn),
),
```
gdzie wcięcia i nowe linie zostały dodane dla poprawy czytelności.
### `par`
`par` umożliwa wykonanie pierwszego argumentu przez całą długość trwania pozostałych - niezależnie od tego jaka długość dźwięku została określona dla pierwszego z nich, zostanie dopasowany do sumy długości pozostałych dźwięków.
Przykład inspirowany Odą do Radości, w którym akord trwa przez całą długość odtwarzania sekwencyjnie pozostałych dźwięków. Wcześniej ustawiamy domyślną oktawę jako 5, by nie musieć powtarzać jej przy każdym dźwięku:
```
oct 5,
par (chord c3 g3 c4) (e, e, f, g)
```
### `sim`
`sim` umożliwia wykonywanie równocześnie kilku sekwencji.
Poniżej "niepoprawna" metoda stworzenia akordu poprzez równocześne odtworzenie dźwięków c, e, g:
```
> sim c e g
```
Trzy dźwięki C w domyślnej oktawie o długości ćwierćnuty odtwarzane równocześnie wraz z pauzą ćwierćnutową i czterema dźwiękami D w 5. oktawie o długości szesnastki:
```
> sim (3 * c qn) (p qn, 4 * (d5 sn))
```

42
editor/musique.vim Normal file
View File

@ -0,0 +1,42 @@
" Vim syntax file
" Language: Musique
" Maintainer: Robert Bendun
" Latest Change: 2022-05-22
" Filenames: *.mq
if exists("b:current_syntax")
finish
endif
syn keyword musiqueVariableDeclaration :=
syn keyword musiqueOperators * + - / < <= == >= > != . ** and or
syn match musiqueParameterSplitter display "|"
syn match musiqueExpressionDelimiter display ";"
syn match musiqueInteger display "[0-9][0-9_]*"
syn keyword musiqueConstant true false nil
syn keyword musiqueDefaultBuiltins bpm call ceil chord down flat floor fold for hash if incoming instrument len max min mix note_off note_on nprimes oct par partition permute pgmchange play program_change range reverse rotate round shuffle sim sort try typeof uniq unique up update
syn keyword musiqueLinuxBuiltins say
syn match musiqueComment "--.*$"
syn match musiqueComment "#!.*$"
syn region musiqueComment start="----*" end="----*"
syn region musiqueBlock matchgroup=musiqueParen start="\[" skip="|.\{-}|" matchgroup=musiqueParen end="\]" fold transparent
let b:current_syntax = "musique"
hi def link musiqueVariableDeclaration Define
hi def link musiqueParameterSplitter Delimiter
hi def link musiqueExpressionDelimiter Delimiter
hi def link musiqueParen Delimiter
hi def link musiqueOperators Operator
hi def link musiqueComment Comment
hi def link musiqueInteger Number
hi def link musiqueConstant Constant
hi def link musiqueDefaultBuiltins Function
hi def link musiqueLinuxBuiltins Function

View File

@ -0,0 +1,17 @@
// A launch configuration that launches the extension inside a new window
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
{
"version": "0.2.0",
"configurations": [
{
"name": "Extension",
"type": "extensionHost",
"request": "launch",
"args": [
"--extensionDevelopmentPath=${workspaceFolder}"
]
}
]
}

View File

@ -0,0 +1,4 @@
.vscode/**
.vscode-test/**
.gitignore
vsc-extension-quickstart.md

View File

@ -0,0 +1,9 @@
# Change Log
All notable changes to the "musique" extension will be documented in this file.
Check [Keep a Changelog](http://keepachangelog.com/) for recommendations on how to structure this file.
## [Unreleased]
- Initial release

View File

@ -0,0 +1,65 @@
# musique README
This is the README for your extension "musique". After writing up a brief description, we recommend including the following sections.
## Features
Describe specific features of your extension including screenshots of your extension in action. Image paths are relative to this README file.
For example if there is an image subfolder under your extension project workspace:
\!\[feature X\]\(images/feature-x.png\)
> Tip: Many popular extensions utilize animations. This is an excellent way to show off your extension! We recommend short, focused animations that are easy to follow.
## Requirements
If you have any requirements or dependencies, add a section describing those and how to install and configure them.
## Extension Settings
Include if your extension adds any VS Code settings through the `contributes.configuration` extension point.
For example:
This extension contributes the following settings:
* `myExtension.enable`: Enable/disable this extension.
* `myExtension.thing`: Set to `blah` to do something.
## Known Issues
Calling out known issues can help limit users opening duplicate issues against your extension.
## Release Notes
Users appreciate release notes as you update your extension.
### 1.0.0
Initial release of ...
### 1.0.1
Fixed issue #.
### 1.1.0
Added features X, Y, and Z.
---
## Working with Markdown
You can author your README using Visual Studio Code. Here are some useful editor keyboard shortcuts:
* Split the editor (`Cmd+\` on macOS or `Ctrl+\` on Windows and Linux).
* Toggle preview (`Shift+Cmd+V` on macOS or `Shift+Ctrl+V` on Windows and Linux).
* Press `Ctrl+Space` (Windows, Linux, macOS) to see a list of Markdown snippets.
## For more information
* [Visual Studio Code's Markdown Support](http://code.visualstudio.com/docs/languages/markdown)
* [Markdown Syntax Reference](https://help.github.com/articles/markdown-basics/)
**Enjoy!**

View File

@ -0,0 +1,26 @@
{
"comments": {
// symbol used for single line comment. Remove this entry if your language does not support line comments
"lineComment": "--",
// symbols used for start and end a block comment. Remove this entry if your language does not support block comments
"blockComment": [ "/*", "*/" ]
},
// symbols used as brackets
"brackets": [
["{", "}"],
["[", "]"],
["(", ")"]
],
// symbols that are auto closed when typing
"autoClosingPairs": [
["{", "}"],
["[", "]"],
["(", ")"]
],
// symbols that can be used to surround a selection
"surroundingPairs": [
["{", "}"],
["[", "]"],
["(", ")"]
]
}

View File

@ -0,0 +1,25 @@
{
"name": "musique",
"displayName": "Musique",
"description": "Support for Musique, programming language for musical expression",
"version": "0.0.1",
"engines": {
"vscode": "^1.72.0"
},
"categories": [
"Programming Languages"
],
"contributes": {
"languages": [{
"id": "musique",
"aliases": ["Musique", "musique"],
"extensions": [".mq"],
"configuration": "./language-configuration.json"
}],
"grammars": [{
"language": "musique",
"scopeName": "source.musique",
"path": "./syntaxes/musique.tmLanguage.json"
}]
}
}

View File

@ -0,0 +1,64 @@
{
"$schema": "https://raw.githubusercontent.com/martinring/tmlanguage/master/tmlanguage.json",
"name": "Musique",
"foldingStartMarker": "\\[",
"foldingStopMarker": "^\\s*\\]|^\\s\\]",
"fileTypes": [
".mq"
],
"patterns": [
{
"include": "#numeric"
},
{
"match": ":=",
"name": "keyword.operator.declaration"
},
{
"match": "--[^-].*$",
"name": "comment.line.double-dash"
},
{
"begin": "--+",
"end": "--+",
"name": "comment.block"
},
{
"match": "\\b(nil)\\b",
"name": "constant.language.nil"
},
{
"match": "\\b(a|b|c|d|e|f|g|h)[#sfb]?\\d*\\b",
"name": "constant.language.music"
},
{
"match": "\\b(true|false)\\b",
"name": "constant.language.boolean"
},
{
"match": "\\b(bpm|call|ceil|chord|down|flat|floor|fold|for|hash|if|instrument|len|max|min|mix|note_off|note_on|nprimes|oct|par|partition|permute|pgmchange|play|program_change|range|reverse|rotate|round|scan|shuffle|sim|sort|try|typeof|uniq|unique|up|update|say)\\b",
"name": "entity.name.function.builtins"
},
{
"match": "(\\*|\\+|\\-|\/|\\\\)",
"name": "keyword.operator.arithmetic"
},
{
"match": "---+()",
"begin": "/---+/",
"end": "/---+/",
"name": "comment.block.musique"
}
],
"repository": {
"numeric": {
"patterns": [
{
"match": "(?<!\\w)-?[0-9]+",
"name": "constant.numeric.integer.musique"
}
]
}
},
"scopeName": "source.musique"
}

View File

@ -0,0 +1,29 @@
# Welcome to your VS Code Extension
## What's in the folder
* This folder contains all of the files necessary for your extension.
* `package.json` - this is the manifest file in which you declare your language support and define the location of the grammar file that has been copied into your extension.
* `syntaxes/musique.tmLanguage.json` - this is the Text mate grammar file that is used for tokenization.
* `language-configuration.json` - this is the language configuration, defining the tokens that are used for comments and brackets.
## Get up and running straight away
* Make sure the language configuration settings in `language-configuration.json` are accurate.
* Press `F5` to open a new window with your extension loaded.
* Create a new file with a file name suffix matching your language.
* Verify that syntax highlighting works and that the language configuration settings are working.
## Make changes
* You can relaunch the extension from the debug toolbar after making changes to the files listed above.
* You can also reload (`Ctrl+R` or `Cmd+R` on Mac) the VS Code window with your extension to load your changes.
## Add more language features
* To add features such as IntelliSense, hovers and validators check out the VS Code extenders documentation at https://code.visualstudio.com/docs
## Install your extension
* To start using your extension with Visual Studio Code copy it into the `<user home>/.vscode/extensions` folder and restart Code.
* To share your extension with the world, read on https://code.visualstudio.com/docs about publishing an extension.

View File

@ -1,3 +0,0 @@
say (1 + 3);
say (3 * 10);
say 42

View File

@ -0,0 +1,27 @@
----------------------------------
Simple variable assigment
----------------------------------
x := 10,
y := 20,
say x,
say y,
x = 30,
say x,
say y,
x = y,
say x,
say y,
----------------------------------
Array updates
----------------------------------
array := flat 1 2 3,
say array,
array = update array 1 10,
say array,
array = update array 1 (array.2),
say array,

View File

@ -0,0 +1,5 @@
map := (fn array | result := (), for array (v | result = result & (| fn v) ), result),
drop := (n arr | arr[range n (len arr)]),
take := (n arr | arr[up n]),
filter := (predicate arr | arr[map predicate arr]),

13
examples/control-flow.mq Normal file
View File

@ -0,0 +1,13 @@
say (if true 4 2),
say (if false 4 2),
if true (say 4) (say 2),
if false (say 4) (say 2),
n := 0,
while (n < 5) (
say 'while n,
n = n + 1,
),

View File

@ -1,12 +1,30 @@
var for = [ start stop iteration |
if (start > stop)
[| nil ]
[| iteration start; for (start + 1) stop iteration ]
];
----------------------------------------------------------------------------
This example shows how to implement factorial operation using different
implementation techniques, showing how one can iterate and accumulate
using Musique programming language
----------------------------------------------------------------------------
var factorial = [n | if (n <= 1)
[| 1]
[| n * (factorial (n-1)) ]
];
-- Calculate factorial using recursive approach
factorial_recursive := (n |
if (n <= 1)
1
(n * (factorial_recursive (n-1)))
),
for 1 10 [i | say (factorial i)];
-- Calculate factorial using iterative approach
factorial_iterative := (n |
x := 1,
for (range 1 (n+1)) (i | x *= i),
x
),
-- Calculate factorial using composition of functions
factorial := (n | fold '* 1 (1 + up n)),
-- Gather all functions into array, and iterate over it
-- This allows to reduce repeatition of this test case
for (factorial_recursive, factorial_iterative, factorial) ( factorial |
for (up 10) ( n |
say (factorial (n)),
)
),

5
examples/fib.mq Normal file
View File

@ -0,0 +1,5 @@
fib := (n |
if (n <= 1)
n
(fib (n-1) + fib (n-2))
),

65
examples/for-elise.mq Normal file
View File

@ -0,0 +1,65 @@
----------------------------------------------
"Für Elise in A Minor" by Ludwig van Beethoven
WIP implemntation
----------------------------------------------
oct 5, bpm 72, len (1/16),
subsection1 := (
sim (a4 en) (a2 e3 a3),
play (oct 4, c e a),
sim (b4 en) (e2 e3 g#3),
play (oct 4, e g# b),
sim (c5 en) (a2 e3 a3),
play (e4 e5 d#5),
play e d# e b4 d c,
sim (a4 en) (a2 e3 a3),
play c4 e4 a4,
sim (b4 en) (e2 e3 g#3),
play d4 c5 b4,
),
section1 := ( n |
play e d#,
play e d# e b4 d c,
call subsection1,
if (n == 1)
( sim (a4 qn) (a2 e3 a3) )
( sim (a4 en) (a2 e3 a3)
, play b4 c5 d5
)
),
section2 := ( n |
sim (e5 den) (c3 g3 c4),
play g4 f e,
sim (d5 den) (g2 g3 b4),
play f4 e d,
sim (c5 den) (a2 e3 a3),
play e4 d c,
sim (b4 en) (e2 e3 e4),
play (e4 e5 e4 e4 e5 e6 d#5 e5 d#5 e5 en),
play d# e d# e d#,
play e d# e b4 d c,
call subsection1,
if (n == 1)
( sim (a4 en) (a2 e3 a3)
, play (b4 c5 d5)
)
),
section1 1,
section1 2,
section2 1,

21
examples/noises.mq Normal file
View File

@ -0,0 +1,21 @@
hand1_pool := (
chord g#3 g4,
chord d#3 d4,
chord g3 g#4,
chord d3 d#4,
),
hand2_pool := (d8, d#8, g8, g#8, d9, d#9),
for (up 10) (
hand1_length := pick (hn, dhn),
say hand1_length,
hand1 := (set_len hand1_length (pick hand1_pool)),
hand2 := (),
while (duration hand2 != hand1_length) (
hand2 = flat hand2 (set_len (1/64) (pick hand2_pool)),
),
sim hand1 hand2,
),

13
examples/ode-to-joy.mq Normal file
View File

@ -0,0 +1,13 @@
C := chord c3 g3 c4,
G := chord g3 d4 g4,
oct 5,
par C e e f g,
par G g f e d,
par C c c d e,
par G (e5 (3/8) d5 (1/8) d5 (1/2)),
par C e e f g,
par G g f e d,
par C c c d e,
par G (d5 (1/2) c5 (1/8)),
par C (c5 1),

11
examples/permutations.mq Normal file
View File

@ -0,0 +1,11 @@
factorial := (n | fold '* (1 + up n)),
list_all_permutations := ( array |
for (up (factorial (len array))) (|
say array,
array = permute array,
),
),
list_all_permutations (1 + up 5),

6
examples/random-rythm.mq Normal file
View File

@ -0,0 +1,6 @@
for (up 10) (n |
snd := c + (pick (up 12)),
o := if (n % 2 == 0) 3 4,
say snd o,
play (oct o, snd qn),
),

View File

@ -0,0 +1,40 @@
--------------------------------------------------------------
Inspired by Marc Evanstein video "The Rythm of The Primes"
Link: https://www.youtube.com/watch?v=8x374slJGuo
This program will iterate over natural numbers, playing chords
based on which prime divides given number. This results in
following execution:
step: 2 3 4 5 6 7 8 9 10
1 1 1 1 1
2 2 2
3 3
where each index corresponds to specific note from scale.
Assuming scale [c,d,e] example above would be
step: 2 3 4 5 6 7 8 9 10
c c c c c
d d d
e e
which would resolve into:
play c d c e (c & d) c d (c & e)
--------------------------------------------------------------
Length := 40,
cmajor := (c,d,e,f,g),
scale := reverse cmajor,
primes := nprimes (len scale),
indicies := up (len scale),
oct 3,
len (1/16),
for (2 + up Length) ( i |
play (chord scale[indicies[i % primes == 0]]),
),

13
examples/sandattack.mq Normal file
View File

@ -0,0 +1,13 @@
bpm 150,
len sn,
play (
oct 3, 4 * h, h3 en,
oct 3, 6 * h, h3 en,
oct 4, 7 * e,
oct 4, 6 * d,
oct 3, a, a, 5 * h,
oct 3, 7 * h,
oct 4, 2 * d, 4 * h3, h3 en
),

View File

@ -1,2 +0,0 @@
var x = 10;
say (x + 1)

164
instruments.mq Normal file
View File

@ -0,0 +1,164 @@
---------------------------------------------------------
List of MIDI programs as defined by General MIDI standard.
This may be unsupported by your device.
---------------------------------------------------------
-- Piano ------------------------------------------------
AcousticGrandPiano := 0,
BrightAcousticPiano := 1,
ElectricGrandPiano := 2,
HonkyTonkPiano := 3,
RhodesPiano := 4,
ChorusedPiano := 5,
Harpsichord := 6,
Clavinet := 7,
-- Chromatic percussion ---------------------------------
Celesta := 8,
Glockenspiel := 9,
MusicBox := 10,
Vibraphone := 11,
Marimba := 12,
Xylophone := 13,
TubularBells := 14,
Dulcimer := 15,
-- Organ ------------------------------------------------
HammondOrgan := 16,
PercussiveOrgan := 17,
RockOrgan := 18,
ChurchOrgan := 19,
ReedOrgan := 20,
Accordion := 21,
Harmonica := 22,
TangoAccordion := 23,
-- Guitar -----------------------------------------------
AcousticGuitarNylon := 24,
AcousticGuitarSteel := 25,
ElectricGuitarJazz := 26,
ElectricGuitarClean := 27,
ElectricGuitarMuted := 28,
OverdrivenGuitar := 29,
DistortionGuitar := 30,
GuitarHarmonics := 31,
-- Bass -------------------------------------------------
AcousticBass := 32,
ElectricBassFingered := 33,
ElectricBassPicked := 34,
FretlessBass := 35,
SlapBass1 := 36,
SlapBass2 := 37,
SynthBass1 := 38,
SynthBass2 := 39,
-- Solo strings -----------------------------------------
Violin := 40,
Viola := 41,
Cello := 42,
Contrabass := 43,
TremoloStrings := 44,
PizzicatoStrings := 45,
OrchestralHarp := 46,
Timpani := 47,
-- Ensamble ---------------------------------------------
StringEnsemble1 := 48,
StringEnsemble2 := 49,
SynthStrings1 := 50,
SynthStrings2 := 51,
ChoirAahs := 52,
VoiceOohs := 53,
SynthVoice := 54,
OrchestraHit := 55,
-- Brass ------------------------------------------------
Trumpet := 56,
Trombone := 57,
Tuba := 58,
MutedTrumpet := 59,
FrenchHorn := 60,
BrassSection := 61,
SynthBrass1 := 62,
SynthBrass2 := 63,
-- Reed -------------------------------------------------
SopranoSax := 64,
AltoSax := 65,
TenorSax := 66,
BaritoneSax := 67,
Oboe := 68,
EnglishHorn := 69,
Bassoon := 70,
Clarinet := 71,
-- Pipe -------------------------------------------------
Piccolo := 72,
Flute := 73,
Recorder := 74,
PanFlute := 75,
BlownBottle := 76,
Shakuhachi := 77,
Whistle := 78,
Ocarina := 79,
-- Synth lead -------------------------------------------
Lead1Square := 80,
Lead2Sawtooth := 81,
Lead3Calliope := 82,
Lead4Chiff := 83,
Lead5Charang := 84,
Lead6Voice := 85,
Lead7Fifths := 86,
Lead8BassLead := 87,
-- Synth pad --------------------------------------------
Pad1NewAge := 88,
Pad2Warm := 89,
Pad3Polysynth := 90,
Pad4Choir := 91,
Pad5Bowed := 92,
Pad6Metallic := 93,
Pad7Halo := 94,
Pad8Sweep := 95,
-- Synth effects ----------------------------------------
FX1Train := 96,
FX2Soundtrack := 97,
FX3Crystal := 98,
FX4Atmosphere := 99,
FX5Brightness := 100,
FX6Goblins := 101,
FX7Echoes := 102,
FX8SciFi := 103,
-- Ethnic -----------------------------------------------
Sitar := 104,
Banjo := 105,
Shamisen := 106,
Koto := 107,
Kalimba := 108,
Bagpipe := 109,
Fiddle := 110,
Shanai := 111,
-- Percussive -------------------------------------------
TinkleBell := 112,
Agogo := 113,
SteelDrums := 114,
Woodblock := 115,
TaikoDrum := 116,
MelodicDrum := 117,
SynthDrum := 118,
ReverseCymbal := 119,
-- Sound effects ----------------------------------------
GuitarFretNoise := 120,
BreathNoise := 121,
Seashore := 122,
BirdTweet := 123,
TelephoneRing := 124,
Helicopter := 125,
Applause := 126,
Gunshot := 127,

4
lib/asio/COPYING Normal file
View File

@ -0,0 +1,4 @@
Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
Distributed under the Boost Software License, Version 1.0. (See accompanying
file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)

2
lib/asio/include/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
Makefile
Makefile.in

View File

@ -0,0 +1,658 @@
# find . -name "*.*pp" | sed -e 's/^\.\///' | sed -e 's/^.*$/ & \\/' | sort
nobase_include_HEADERS = \
asio/any_io_executor.hpp \
asio/associated_allocator.hpp \
asio/associated_cancellation_slot.hpp \
asio/associated_executor.hpp \
asio/associator.hpp \
asio/async_result.hpp \
asio/awaitable.hpp \
asio/basic_datagram_socket.hpp \
asio/basic_deadline_timer.hpp \
asio/basic_file.hpp \
asio/basic_io_object.hpp \
asio/basic_random_access_file.hpp \
asio/basic_raw_socket.hpp \
asio/basic_readable_pipe.hpp \
asio/basic_seq_packet_socket.hpp \
asio/basic_serial_port.hpp \
asio/basic_signal_set.hpp \
asio/basic_socket_acceptor.hpp \
asio/basic_socket.hpp \
asio/basic_socket_iostream.hpp \
asio/basic_socket_streambuf.hpp \
asio/basic_streambuf_fwd.hpp \
asio/basic_streambuf.hpp \
asio/basic_stream_file.hpp \
asio/basic_stream_socket.hpp \
asio/basic_waitable_timer.hpp \
asio/basic_writable_pipe.hpp \
asio/bind_allocator.hpp \
asio/bind_cancellation_slot.hpp \
asio/bind_executor.hpp \
asio/buffered_read_stream_fwd.hpp \
asio/buffered_read_stream.hpp \
asio/buffered_stream_fwd.hpp \
asio/buffered_stream.hpp \
asio/buffered_write_stream_fwd.hpp \
asio/buffered_write_stream.hpp \
asio/buffer.hpp \
asio/buffer_registration.hpp \
asio/buffers_iterator.hpp \
asio/cancellation_signal.hpp \
asio/cancellation_state.hpp \
asio/cancellation_type.hpp \
asio/co_spawn.hpp \
asio/completion_condition.hpp \
asio/compose.hpp \
asio/connect.hpp \
asio/connect_pipe.hpp \
asio/coroutine.hpp \
asio/deadline_timer.hpp \
asio/defer.hpp \
asio/detached.hpp \
asio/detail/array_fwd.hpp \
asio/detail/array.hpp \
asio/detail/assert.hpp \
asio/detail/atomic_count.hpp \
asio/detail/base_from_cancellation_state.hpp \
asio/detail/base_from_completion_cond.hpp \
asio/detail/bind_handler.hpp \
asio/detail/blocking_executor_op.hpp \
asio/detail/buffered_stream_storage.hpp \
asio/detail/buffer_resize_guard.hpp \
asio/detail/buffer_sequence_adapter.hpp \
asio/detail/bulk_executor_op.hpp \
asio/detail/call_stack.hpp \
asio/detail/chrono.hpp \
asio/detail/chrono_time_traits.hpp \
asio/detail/completion_handler.hpp \
asio/detail/concurrency_hint.hpp \
asio/detail/conditionally_enabled_event.hpp \
asio/detail/conditionally_enabled_mutex.hpp \
asio/detail/config.hpp \
asio/detail/consuming_buffers.hpp \
asio/detail/cstddef.hpp \
asio/detail/cstdint.hpp \
asio/detail/date_time_fwd.hpp \
asio/detail/deadline_timer_service.hpp \
asio/detail/dependent_type.hpp \
asio/detail/descriptor_ops.hpp \
asio/detail/descriptor_read_op.hpp \
asio/detail/descriptor_write_op.hpp \
asio/detail/dev_poll_reactor.hpp \
asio/detail/epoll_reactor.hpp \
asio/detail/eventfd_select_interrupter.hpp \
asio/detail/event.hpp \
asio/detail/executor_function.hpp \
asio/detail/executor_op.hpp \
asio/detail/fd_set_adapter.hpp \
asio/detail/fenced_block.hpp \
asio/detail/functional.hpp \
asio/detail/future.hpp \
asio/detail/gcc_arm_fenced_block.hpp \
asio/detail/gcc_hppa_fenced_block.hpp \
asio/detail/gcc_sync_fenced_block.hpp \
asio/detail/gcc_x86_fenced_block.hpp \
asio/detail/global.hpp \
asio/detail/handler_alloc_helpers.hpp \
asio/detail/handler_cont_helpers.hpp \
asio/detail/handler_invoke_helpers.hpp \
asio/detail/handler_tracking.hpp \
asio/detail/handler_type_requirements.hpp \
asio/detail/handler_work.hpp \
asio/detail/hash_map.hpp \
asio/detail/impl/buffer_sequence_adapter.ipp \
asio/detail/impl/descriptor_ops.ipp \
asio/detail/impl/dev_poll_reactor.hpp \
asio/detail/impl/dev_poll_reactor.ipp \
asio/detail/impl/epoll_reactor.hpp \
asio/detail/impl/epoll_reactor.ipp \
asio/detail/impl/eventfd_select_interrupter.ipp \
asio/detail/impl/handler_tracking.ipp \
asio/detail/impl/io_uring_descriptor_service.ipp \
asio/detail/impl/io_uring_file_service.ipp \
asio/detail/impl/io_uring_service.hpp \
asio/detail/impl/io_uring_service.ipp \
asio/detail/impl/io_uring_socket_service_base.ipp \
asio/detail/impl/kqueue_reactor.hpp \
asio/detail/impl/kqueue_reactor.ipp \
asio/detail/impl/null_event.ipp \
asio/detail/impl/pipe_select_interrupter.ipp \
asio/detail/impl/posix_event.ipp \
asio/detail/impl/posix_mutex.ipp \
asio/detail/impl/posix_serial_port_service.ipp \
asio/detail/impl/posix_thread.ipp \
asio/detail/impl/posix_tss_ptr.ipp \
asio/detail/impl/reactive_descriptor_service.ipp \
asio/detail/impl/reactive_socket_service_base.ipp \
asio/detail/impl/resolver_service_base.ipp \
asio/detail/impl/scheduler.ipp \
asio/detail/impl/select_reactor.hpp \
asio/detail/impl/select_reactor.ipp \
asio/detail/impl/service_registry.hpp \
asio/detail/impl/service_registry.ipp \
asio/detail/impl/signal_set_service.ipp \
asio/detail/impl/socket_ops.ipp \
asio/detail/impl/socket_select_interrupter.ipp \
asio/detail/impl/strand_executor_service.hpp \
asio/detail/impl/strand_executor_service.ipp \
asio/detail/impl/strand_service.hpp \
asio/detail/impl/strand_service.ipp \
asio/detail/impl/thread_context.ipp \
asio/detail/impl/throw_error.ipp \
asio/detail/impl/timer_queue_ptime.ipp \
asio/detail/impl/timer_queue_set.ipp \
asio/detail/impl/win_event.ipp \
asio/detail/impl/win_iocp_file_service.ipp \
asio/detail/impl/win_iocp_handle_service.ipp \
asio/detail/impl/win_iocp_io_context.hpp \
asio/detail/impl/win_iocp_io_context.ipp \
asio/detail/impl/win_iocp_serial_port_service.ipp \
asio/detail/impl/win_iocp_socket_service_base.ipp \
asio/detail/impl/win_mutex.ipp \
asio/detail/impl/win_object_handle_service.ipp \
asio/detail/impl/winrt_ssocket_service_base.ipp \
asio/detail/impl/winrt_timer_scheduler.hpp \
asio/detail/impl/winrt_timer_scheduler.ipp \
asio/detail/impl/winsock_init.ipp \
asio/detail/impl/win_static_mutex.ipp \
asio/detail/impl/win_thread.ipp \
asio/detail/impl/win_tss_ptr.ipp \
asio/detail/io_control.hpp \
asio/detail/io_object_impl.hpp \
asio/detail/io_uring_descriptor_read_at_op.hpp \
asio/detail/io_uring_descriptor_read_op.hpp \
asio/detail/io_uring_descriptor_service.hpp \
asio/detail/io_uring_descriptor_write_at_op.hpp \
asio/detail/io_uring_descriptor_write_op.hpp \
asio/detail/io_uring_file_service.hpp \
asio/detail/io_uring_null_buffers_op.hpp \
asio/detail/io_uring_operation.hpp \
asio/detail/io_uring_service.hpp \
asio/detail/io_uring_socket_accept_op.hpp \
asio/detail/io_uring_socket_connect_op.hpp \
asio/detail/io_uring_socket_recvfrom_op.hpp \
asio/detail/io_uring_socket_recvmsg_op.hpp \
asio/detail/io_uring_socket_recv_op.hpp \
asio/detail/io_uring_socket_send_op.hpp \
asio/detail/io_uring_socket_sendto_op.hpp \
asio/detail/io_uring_socket_service_base.hpp \
asio/detail/io_uring_socket_service.hpp \
asio/detail/io_uring_wait_op.hpp \
asio/detail/is_buffer_sequence.hpp \
asio/detail/is_executor.hpp \
asio/detail/keyword_tss_ptr.hpp \
asio/detail/kqueue_reactor.hpp \
asio/detail/limits.hpp \
asio/detail/local_free_on_block_exit.hpp \
asio/detail/macos_fenced_block.hpp \
asio/detail/memory.hpp \
asio/detail/mutex.hpp \
asio/detail/non_const_lvalue.hpp \
asio/detail/noncopyable.hpp \
asio/detail/null_event.hpp \
asio/detail/null_fenced_block.hpp \
asio/detail/null_global.hpp \
asio/detail/null_mutex.hpp \
asio/detail/null_reactor.hpp \
asio/detail/null_signal_blocker.hpp \
asio/detail/null_socket_service.hpp \
asio/detail/null_static_mutex.hpp \
asio/detail/null_thread.hpp \
asio/detail/null_tss_ptr.hpp \
asio/detail/object_pool.hpp \
asio/detail/old_win_sdk_compat.hpp \
asio/detail/operation.hpp \
asio/detail/op_queue.hpp \
asio/detail/pipe_select_interrupter.hpp \
asio/detail/pop_options.hpp \
asio/detail/posix_event.hpp \
asio/detail/posix_fd_set_adapter.hpp \
asio/detail/posix_global.hpp \
asio/detail/posix_mutex.hpp \
asio/detail/posix_serial_port_service.hpp \
asio/detail/posix_signal_blocker.hpp \
asio/detail/posix_static_mutex.hpp \
asio/detail/posix_thread.hpp \
asio/detail/posix_tss_ptr.hpp \
asio/detail/push_options.hpp \
asio/detail/reactive_descriptor_service.hpp \
asio/detail/reactive_null_buffers_op.hpp \
asio/detail/reactive_socket_accept_op.hpp \
asio/detail/reactive_socket_connect_op.hpp \
asio/detail/reactive_socket_recvfrom_op.hpp \
asio/detail/reactive_socket_recvmsg_op.hpp \
asio/detail/reactive_socket_recv_op.hpp \
asio/detail/reactive_socket_send_op.hpp \
asio/detail/reactive_socket_sendto_op.hpp \
asio/detail/reactive_socket_service_base.hpp \
asio/detail/reactive_socket_service.hpp \
asio/detail/reactive_wait_op.hpp \
asio/detail/reactor.hpp \
asio/detail/reactor_op.hpp \
asio/detail/reactor_op_queue.hpp \
asio/detail/recycling_allocator.hpp \
asio/detail/regex_fwd.hpp \
asio/detail/resolve_endpoint_op.hpp \
asio/detail/resolve_op.hpp \
asio/detail/resolve_query_op.hpp \
asio/detail/resolver_service_base.hpp \
asio/detail/resolver_service.hpp \
asio/detail/scheduler.hpp \
asio/detail/scheduler_operation.hpp \
asio/detail/scheduler_task.hpp \
asio/detail/scheduler_thread_info.hpp \
asio/detail/scoped_lock.hpp \
asio/detail/scoped_ptr.hpp \
asio/detail/select_interrupter.hpp \
asio/detail/select_reactor.hpp \
asio/detail/service_registry.hpp \
asio/detail/signal_blocker.hpp \
asio/detail/signal_handler.hpp \
asio/detail/signal_init.hpp \
asio/detail/signal_op.hpp \
asio/detail/signal_set_service.hpp \
asio/detail/socket_holder.hpp \
asio/detail/socket_ops.hpp \
asio/detail/socket_option.hpp \
asio/detail/socket_select_interrupter.hpp \
asio/detail/socket_types.hpp \
asio/detail/solaris_fenced_block.hpp \
asio/detail/source_location.hpp \
asio/detail/static_mutex.hpp \
asio/detail/std_event.hpp \
asio/detail/std_fenced_block.hpp \
asio/detail/std_global.hpp \
asio/detail/std_mutex.hpp \
asio/detail/std_static_mutex.hpp \
asio/detail/std_thread.hpp \
asio/detail/strand_executor_service.hpp \
asio/detail/strand_service.hpp \
asio/detail/string_view.hpp \
asio/detail/thread_context.hpp \
asio/detail/thread_group.hpp \
asio/detail/thread.hpp \
asio/detail/thread_info_base.hpp \
asio/detail/throw_error.hpp \
asio/detail/throw_exception.hpp \
asio/detail/timer_queue_base.hpp \
asio/detail/timer_queue.hpp \
asio/detail/timer_queue_ptime.hpp \
asio/detail/timer_queue_set.hpp \
asio/detail/timer_scheduler_fwd.hpp \
asio/detail/timer_scheduler.hpp \
asio/detail/tss_ptr.hpp \
asio/detail/type_traits.hpp \
asio/detail/variadic_templates.hpp \
asio/detail/wait_handler.hpp \
asio/detail/wait_op.hpp \
asio/detail/winapp_thread.hpp \
asio/detail/wince_thread.hpp \
asio/detail/win_event.hpp \
asio/detail/win_fd_set_adapter.hpp \
asio/detail/win_fenced_block.hpp \
asio/detail/win_global.hpp \
asio/detail/win_iocp_file_service.hpp \
asio/detail/win_iocp_handle_read_op.hpp \
asio/detail/win_iocp_handle_service.hpp \
asio/detail/win_iocp_handle_write_op.hpp \
asio/detail/win_iocp_io_context.hpp \
asio/detail/win_iocp_null_buffers_op.hpp \
asio/detail/win_iocp_operation.hpp \
asio/detail/win_iocp_overlapped_op.hpp \
asio/detail/win_iocp_overlapped_ptr.hpp \
asio/detail/win_iocp_serial_port_service.hpp \
asio/detail/win_iocp_socket_accept_op.hpp \
asio/detail/win_iocp_socket_connect_op.hpp \
asio/detail/win_iocp_socket_recvfrom_op.hpp \
asio/detail/win_iocp_socket_recvmsg_op.hpp \
asio/detail/win_iocp_socket_recv_op.hpp \
asio/detail/win_iocp_socket_send_op.hpp \
asio/detail/win_iocp_socket_service_base.hpp \
asio/detail/win_iocp_socket_service.hpp \
asio/detail/win_iocp_thread_info.hpp \
asio/detail/win_iocp_wait_op.hpp \
asio/detail/win_mutex.hpp \
asio/detail/win_object_handle_service.hpp \
asio/detail/winrt_async_manager.hpp \
asio/detail/winrt_async_op.hpp \
asio/detail/winrt_resolve_op.hpp \
asio/detail/winrt_resolver_service.hpp \
asio/detail/winrt_socket_connect_op.hpp \
asio/detail/winrt_socket_recv_op.hpp \
asio/detail/winrt_socket_send_op.hpp \
asio/detail/winrt_ssocket_service_base.hpp \
asio/detail/winrt_ssocket_service.hpp \
asio/detail/winrt_timer_scheduler.hpp \
asio/detail/winrt_utils.hpp \
asio/detail/winsock_init.hpp \
asio/detail/win_static_mutex.hpp \
asio/detail/win_thread.hpp \
asio/detail/win_tss_ptr.hpp \
asio/detail/work_dispatcher.hpp \
asio/detail/wrapped_handler.hpp \
asio/dispatch.hpp \
asio/error_code.hpp \
asio/error.hpp \
asio/execution.hpp \
asio/execution_context.hpp \
asio/execution/allocator.hpp \
asio/execution/any_executor.hpp \
asio/execution/bad_executor.hpp \
asio/execution/blocking.hpp \
asio/execution/blocking_adaptation.hpp \
asio/execution/bulk_execute.hpp \
asio/execution/bulk_guarantee.hpp \
asio/execution/connect.hpp \
asio/execution/context.hpp \
asio/execution/context_as.hpp \
asio/execution/detail/as_invocable.hpp \
asio/execution/detail/as_operation.hpp \
asio/execution/detail/as_receiver.hpp \
asio/execution/detail/bulk_sender.hpp \
asio/execution/detail/submit_receiver.hpp \
asio/execution/detail/void_receiver.hpp \
asio/execution/execute.hpp \
asio/execution/executor.hpp \
asio/execution/impl/bad_executor.ipp \
asio/execution/impl/receiver_invocation_error.ipp \
asio/execution/invocable_archetype.hpp \
asio/execution/mapping.hpp \
asio/execution/occupancy.hpp \
asio/execution/operation_state.hpp \
asio/execution/outstanding_work.hpp \
asio/execution/prefer_only.hpp \
asio/execution/receiver.hpp \
asio/execution/receiver_invocation_error.hpp \
asio/execution/relationship.hpp \
asio/execution/schedule.hpp \
asio/execution/scheduler.hpp \
asio/execution/sender.hpp \
asio/execution/set_done.hpp \
asio/execution/set_error.hpp \
asio/execution/set_value.hpp \
asio/execution/start.hpp \
asio/execution/submit.hpp \
asio/executor.hpp \
asio/executor_work_guard.hpp \
asio/experimental/append.hpp \
asio/experimental/as_single.hpp \
asio/experimental/as_tuple.hpp \
asio/experimental/awaitable_operators.hpp \
asio/experimental/basic_channel.hpp \
asio/experimental/basic_concurrent_channel.hpp \
asio/experimental/cancellation_condition.hpp \
asio/experimental/channel.hpp \
asio/experimental/channel_error.hpp \
asio/experimental/channel_traits.hpp \
asio/experimental/co_spawn.hpp \
asio/experimental/concurrent_channel.hpp \
asio/experimental/coro.hpp \
asio/experimental/coro_traits.hpp \
asio/experimental/deferred.hpp \
asio/experimental/detail/channel_handler.hpp \
asio/experimental/detail/channel_message.hpp \
asio/experimental/detail/channel_operation.hpp \
asio/experimental/detail/channel_payload.hpp \
asio/experimental/detail/channel_receive_op.hpp \
asio/experimental/detail/channel_send_functions.hpp \
asio/experimental/detail/channel_send_op.hpp \
asio/experimental/detail/channel_service.hpp \
asio/experimental/detail/completion_handler_erasure.hpp \
asio/experimental/detail/coro_promise_allocator.hpp \
asio/experimental/detail/has_signature.hpp \
asio/experimental/detail/impl/channel_service.hpp \
asio/experimental/detail/partial_promise.hpp \
asio/experimental/impl/append.hpp \
asio/experimental/impl/as_single.hpp \
asio/experimental/impl/as_tuple.hpp \
asio/experimental/impl/channel_error.ipp \
asio/experimental/impl/coro.hpp \
asio/experimental/impl/deferred.hpp \
asio/experimental/impl/parallel_group.hpp \
asio/experimental/impl/prepend.hpp \
asio/experimental/impl/promise.hpp \
asio/experimental/impl/use_coro.hpp \
asio/experimental/parallel_group.hpp \
asio/experimental/prepend.hpp \
asio/experimental/promise.hpp \
asio/experimental/use_coro.hpp \
asio/file_base.hpp \
asio/generic/basic_endpoint.hpp \
asio/generic/datagram_protocol.hpp \
asio/generic/detail/endpoint.hpp \
asio/generic/detail/impl/endpoint.ipp \
asio/generic/raw_protocol.hpp \
asio/generic/seq_packet_protocol.hpp \
asio/generic/stream_protocol.hpp \
asio/handler_alloc_hook.hpp \
asio/handler_continuation_hook.hpp \
asio/handler_invoke_hook.hpp \
asio/high_resolution_timer.hpp \
asio.hpp \
asio/impl/any_io_executor.ipp \
asio/impl/awaitable.hpp \
asio/impl/buffered_read_stream.hpp \
asio/impl/buffered_write_stream.hpp \
asio/impl/cancellation_signal.ipp \
asio/impl/co_spawn.hpp \
asio/impl/compose.hpp \
asio/impl/connect.hpp \
asio/impl/connect_pipe.hpp \
asio/impl/connect_pipe.ipp \
asio/impl/defer.hpp \
asio/impl/detached.hpp \
asio/impl/dispatch.hpp \
asio/impl/error_code.ipp \
asio/impl/error.ipp \
asio/impl/execution_context.hpp \
asio/impl/execution_context.ipp \
asio/impl/executor.hpp \
asio/impl/executor.ipp \
asio/impl/handler_alloc_hook.ipp \
asio/impl/io_context.hpp \
asio/impl/io_context.ipp \
asio/impl/multiple_exceptions.ipp \
asio/impl/post.hpp \
asio/impl/read_at.hpp \
asio/impl/read.hpp \
asio/impl/read_until.hpp \
asio/impl/redirect_error.hpp \
asio/impl/serial_port_base.hpp \
asio/impl/serial_port_base.ipp \
asio/impl/spawn.hpp \
asio/impl/src.hpp \
asio/impl/system_context.hpp \
asio/impl/system_context.ipp \
asio/impl/system_executor.hpp \
asio/impl/thread_pool.hpp \
asio/impl/thread_pool.ipp \
asio/impl/use_awaitable.hpp \
asio/impl/use_future.hpp \
asio/impl/write_at.hpp \
asio/impl/write.hpp \
asio/io_context.hpp \
asio/io_context_strand.hpp \
asio/io_service.hpp \
asio/io_service_strand.hpp \
asio/ip/address.hpp \
asio/ip/address_v4.hpp \
asio/ip/address_v4_iterator.hpp \
asio/ip/address_v4_range.hpp \
asio/ip/address_v6.hpp \
asio/ip/address_v6_iterator.hpp \
asio/ip/address_v6_range.hpp \
asio/ip/bad_address_cast.hpp \
asio/ip/basic_endpoint.hpp \
asio/ip/basic_resolver_entry.hpp \
asio/ip/basic_resolver.hpp \
asio/ip/basic_resolver_iterator.hpp \
asio/ip/basic_resolver_query.hpp \
asio/ip/basic_resolver_results.hpp \
asio/ip/detail/endpoint.hpp \
asio/ip/detail/impl/endpoint.ipp \
asio/ip/detail/socket_option.hpp \
asio/ip/host_name.hpp \
asio/ip/icmp.hpp \
asio/ip/impl/address.hpp \
asio/ip/impl/address.ipp \
asio/ip/impl/address_v4.hpp \
asio/ip/impl/address_v4.ipp \
asio/ip/impl/address_v6.hpp \
asio/ip/impl/address_v6.ipp \
asio/ip/impl/basic_endpoint.hpp \
asio/ip/impl/host_name.ipp \
asio/ip/impl/network_v4.hpp \
asio/ip/impl/network_v4.ipp \
asio/ip/impl/network_v6.hpp \
asio/ip/impl/network_v6.ipp \
asio/ip/multicast.hpp \
asio/ip/network_v4.hpp \
asio/ip/network_v6.hpp \
asio/ip/resolver_base.hpp \
asio/ip/resolver_query_base.hpp \
asio/ip/tcp.hpp \
asio/ip/udp.hpp \
asio/ip/unicast.hpp \
asio/ip/v6_only.hpp \
asio/is_applicable_property.hpp \
asio/is_executor.hpp \
asio/is_read_buffered.hpp \
asio/is_write_buffered.hpp \
asio/local/basic_endpoint.hpp \
asio/local/connect_pair.hpp \
asio/local/datagram_protocol.hpp \
asio/local/detail/endpoint.hpp \
asio/local/detail/impl/endpoint.ipp \
asio/local/stream_protocol.hpp \
asio/multiple_exceptions.hpp \
asio/packaged_task.hpp \
asio/placeholders.hpp \
asio/posix/basic_descriptor.hpp \
asio/posix/basic_stream_descriptor.hpp \
asio/posix/descriptor_base.hpp \
asio/posix/descriptor.hpp \
asio/posix/stream_descriptor.hpp \
asio/post.hpp \
asio/prefer.hpp \
asio/query.hpp \
asio/random_access_file.hpp \
asio/read_at.hpp \
asio/read.hpp \
asio/read_until.hpp \
asio/readable_pipe.hpp \
asio/recycling_allocator.hpp \
asio/redirect_error.hpp \
asio/registered_buffer.hpp \
asio/require.hpp \
asio/require_concept.hpp \
asio/serial_port_base.hpp \
asio/serial_port.hpp \
asio/signal_set.hpp \
asio/socket_base.hpp \
asio/spawn.hpp \
asio/ssl/context_base.hpp \
asio/ssl/context.hpp \
asio/ssl/detail/buffered_handshake_op.hpp \
asio/ssl/detail/engine.hpp \
asio/ssl/detail/handshake_op.hpp \
asio/ssl/detail/impl/engine.ipp \
asio/ssl/detail/impl/openssl_init.ipp \
asio/ssl/detail/io.hpp \
asio/ssl/detail/openssl_init.hpp \
asio/ssl/detail/openssl_types.hpp \
asio/ssl/detail/password_callback.hpp \
asio/ssl/detail/read_op.hpp \
asio/ssl/detail/shutdown_op.hpp \
asio/ssl/detail/stream_core.hpp \
asio/ssl/detail/verify_callback.hpp \
asio/ssl/detail/write_op.hpp \
asio/ssl/error.hpp \
asio/ssl.hpp \
asio/ssl/host_name_verification.hpp \
asio/ssl/impl/context.hpp \
asio/ssl/impl/context.ipp \
asio/ssl/impl/error.ipp \
asio/ssl/impl/host_name_verification.ipp \
asio/ssl/impl/rfc2818_verification.ipp \
asio/ssl/impl/src.hpp \
asio/ssl/rfc2818_verification.hpp \
asio/ssl/stream_base.hpp \
asio/ssl/stream.hpp \
asio/ssl/verify_context.hpp \
asio/ssl/verify_mode.hpp \
asio/static_thread_pool.hpp \
asio/steady_timer.hpp \
asio/strand.hpp \
asio/streambuf.hpp \
asio/stream_file.hpp \
asio/system_context.hpp \
asio/system_error.hpp \
asio/system_executor.hpp \
asio/system_timer.hpp \
asio/this_coro.hpp \
asio/thread.hpp \
asio/thread_pool.hpp \
asio/time_traits.hpp \
asio/traits/bulk_execute_free.hpp \
asio/traits/bulk_execute_member.hpp \
asio/traits/connect_free.hpp \
asio/traits/connect_member.hpp \
asio/traits/equality_comparable.hpp \
asio/traits/execute_free.hpp \
asio/traits/execute_member.hpp \
asio/traits/prefer_free.hpp \
asio/traits/prefer_member.hpp \
asio/traits/query_free.hpp \
asio/traits/query_member.hpp \
asio/traits/query_static_constexpr_member.hpp \
asio/traits/require_concept_free.hpp \
asio/traits/require_concept_member.hpp \
asio/traits/require_free.hpp \
asio/traits/require_member.hpp \
asio/traits/schedule_free.hpp \
asio/traits/schedule_member.hpp \
asio/traits/set_done_free.hpp \
asio/traits/set_done_member.hpp \
asio/traits/set_error_free.hpp \
asio/traits/set_error_member.hpp \
asio/traits/set_value_free.hpp \
asio/traits/set_value_member.hpp \
asio/traits/start_free.hpp \
asio/traits/start_member.hpp \
asio/traits/static_query.hpp \
asio/traits/static_require.hpp \
asio/traits/static_require_concept.hpp \
asio/traits/submit_free.hpp \
asio/traits/submit_member.hpp \
asio/ts/buffer.hpp \
asio/ts/executor.hpp \
asio/ts/internet.hpp \
asio/ts/io_context.hpp \
asio/ts/netfwd.hpp \
asio/ts/net.hpp \
asio/ts/socket.hpp \
asio/ts/timer.hpp \
asio/unyield.hpp \
asio/use_awaitable.hpp \
asio/use_future.hpp \
asio/uses_executor.hpp \
asio/version.hpp \
asio/wait_traits.hpp \
asio/windows/basic_object_handle.hpp \
asio/windows/basic_overlapped_handle.hpp \
asio/windows/basic_random_access_handle.hpp \
asio/windows/basic_stream_handle.hpp \
asio/windows/object_handle.hpp \
asio/windows/overlapped_handle.hpp \
asio/windows/overlapped_ptr.hpp \
asio/windows/random_access_handle.hpp \
asio/windows/stream_handle.hpp \
asio/writable_pipe.hpp \
asio/write_at.hpp \
asio/write.hpp \
asio/yield.hpp
MAINTAINERCLEANFILES = \
$(srcdir)/Makefile.in

203
lib/asio/include/asio.hpp Normal file
View File

@ -0,0 +1,203 @@
//
// asio.hpp
// ~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_HPP
#define ASIO_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/associated_allocator.hpp"
#include "asio/associated_executor.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/awaitable.hpp"
#include "asio/basic_datagram_socket.hpp"
#include "asio/basic_deadline_timer.hpp"
#include "asio/basic_file.hpp"
#include "asio/basic_io_object.hpp"
#include "asio/basic_random_access_file.hpp"
#include "asio/basic_raw_socket.hpp"
#include "asio/basic_readable_pipe.hpp"
#include "asio/basic_seq_packet_socket.hpp"
#include "asio/basic_serial_port.hpp"
#include "asio/basic_signal_set.hpp"
#include "asio/basic_socket.hpp"
#include "asio/basic_socket_acceptor.hpp"
#include "asio/basic_socket_iostream.hpp"
#include "asio/basic_socket_streambuf.hpp"
#include "asio/basic_stream_file.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/basic_streambuf.hpp"
#include "asio/basic_waitable_timer.hpp"
#include "asio/basic_writable_pipe.hpp"
#include "asio/bind_allocator.hpp"
#include "asio/bind_cancellation_slot.hpp"
#include "asio/bind_executor.hpp"
#include "asio/buffer.hpp"
#include "asio/buffer_registration.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/buffered_stream.hpp"
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffers_iterator.hpp"
#include "asio/cancellation_signal.hpp"
#include "asio/cancellation_state.hpp"
#include "asio/cancellation_type.hpp"
#include "asio/co_spawn.hpp"
#include "asio/completion_condition.hpp"
#include "asio/compose.hpp"
#include "asio/connect.hpp"
#include "asio/connect_pipe.hpp"
#include "asio/coroutine.hpp"
#include "asio/deadline_timer.hpp"
#include "asio/defer.hpp"
#include "asio/detached.hpp"
#include "asio/dispatch.hpp"
#include "asio/error.hpp"
#include "asio/error_code.hpp"
#include "asio/execution.hpp"
#include "asio/execution/allocator.hpp"
#include "asio/execution/any_executor.hpp"
#include "asio/execution/blocking.hpp"
#include "asio/execution/blocking_adaptation.hpp"
#include "asio/execution/bulk_execute.hpp"
#include "asio/execution/bulk_guarantee.hpp"
#include "asio/execution/connect.hpp"
#include "asio/execution/context.hpp"
#include "asio/execution/context_as.hpp"
#include "asio/execution/execute.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution/invocable_archetype.hpp"
#include "asio/execution/mapping.hpp"
#include "asio/execution/occupancy.hpp"
#include "asio/execution/operation_state.hpp"
#include "asio/execution/outstanding_work.hpp"
#include "asio/execution/prefer_only.hpp"
#include "asio/execution/receiver.hpp"
#include "asio/execution/receiver_invocation_error.hpp"
#include "asio/execution/relationship.hpp"
#include "asio/execution/schedule.hpp"
#include "asio/execution/scheduler.hpp"
#include "asio/execution/sender.hpp"
#include "asio/execution/set_done.hpp"
#include "asio/execution/set_error.hpp"
#include "asio/execution/set_value.hpp"
#include "asio/execution/start.hpp"
#include "asio/execution_context.hpp"
#include "asio/executor.hpp"
#include "asio/executor_work_guard.hpp"
#include "asio/file_base.hpp"
#include "asio/generic/basic_endpoint.hpp"
#include "asio/generic/datagram_protocol.hpp"
#include "asio/generic/raw_protocol.hpp"
#include "asio/generic/seq_packet_protocol.hpp"
#include "asio/generic/stream_protocol.hpp"
#include "asio/handler_alloc_hook.hpp"
#include "asio/handler_continuation_hook.hpp"
#include "asio/handler_invoke_hook.hpp"
#include "asio/high_resolution_timer.hpp"
#include "asio/io_context.hpp"
#include "asio/io_context_strand.hpp"
#include "asio/io_service.hpp"
#include "asio/io_service_strand.hpp"
#include "asio/ip/address.hpp"
#include "asio/ip/address_v4.hpp"
#include "asio/ip/address_v4_iterator.hpp"
#include "asio/ip/address_v4_range.hpp"
#include "asio/ip/address_v6.hpp"
#include "asio/ip/address_v6_iterator.hpp"
#include "asio/ip/address_v6_range.hpp"
#include "asio/ip/network_v4.hpp"
#include "asio/ip/network_v6.hpp"
#include "asio/ip/bad_address_cast.hpp"
#include "asio/ip/basic_endpoint.hpp"
#include "asio/ip/basic_resolver.hpp"
#include "asio/ip/basic_resolver_entry.hpp"
#include "asio/ip/basic_resolver_iterator.hpp"
#include "asio/ip/basic_resolver_query.hpp"
#include "asio/ip/host_name.hpp"
#include "asio/ip/icmp.hpp"
#include "asio/ip/multicast.hpp"
#include "asio/ip/resolver_base.hpp"
#include "asio/ip/resolver_query_base.hpp"
#include "asio/ip/tcp.hpp"
#include "asio/ip/udp.hpp"
#include "asio/ip/unicast.hpp"
#include "asio/ip/v6_only.hpp"
#include "asio/is_applicable_property.hpp"
#include "asio/is_executor.hpp"
#include "asio/is_read_buffered.hpp"
#include "asio/is_write_buffered.hpp"
#include "asio/local/basic_endpoint.hpp"
#include "asio/local/connect_pair.hpp"
#include "asio/local/datagram_protocol.hpp"
#include "asio/local/stream_protocol.hpp"
#include "asio/multiple_exceptions.hpp"
#include "asio/packaged_task.hpp"
#include "asio/placeholders.hpp"
#include "asio/posix/basic_descriptor.hpp"
#include "asio/posix/basic_stream_descriptor.hpp"
#include "asio/posix/descriptor.hpp"
#include "asio/posix/descriptor_base.hpp"
#include "asio/posix/stream_descriptor.hpp"
#include "asio/post.hpp"
#include "asio/prefer.hpp"
#include "asio/query.hpp"
#include "asio/random_access_file.hpp"
#include "asio/read.hpp"
#include "asio/read_at.hpp"
#include "asio/read_until.hpp"
#include "asio/readable_pipe.hpp"
#include "asio/recycling_allocator.hpp"
#include "asio/redirect_error.hpp"
#include "asio/registered_buffer.hpp"
#include "asio/require.hpp"
#include "asio/require_concept.hpp"
#include "asio/serial_port.hpp"
#include "asio/serial_port_base.hpp"
#include "asio/signal_set.hpp"
#include "asio/socket_base.hpp"
#include "asio/static_thread_pool.hpp"
#include "asio/steady_timer.hpp"
#include "asio/strand.hpp"
#include "asio/stream_file.hpp"
#include "asio/streambuf.hpp"
#include "asio/system_context.hpp"
#include "asio/system_error.hpp"
#include "asio/system_executor.hpp"
#include "asio/system_timer.hpp"
#include "asio/this_coro.hpp"
#include "asio/thread.hpp"
#include "asio/thread_pool.hpp"
#include "asio/time_traits.hpp"
#include "asio/use_awaitable.hpp"
#include "asio/use_future.hpp"
#include "asio/uses_executor.hpp"
#include "asio/version.hpp"
#include "asio/wait_traits.hpp"
#include "asio/windows/basic_object_handle.hpp"
#include "asio/windows/basic_overlapped_handle.hpp"
#include "asio/windows/basic_random_access_handle.hpp"
#include "asio/windows/basic_stream_handle.hpp"
#include "asio/windows/object_handle.hpp"
#include "asio/windows/overlapped_handle.hpp"
#include "asio/windows/overlapped_ptr.hpp"
#include "asio/windows/random_access_handle.hpp"
#include "asio/windows/stream_handle.hpp"
#include "asio/writable_pipe.hpp"
#include "asio/write.hpp"
#include "asio/write_at.hpp"
#endif // ASIO_HPP

View File

@ -0,0 +1,303 @@
//
// any_io_executor.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ANY_IO_EXECUTOR_HPP
#define ASIO_ANY_IO_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/executor.hpp"
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/execution.hpp"
# include "asio/execution_context.hpp"
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
typedef executor any_io_executor;
#else // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
/// Polymorphic executor type for use with I/O objects.
/**
* The @c any_io_executor type is a polymorphic executor that supports the set
* of properties required by I/O objects. It is defined as the
* execution::any_executor class template parameterised as follows:
* @code execution::any_executor<
* execution::context_as_t<execution_context&>,
* execution::blocking_t::never_t,
* execution::prefer_only<execution::blocking_t::possibly_t>,
* execution::prefer_only<execution::outstanding_work_t::tracked_t>,
* execution::prefer_only<execution::outstanding_work_t::untracked_t>,
* execution::prefer_only<execution::relationship_t::fork_t>,
* execution::prefer_only<execution::relationship_t::continuation_t>
* > @endcode
*/
class any_io_executor :
#if defined(GENERATING_DOCUMENTATION)
public execution::any_executor<...>
#else // defined(GENERATING_DOCUMENTATION)
public execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
>
#endif // defined(GENERATING_DOCUMENTATION)
{
public:
#if !defined(GENERATING_DOCUMENTATION)
typedef execution::any_executor<
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
> base_type;
typedef void supportable_properties_type(
execution::context_as_t<execution_context&>,
execution::blocking_t::never_t,
execution::prefer_only<execution::blocking_t::possibly_t>,
execution::prefer_only<execution::outstanding_work_t::tracked_t>,
execution::prefer_only<execution::outstanding_work_t::untracked_t>,
execution::prefer_only<execution::relationship_t::fork_t>,
execution::prefer_only<execution::relationship_t::continuation_t>
);
#endif // !defined(GENERATING_DOCUMENTATION)
/// Default constructor.
ASIO_DECL any_io_executor() ASIO_NOEXCEPT;
/// Construct in an empty state. Equivalent effects to default constructor.
ASIO_DECL any_io_executor(nullptr_t) ASIO_NOEXCEPT;
/// Copy constructor.
ASIO_DECL any_io_executor(const any_io_executor& e) ASIO_NOEXCEPT;
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor.
ASIO_DECL any_io_executor(any_io_executor&& e) ASIO_NOEXCEPT;
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct to point to the same target as another any_executor.
#if defined(GENERATING_DOCUMENTATION)
template <class... OtherSupportableProperties>
any_io_executor(execution::any_executor<OtherSupportableProperties...> e);
#else // defined(GENERATING_DOCUMENTATION)
template <typename OtherAnyExecutor>
any_io_executor(OtherAnyExecutor e,
typename constraint<
conditional<
!is_same<OtherAnyExecutor, any_io_executor>::value
&& is_base_of<execution::detail::any_executor_base,
OtherAnyExecutor>::value,
typename execution::detail::supportable_properties<
0, supportable_properties_type>::template
is_valid_target<OtherAnyExecutor>,
false_type
>::type::value
>::type = 0)
: base_type(ASIO_MOVE_CAST(OtherAnyExecutor)(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a polymorphic wrapper for the specified executor.
#if defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e);
#else // defined(GENERATING_DOCUMENTATION)
template <ASIO_EXECUTION_EXECUTOR Executor>
any_io_executor(Executor e,
typename constraint<
conditional<
!is_same<Executor, any_io_executor>::value
&& !is_base_of<execution::detail::any_executor_base,
Executor>::value,
execution::detail::is_valid_target_executor<
Executor, supportable_properties_type>,
false_type
>::type::value
>::type = 0)
: base_type(ASIO_MOVE_CAST(Executor)(e))
{
}
#endif // defined(GENERATING_DOCUMENTATION)
/// Assignment operator.
ASIO_DECL any_io_executor& operator=(
const any_io_executor& e) ASIO_NOEXCEPT;
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move assignment operator.
ASIO_DECL any_io_executor& operator=(
any_io_executor&& e) ASIO_NOEXCEPT;
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Assignment operator that sets the polymorphic wrapper to the empty state.
ASIO_DECL any_io_executor& operator=(nullptr_t);
/// Destructor.
ASIO_DECL ~any_io_executor();
/// Swap targets with another polymorphic wrapper.
ASIO_DECL void swap(any_io_executor& other) ASIO_NOEXCEPT;
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::require and asio::prefer customisation points.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = asio::require(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor require(const Property& p,
typename constraint<
traits::require_member<const base_type&, const Property&>::is_valid
>::type = 0) const
{
return static_cast<const base_type&>(*this).require(p);
}
/// Obtain a polymorphic wrapper with the specified property.
/**
* Do not call this function directly. It is intended for use with the
* asio::prefer customisation point.
*
* For example:
* @code any_io_executor ex = ...;
* auto ex2 = asio::prefer(ex, execution::blocking.possibly); @endcode
*/
template <typename Property>
any_io_executor prefer(const Property& p,
typename constraint<
traits::prefer_member<const base_type&, const Property&>::is_valid
>::type = 0) const
{
return static_cast<const base_type&>(*this).prefer(p);
}
};
#if !defined(GENERATING_DOCUMENTATION)
template <>
ASIO_DECL any_io_executor any_io_executor::require(
const execution::blocking_t::never_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::blocking_t::possibly_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::tracked_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::outstanding_work_t::untracked_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::fork_t&, int) const;
template <>
ASIO_DECL any_io_executor any_io_executor::prefer(
const execution::relationship_t::continuation_t&, int) const;
namespace traits {
#if !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
template <>
struct equality_comparable<any_io_executor>
{
static const bool is_valid = true;
static const bool is_noexcept = true;
};
#endif // !defined(ASIO_HAS_DEDUCED_EQUALITY_COMPARABLE_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
template <typename F>
struct execute_member<any_io_executor, F>
{
static const bool is_valid = true;
static const bool is_noexcept = false;
typedef void result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_EXECUTE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
template <typename Prop>
struct query_member<any_io_executor, Prop> :
query_member<any_io_executor::base_type, Prop>
{
};
#endif // !defined(ASIO_HAS_DEDUCED_QUERY_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
template <typename Prop>
struct require_member<any_io_executor, Prop> :
require_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_REQUIRE_MEMBER_TRAIT)
#if !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
template <typename Prop>
struct prefer_member<any_io_executor, Prop> :
prefer_member<any_io_executor::base_type, Prop>
{
typedef any_io_executor result_type;
};
#endif // !defined(ASIO_HAS_DEDUCED_PREFER_MEMBER_TRAIT)
} // namespace traits
#endif // !defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY) \
&& !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
# include "asio/impl/any_io_executor.ipp"
#endif // defined(ASIO_HEADER_ONLY)
// && !defined(ASIO_USE_TS_EXECUTOR_AS_DEFAULT)
#endif // ASIO_ANY_IO_EXECUTOR_HPP

View File

@ -0,0 +1,177 @@
//
// associated_allocator.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_ALLOCATOR_HPP
#define ASIO_ASSOCIATED_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <memory>
#include "asio/associator.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename T, typename Allocator>
struct associated_allocator;
namespace detail {
template <typename T, typename = void>
struct has_allocator_type : false_type
{
};
template <typename T>
struct has_allocator_type<T,
typename void_type<typename T::allocator_type>::type>
: true_type
{
};
template <typename T, typename E, typename = void, typename = void>
struct associated_allocator_impl
{
typedef E type;
static type get(const T&, const E& e) ASIO_NOEXCEPT
{
return e;
}
};
template <typename T, typename E>
struct associated_allocator_impl<T, E,
typename void_type<typename T::allocator_type>::type>
{
typedef typename T::allocator_type type;
static type get(const T& t, const E&) ASIO_NOEXCEPT
{
return t.get_allocator();
}
};
template <typename T, typename E>
struct associated_allocator_impl<T, E,
typename enable_if<
!has_allocator_type<T>::value
>::type,
typename void_type<
typename associator<associated_allocator, T, E>::type
>::type> : associator<associated_allocator, T, E>
{
};
} // namespace detail
/// Traits type used to obtain the allocator associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Allocator shall be a type meeting the Allocator requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c a is an object of type @c
* Allocator.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Allocator requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,a) and with return type @c type.
*/
template <typename T, typename Allocator = std::allocator<void> >
struct associated_allocator
{
/// If @c T has a nested type @c allocator_type, <tt>T::allocator_type</tt>.
/// Otherwise @c Allocator.
#if defined(GENERATING_DOCUMENTATION)
typedef see_below type;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::associated_allocator_impl<T, Allocator>::type type;
#endif // defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c allocator_type, returns
/// <tt>t.get_allocator()</tt>. Otherwise returns @c a.
static type get(const T& t,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{
return detail::associated_allocator_impl<T, Allocator>::get(t, a);
}
};
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T>::get(t)</tt>
*/
template <typename T>
ASIO_NODISCARD inline typename associated_allocator<T>::type
get_associated_allocator(const T& t) ASIO_NOEXCEPT
{
return associated_allocator<T>::get(t);
}
/// Helper function to obtain an object's associated allocator.
/**
* @returns <tt>associated_allocator<T, Allocator>::get(t, a)</tt>
*/
template <typename T, typename Allocator>
ASIO_NODISCARD inline typename associated_allocator<T, Allocator>::type
get_associated_allocator(const T& t, const Allocator& a) ASIO_NOEXCEPT
{
return associated_allocator<T, Allocator>::get(t, a);
}
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Allocator = std::allocator<void> >
using associated_allocator_t
= typename associated_allocator<T, Allocator>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
#if defined(ASIO_HAS_STD_REFERENCE_WRAPPER) \
|| defined(GENERATING_DOCUMENTATION)
/// Specialisation of associated_allocator for @c std::reference_wrapper.
template <typename T, typename Allocator>
struct associated_allocator<reference_wrapper<T>, Allocator>
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_allocator<T, Allocator>::type type;
/// Forwards the request to get the allocator to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t,
const Allocator& a = Allocator()) ASIO_NOEXCEPT
{
return associated_allocator<T, Allocator>::get(t.get(), a);
}
};
#endif // defined(ASIO_HAS_STD_REFERENCE_WRAPPER)
// || defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_ALLOCATOR_HPP

View File

@ -0,0 +1,178 @@
//
// associated_cancellation_slot.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#define ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associator.hpp"
#include "asio/cancellation_signal.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename T, typename CancellationSlot>
struct associated_cancellation_slot;
namespace detail {
template <typename T, typename = void>
struct has_cancellation_slot_type : false_type
{
};
template <typename T>
struct has_cancellation_slot_type<T,
typename void_type<typename T::cancellation_slot_type>::type>
: true_type
{
};
template <typename T, typename S, typename = void, typename = void>
struct associated_cancellation_slot_impl
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
typedef S type;
static type get(const T&, const S& s = S()) ASIO_NOEXCEPT
{
return s;
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
typename void_type<typename T::cancellation_slot_type>::type>
{
typedef typename T::cancellation_slot_type type;
static type get(const T& t, const S& = S()) ASIO_NOEXCEPT
{
return t.get_cancellation_slot();
}
};
template <typename T, typename S>
struct associated_cancellation_slot_impl<T, S,
typename enable_if<
!has_cancellation_slot_type<T>::value
>::type,
typename void_type<
typename associator<associated_cancellation_slot, T, S>::type
>::type> : associator<associated_cancellation_slot, T, S>
{
};
} // namespace detail
/// Traits type used to obtain the cancellation_slot associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* CancellationSlot shall be a type meeting the CancellationSlot requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c s is an object of type @c
* CancellationSlot.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* CancellationSlot requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,s) and with return type @c type.
*/
template <typename T, typename CancellationSlot = cancellation_slot>
struct associated_cancellation_slot
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_cancellation_slot_impl<T, CancellationSlot>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c cancellation_slot_type,
/// <tt>T::cancellation_slot_type</tt>. Otherwise
/// @c CancellationSlot.
typedef see_below type;
/// If @c T has a nested type @c cancellation_slot_type, returns
/// <tt>t.get_cancellation_slot()</tt>. Otherwise returns @c s.
static type get(const T& t,
const CancellationSlot& s = CancellationSlot()) ASIO_NOEXCEPT;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T>::get(t)</tt>
*/
template <typename T>
ASIO_NODISCARD inline typename associated_cancellation_slot<T>::type
get_associated_cancellation_slot(const T& t) ASIO_NOEXCEPT
{
return associated_cancellation_slot<T>::get(t);
}
/// Helper function to obtain an object's associated cancellation_slot.
/**
* @returns <tt>associated_cancellation_slot<T,
* CancellationSlot>::get(t, st)</tt>
*/
template <typename T, typename CancellationSlot>
ASIO_NODISCARD inline
typename associated_cancellation_slot<T, CancellationSlot>::type
get_associated_cancellation_slot(const T& t,
const CancellationSlot& st) ASIO_NOEXCEPT
{
return associated_cancellation_slot<T, CancellationSlot>::get(t, st);
}
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename CancellationSlot = cancellation_slot>
using associated_cancellation_slot_t =
typename associated_cancellation_slot<T, CancellationSlot>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
namespace detail {
template <typename T, typename S, typename = void>
struct associated_cancellation_slot_forwarding_base
{
};
template <typename T, typename S>
struct associated_cancellation_slot_forwarding_base<T, S,
typename enable_if<
is_same<
typename associated_cancellation_slot<T,
S>::asio_associated_cancellation_slot_is_unspecialised,
void
>::value
>::type>
{
typedef void asio_associated_cancellation_slot_is_unspecialised;
};
} // namespace detail
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_CANCELLATION_SLOT_HPP

View File

@ -0,0 +1,222 @@
//
// associated_executor.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATED_EXECUTOR_HPP
#define ASIO_ASSOCIATED_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/associator.hpp"
#include "asio/detail/functional.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution/executor.hpp"
#include "asio/is_executor.hpp"
#include "asio/system_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
template <typename T, typename Executor>
struct associated_executor;
namespace detail {
template <typename T, typename = void>
struct has_executor_type : false_type
{
};
template <typename T>
struct has_executor_type<T,
typename void_type<typename T::executor_type>::type>
: true_type
{
};
template <typename T, typename E, typename = void, typename = void>
struct associated_executor_impl
{
typedef void asio_associated_executor_is_unspecialised;
typedef E type;
static type get(const T&, const E& e = E()) ASIO_NOEXCEPT
{
return e;
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E,
typename void_type<typename T::executor_type>::type>
{
typedef typename T::executor_type type;
static type get(const T& t, const E& = E()) ASIO_NOEXCEPT
{
return t.get_executor();
}
};
template <typename T, typename E>
struct associated_executor_impl<T, E,
typename enable_if<
!has_executor_type<T>::value
>::type,
typename void_type<
typename associator<associated_executor, T, E>::type
>::type> : associator<associated_executor, T, E>
{
};
} // namespace detail
/// Traits type used to obtain the executor associated with an object.
/**
* A program may specialise this traits type if the @c T template parameter in
* the specialisation is a user-defined type. The template parameter @c
* Executor shall be a type meeting the Executor requirements.
*
* Specialisations shall meet the following requirements, where @c t is a const
* reference to an object of type @c T, and @c e is an object of type @c
* Executor.
*
* @li Provide a nested typedef @c type that identifies a type meeting the
* Executor requirements.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t) and with return type @c type.
*
* @li Provide a noexcept static member function named @c get, callable as @c
* get(t,e) and with return type @c type.
*/
template <typename T, typename Executor = system_executor>
struct associated_executor
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_impl<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
#if defined(GENERATING_DOCUMENTATION)
/// If @c T has a nested type @c executor_type, <tt>T::executor_type</tt>.
/// Otherwise @c Executor.
typedef see_below type;
/// If @c T has a nested type @c executor_type, returns
/// <tt>t.get_executor()</tt>. Otherwise returns @c ex.
static type get(const T& t,
const Executor& ex = Executor()) ASIO_NOEXCEPT;
#endif // defined(GENERATING_DOCUMENTATION)
};
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T>::get(t)</tt>
*/
template <typename T>
ASIO_NODISCARD inline typename associated_executor<T>::type
get_associated_executor(const T& t) ASIO_NOEXCEPT
{
return associated_executor<T>::get(t);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, Executor>::get(t, ex)</tt>
*/
template <typename T, typename Executor>
ASIO_NODISCARD inline typename associated_executor<T, Executor>::type
get_associated_executor(const T& t, const Executor& ex,
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0) ASIO_NOEXCEPT
{
return associated_executor<T, Executor>::get(t, ex);
}
/// Helper function to obtain an object's associated executor.
/**
* @returns <tt>associated_executor<T, typename
* ExecutionContext::executor_type>::get(t, ctx.get_executor())</tt>
*/
template <typename T, typename ExecutionContext>
ASIO_NODISCARD inline typename associated_executor<T,
typename ExecutionContext::executor_type>::type
get_associated_executor(const T& t, ExecutionContext& ctx,
typename constraint<is_convertible<ExecutionContext&,
execution_context&>::value>::type = 0) ASIO_NOEXCEPT
{
return associated_executor<T,
typename ExecutionContext::executor_type>::get(t, ctx.get_executor());
}
#if defined(ASIO_HAS_ALIAS_TEMPLATES)
template <typename T, typename Executor = system_executor>
using associated_executor_t = typename associated_executor<T, Executor>::type;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
namespace detail {
template <typename T, typename E, typename = void>
struct associated_executor_forwarding_base
{
};
template <typename T, typename E>
struct associated_executor_forwarding_base<T, E,
typename enable_if<
is_same<
typename associated_executor<T,
E>::asio_associated_executor_is_unspecialised,
void
>::value
>::type>
{
typedef void asio_associated_executor_is_unspecialised;
};
} // namespace detail
#if defined(ASIO_HAS_STD_REFERENCE_WRAPPER) \
|| defined(GENERATING_DOCUMENTATION)
/// Specialisation of associated_executor for @c std::reference_wrapper.
template <typename T, typename Executor>
struct associated_executor<reference_wrapper<T>, Executor>
#if !defined(GENERATING_DOCUMENTATION)
: detail::associated_executor_forwarding_base<T, Executor>
#endif // !defined(GENERATING_DOCUMENTATION)
{
/// Forwards @c type to the associator specialisation for the unwrapped type
/// @c T.
typedef typename associated_executor<T, Executor>::type type;
/// Forwards the request to get the executor to the associator specialisation
/// for the unwrapped type @c T.
static type get(reference_wrapper<T> t,
const Executor& ex = Executor()) ASIO_NOEXCEPT
{
return associated_executor<T, Executor>::get(t.get(), ex);
}
};
#endif // defined(ASIO_HAS_STD_REFERENCE_WRAPPER)
// || defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATED_EXECUTOR_HPP

View File

@ -0,0 +1,35 @@
//
// associator.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_ASSOCIATOR_HPP
#define ASIO_ASSOCIATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Used to generically specialise associators for a type.
template <template <typename, typename> class Associator,
typename T, typename DefaultCandidate>
struct associator
{
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_ASSOCIATOR_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,142 @@
//
// awaitable.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_AWAITABLE_HPP
#define ASIO_AWAITABLE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#if defined(ASIO_HAS_STD_COROUTINE)
# include <coroutine>
#else // defined(ASIO_HAS_STD_COROUTINE)
# include <experimental/coroutine>
#endif // defined(ASIO_HAS_STD_COROUTINE)
#include <utility>
#include "asio/any_io_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
#if defined(ASIO_HAS_STD_COROUTINE)
using std::coroutine_handle;
using std::suspend_always;
#else // defined(ASIO_HAS_STD_COROUTINE)
using std::experimental::coroutine_handle;
using std::experimental::suspend_always;
#endif // defined(ASIO_HAS_STD_COROUTINE)
template <typename> class awaitable_thread;
template <typename, typename> class awaitable_frame;
} // namespace detail
/// The return type of a coroutine or asynchronous operation.
template <typename T, typename Executor = any_io_executor>
class ASIO_NODISCARD awaitable
{
public:
/// The type of the awaited value.
typedef T value_type;
/// The executor type that will be used for the coroutine.
typedef Executor executor_type;
/// Default constructor.
constexpr awaitable() noexcept
: frame_(nullptr)
{
}
/// Move constructor.
awaitable(awaitable&& other) noexcept
: frame_(std::exchange(other.frame_, nullptr))
{
}
/// Destructor
~awaitable()
{
if (frame_)
frame_->destroy();
}
/// Move assignment.
awaitable& operator=(awaitable&& other) noexcept
{
if (this != &other)
frame_ = std::exchange(other.frame_, nullptr);
return *this;
}
/// Checks if the awaitable refers to a future result.
bool valid() const noexcept
{
return !!frame_;
}
#if !defined(GENERATING_DOCUMENTATION)
// Support for co_await keyword.
bool await_ready() const noexcept
{
return false;
}
// Support for co_await keyword.
template <class U>
void await_suspend(
detail::coroutine_handle<detail::awaitable_frame<U, Executor>> h)
{
frame_->push_frame(&h.promise());
}
// Support for co_await keyword.
T await_resume()
{
return awaitable(static_cast<awaitable&&>(*this)).frame_->get();
}
#endif // !defined(GENERATING_DOCUMENTATION)
private:
template <typename> friend class detail::awaitable_thread;
template <typename, typename> friend class detail::awaitable_frame;
// Not copy constructible or copy assignable.
awaitable(const awaitable&) = delete;
awaitable& operator=(const awaitable&) = delete;
// Construct the awaitable from a coroutine's frame object.
explicit awaitable(detail::awaitable_frame<T, Executor>* a)
: frame_(a)
{
}
detail::awaitable_frame<T, Executor>* frame_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/awaitable.hpp"
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_AWAITABLE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,709 @@
//
// basic_deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_DEADLINE_TIMER_HPP
#define ASIO_BASIC_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include "asio/any_io_executor.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/time_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides waitable timer functionality.
/**
* The basic_deadline_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* A deadline timer is always in one of two states: "expired" or "not expired".
* If the wait() or async_wait() function is called on an expired timer, the
* wait operation will complete immediately.
*
* Most applications will use the asio::deadline_timer typedef.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Examples
* Performing a blocking wait:
* @code
* // Construct a timer without setting an expiry time.
* asio::deadline_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_from_now(boost::posix_time::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait:
* @code
* void handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::deadline_timer timer(my_context,
* boost::posix_time::time_from_string("2005-12-07 23:59:59.000"));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active deadline_timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_from_now(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_deadline_timer::expires_from_now() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Time,
typename TimeTraits = asio::time_traits<Time>,
typename Executor = any_io_executor>
class basic_deadline_timer
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_deadline_timer<Time, TimeTraits, Executor1> other;
};
/// The time traits type.
typedef TimeTraits traits_type;
/// The time type.
typedef typename traits_type::time_type time_type;
/// The duration type.
typedef typename traits_type::duration_type duration_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_deadline_timer(const executor_type& ex)
: impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_from_now() functions must be called to set an
* expiry time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_deadline_timer(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_deadline_timer(const executor_type& ex, const time_type& expiry_time)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context, const time_type& expiry_time,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_deadline_timer(const executor_type& ex,
const duration_type& expiry_time)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
basic_deadline_timer(ExecutionContext& context,
const duration_type& expiry_time,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_deadline_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer(basic_deadline_timer&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_deadline_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_deadline_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_deadline_timer(const executor_type&)
* constructor.
*/
basic_deadline_timer& operator=(basic_deadline_timer&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_deadline_timer()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
return s;
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel(asio::error_code& ec)
{
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one()
{
asio::error_code ec;
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one");
return s;
}
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one(asio::error_code& ec)
{
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_type expires_at() const
{
return impl_.get_service().expires_at(impl_.get_implementation());
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_type& expiry_time)
{
asio::error_code ec;
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
return s;
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_type& expiry_time,
asio::error_code& ec)
{
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}
/// Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration_type expires_from_now() const
{
return impl_.get_service().expires_from_now(impl_.get_implementation());
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration_type& expiry_time)
{
asio::error_code ec;
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
return s;
}
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration_type& expiry_time,
asio::error_code& ec)
{
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws asio::system_error Thrown on failure.
*/
void wait()
{
asio::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(asio::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the timer expires. Potential
* completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
WaitToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WaitToken,
void (asio::error_code))
async_wait(
ASIO_MOVE_ARG(WaitToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WaitToken, void (asio::error_code)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_deadline_timer(const basic_deadline_timer&) ASIO_DELETED;
basic_deadline_timer& operator=(
const basic_deadline_timer&) ASIO_DELETED;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_deadline_timer* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
detail::non_const_lvalue<WaitHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_deadline_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<TimeTraits>, Executor> impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_DEADLINE_TIMER_HPP

View File

@ -0,0 +1,829 @@
//
// basic_file.hpp
// ~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_FILE_HPP
#define ASIO_BASIC_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/cstdint.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/post.hpp"
#include "asio/file_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_file_service.hpp"
#elif defined(ASIO_HAS_IO_URING)
# include "asio/detail/io_uring_file_service.hpp"
#endif
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_FILE_FWD_DECL)
#define ASIO_BASIC_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_file;
#endif // !defined(ASIO_BASIC_FILE_FWD_DECL)
/// Provides file functionality.
/**
* The basic_file class template provides functionality that is common to both
* stream-oriented and random-access files.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor>
class basic_file
: public file_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_file_service::native_handle_type native_handle_type;
#elif defined(ASIO_HAS_IO_URING)
typedef detail::io_uring_file_service::native_handle_type native_handle_type;
#endif
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_file(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file without opening it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_file.
/**
* This constructor initialises a file and opens it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
explicit basic_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file without opening it.
/**
* This constructor initialises a file and opens it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*/
template <typename ExecutionContext>
explicit basic_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_file on an existing native file handle.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file A native file handle.
*
* @throws asio::system_error Thrown on failure.
*/
basic_file(const executor_type& ex, const native_handle_type& native_file)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_file on an existing native file.
/**
* This constructor initialises a file object to hold an existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file A native file.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_file(ExecutionContext& context, const native_handle_type& native_file,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_file from another.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file(basic_file&& other) ASIO_NOEXCEPT
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from another.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
basic_file& operator=(basic_file&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All files have access to each other's implementations.
template <typename Executor1>
friend class basic_file;
/// Move-construct a basic_file from a file of another executor type.
/**
* This constructor moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
basic_file(basic_file<Executor1>&& other,
typename constraint<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_file from a file of another executor type.
/**
* This assignment operator moves a file from one object to another.
*
* @param other The other basic_file object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_file(const executor_type&) constructor.
*/
template <typename Executor1>
typename constraint<
is_convertible<Executor1, Executor>::value,
basic_file&
>::type operator=(basic_file<Executor1> && other)
{
basic_file tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* file.open("/path/to/my/file", asio::stream_file::read_only);
* @endcode
*/
void open(const char* path, file_base::flags open_flags)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* asio::error_code ec;
* file.open("/path/to/my/file", asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID open(const char* path,
file_base::flags open_flags, asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), path, open_flags, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* file.open("/path/to/my/file", asio::stream_file::read_only);
* @endcode
*/
void open(const std::string& path, file_base::flags open_flags)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the file using the specified path.
/**
* This function opens the file so that it will use the specified path.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @param ec Set to indicate what error occurred, if any.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* asio::error_code ec;
* file.open("/path/to/my/file", asio::stream_file::read_only, ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID open(const std::string& path,
file_base::flags open_flags, asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(),
path.c_str(), open_flags, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_file)
{
asio::error_code ec;
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native file to the file.
/*
* This function opens the file to hold an existing native file.
*
* @param native_file A native file.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_file,
asio::error_code& ec)
{
impl_.get_service().assign(
impl_.get_implementation(), native_file, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the file is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the file.
/**
* This function is used to close the file. Any asynchronous read or write
* operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any. Note that, even if
* the function indicates an error, the underlying descriptor is closed.
*
* @par Example
* @code
* asio::stream_file file(my_context);
* ...
* asio::error_code ec;
* file.close(ec);
* if (ec)
* {
* // An error occurred.
* }
* @endcode
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @throws asio::system_error Thrown on failure.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release()
{
asio::error_code ec;
native_handle_type s = impl_.get_service().release(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "release");
return s;
}
/// Release ownership of the underlying native file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
* Ownership of the native file is then transferred to the caller.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note This function is unsupported on Windows versions prior to Windows
* 8.1, and will fail with asio::error::operation_not_supported on
* these platforms.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0603)
__declspec(deprecated("This function always fails with "
"operation_not_supported when used on Windows versions "
"prior to Windows 8.1."))
#endif
native_handle_type release(asio::error_code& ec)
{
return impl_.get_service().release(impl_.get_implementation(), ec);
}
/// Get the native file representation.
/**
* This function may be used to obtain the underlying representation of the
* file. This is intended to allow access to native file functionality
* that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*
* @note Calls to cancel() will always fail with
* asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the file.
/**
* This function causes all outstanding asynchronous read and write
* operations to finish immediately, and the handlers for cancelled
* operations will be passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Calls to cancel() will always fail with
* asio::error::operation_not_supported when run on Windows XP, Windows
* Server 2003, and earlier versions of Windows, unless
* ASIO_ENABLE_CANCELIO is defined. However, the CancelIo function has
* two issues that should be considered before enabling its use:
*
* @li It will only cancel asynchronous operations that were initiated in the
* current thread.
*
* @li It can appear to complete without error, but the request to cancel the
* unfinished operations may be silently ignored by the operating system.
* Whether it works or not seems to depend on the drivers that are installed.
*
* For portable cancellation, consider using the close() function to
* simultaneously cancel the outstanding operations and close the file.
*
* When running on Windows Vista, Windows Server 2008, and later, the
* CancelIoEx function is always used. This function does not have the
* problems described above.
*/
#if defined(ASIO_MSVC) && (ASIO_MSVC >= 1400) \
&& (!defined(_WIN32_WINNT) || _WIN32_WINNT < 0x0600) \
&& !defined(ASIO_ENABLE_CANCELIO)
__declspec(deprecated("By default, this function always fails with "
"operation_not_supported when used on Windows XP, Windows Server 2003, "
"or earlier. Consult documentation for details."))
#endif
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @throws asio::system_error Thrown on failure.
*/
uint64_t size() const
{
asio::error_code ec;
uint64_t s = impl_.get_service().size(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "size");
return s;
}
/// Get the size of the file.
/**
* This function determines the size of the file, in bytes.
*
* @param ec Set to indicate what error occurred, if any.
*/
uint64_t size(asio::error_code& ec) const
{
return impl_.get_service().size(impl_.get_implementation(), ec);
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @throws asio::system_error Thrown on failure.
*/
void resize(uint64_t n)
{
asio::error_code ec;
impl_.get_service().resize(impl_.get_implementation(), n, ec);
asio::detail::throw_error(ec, "resize");
}
/// Alter the size of the file.
/**
* This function resizes the file to the specified size, in bytes. If the
* current file size exceeds @c n then any extra data is discarded. If the
* current size is less than @c n then the file is extended and filled with
* zeroes.
*
* @param n The new size for the file.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID resize(uint64_t n, asio::error_code& ec)
{
impl_.get_service().resize(impl_.get_implementation(), n, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @throws asio::system_error Thrown on failure.
*/
void sync_all()
{
asio::error_code ec;
impl_.get_service().sync_all(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "sync_all");
}
/// Synchronise the file to disk.
/**
* This function synchronises the file data and metadata to disk. Note that
* the semantics of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID sync_all(asio::error_code& ec)
{
impl_.get_service().sync_all(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @throws asio::system_error Thrown on failure.
*/
void sync_data()
{
asio::error_code ec;
impl_.get_service().sync_data(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "sync_data");
}
/// Synchronise the file data to disk.
/**
* This function synchronises the file data to disk. Note that the semantics
* of this synchronisation vary between operation systems.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID sync_data(asio::error_code& ec)
{
impl_.get_service().sync_data(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
protected:
/// Protected destructor to prevent deletion through this type.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_file()
{
}
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_file_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING)
detail::io_object_impl<detail::io_uring_file_service, Executor> impl_;
#endif
private:
// Disallow copying and assignment.
basic_file(const basic_file&) ASIO_DELETED;
basic_file& operator=(const basic_file&) ASIO_DELETED;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_FILE_HPP

View File

@ -0,0 +1,290 @@
//
// basic_io_object.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_IO_OBJECT_HPP
#define ASIO_BASIC_IO_OBJECT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/io_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_HAS_MOVE)
namespace detail
{
// Type trait used to determine whether a service supports move.
template <typename IoObjectService>
class service_has_move
{
private:
typedef IoObjectService service_type;
typedef typename service_type::implementation_type implementation_type;
template <typename T, typename U>
static auto asio_service_has_move_eval(T* t, U* u)
-> decltype(t->move_construct(*u, *u), char());
static char (&asio_service_has_move_eval(...))[2];
public:
static const bool value =
sizeof(asio_service_has_move_eval(
static_cast<service_type*>(0),
static_cast<implementation_type*>(0))) == 1;
};
}
#endif // defined(ASIO_HAS_MOVE)
/// Base class for all I/O objects.
/**
* @note All I/O objects are non-copyable. However, when using C++0x, certain
* I/O objects do support move construction and move assignment.
*/
#if !defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
template <typename IoObjectService>
#else
template <typename IoObjectService,
bool Movable = detail::service_has_move<IoObjectService>::value>
#endif
class basic_io_object
{
public:
/// The type of the service that will be used to provide I/O operations.
typedef IoObjectService service_type;
/// The underlying implementation type of I/O object.
typedef typename service_type::implementation_type implementation_type;
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_context()
{
return service_.get_io_context();
}
/// (Deprecated: Use get_executor().) Get the io_context associated with the
/// object.
/**
* This function may be used to obtain the io_context object that the I/O
* object uses to dispatch handlers for asynchronous operations.
*
* @return A reference to the io_context object that the I/O object will use
* to dispatch handlers. Ownership is not transferred to the caller.
*/
asio::io_context& get_io_service()
{
return service_.get_io_context();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// The type of the executor associated with the object.
typedef asio::io_context::executor_type executor_type;
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return service_.get_io_context().get_executor();
}
protected:
/// Construct a basic_io_object.
/**
* Performs:
* @code get_service().construct(get_implementation()); @endcode
*/
explicit basic_io_object(asio::io_context& io_context)
: service_(asio::use_service<IoObjectService>(io_context))
{
service_.construct(implementation_);
}
#if defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_io_object.
/**
* Performs:
* @code get_service().move_construct(
* get_implementation(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object(basic_io_object&& other);
/// Move-assign a basic_io_object.
/**
* Performs:
* @code get_service().move_assign(get_implementation(),
* other.get_service(), other.get_implementation()); @endcode
*
* @note Available only for services that support movability,
*/
basic_io_object& operator=(basic_io_object&& other);
/// Perform a converting move-construction of a basic_io_object.
template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation);
#endif // defined(GENERATING_DOCUMENTATION)
/// Protected destructor to prevent deletion through this type.
/**
* Performs:
* @code get_service().destroy(get_implementation()); @endcode
*/
~basic_io_object()
{
service_.destroy(implementation_);
}
/// Get the service associated with the I/O object.
service_type& get_service()
{
return service_;
}
/// Get the service associated with the I/O object.
const service_type& get_service() const
{
return service_;
}
/// Get the underlying implementation of the I/O object.
implementation_type& get_implementation()
{
return implementation_;
}
/// Get the underlying implementation of the I/O object.
const implementation_type& get_implementation() const
{
return implementation_;
}
private:
basic_io_object(const basic_io_object&);
basic_io_object& operator=(const basic_io_object&);
// The service associated with the I/O object.
service_type& service_;
/// The underlying implementation of the I/O object.
implementation_type implementation_;
};
#if defined(ASIO_HAS_MOVE)
// Specialisation for movable objects.
template <typename IoObjectService>
class basic_io_object<IoObjectService, true>
{
public:
typedef IoObjectService service_type;
typedef typename service_type::implementation_type implementation_type;
#if !defined(ASIO_NO_DEPRECATED)
asio::io_context& get_io_context()
{
return service_->get_io_context();
}
asio::io_context& get_io_service()
{
return service_->get_io_context();
}
#endif // !defined(ASIO_NO_DEPRECATED)
typedef asio::io_context::executor_type executor_type;
executor_type get_executor() ASIO_NOEXCEPT
{
return service_->get_io_context().get_executor();
}
protected:
explicit basic_io_object(asio::io_context& io_context)
: service_(&asio::use_service<IoObjectService>(io_context))
{
service_->construct(implementation_);
}
basic_io_object(basic_io_object&& other)
: service_(&other.get_service())
{
service_->move_construct(implementation_, other.implementation_);
}
template <typename IoObjectService1>
basic_io_object(IoObjectService1& other_service,
typename IoObjectService1::implementation_type& other_implementation)
: service_(&asio::use_service<IoObjectService>(
other_service.get_io_context()))
{
service_->converting_move_construct(implementation_,
other_service, other_implementation);
}
~basic_io_object()
{
service_->destroy(implementation_);
}
basic_io_object& operator=(basic_io_object&& other)
{
service_->move_assign(implementation_,
*other.service_, other.implementation_);
service_ = other.service_;
return *this;
}
service_type& get_service()
{
return *service_;
}
const service_type& get_service() const
{
return *service_;
}
implementation_type& get_implementation()
{
return implementation_;
}
const implementation_type& get_implementation() const
{
return implementation_;
}
private:
basic_io_object(const basic_io_object&);
void operator=(const basic_io_object&);
IoObjectService* service_;
implementation_type implementation_;
};
#endif // defined(ASIO_HAS_MOVE)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_IO_OBJECT_HPP

View File

@ -0,0 +1,689 @@
//
// basic_random_access_file.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#define ASIO_BASIC_RANDOM_ACCESS_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/basic_file.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
#define ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_random_access_file;
#endif // !defined(ASIO_BASIC_RANDOM_ACCESS_FILE_FWD_DECL)
/// Provides random-access file functionality.
/**
* The basic_random_access_file class template provides asynchronous and
* blocking random-access file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* Synchronous @c read_some_at and @c write_some_at operations are thread safe
* with respect to each other, if the underlying operating system calls are
* also thread safe. This means that it is permitted to perform concurrent
* calls to these synchronous operations on a single file object. Other
* synchronous operations, such as @c open or @c close, are not thread safe.
*/
template <typename Executor>
class basic_random_access_file
: public basic_file<Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_random_access_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_random_access_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
}
/// Construct a basic_random_access_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_random_access_file(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex, path, open_flags)
{
}
/// Construct and open a basic_random_access_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context, path, open_flags)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_random_access_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
}
/// Construct a basic_random_access_file on an existing native file.
/**
* This constructor initialises a random-access file object to hold an
* existing native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_random_access_file(ExecutionContext& context,
const native_handle_type& native_file,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_random_access_file from another.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file(basic_random_access_file&& other) ASIO_NOEXCEPT
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from another.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
basic_random_access_file& operator=(basic_random_access_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_random_access_file from a file of another executor
/// type.
/**
* This constructor moves a random-access file from one object to another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_random_access_file(basic_random_access_file<Executor1>&& other,
typename constraint<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_random_access_file from a file of another executor
/// type.
/**
* This assignment operator moves a random-access file from one object to
* another.
*
* @param other The other basic_random_access_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_random_access_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
typename constraint<
is_convertible<Executor1, Executor>::value,
basic_random_access_file&
>::type operator=(basic_random_access_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_random_access_file()
{
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some_at operation may not write all of the data. Consider
* using the @ref write_at function if you need to ensure that all data is
* written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.write_some_at(42, asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
asio::detail::throw_error(ec, "write_some_at");
return s;
}
/// Write some data to the handle at the specified offset.
/**
* This function is used to write data to the random-access handle. The
* function call will block until one or more bytes of the data has been
* written successfully, or until an error occurs.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not write all of the data to the
* file. Consider using the @ref write_at function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some_at(uint64_t offset,
const ConstBufferSequence& buffers, asio::error_code& ec)
{
return this->impl_.get_service().write_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous write at the specified offset.
/**
* This function is used to asynchronously write data to the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be written.
*
* @param buffers One or more data buffers to be written to the handle.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not write all of the data to the file.
* Consider using the @ref async_write_at function if you need to ensure that
* all data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_write_some_at(42, asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (asio::error_code, std::size_t))
async_write_some_at(uint64_t offset,
const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some_at(this), token, offset, buffers);
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.read_some_at(42, asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
asio::detail::throw_error(ec, "read_some_at");
return s;
}
/// Read some data from the handle at the specified offset.
/**
* This function is used to read data from the random-access handle. The
* function call will block until one or more bytes of data has been read
* successfully, or until an error occurs.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read_at function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some_at(uint64_t offset,
const MutableBufferSequence& buffers, asio::error_code& ec)
{
return this->impl_.get_service().read_some_at(
this->impl_.get_implementation(), offset, buffers, ec);
}
/// Start an asynchronous read at the specified offset.
/**
* This function is used to asynchronously read data from the random-access
* handle. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param offset The offset at which the data will be read.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read_at function if you need to ensure that
* the requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* handle.async_read_some_at(42, asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_read_some_at(uint64_t offset,
const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some_at(this), token, offset, buffers);
}
private:
// Disallow copying and assignment.
basic_random_access_file(const basic_random_access_file&) ASIO_DELETED;
basic_random_access_file& operator=(
const basic_random_access_file&) ASIO_DELETED;
class initiate_async_write_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some_at(basic_random_access_file* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
uint64_t offset, const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
class initiate_async_read_some_at
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some_at(basic_random_access_file* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
uint64_t offset, const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some_at(
self_->impl_.get_implementation(), offset, buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_random_access_file* self_;
};
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_RANDOM_ACCESS_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,529 @@
//
// basic_readable_pipe.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_READABLE_PIPE_HPP
#define ASIO_BASIC_READABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_handle_service.hpp"
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
# include "asio/detail/io_uring_descriptor_service.hpp"
#else
# include "asio/detail/reactive_descriptor_service.hpp"
#endif
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides pipe functionality.
/**
* The basic_readable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_readable_pipe
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_readable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_readable_pipe is always the lowest layer.
typedef basic_readable_pipe lowest_layer_type;
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_readable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_readable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_readable_pipe(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
basic_readable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_readable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_readable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_readable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe(basic_readable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_readable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_readable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_readable_pipe(const executor_type&)
* constructor.
*/
basic_readable_pipe& operator=(basic_readable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_readable_pipe()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_readable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous read operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous read operations to finish
* immediately, and the handlers for cancelled operations will be passed the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the pipe.
/**
* This function is used to read data from the pipe. The function call will
* block until one or more bytes of data has been read successfully, or until
* an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_readable_pipe.async_read_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_readable_pipe(const basic_readable_pipe&) ASIO_DELETED;
basic_readable_pipe& operator=(const basic_readable_pipe&) ASIO_DELETED;
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_readable_pipe* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_readable_pipe* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_READABLE_PIPE_HPP

View File

@ -0,0 +1,816 @@
//
// basic_seq_packet_socket.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
#define ASIO_BASIC_SEQ_PACKET_SOCKET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/basic_socket.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
#define ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol, typename Executor = any_io_executor>
class basic_seq_packet_socket;
#endif // !defined(ASIO_BASIC_SEQ_PACKET_SOCKET_FWD_DECL)
/// Provides sequenced packet socket functionality.
/**
* The basic_seq_packet_socket class template provides asynchronous and blocking
* sequenced packet socket functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* Synchronous @c send, @c receive, and @c connect operations are thread safe
* with respect to each other, if the underlying operating system calls are
* also thread safe. This means that it is permitted to perform concurrent
* calls to these synchronous operations on a single socket object. Other
* synchronous operations, such as @c open or @c close, are not thread safe.
*/
template <typename Protocol, typename Executor>
class basic_seq_packet_socket
: public basic_socket<Protocol, Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the socket type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The socket type when rebound to the specified executor.
typedef basic_seq_packet_socket<Protocol, Executor1> other;
};
/// The native representation of a socket.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_socket<Protocol,
Executor>::native_handle_type native_handle_type;
#endif
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*/
explicit basic_seq_packet_socket(const executor_type& ex)
: basic_socket<Protocol, Executor>(ex)
{
}
/// Construct a basic_seq_packet_socket without opening it.
/**
* This constructor creates a sequenced packet socket without opening it. The
* socket needs to be opened and then connected or accepted before data can
* be sent or received on it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*/
template <typename ExecutionContext>
explicit basic_seq_packet_socket(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: basic_socket<Protocol, Executor>(context)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol)
: basic_socket<Protocol, Executor>(ex, protocol)
{
}
/// Construct and open a basic_seq_packet_socket.
/**
* This constructor creates and opens a sequenced_packet socket. The socket
* needs to be connected or accepted before data can be sent or received on
* it.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_socket<Protocol, Executor>(context, protocol)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const endpoint_type& endpoint)
: basic_socket<Protocol, Executor>(ex, endpoint)
{
}
/// Construct a basic_seq_packet_socket, opening it and binding it to the
/// given local endpoint.
/**
* This constructor creates a sequenced packet socket and automatically opens
* it bound to the specified endpoint on the local machine. The protocol used
* is the protocol associated with the given endpoint.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param endpoint An endpoint on the local machine to which the sequenced
* packet socket will be bound.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const endpoint_type& endpoint,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: basic_socket<Protocol, Executor>(context, endpoint)
{
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param ex The I/O executor that the socket will use, by default, to
* dispatch handlers for any asynchronous operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_seq_packet_socket(const executor_type& ex,
const protocol_type& protocol, const native_handle_type& native_socket)
: basic_socket<Protocol, Executor>(ex, protocol, native_socket)
{
}
/// Construct a basic_seq_packet_socket on an existing native socket.
/**
* This constructor creates a sequenced packet socket object to hold an
* existing native socket.
*
* @param context An execution context which provides the I/O executor that
* the socket will use, by default, to dispatch handlers for any asynchronous
* operations performed on the socket.
*
* @param protocol An object specifying protocol parameters to be used.
*
* @param native_socket The new underlying socket implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_seq_packet_socket(ExecutionContext& context,
const protocol_type& protocol, const native_handle_type& native_socket,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: basic_socket<Protocol, Executor>(context, protocol, native_socket)
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_seq_packet_socket from another.
/**
* This constructor moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket(basic_seq_packet_socket&& other) ASIO_NOEXCEPT
: basic_socket<Protocol, Executor>(std::move(other))
{
}
/// Move-assign a basic_seq_packet_socket from another.
/**
* This assignment operator moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
basic_seq_packet_socket& operator=(basic_seq_packet_socket&& other)
{
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_seq_packet_socket from a socket of another protocol
/// type.
/**
* This constructor moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename Executor1>
basic_seq_packet_socket(basic_seq_packet_socket<Protocol1, Executor1>&& other,
typename constraint<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value
>::type = 0)
: basic_socket<Protocol, Executor>(std::move(other))
{
}
/// Move-assign a basic_seq_packet_socket from a socket of another protocol
/// type.
/**
* This assignment operator moves a sequenced packet socket from one object to
* another.
*
* @param other The other basic_seq_packet_socket object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_seq_packet_socket(const executor_type&)
* constructor.
*/
template <typename Protocol1, typename Executor1>
typename constraint<
is_convertible<Protocol1, Protocol>::value
&& is_convertible<Executor1, Executor>::value,
basic_seq_packet_socket&
>::type operator=(basic_seq_packet_socket<Protocol1, Executor1>&& other)
{
basic_socket<Protocol, Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the socket.
/**
* This function destroys the socket, cancelling any outstanding asynchronous
* operations associated with the socket as if by calling @c cancel.
*/
~basic_seq_packet_socket()
{
}
/// Send some data on the socket.
/**
* This function is used to send data on the sequenced packet socket. The
* function call will block until the data has been sent successfully, or an
* until error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @returns The number of bytes sent.
*
* @throws asio::system_error Thrown on failure.
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.send(asio::buffer(data, size), 0);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
asio::detail::throw_error(ec, "send");
return s;
}
/// Send some data on the socket.
/**
* This function is used to send data on the sequenced packet socket. The
* function call will block the data has been sent successfully, or an until
* error occurs.
*
* @param buffers One or more data buffers to be sent on the socket.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes sent. Returns 0 if an error occurred.
*
* @note The send operation may not transmit all of the data to the peer.
* Consider using the @ref write function if you need to ensure that all data
* is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t send(const ConstBufferSequence& buffers,
socket_base::message_flags flags, asio::error_code& ec)
{
return this->impl_.get_service().send(
this->impl_.get_implementation(), buffers, flags, ec);
}
/// Start an asynchronous send.
/**
* This function is used to asynchronously send data on the sequenced packet
* socket. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* @param buffers One or more data buffers to be sent on the socket. Although
* the buffers object may be copied as necessary, ownership of the underlying
* memory blocks is retained by the caller, which must guarantee that they
* remain valid until the completion handler is called.
*
* @param flags Flags specifying how the send call is to be made.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the send completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes sent.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @par Example
* To send a single data buffer use the @ref buffer function as follows:
* @code
* socket.async_send(asio::buffer(data, size), 0, handler);
* @endcode
* See the @ref buffer documentation for information on sending multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (asio::error_code, std::size_t))
async_send(const ConstBufferSequence& buffers,
socket_base::message_flags flags,
ASIO_MOVE_ARG(WriteToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_send(this), token, buffers, flags);
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size), out_flags);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, 0, out_flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
/// Receive some data on the socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @returns The number of bytes received.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.receive(asio::buffer(data, size), 0, out_flags);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
asio::detail::throw_error(ec, "receive");
return s;
}
/// Receive some data on a connected socket.
/**
* This function is used to receive data on the sequenced packet socket. The
* function call will block until data has been received successfully, or
* until an error occurs.
*
* @param buffers One or more buffers into which the data will be received.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags After the receive call completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes received. Returns 0 if an error occurred.
*
* @note The receive operation may not receive all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that the
* requested amount of data is read before the blocking operation completes.
*/
template <typename MutableBufferSequence>
std::size_t receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags, asio::error_code& ec)
{
return this->impl_.get_service().receive_with_flags(
this->impl_.get_implementation(), buffers, in_flags, out_flags, ec);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the sequenced
* packet socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param out_flags Once the asynchronous operation completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced
* variable remains valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the receive completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(asio::buffer(data, size), out_flags, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_receive_with_flags(this), token,
buffers, socket_base::message_flags(0), &out_flags);
}
/// Start an asynchronous receive.
/**
* This function is used to asynchronously receive data from the sequenced
* data socket. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* @param buffers One or more buffers into which the data will be received.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param in_flags Flags specifying how the receive call is to be made.
*
* @param out_flags Once the asynchronous operation completes, contains flags
* associated with the received data. For example, if the
* socket_base::message_end_of_record bit is set then the received data marks
* the end of a record. The caller must guarantee that the referenced
* variable remains valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the receive completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes received.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @par Example
* To receive into a single data buffer use the @ref buffer function as
* follows:
* @code
* socket.async_receive(
* asio::buffer(data, size),
* 0, out_flags, handler);
* @endcode
* See the @ref buffer documentation for information on receiving into
* multiple buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_receive(const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags& out_flags,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_receive_with_flags(this),
token, buffers, in_flags, &out_flags);
}
private:
// Disallow copying and assignment.
basic_seq_packet_socket(const basic_seq_packet_socket&) ASIO_DELETED;
basic_seq_packet_socket& operator=(
const basic_seq_packet_socket&) ASIO_DELETED;
class initiate_async_send
{
public:
typedef Executor executor_type;
explicit initiate_async_send(basic_seq_packet_socket* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
const ConstBufferSequence& buffers,
socket_base::message_flags flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_send(
self_->impl_.get_implementation(), buffers, flags,
handler2.value, self_->impl_.get_executor());
}
private:
basic_seq_packet_socket* self_;
};
class initiate_async_receive_with_flags
{
public:
typedef Executor executor_type;
explicit initiate_async_receive_with_flags(basic_seq_packet_socket* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
const MutableBufferSequence& buffers,
socket_base::message_flags in_flags,
socket_base::message_flags* out_flags) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_receive_with_flags(
self_->impl_.get_implementation(), buffers, in_flags,
*out_flags, handler2.value, self_->impl_.get_executor());
}
private:
basic_seq_packet_socket* self_;
};
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SEQ_PACKET_SOCKET_HPP

View File

@ -0,0 +1,939 @@
//
// basic_serial_port.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
// Copyright (c) 2008 Rep Invariant Systems, Inc. (info@repinvariant.com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SERIAL_PORT_HPP
#define ASIO_BASIC_SERIAL_PORT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_SERIAL_PORT) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/serial_port_base.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_serial_port_service.hpp"
#else
# include "asio/detail/posix_serial_port_service.hpp"
#endif
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides serial port functionality.
/**
* The basic_serial_port class provides a wrapper over serial port
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_serial_port
: public serial_port_base
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the serial port type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The serial port type when rebound to the specified executor.
typedef basic_serial_port<Executor1> other;
};
/// The native representation of a serial port.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_serial_port_service::native_handle_type
native_handle_type;
#else
typedef detail::posix_serial_port_service::native_handle_type
native_handle_type;
#endif
/// A basic_basic_serial_port is always the lowest layer.
typedef basic_serial_port lowest_layer_type;
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*/
explicit basic_serial_port(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_serial_port without opening it.
/**
* This constructor creates a serial port without opening it.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*/
template <typename ExecutionContext>
explicit basic_serial_port(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const char* device)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const char* device,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
basic_serial_port(const executor_type& ex, const std::string& device)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_serial_port.
/**
* This constructor creates and opens a serial port for the specified device
* name.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param device The platform-specific device name for this serial
* port.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context, const std::string& device,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param ex The I/O executor that the serial port will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
basic_serial_port(const executor_type& ex,
const native_handle_type& native_serial_port)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_serial_port on an existing native serial port.
/**
* This constructor creates a serial port object to hold an existing native
* serial port.
*
* @param context An execution context which provides the I/O executor that
* the serial port will use, by default, to dispatch handlers for any
* asynchronous operations performed on the serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_serial_port(ExecutionContext& context,
const native_handle_type& native_serial_port,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_serial_port from another.
/**
* This constructor moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port(basic_serial_port&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_serial_port from another.
/**
* This assignment operator moves a serial port from one object to another.
*
* @param other The other basic_serial_port object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_serial_port(const executor_type&)
* constructor.
*/
basic_serial_port& operator=(basic_serial_port&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the serial port.
/**
* This function destroys the serial port, cancelling any outstanding
* asynchronous wait operations associated with the serial port as if by
* calling @c cancel.
*/
~basic_serial_port()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_serial_port cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port for the specified device name.
*
* @param device The platform-specific device name.
*
* @throws asio::system_error Thrown on failure.
*/
void open(const std::string& device)
{
asio::error_code ec;
impl_.get_service().open(impl_.get_implementation(), device, ec);
asio::detail::throw_error(ec, "open");
}
/// Open the serial port using the specified device name.
/**
* This function opens the serial port using the given platform-specific
* device name.
*
* @param device The platform-specific device name.
*
* @param ec Set the indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID open(const std::string& device,
asio::error_code& ec)
{
impl_.get_service().open(impl_.get_implementation(), device, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_serial_port)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native serial port to the serial port.
/*
* This function opens the serial port to hold an existing native serial port.
*
* @param native_serial_port A native serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_serial_port,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(),
native_serial_port, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the serial port is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the serial port.
/**
* This function is used to close the serial port. Any asynchronous read or
* write operations will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native serial port representation.
/**
* This function may be used to obtain the underlying representation of the
* serial port. This is intended to allow access to native serial port
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the serial port.
/**
* This function causes all outstanding asynchronous read or write operations
* to finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @throws asio::system_error Thrown on failure.
*/
void send_break()
{
asio::error_code ec;
impl_.get_service().send_break(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "send_break");
}
/// Send a break sequence to the serial port.
/**
* This function causes a break sequence of platform-specific duration to be
* sent out the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID send_break(asio::error_code& ec)
{
impl_.get_service().send_break(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
void set_option(const SettableSerialPortOption& option)
{
asio::error_code ec;
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "set_option");
}
/// Set an option on the serial port.
/**
* This function is used to set an option on the serial port.
*
* @param option The option value to be set on the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa SettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename SettableSerialPortOption>
ASIO_SYNC_OP_VOID set_option(const SettableSerialPortOption& option,
asio::error_code& ec)
{
impl_.get_service().set_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @throws asio::system_error Thrown on failure.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
void get_option(GettableSerialPortOption& option) const
{
asio::error_code ec;
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
asio::detail::throw_error(ec, "get_option");
}
/// Get an option from the serial port.
/**
* This function is used to get the current value of an option on the serial
* port.
*
* @param option The option value to be obtained from the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @sa GettableSerialPortOption @n
* asio::serial_port_base::baud_rate @n
* asio::serial_port_base::flow_control @n
* asio::serial_port_base::parity @n
* asio::serial_port_base::stop_bits @n
* asio::serial_port_base::character_size
*/
template <typename GettableSerialPortOption>
ASIO_SYNC_OP_VOID get_option(GettableSerialPortOption& option,
asio::error_code& ec) const
{
impl_.get_service().get_option(impl_.get_implementation(), option, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the serial port.
/**
* This function is used to write data to the serial port. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the serial port.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the serial port.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more data buffers to be written to the serial port.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_write_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the serial port.
/**
* This function is used to read data from the serial port. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().read_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the serial port.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* basic_serial_port.async_read_some(
* asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_serial_port(const basic_serial_port&) ASIO_DELETED;
basic_serial_port& operator=(const basic_serial_port&) ASIO_DELETED;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_serial_port* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_serial_port* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_serial_port* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_serial_port* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_serial_port_service, Executor> impl_;
#else
detail::io_object_impl<detail::posix_serial_port_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_SERIAL_PORT)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_SERIAL_PORT_HPP

View File

@ -0,0 +1,592 @@
//
// basic_signal_set.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SIGNAL_SET_HPP
#define ASIO_BASIC_SIGNAL_SET_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/signal_set_service.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides signal functionality.
/**
* The basic_signal_set class provides the ability to perform an asynchronous
* wait for one or more signals to occur.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Example
* Performing an asynchronous wait:
* @code
* void handler(
* const asio::error_code& error,
* int signal_number)
* {
* if (!error)
* {
* // A signal occurred.
* }
* }
*
* ...
*
* // Construct a signal set registered for process termination.
* asio::signal_set signals(my_context, SIGINT, SIGTERM);
*
* // Start an asynchronous wait for one of the signals to occur.
* signals.async_wait(handler);
* @endcode
*
* @par Queueing of signal notifications
*
* If a signal is registered with a signal_set, and the signal occurs when
* there are no waiting handlers, then the signal notification is queued. The
* next async_wait operation on that signal_set will dequeue the notification.
* If multiple notifications are queued, subsequent async_wait operations
* dequeue them one at a time. Signal notifications are dequeued in order of
* ascending signal number.
*
* If a signal number is removed from a signal_set (using the @c remove or @c
* erase member functions) then any queued notifications for that signal are
* discarded.
*
* @par Multiple registration of signals
*
* The same signal number may be registered with different signal_set objects.
* When the signal occurs, one handler is called for each signal_set object.
*
* Note that multiple registration only works for signals that are registered
* using Asio. The application must not also register a signal handler using
* functions such as @c signal() or @c sigaction().
*
* @par Signal masking on POSIX platforms
*
* POSIX allows signals to be blocked using functions such as @c sigprocmask()
* and @c pthread_sigmask(). For signals to be delivered, programs must ensure
* that any signals registered using signal_set objects are unblocked in at
* least one thread.
*/
template <typename Executor = any_io_executor>
class basic_signal_set
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the signal set type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The signal set type when rebound to the specified executor.
typedef basic_signal_set<Executor1> other;
};
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*/
explicit basic_signal_set(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a signal set without adding any signals.
/**
* This constructor creates a signal set without registering for any signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*/
template <typename ExecutionContext>
explicit basic_signal_set(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add one signal.
/**
* This constructor creates a signal set and registers for one signal.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add two signals.
/**
* This constructor creates a signal set and registers for two signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param ex The I/O executor that the signal set will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(ex);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
basic_signal_set(const executor_type& ex, int signal_number_1,
int signal_number_2, int signal_number_3)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}
/// Construct a signal set and add three signals.
/**
* This constructor creates a signal set and registers for three signals.
*
* @param context An execution context which provides the I/O executor that
* the signal set will use, by default, to dispatch handlers for any
* asynchronous operations performed on the signal set.
*
* @param signal_number_1 The first signal number to be added.
*
* @param signal_number_2 The second signal number to be added.
*
* @param signal_number_3 The third signal number to be added.
*
* @note This constructor is equivalent to performing:
* @code asio::signal_set signals(context);
* signals.add(signal_number_1);
* signals.add(signal_number_2);
* signals.add(signal_number_3); @endcode
*/
template <typename ExecutionContext>
basic_signal_set(ExecutionContext& context, int signal_number_1,
int signal_number_2, int signal_number_3,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number_1, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_2, ec);
asio::detail::throw_error(ec, "add");
impl_.get_service().add(impl_.get_implementation(), signal_number_3, ec);
asio::detail::throw_error(ec, "add");
}
/// Destroys the signal set.
/**
* This function destroys the signal set, cancelling any outstanding
* asynchronous wait operations associated with the signal set as if by
* calling @c cancel.
*/
~basic_signal_set()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @throws asio::system_error Thrown on failure.
*/
void add(int signal_number)
{
asio::error_code ec;
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "add");
}
/// Add a signal to a signal_set.
/**
* This function adds the specified signal to the set. It has no effect if the
* signal is already in the set.
*
* @param signal_number The signal to be added to the set.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID add(int signal_number,
asio::error_code& ec)
{
impl_.get_service().add(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @throws asio::system_error Thrown on failure.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
void remove(int signal_number)
{
asio::error_code ec;
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
asio::detail::throw_error(ec, "remove");
}
/// Remove a signal from a signal_set.
/**
* This function removes the specified signal from the set. It has no effect
* if the signal is not in the set.
*
* @param signal_number The signal to be removed from the set.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes any notifications that have been queued for the specified
* signal number.
*/
ASIO_SYNC_OP_VOID remove(int signal_number,
asio::error_code& ec)
{
impl_.get_service().remove(impl_.get_implementation(), signal_number, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @throws asio::system_error Thrown on failure.
*
* @note Removes all queued notifications.
*/
void clear()
{
asio::error_code ec;
impl_.get_service().clear(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "clear");
}
/// Remove all signals from a signal_set.
/**
* This function removes all signals from the set. It has no effect if the set
* is already empty.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note Removes all queued notifications.
*/
ASIO_SYNC_OP_VOID clear(asio::error_code& ec)
{
impl_.get_service().clear(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @throws asio::system_error Thrown on failure.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all operations associated with the signal set.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the signal set. The handler for each cancelled
* operation will be invoked with the asio::error::operation_aborted
* error code.
*
* Cancellation does not alter the set of registered signals.
*
* @param ec Set to indicate what error occurred, if any.
*
* @note If a registered signal occurred before cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Start an asynchronous operation to wait for a signal to be delivered.
/**
* This function may be used to initiate an asynchronous wait against the
* signal set. It is an initiating function for an @ref
* asynchronous_operation, and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li One of the registered signals in the signal set occurs; or
*
* @li The signal set was cancelled, in which case the handler is passed the
* error code asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the wait completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* int signal_number // Indicates which signal occurred.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, int) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code, int))
SignalToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(SignalToken,
void (asio::error_code, int))
async_wait(
ASIO_MOVE_ARG(SignalToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<SignalToken, void (asio::error_code, int)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_signal_set(const basic_signal_set&) ASIO_DELETED;
basic_signal_set& operator=(const basic_signal_set&) ASIO_DELETED;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_signal_set* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename SignalHandler>
void operator()(ASIO_MOVE_ARG(SignalHandler) handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a SignalHandler.
ASIO_SIGNAL_HANDLER_CHECK(SignalHandler, handler) type_check;
detail::non_const_lvalue<SignalHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_signal_set* self_;
};
detail::io_object_impl<detail::signal_set_service, Executor> impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_SIGNAL_SET_HPP

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,407 @@
//
// basic_socket_iostream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_IOSTREAM_HPP
#define ASIO_BASIC_SOCKET_IOSTREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_NO_IOSTREAM)
#include <istream>
#include <ostream>
#include "asio/basic_socket_streambuf.hpp"
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# include "asio/detail/variadic_templates.hpp"
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// explicit basic_socket_iostream(T1 x1, ..., Tn xn)
// : std::basic_iostream<char>(
// &this->detail::socket_iostream_base<
// Protocol, Clock, WaitTraits>::streambuf_)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CTR_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
explicit basic_socket_iostream(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
: std::basic_iostream<char>( \
&this->detail::socket_iostream_base< \
Protocol, Clock, WaitTraits>::streambuf_) \
{ \
this->setf(std::ios_base::unitbuf); \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// void connect(T1 x1, ..., Tn xn)
// {
// if (rdbuf()->connect(x1, ..., xn) == 0)
// this->setstate(std::ios_base::failbit);
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CONNECT_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
void connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
if (rdbuf()->connect(ASIO_VARIADIC_BYVAL_ARGS(n)) == 0) \
this->setstate(std::ios_base::failbit); \
} \
/**/
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// A separate base class is used to ensure that the streambuf is initialised
// prior to the basic_socket_iostream's basic_iostream base class.
template <typename Protocol, typename Clock, typename WaitTraits>
class socket_iostream_base
{
protected:
socket_iostream_base()
{
}
#if defined(ASIO_HAS_MOVE)
socket_iostream_base(socket_iostream_base&& other)
: streambuf_(std::move(other.streambuf_))
{
}
socket_iostream_base(basic_stream_socket<Protocol> s)
: streambuf_(std::move(s))
{
}
socket_iostream_base& operator=(socket_iostream_base&& other)
{
streambuf_ = std::move(other.streambuf_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE)
basic_socket_streambuf<Protocol, Clock, WaitTraits> streambuf_;
};
} // namespace detail
#if !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
#define ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol,
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> >
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_iostream;
#endif // !defined(ASIO_BASIC_SOCKET_IOSTREAM_FWD_DECL)
/// Iostream interface for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_iostream
: private detail::socket_iostream_base<Protocol, Clock, WaitTraits>,
public std::basic_iostream<char>
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The clock type.
typedef Clock clock_type;
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename WaitTraits::time_type time_type;
/// The time type.
typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
typedef typename traits_helper::duration_type duration_type;
# endif // !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_point;
typedef typename traits_helper::duration_type duration;
#endif
/// Construct a basic_socket_iostream without establishing a connection.
basic_socket_iostream()
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_iostream from the supplied socket.
explicit basic_socket_iostream(basic_stream_socket<protocol_type> s)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(s)),
std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
}
#if defined(ASIO_HAS_STD_IOSTREAM_MOVE) \
|| defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_socket_iostream from another.
basic_socket_iostream(basic_socket_iostream&& other)
: detail::socket_iostream_base<
Protocol, Clock, WaitTraits>(std::move(other)),
std::basic_iostream<char>(std::move(other))
{
this->set_rdbuf(&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_);
}
/// Move-assign a basic_socket_iostream from another.
basic_socket_iostream& operator=(basic_socket_iostream&& other)
{
std::basic_iostream<char>::operator=(std::move(other));
detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_STD_IOSTREAM_MOVE)
// || defined(GENERATING_DOCUMENTATION)
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This constructor automatically establishes a connection based on the
* supplied resolver query parameters. The arguments are used to construct
* a resolver query object.
*/
template <typename T1, ..., typename TN>
explicit basic_socket_iostream(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T>
explicit basic_socket_iostream(T... x)
: std::basic_iostream<char>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_)
{
this->setf(std::ios_base::unitbuf);
if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit);
}
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CTR_DEF)
#endif
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection to an endpoint corresponding to a resolver query.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*/
template <typename T1, ..., typename TN>
void connect(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T>
void connect(T... x)
{
if (rdbuf()->connect(x...) == 0)
this->setstate(std::ios_base::failbit);
}
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
#endif
/// Close the connection.
void close()
{
if (rdbuf()->close() == 0)
this->setstate(std::ios_base::failbit);
}
/// Return a pointer to the underlying streambuf.
basic_socket_streambuf<Protocol, Clock, WaitTraits>* rdbuf() const
{
return const_cast<basic_socket_streambuf<Protocol, Clock, WaitTraits>*>(
&this->detail::socket_iostream_base<
Protocol, Clock, WaitTraits>::streambuf_);
}
/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return rdbuf()->socket();
}
/// Get the last error associated with the stream.
/**
* @return An \c error_code corresponding to the last error from the stream.
*
* @par Example
* To print the error associated with a failure to establish a connection:
* @code tcp::iostream s("www.boost.org", "http");
* if (!s)
* {
* std::cout << "Error: " << s.error().message() << std::endl;
* } @endcode
*/
const asio::error_code& error() const
{
return rdbuf()->error();
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream's expiry time as an absolute
/// time.
/**
* @return An absolute time value representing the stream's expiry time.
*/
time_point expires_at() const
{
return rdbuf()->expires_at();
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Get the stream's expiry time as an absolute time.
/**
* @return An absolute time value representing the stream's expiry time.
*/
time_point expiry() const
{
return rdbuf()->expiry();
}
/// Set the stream's expiry time as an absolute time.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the stream.
*/
void expires_at(const time_point& expiry_time)
{
rdbuf()->expires_at(expiry_time);
}
/// Set the stream's expiry time relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_after(const duration& expiry_time)
{
rdbuf()->expires_after(expiry_time);
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream's expiry time relative to now.
/**
* @return A relative time value representing the stream's expiry time.
*/
duration expires_from_now() const
{
return rdbuf()->expires_from_now();
}
/// (Deprecated: Use expires_after().) Set the stream's expiry time relative
/// to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_from_now(const duration& expiry_time)
{
rdbuf()->expires_from_now(expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)
private:
// Disallow copying and assignment.
basic_socket_iostream(const basic_socket_iostream&) ASIO_DELETED;
basic_socket_iostream& operator=(
const basic_socket_iostream&) ASIO_DELETED;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# undef ASIO_PRIVATE_CTR_DEF
# undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_SOCKET_IOSTREAM_HPP

View File

@ -0,0 +1,687 @@
//
// basic_socket_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_SOCKET_STREAMBUF_HPP
#define ASIO_BASIC_SOCKET_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_NO_IOSTREAM)
#include <streambuf>
#include <vector>
#include "asio/basic_socket.hpp"
#include "asio/basic_stream_socket.hpp"
#include "asio/detail/buffer_sequence_adapter.hpp"
#include "asio/detail/memory.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/io_context.hpp"
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include "asio/detail/deadline_timer_service.hpp"
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
# include "asio/steady_timer.hpp"
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# include "asio/detail/variadic_templates.hpp"
// A macro that should expand to:
// template <typename T1, ..., typename Tn>
// basic_socket_streambuf* connect(T1 x1, ..., Tn xn)
// {
// init_buffers();
// typedef typename Protocol::resolver resolver_type;
// resolver_type resolver(socket().get_executor());
// connect_to_endpoints(
// resolver.resolve(x1, ..., xn, ec_));
// return !ec_ ? this : 0;
// }
// This macro should only persist within this file.
# define ASIO_PRIVATE_CONNECT_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
basic_socket_streambuf* connect(ASIO_VARIADIC_BYVAL_PARAMS(n)) \
{ \
init_buffers(); \
typedef typename Protocol::resolver resolver_type; \
resolver_type resolver(socket().get_executor()); \
connect_to_endpoints( \
resolver.resolve(ASIO_VARIADIC_BYVAL_ARGS(n), ec_)); \
return !ec_ ? this : 0; \
} \
/**/
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// A separate base class is used to ensure that the io_context member is
// initialised prior to the basic_socket_streambuf's basic_socket base class.
class socket_streambuf_io_context
{
protected:
socket_streambuf_io_context(io_context* ctx)
: default_io_context_(ctx)
{
}
shared_ptr<io_context> default_io_context_;
};
// A separate base class is used to ensure that the dynamically allocated
// buffers are constructed prior to the basic_socket_streambuf's basic_socket
// base class. This makes moving the socket is the last potentially throwing
// step in the streambuf's move constructor, giving the constructor a strong
// exception safety guarantee.
class socket_streambuf_buffers
{
protected:
socket_streambuf_buffers()
: get_buffer_(buffer_size),
put_buffer_(buffer_size)
{
}
enum { buffer_size = 512 };
std::vector<char> get_buffer_;
std::vector<char> put_buffer_;
};
} // namespace detail
#if !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
#define ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Protocol,
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = boost::posix_time::ptime,
typename WaitTraits = time_traits<Clock> >
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
class basic_socket_streambuf;
#endif // !defined(ASIO_BASIC_SOCKET_STREAMBUF_FWD_DECL)
/// Iostream streambuf for a socket.
#if defined(GENERATING_DOCUMENTATION)
template <typename Protocol,
typename Clock = chrono::steady_clock,
typename WaitTraits = wait_traits<Clock> >
#else // defined(GENERATING_DOCUMENTATION)
template <typename Protocol, typename Clock, typename WaitTraits>
#endif // defined(GENERATING_DOCUMENTATION)
class basic_socket_streambuf
: public std::streambuf,
private detail::socket_streambuf_io_context,
private detail::socket_streambuf_buffers,
#if defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
private basic_socket<Protocol>
#else // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
public basic_socket<Protocol>
#endif // defined(ASIO_NO_DEPRECATED) || defined(GENERATING_DOCUMENTATION)
{
private:
// These typedefs are intended keep this class's implementation independent
// of whether it's using Boost.DateClock, Boost.Chrono or std::chrono.
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef WaitTraits traits_helper;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
typedef detail::chrono_time_traits<Clock, WaitTraits> traits_helper;
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
public:
/// The protocol type.
typedef Protocol protocol_type;
/// The endpoint type.
typedef typename Protocol::endpoint endpoint_type;
/// The clock type.
typedef Clock clock_type;
#if defined(GENERATING_DOCUMENTATION)
/// (Deprecated: Use time_point.) The time type.
typedef typename WaitTraits::time_type time_type;
/// The time type.
typedef typename WaitTraits::time_point time_point;
/// (Deprecated: Use duration.) The duration type.
typedef typename WaitTraits::duration_type duration_type;
/// The duration type.
typedef typename WaitTraits::duration duration;
#else
# if !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_type;
typedef typename traits_helper::duration_type duration_type;
# endif // !defined(ASIO_NO_DEPRECATED)
typedef typename traits_helper::time_type time_point;
typedef typename traits_helper::duration_type duration;
#endif
/// Construct a basic_socket_streambuf without establishing a connection.
basic_socket_streambuf()
: detail::socket_streambuf_io_context(new io_context),
basic_socket<Protocol>(*default_io_context_),
expiry_time_(max_expiry_time())
{
init_buffers();
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Construct a basic_socket_streambuf from the supplied socket.
explicit basic_socket_streambuf(basic_stream_socket<protocol_type> s)
: detail::socket_streambuf_io_context(0),
basic_socket<Protocol>(std::move(s)),
expiry_time_(max_expiry_time())
{
init_buffers();
}
/// Move-construct a basic_socket_streambuf from another.
basic_socket_streambuf(basic_socket_streambuf&& other)
: detail::socket_streambuf_io_context(other),
basic_socket<Protocol>(std::move(other.socket())),
ec_(other.ec_),
expiry_time_(other.expiry_time_)
{
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = asio::error_code();
other.expiry_time_ = max_expiry_time();
other.init_buffers();
}
/// Move-assign a basic_socket_streambuf from another.
basic_socket_streambuf& operator=(basic_socket_streambuf&& other)
{
this->close();
socket() = std::move(other.socket());
detail::socket_streambuf_io_context::operator=(other);
ec_ = other.ec_;
expiry_time_ = other.expiry_time_;
get_buffer_.swap(other.get_buffer_);
put_buffer_.swap(other.put_buffer_);
setg(other.eback(), other.gptr(), other.egptr());
setp(other.pptr(), other.epptr());
other.ec_ = asio::error_code();
other.expiry_time_ = max_expiry_time();
other.put_buffer_.resize(buffer_size);
other.init_buffers();
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor flushes buffered data.
virtual ~basic_socket_streambuf()
{
if (pptr() != pbase())
overflow(traits_type::eof());
}
/// Establish a connection.
/**
* This function establishes a connection to the specified endpoint.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf* connect(const endpoint_type& endpoint)
{
init_buffers();
ec_ = asio::error_code();
this->connect_to_endpoints(&endpoint, &endpoint + 1);
return !ec_ ? this : 0;
}
#if defined(GENERATING_DOCUMENTATION)
/// Establish a connection.
/**
* This function automatically establishes a connection based on the supplied
* resolver query parameters. The arguments are used to construct a resolver
* query object.
*
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
template <typename T1, ..., typename TN>
basic_socket_streambuf* connect(T1 t1, ..., TN tn);
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... T>
basic_socket_streambuf* connect(T... x)
{
init_buffers();
typedef typename Protocol::resolver resolver_type;
resolver_type resolver(socket().get_executor());
connect_to_endpoints(resolver.resolve(x..., ec_));
return !ec_ ? this : 0;
}
#else
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_CONNECT_DEF)
#endif
/// Close the connection.
/**
* @return \c this if a connection was successfully established, a null
* pointer otherwise.
*/
basic_socket_streambuf* close()
{
sync();
socket().close(ec_);
if (!ec_)
init_buffers();
return !ec_ ? this : 0;
}
/// Get a reference to the underlying socket.
basic_socket<Protocol>& socket()
{
return *this;
}
/// Get the last error associated with the stream buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
const asio::error_code& error() const
{
return ec_;
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use error().) Get the last error associated with the stream
/// buffer.
/**
* @return An \c error_code corresponding to the last error from the stream
* buffer.
*/
const asio::error_code& puberror() const
{
return error();
}
/// (Deprecated: Use expiry().) Get the stream buffer's expiry time as an
/// absolute time.
/**
* @return An absolute time value representing the stream buffer's expiry
* time.
*/
time_point expires_at() const
{
return expiry_time_;
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Get the stream buffer's expiry time as an absolute time.
/**
* @return An absolute time value representing the stream buffer's expiry
* time.
*/
time_point expiry() const
{
return expiry_time_;
}
/// Set the stream buffer's expiry time as an absolute time.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the stream.
*/
void expires_at(const time_point& expiry_time)
{
expiry_time_ = expiry_time;
}
/// Set the stream buffer's expiry time relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_after(const duration& expiry_time)
{
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the stream buffer's expiry time relative
/// to now.
/**
* @return A relative time value representing the stream buffer's expiry time.
*/
duration expires_from_now() const
{
return traits_helper::subtract(expires_at(), traits_helper::now());
}
/// (Deprecated: Use expires_after().) Set the stream buffer's expiry time
/// relative to now.
/**
* This function sets the expiry time associated with the stream. Stream
* operations performed after this time (where the operations cannot be
* completed using the internal buffers) will fail with the error
* asio::error::operation_aborted.
*
* @param expiry_time The expiry time to be used for the timer.
*/
void expires_from_now(const duration& expiry_time)
{
expiry_time_ = traits_helper::add(traits_helper::now(), expiry_time);
}
#endif // !defined(ASIO_NO_DEPRECATED)
protected:
int_type underflow()
{
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(ASIO_WINDOWS_RUNTIME)
if (gptr() != egptr())
return traits_type::eof();
for (;;)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = asio::error::timed_out;
return traits_type::eof();
}
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<mutable_buffer, mutable_buffer>
bufs(asio::buffer(get_buffer_) + putback_max);
detail::signed_size_type bytes = detail::socket_ops::recv(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
// Check if operation succeeded.
if (bytes > 0)
{
setg(&get_buffer_[0], &get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max + bytes);
return traits_type::to_int_type(*gptr());
}
// Check for EOF.
if (bytes == 0)
{
ec_ = asio::error::eof;
return traits_type::eof();
}
// Operation failed.
if (ec_ != asio::error::would_block
&& ec_ != asio::error::try_again)
return traits_type::eof();
// Wait for socket to become ready.
if (detail::socket_ops::poll_read(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
#endif // defined(ASIO_WINDOWS_RUNTIME)
}
int_type overflow(int_type c)
{
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
return traits_type::eof();
#else // defined(ASIO_WINDOWS_RUNTIME)
char_type ch = traits_type::to_char_type(c);
// Determine what needs to be sent.
const_buffer output_buffer;
if (put_buffer_.empty())
{
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c); // Nothing to do.
output_buffer = asio::buffer(&ch, sizeof(char_type));
}
else
{
output_buffer = asio::buffer(pbase(),
(pptr() - pbase()) * sizeof(char_type));
}
while (output_buffer.size() > 0)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = asio::error::timed_out;
return traits_type::eof();
}
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::buffer_sequence_adapter<
const_buffer, const_buffer> bufs(output_buffer);
detail::signed_size_type bytes = detail::socket_ops::send(
socket().native_handle(), bufs.buffers(), bufs.count(), 0, ec_);
// Check if operation succeeded.
if (bytes > 0)
{
output_buffer += static_cast<std::size_t>(bytes);
continue;
}
// Operation failed.
if (ec_ != asio::error::would_block
&& ec_ != asio::error::try_again)
return traits_type::eof();
// Wait for socket to become ready.
if (detail::socket_ops::poll_write(
socket().native_handle(), 0, timeout(), ec_) < 0)
return traits_type::eof();
}
if (!put_buffer_.empty())
{
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
// If the new character is eof then our work here is done.
if (traits_type::eq_int_type(c, traits_type::eof()))
return traits_type::not_eof(c);
// Add the new character to the output buffer.
*pptr() = ch;
pbump(1);
}
return c;
#endif // defined(ASIO_WINDOWS_RUNTIME)
}
int sync()
{
return overflow(traits_type::eof());
}
std::streambuf* setbuf(char_type* s, std::streamsize n)
{
if (pptr() == pbase() && s == 0 && n == 0)
{
put_buffer_.clear();
setp(0, 0);
sync();
return this;
}
return 0;
}
private:
// Disallow copying and assignment.
basic_socket_streambuf(const basic_socket_streambuf&) ASIO_DELETED;
basic_socket_streambuf& operator=(
const basic_socket_streambuf&) ASIO_DELETED;
void init_buffers()
{
setg(&get_buffer_[0],
&get_buffer_[0] + putback_max,
&get_buffer_[0] + putback_max);
if (put_buffer_.empty())
setp(0, 0);
else
setp(&put_buffer_[0], &put_buffer_[0] + put_buffer_.size());
}
int timeout() const
{
int64_t msec = traits_helper::to_posix_duration(
traits_helper::subtract(expiry_time_,
traits_helper::now())).total_milliseconds();
if (msec > (std::numeric_limits<int>::max)())
msec = (std::numeric_limits<int>::max)();
else if (msec < 0)
msec = 0;
return static_cast<int>(msec);
}
template <typename EndpointSequence>
void connect_to_endpoints(const EndpointSequence& endpoints)
{
this->connect_to_endpoints(endpoints.begin(), endpoints.end());
}
template <typename EndpointIterator>
void connect_to_endpoints(EndpointIterator begin, EndpointIterator end)
{
#if defined(ASIO_WINDOWS_RUNTIME)
ec_ = asio::error::operation_not_supported;
#else // defined(ASIO_WINDOWS_RUNTIME)
if (ec_)
return;
ec_ = asio::error::not_found;
for (EndpointIterator i = begin; i != end; ++i)
{
// Check if we are past the expiry time.
if (traits_helper::less_than(expiry_time_, traits_helper::now()))
{
ec_ = asio::error::timed_out;
return;
}
// Close and reopen the socket.
typename Protocol::endpoint ep(*i);
socket().close(ec_);
socket().open(ep.protocol(), ec_);
if (ec_)
continue;
// Try to complete the operation without blocking.
if (!socket().native_non_blocking())
socket().native_non_blocking(true, ec_);
detail::socket_ops::connect(socket().native_handle(),
ep.data(), ep.size(), ec_);
// Check if operation succeeded.
if (!ec_)
return;
// Operation failed.
if (ec_ != asio::error::in_progress
&& ec_ != asio::error::would_block)
continue;
// Wait for socket to become ready.
if (detail::socket_ops::poll_connect(
socket().native_handle(), timeout(), ec_) < 0)
continue;
// Get the error code from the connect operation.
int connect_error = 0;
size_t connect_error_len = sizeof(connect_error);
if (detail::socket_ops::getsockopt(socket().native_handle(), 0,
SOL_SOCKET, SO_ERROR, &connect_error, &connect_error_len, ec_)
== detail::socket_error_retval)
return;
// Check the result of the connect operation.
ec_ = asio::error_code(connect_error,
asio::error::get_system_category());
if (!ec_)
return;
}
#endif // defined(ASIO_WINDOWS_RUNTIME)
}
// Helper function to get the maximum expiry time.
static time_point max_expiry_time()
{
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
&& defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return boost::posix_time::pos_infin;
#else // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
return (time_point::max)();
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// && defined(ASIO_USE_BOOST_DATE_TIME_FOR_SOCKET_IOSTREAM)
}
enum { putback_max = 8 };
asio::error_code ec_;
time_point expiry_time_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if !defined(ASIO_HAS_VARIADIC_TEMPLATES)
# undef ASIO_PRIVATE_CONNECT_DEF
#endif // !defined(ASIO_HAS_VARIADIC_TEMPLATES)
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_SOCKET_STREAMBUF_HPP

View File

@ -0,0 +1,742 @@
//
// basic_stream_file.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_STREAM_FILE_HPP
#define ASIO_BASIC_STREAM_FILE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_FILE) \
|| defined(GENERATING_DOCUMENTATION)
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/basic_file.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL)
#define ASIO_BASIC_STREAM_FILE_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Executor = any_io_executor>
class basic_stream_file;
#endif // !defined(ASIO_BASIC_STREAM_FILE_FWD_DECL)
/// Provides stream-oriented file functionality.
/**
* The basic_stream_file class template provides asynchronous and blocking
* stream-oriented file functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Executor>
class basic_stream_file
: public basic_file<Executor>
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the file type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The file type when rebound to the specified executor.
typedef basic_stream_file<Executor1> other;
};
/// The native representation of a file.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#else
typedef typename basic_file<Executor>::native_handle_type native_handle_type;
#endif
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*/
explicit basic_stream_file(const executor_type& ex)
: basic_file<Executor>(ex)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file without opening it.
/**
* This constructor initialises a file without opening it. The file needs to
* be opened before data can be read from or or written to it.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*/
template <typename ExecutionContext>
explicit basic_stream_file(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const char* path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const char* path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path, open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const std::string& path, file_base::flags open_flags)
: basic_file<Executor>(ex)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct and open a basic_stream_file.
/**
* This constructor initialises and opens a file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param path The path name identifying the file to be opened.
*
* @param open_flags A set of flags that determine how the file should be
* opened.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const std::string& path, file_base::flags open_flags,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context)
{
asio::error_code ec;
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
this->impl_.get_service().open(
this->impl_.get_implementation(),
path.c_str(), open_flags, ec);
asio::detail::throw_error(ec, "open");
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param ex The I/O executor that the file will use, by default, to
* dispatch handlers for any asynchronous operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
basic_stream_file(const executor_type& ex,
const native_handle_type& native_file)
: basic_file<Executor>(ex, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
/// Construct a basic_stream_file on an existing native file.
/**
* This constructor initialises a stream file object to hold an existing
* native file.
*
* @param context An execution context which provides the I/O executor that
* the file will use, by default, to dispatch handlers for any asynchronous
* operations performed on the file.
*
* @param native_file The new underlying file implementation.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_stream_file(ExecutionContext& context,
const native_handle_type& native_file,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(context, native_file)
{
this->impl_.get_service().set_is_stream(
this->impl_.get_implementation(), true);
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_stream_file from another.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file(basic_stream_file&& other) ASIO_NOEXCEPT
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from another.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
basic_stream_file& operator=(basic_stream_file&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
/// Move-construct a basic_stream_file from a file of another executor
/// type.
/**
* This constructor moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_stream_file(basic_stream_file<Executor1>&& other,
typename constraint<
is_convertible<Executor1, Executor>::value,
defaulted_constraint
>::type = defaulted_constraint())
: basic_file<Executor>(std::move(other))
{
}
/// Move-assign a basic_stream_file from a file of another executor type.
/**
* This assignment operator moves a stream file from one object to another.
*
* @param other The other basic_stream_file object from which the move
* will occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_stream_file(const executor_type&)
* constructor.
*/
template <typename Executor1>
typename constraint<
is_convertible<Executor1, Executor>::value,
basic_stream_file&
>::type operator=(basic_stream_file<Executor1>&& other)
{
basic_file<Executor>::operator=(std::move(other));
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the file.
/**
* This function destroys the file, cancelling any outstanding asynchronous
* operations associated with the file as if by calling @c cancel.
*/
~basic_stream_file()
{
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @returns The new position relative to the beginning of the file.
*
* @throws asio::system_error Thrown on failure.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence)
{
asio::error_code ec;
uint64_t n = this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
asio::detail::throw_error(ec, "seek");
return n;
}
/// Seek to a position in the file.
/**
* This function updates the current position in the file.
*
* @param offset The requested position in the file, relative to @c whence.
*
* @param whence One of @c seek_set, @c seek_cur or @c seek_end.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The new position relative to the beginning of the file.
*/
uint64_t seek(int64_t offset, file_base::seek_basis whence,
asio::error_code& ec)
{
return this->impl_.get_service().seek(
this->impl_.get_implementation(), offset, whence, ec);
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the file.
/**
* This function is used to write data to the stream file. The function call
* will block until one or more bytes of the data has been written
* successfully, or until an error occurs.
*
* @param buffers One or more data buffers to be written to the file.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().write_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more data buffers to be written to the file.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* file.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @returns The number of bytes read.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the end of the file was reached.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.read_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "read_some");
return s;
}
/// Read some data from the file.
/**
* This function is used to read data from the stream file. The function
* call will block until one or more bytes of data has been read successfully,
* or until an error occurs.
*
* @param buffers One or more buffers into which the data will be read.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes read. Returns 0 if an error occurred.
*
* @note The read_some operation may not read all of the requested number of
* bytes. Consider using the @ref read function if you need to ensure that
* the requested amount of data is read before the blocking operation
* completes.
*/
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return this->impl_.get_service().read_some(
this->impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous read.
/**
* This function is used to asynchronously read data from the stream file.
* It is an initiating function for an @ref asynchronous_operation, and always
* returns immediately.
*
* @param buffers One or more buffers into which the data will be read.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the read completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes read.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The read operation may not read all of the requested number of bytes.
* Consider using the @ref async_read function if you need to ensure that the
* requested amount of data is read before the asynchronous operation
* completes.
*
* @par Example
* To read into a single data buffer use the @ref buffer function as follows:
* @code
* file.async_read_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on reading into multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*
* @par Per-Operation Cancellation
* On POSIX or Windows operating systems, this asynchronous operation supports
* cancellation for the following asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadToken,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<ReadToken,
void (asio::error_code, std::size_t)>(
initiate_async_read_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_stream_file(const basic_stream_file&) ASIO_DELETED;
basic_stream_file& operator=(const basic_stream_file&) ASIO_DELETED;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_stream_file* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
class initiate_async_read_some
{
public:
typedef Executor executor_type;
explicit initiate_async_read_some(basic_stream_file* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename ReadHandler, typename MutableBufferSequence>
void operator()(ASIO_MOVE_ARG(ReadHandler) handler,
const MutableBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a ReadHandler.
ASIO_READ_HANDLER_CHECK(ReadHandler, handler) type_check;
detail::non_const_lvalue<ReadHandler> handler2(handler);
self_->impl_.get_service().async_read_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_stream_file* self_;
};
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_FILE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_STREAM_FILE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,452 @@
//
// basic_streambuf.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_STREAMBUF_HPP
#define ASIO_BASIC_STREAMBUF_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_NO_IOSTREAM)
#include <algorithm>
#include <cstring>
#include <stdexcept>
#include <streambuf>
#include <vector>
#include "asio/basic_streambuf_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/limits.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/throw_exception.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Automatically resizable buffer class based on std::streambuf.
/**
* The @c basic_streambuf class is derived from @c std::streambuf to associate
* the streambuf's input and output sequences with one or more character
* arrays. These character arrays are internal to the @c basic_streambuf
* object, but direct access to the array elements is provided to permit them
* to be used efficiently with I/O operations. Characters written to the output
* sequence of a @c basic_streambuf object are appended to the input sequence
* of the same object.
*
* The @c basic_streambuf class's public interface is intended to permit the
* following implementation strategies:
*
* @li A single contiguous character array, which is reallocated as necessary
* to accommodate changes in the size of the character sequence. This is the
* implementation approach currently used in Asio.
*
* @li A sequence of one or more character arrays, where each array is of the
* same size. Additional character array objects are appended to the sequence
* to accommodate changes in the size of the character sequence.
*
* @li A sequence of one or more character arrays of varying sizes. Additional
* character array objects are appended to the sequence to accommodate changes
* in the size of the character sequence.
*
* The constructor for basic_streambuf accepts a @c size_t argument specifying
* the maximum of the sum of the sizes of the input sequence and output
* sequence. During the lifetime of the @c basic_streambuf object, the following
* invariant holds:
* @code size() <= max_size()@endcode
* Any member function that would, if successful, cause the invariant to be
* violated shall throw an exception of class @c std::length_error.
*
* The constructor for @c basic_streambuf takes an Allocator argument. A copy
* of this argument is used for any memory allocation performed, by the
* constructor and by all member functions, during the lifetime of each @c
* basic_streambuf object.
*
* @par Examples
* Writing directly from an streambuf to a socket:
* @code
* asio::streambuf b;
* std::ostream os(&b);
* os << "Hello, World!\n";
*
* // try sending some data in input sequence
* size_t n = sock.send(b.data());
*
* b.consume(n); // sent data is removed from input sequence
* @endcode
*
* Reading from a socket directly into a streambuf:
* @code
* asio::streambuf b;
*
* // reserve 512 bytes in output sequence
* asio::streambuf::mutable_buffers_type bufs = b.prepare(512);
*
* size_t n = sock.receive(bufs);
*
* // received data is "committed" from output sequence to input sequence
* b.commit(n);
*
* std::istream is(&b);
* std::string s;
* is >> s;
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char> >
#else
template <typename Allocator>
#endif
class basic_streambuf
: public std::streambuf,
private noncopyable
{
public:
#if defined(GENERATING_DOCUMENTATION)
/// The type used to represent the input sequence as a list of buffers.
typedef implementation_defined const_buffers_type;
/// The type used to represent the output sequence as a list of buffers.
typedef implementation_defined mutable_buffers_type;
#else
typedef ASIO_CONST_BUFFER const_buffers_type;
typedef ASIO_MUTABLE_BUFFER mutable_buffers_type;
#endif
/// Construct a basic_streambuf object.
/**
* Constructs a streambuf with the specified maximum size. The initial size
* of the streambuf's input sequence is 0.
*/
explicit basic_streambuf(
std::size_t maximum_size = (std::numeric_limits<std::size_t>::max)(),
const Allocator& allocator = Allocator())
: max_size_(maximum_size),
buffer_(allocator)
{
std::size_t pend = (std::min<std::size_t>)(max_size_, buffer_delta);
buffer_.resize((std::max<std::size_t>)(pend, 1));
setg(&buffer_[0], &buffer_[0], &buffer_[0]);
setp(&buffer_[0], &buffer_[0] + pend);
}
/// Get the size of the input sequence.
/**
* @returns The size of the input sequence. The value is equal to that
* calculated for @c s in the following code:
* @code
* size_t s = 0;
* const_buffers_type bufs = data();
* const_buffers_type::const_iterator i = bufs.begin();
* while (i != bufs.end())
* {
* const_buffer buf(*i++);
* s += buf.size();
* }
* @endcode
*/
std::size_t size() const ASIO_NOEXCEPT
{
return pptr() - gptr();
}
/// Get the maximum size of the basic_streambuf.
/**
* @returns The allowed maximum of the sum of the sizes of the input sequence
* and output sequence.
*/
std::size_t max_size() const ASIO_NOEXCEPT
{
return max_size_;
}
/// Get the current capacity of the basic_streambuf.
/**
* @returns The current total capacity of the streambuf, i.e. for both the
* input sequence and output sequence.
*/
std::size_t capacity() const ASIO_NOEXCEPT
{
return buffer_.capacity();
}
/// Get a list of buffers that represents the input sequence.
/**
* @returns An object of type @c const_buffers_type that satisfies
* ConstBufferSequence requirements, representing all character arrays in the
* input sequence.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
const_buffers_type data() const ASIO_NOEXCEPT
{
return asio::buffer(asio::const_buffer(gptr(),
(pptr() - gptr()) * sizeof(char_type)));
}
/// Get a list of buffers that represents the output sequence, with the given
/// size.
/**
* Ensures that the output sequence can accommodate @c n characters,
* reallocating character array objects as necessary.
*
* @returns An object of type @c mutable_buffers_type that satisfies
* MutableBufferSequence requirements, representing character array objects
* at the start of the output sequence such that the sum of the buffer sizes
* is @c n.
*
* @throws std::length_error If <tt>size() + n > max_size()</tt>.
*
* @note The returned object is invalidated by any @c basic_streambuf member
* function that modifies the input sequence or output sequence.
*/
mutable_buffers_type prepare(std::size_t n)
{
reserve(n);
return asio::buffer(asio::mutable_buffer(
pptr(), n * sizeof(char_type)));
}
/// Move characters from the output sequence to the input sequence.
/**
* Appends @c n characters from the start of the output sequence to the input
* sequence. The beginning of the output sequence is advanced by @c n
* characters.
*
* Requires a preceding call <tt>prepare(x)</tt> where <tt>x >= n</tt>, and
* no intervening operations that modify the input or output sequence.
*
* @note If @c n is greater than the size of the output sequence, the entire
* output sequence is moved to the input sequence and no error is issued.
*/
void commit(std::size_t n)
{
n = std::min<std::size_t>(n, epptr() - pptr());
pbump(static_cast<int>(n));
setg(eback(), gptr(), pptr());
}
/// Remove characters from the input sequence.
/**
* Removes @c n characters from the beginning of the input sequence.
*
* @note If @c n is greater than the size of the input sequence, the entire
* input sequence is consumed and no error is issued.
*/
void consume(std::size_t n)
{
if (egptr() < pptr())
setg(&buffer_[0], gptr(), pptr());
if (gptr() + n > pptr())
n = pptr() - gptr();
gbump(static_cast<int>(n));
}
protected:
enum { buffer_delta = 128 };
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::underflow().
*/
int_type underflow()
{
if (gptr() < pptr())
{
setg(&buffer_[0], gptr(), pptr());
return traits_type::to_int_type(*gptr());
}
else
{
return traits_type::eof();
}
}
/// Override std::streambuf behaviour.
/**
* Behaves according to the specification of @c std::streambuf::overflow(),
* with the specialisation that @c std::length_error is thrown if appending
* the character to the input sequence would require the condition
* <tt>size() > max_size()</tt> to be true.
*/
int_type overflow(int_type c)
{
if (!traits_type::eq_int_type(c, traits_type::eof()))
{
if (pptr() == epptr())
{
std::size_t buffer_size = pptr() - gptr();
if (buffer_size < max_size_ && max_size_ - buffer_size < buffer_delta)
{
reserve(max_size_ - buffer_size);
}
else
{
reserve(buffer_delta);
}
}
*pptr() = traits_type::to_char_type(c);
pbump(1);
return c;
}
return traits_type::not_eof(c);
}
void reserve(std::size_t n)
{
// Get current stream positions as offsets.
std::size_t gnext = gptr() - &buffer_[0];
std::size_t pnext = pptr() - &buffer_[0];
std::size_t pend = epptr() - &buffer_[0];
// Check if there is already enough space in the put area.
if (n <= pend - pnext)
{
return;
}
// Shift existing contents of get area to start of buffer.
if (gnext > 0)
{
pnext -= gnext;
std::memmove(&buffer_[0], &buffer_[0] + gnext, pnext);
}
// Ensure buffer is large enough to hold at least the specified size.
if (n > pend - pnext)
{
if (n <= max_size_ && pnext <= max_size_ - n)
{
pend = pnext + n;
buffer_.resize((std::max<std::size_t>)(pend, 1));
}
else
{
std::length_error ex("asio::streambuf too long");
asio::detail::throw_exception(ex);
}
}
// Update stream positions.
setg(&buffer_[0], &buffer_[0], &buffer_[0] + pnext);
setp(&buffer_[0] + pnext, &buffer_[0] + pend);
}
private:
std::size_t max_size_;
std::vector<char_type, Allocator> buffer_;
// Helper function to get the preferred size for reading data.
friend std::size_t read_size_helper(
basic_streambuf& sb, std::size_t max_size)
{
return std::min<std::size_t>(
std::max<std::size_t>(512, sb.buffer_.capacity() - sb.size()),
std::min<std::size_t>(max_size, sb.max_size() - sb.size()));
}
};
/// Adapts basic_streambuf to the dynamic buffer sequence type requirements.
#if defined(GENERATING_DOCUMENTATION)
template <typename Allocator = std::allocator<char> >
#else
template <typename Allocator>
#endif
class basic_streambuf_ref
{
public:
/// The type used to represent the input sequence as a list of buffers.
typedef typename basic_streambuf<Allocator>::const_buffers_type
const_buffers_type;
/// The type used to represent the output sequence as a list of buffers.
typedef typename basic_streambuf<Allocator>::mutable_buffers_type
mutable_buffers_type;
/// Construct a basic_streambuf_ref for the given basic_streambuf object.
explicit basic_streambuf_ref(basic_streambuf<Allocator>& sb)
: sb_(sb)
{
}
/// Copy construct a basic_streambuf_ref.
basic_streambuf_ref(const basic_streambuf_ref& other) ASIO_NOEXCEPT
: sb_(other.sb_)
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move construct a basic_streambuf_ref.
basic_streambuf_ref(basic_streambuf_ref&& other) ASIO_NOEXCEPT
: sb_(other.sb_)
{
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the size of the input sequence.
std::size_t size() const ASIO_NOEXCEPT
{
return sb_.size();
}
/// Get the maximum size of the dynamic buffer.
std::size_t max_size() const ASIO_NOEXCEPT
{
return sb_.max_size();
}
/// Get the current capacity of the dynamic buffer.
std::size_t capacity() const ASIO_NOEXCEPT
{
return sb_.capacity();
}
/// Get a list of buffers that represents the input sequence.
const_buffers_type data() const ASIO_NOEXCEPT
{
return sb_.data();
}
/// Get a list of buffers that represents the output sequence, with the given
/// size.
mutable_buffers_type prepare(std::size_t n)
{
return sb_.prepare(n);
}
/// Move bytes from the output sequence to the input sequence.
void commit(std::size_t n)
{
return sb_.commit(n);
}
/// Remove characters from the input sequence.
void consume(std::size_t n)
{
return sb_.consume(n);
}
private:
basic_streambuf<Allocator>& sb_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_STREAMBUF_HPP

View File

@ -0,0 +1,36 @@
//
// basic_streambuf_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_STREAMBUF_FWD_HPP
#define ASIO_BASIC_STREAMBUF_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if !defined(ASIO_NO_IOSTREAM)
#include <memory>
namespace asio {
template <typename Allocator = std::allocator<char> >
class basic_streambuf;
template <typename Allocator = std::allocator<char> >
class basic_streambuf_ref;
} // namespace asio
#endif // !defined(ASIO_NO_IOSTREAM)
#endif // ASIO_BASIC_STREAMBUF_FWD_HPP

View File

@ -0,0 +1,827 @@
//
// basic_waitable_timer.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_WAITABLE_TIMER_HPP
#define ASIO_BASIC_WAITABLE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/any_io_executor.hpp"
#include "asio/detail/chrono_time_traits.hpp"
#include "asio/detail/deadline_timer_service.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/error.hpp"
#include "asio/wait_traits.hpp"
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
#if !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
#define ASIO_BASIC_WAITABLE_TIMER_FWD_DECL
// Forward declaration with defaulted arguments.
template <typename Clock,
typename WaitTraits = asio::wait_traits<Clock>,
typename Executor = any_io_executor>
class basic_waitable_timer;
#endif // !defined(ASIO_BASIC_WAITABLE_TIMER_FWD_DECL)
/// Provides waitable timer functionality.
/**
* The basic_waitable_timer class template provides the ability to perform a
* blocking or asynchronous wait for a timer to expire.
*
* A waitable timer is always in one of two states: "expired" or "not expired".
* If the wait() or async_wait() function is called on an expired timer, the
* wait operation will complete immediately.
*
* Most applications will use one of the asio::steady_timer,
* asio::system_timer or asio::high_resolution_timer typedefs.
*
* @note This waitable timer functionality is for use with the C++11 standard
* library's @c &lt;chrono&gt; facility, or with the Boost.Chrono library.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Examples
* Performing a blocking wait (C++11):
* @code
* // Construct a timer without setting an expiry time.
* asio::steady_timer timer(my_context);
*
* // Set an expiry time relative to now.
* timer.expires_after(std::chrono::seconds(5));
*
* // Wait for the timer to expire.
* timer.wait();
* @endcode
*
* @par
* Performing an asynchronous wait (C++11):
* @code
* void handler(const asio::error_code& error)
* {
* if (!error)
* {
* // Timer expired.
* }
* }
*
* ...
*
* // Construct a timer with an absolute expiry time.
* asio::steady_timer timer(my_context,
* std::chrono::steady_clock::now() + std::chrono::seconds(60));
*
* // Start an asynchronous wait.
* timer.async_wait(handler);
* @endcode
*
* @par Changing an active waitable timer's expiry time
*
* Changing the expiry time of a timer while there are pending asynchronous
* waits causes those wait operations to be cancelled. To ensure that the action
* associated with the timer is performed only once, use something like this:
* used:
*
* @code
* void on_some_event()
* {
* if (my_timer.expires_after(seconds(5)) > 0)
* {
* // We managed to cancel the timer. Start new asynchronous wait.
* my_timer.async_wait(on_timeout);
* }
* else
* {
* // Too late, timer has already expired!
* }
* }
*
* void on_timeout(const asio::error_code& e)
* {
* if (e != asio::error::operation_aborted)
* {
* // Timer was not cancelled, take necessary action.
* }
* }
* @endcode
*
* @li The asio::basic_waitable_timer::expires_after() function
* cancels any pending asynchronous waits, and returns the number of
* asynchronous waits that were cancelled. If it returns 0 then you were too
* late and the wait handler has already been executed, or will soon be
* executed. If it returns 1 then the wait handler was successfully cancelled.
*
* @li If a wait handler is cancelled, the asio::error_code passed to
* it contains the value asio::error::operation_aborted.
*/
template <typename Clock, typename WaitTraits, typename Executor>
class basic_waitable_timer
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the timer type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The timer type when rebound to the specified executor.
typedef basic_waitable_timer<Clock, WaitTraits, Executor1> other;
};
/// The clock type.
typedef Clock clock_type;
/// The duration type of the clock.
typedef typename clock_type::duration duration;
/// The time point type of the clock.
typedef typename clock_type::time_point time_point;
/// The wait traits type.
typedef WaitTraits traits_type;
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*/
explicit basic_waitable_timer(const executor_type& ex)
: impl_(0, ex)
{
}
/// Constructor.
/**
* This constructor creates a timer without setting an expiry time. The
* expires_at() or expires_after() functions must be called to set an expiry
* time before the timer can be waited on.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor object that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
basic_waitable_timer(const executor_type& ex, const time_point& expiry_time)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time as an absolute time.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, expressed
* as an absolute time.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const time_point& expiry_time,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_at(impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param ex The I/O executor that the timer will use, by default, to
* dispatch handlers for any asynchronous operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
basic_waitable_timer(const executor_type& ex, const duration& expiry_time)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
/// Constructor to set a particular expiry time relative to now.
/**
* This constructor creates a timer and sets the expiry time.
*
* @param context An execution context which provides the I/O executor that
* the timer will use, by default, to dispatch handlers for any asynchronous
* operations performed on the timer.
*
* @param expiry_time The expiry time to be used for the timer, relative to
* now.
*/
template <typename ExecutionContext>
explicit basic_waitable_timer(ExecutionContext& context,
const duration& expiry_time,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_waitable_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer(basic_waitable_timer&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
basic_waitable_timer& operator=(basic_waitable_timer&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
// All timers have access to each other's implementations.
template <typename Clock1, typename WaitTraits1, typename Executor1>
friend class basic_waitable_timer;
/// Move-construct a basic_waitable_timer from another.
/**
* This constructor moves a timer from one object to another.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
basic_waitable_timer(
basic_waitable_timer<Clock, WaitTraits, Executor1>&& other,
typename constraint<
is_convertible<Executor1, Executor>::value
>::type = 0)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_waitable_timer from another.
/**
* This assignment operator moves a timer from one object to another. Cancels
* any outstanding asynchronous operations associated with the target object.
*
* @param other The other basic_waitable_timer object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_waitable_timer(const executor_type&)
* constructor.
*/
template <typename Executor1>
typename constraint<
is_convertible<Executor1, Executor>::value,
basic_waitable_timer&
>::type operator=(basic_waitable_timer<Clock, WaitTraits, Executor1>&& other)
{
basic_waitable_timer tmp(std::move(other));
impl_ = std::move(tmp.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the timer.
/**
* This function destroys the timer, cancelling any outstanding asynchronous
* wait operations associated with the timer as if by calling @c cancel.
*/
~basic_waitable_timer()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Cancel any asynchronous operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel()
{
asio::error_code ec;
std::size_t s = impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancel any asynchronous
/// operations that are waiting on the timer.
/**
* This function forces the completion of any pending asynchronous wait
* operations against the timer. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when cancel() is called, then the
* handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel(asio::error_code& ec)
{
return impl_.get_service().cancel(impl_.get_implementation(), ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Cancels one asynchronous operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one()
{
asio::error_code ec;
std::size_t s = impl_.get_service().cancel_one(
impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel_one");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Cancels one asynchronous
/// operation that is waiting on the timer.
/**
* This function forces the completion of one pending asynchronous wait
* operation against the timer. Handlers are cancelled in FIFO order. The
* handler for the cancelled operation will be invoked with the
* asio::error::operation_aborted error code.
*
* Cancelling the timer does not change the expiry time.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled. That is,
* either 0 or 1.
*
* @note If the timer has already expired when cancel_one() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t cancel_one(asio::error_code& ec)
{
return impl_.get_service().cancel_one(impl_.get_implementation(), ec);
}
/// (Deprecated: Use expiry().) Get the timer's expiry time as an absolute
/// time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_point expires_at() const
{
return impl_.get_service().expires_at(impl_.get_implementation());
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Get the timer's expiry time as an absolute time.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
time_point expiry() const
{
return impl_.get_service().expiry(impl_.get_implementation());
}
/// Set the timer's expiry time as an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_point& expiry_time)
{
asio::error_code ec;
std::size_t s = impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_at");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use non-error_code overload.) Set the timer's expiry time as
/// an absolute time.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_at() is called, then
* the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_at(const time_point& expiry_time,
asio::error_code& ec)
{
return impl_.get_service().expires_at(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Set the timer's expiry time relative to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_after() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_after(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = impl_.get_service().expires_after(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_after");
return s;
}
#if !defined(ASIO_NO_DEPRECATED)
/// (Deprecated: Use expiry().) Get the timer's expiry time relative to now.
/**
* This function may be used to obtain the timer's current expiry time.
* Whether the timer has expired or not does not affect this value.
*/
duration expires_from_now() const
{
return impl_.get_service().expires_from_now(impl_.get_implementation());
}
/// (Deprecated: Use expires_after().) Set the timer's expiry time relative
/// to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @return The number of asynchronous operations that were cancelled.
*
* @throws asio::system_error Thrown on failure.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration& expiry_time)
{
asio::error_code ec;
std::size_t s = impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
asio::detail::throw_error(ec, "expires_from_now");
return s;
}
/// (Deprecated: Use expires_after().) Set the timer's expiry time relative
/// to now.
/**
* This function sets the expiry time. Any pending asynchronous wait
* operations will be cancelled. The handler for each cancelled operation will
* be invoked with the asio::error::operation_aborted error code.
*
* @param expiry_time The expiry time to be used for the timer.
*
* @param ec Set to indicate what error occurred, if any.
*
* @return The number of asynchronous operations that were cancelled.
*
* @note If the timer has already expired when expires_from_now() is called,
* then the handlers for asynchronous wait operations will:
*
* @li have already been invoked; or
*
* @li have been queued for invocation in the near future.
*
* These handlers can no longer be cancelled, and therefore are passed an
* error code that indicates the successful completion of the wait operation.
*/
std::size_t expires_from_now(const duration& expiry_time,
asio::error_code& ec)
{
return impl_.get_service().expires_from_now(
impl_.get_implementation(), expiry_time, ec);
}
#endif // !defined(ASIO_NO_DEPRECATED)
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @throws asio::system_error Thrown on failure.
*/
void wait()
{
asio::error_code ec;
impl_.get_service().wait(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "wait");
}
/// Perform a blocking wait on the timer.
/**
* This function is used to wait for the timer to expire. This function
* blocks and does not return until the timer has expired.
*
* @param ec Set to indicate what error occurred, if any.
*/
void wait(asio::error_code& ec)
{
impl_.get_service().wait(impl_.get_implementation(), ec);
}
/// Start an asynchronous wait on the timer.
/**
* This function may be used to initiate an asynchronous wait against the
* timer. It is an initiating function for an @ref asynchronous_operation,
* and always returns immediately.
*
* For each call to async_wait(), the completion handler will be called
* exactly once. The completion handler will be called when:
*
* @li The timer has expired.
*
* @li The timer was cancelled, in which case the handler is passed the error
* code asio::error::operation_aborted.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the timer expires. Potential
* completion tokens include @ref use_future, @ref use_awaitable, @ref
* yield_context, or a function object with the correct completion signature.
* The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error // Result of operation.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code) @endcode
*
* @par Per-Operation Cancellation
* This asynchronous operation supports cancellation for the following
* asio::cancellation_type values:
*
* @li @c cancellation_type::terminal
*
* @li @c cancellation_type::partial
*
* @li @c cancellation_type::total
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code))
WaitToken ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WaitToken,
void (asio::error_code))
async_wait(
ASIO_MOVE_ARG(WaitToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WaitToken, void (asio::error_code)>(
initiate_async_wait(this), token);
}
private:
// Disallow copying and assignment.
basic_waitable_timer(const basic_waitable_timer&) ASIO_DELETED;
basic_waitable_timer& operator=(
const basic_waitable_timer&) ASIO_DELETED;
class initiate_async_wait
{
public:
typedef Executor executor_type;
explicit initiate_async_wait(basic_waitable_timer* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WaitHandler>
void operator()(ASIO_MOVE_ARG(WaitHandler) handler) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WaitHandler.
ASIO_WAIT_HANDLER_CHECK(WaitHandler, handler) type_check;
detail::non_const_lvalue<WaitHandler> handler2(handler);
self_->impl_.get_service().async_wait(
self_->impl_.get_implementation(),
handler2.value, self_->impl_.get_executor());
}
private:
basic_waitable_timer* self_;
};
detail::io_object_impl<
detail::deadline_timer_service<
detail::chrono_time_traits<Clock, WaitTraits> >,
executor_type > impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BASIC_WAITABLE_TIMER_HPP

View File

@ -0,0 +1,525 @@
//
// basic_writable_pipe.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BASIC_WRITABLE_PIPE_HPP
#define ASIO_BASIC_WRITABLE_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include <string>
#include "asio/any_io_executor.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/handler_type_requirements.hpp"
#include "asio/detail/io_object_impl.hpp"
#include "asio/detail/non_const_lvalue.hpp"
#include "asio/detail/throw_error.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/execution_context.hpp"
#if defined(ASIO_HAS_IOCP)
# include "asio/detail/win_iocp_handle_service.hpp"
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
# include "asio/detail/io_uring_descriptor_service.hpp"
#else
# include "asio/detail/reactive_descriptor_service.hpp"
#endif
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
/// Provides pipe functionality.
/**
* The basic_writable_pipe class provides a wrapper over pipe
* functionality.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*/
template <typename Executor = any_io_executor>
class basic_writable_pipe
{
public:
/// The type of the executor associated with the object.
typedef Executor executor_type;
/// Rebinds the pipe type to another executor.
template <typename Executor1>
struct rebind_executor
{
/// The pipe type when rebound to the specified executor.
typedef basic_writable_pipe<Executor1> other;
};
/// The native representation of a pipe.
#if defined(GENERATING_DOCUMENTATION)
typedef implementation_defined native_handle_type;
#elif defined(ASIO_HAS_IOCP)
typedef detail::win_iocp_handle_service::native_handle_type
native_handle_type;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
typedef detail::io_uring_descriptor_service::native_handle_type
native_handle_type;
#else
typedef detail::reactive_descriptor_service::native_handle_type
native_handle_type;
#endif
/// A basic_writable_pipe is always the lowest layer.
typedef basic_writable_pipe lowest_layer_type;
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param ex The I/O executor that the pipe will use, by default, to dispatch
* handlers for any asynchronous operations performed on the pipe.
*/
explicit basic_writable_pipe(const executor_type& ex)
: impl_(0, ex)
{
}
/// Construct a basic_writable_pipe without opening it.
/**
* This constructor creates a pipe without opening it.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any asynchronous
* operations performed on the pipe.
*/
template <typename ExecutionContext>
explicit basic_writable_pipe(ExecutionContext& context,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value,
defaulted_constraint
>::type = defaulted_constraint())
: impl_(0, 0, context)
{
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param ex The I/O executor that the pipe will use, by default, to
* dispatch handlers for any asynchronous operations performed on the
* pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
basic_writable_pipe(const executor_type& ex,
const native_handle_type& native_pipe)
: impl_(0, ex)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Construct a basic_writable_pipe on an existing native pipe.
/**
* This constructor creates a pipe object to hold an existing native
* pipe.
*
* @param context An execution context which provides the I/O executor that
* the pipe will use, by default, to dispatch handlers for any
* asynchronous operations performed on the pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename ExecutionContext>
basic_writable_pipe(ExecutionContext& context,
const native_handle_type& native_pipe,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: impl_(0, 0, context)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(),
native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move-construct a basic_writable_pipe from another.
/**
* This constructor moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe(basic_writable_pipe&& other)
: impl_(std::move(other.impl_))
{
}
/// Move-assign a basic_writable_pipe from another.
/**
* This assignment operator moves a pipe from one object to another.
*
* @param other The other basic_writable_pipe object from which the move will
* occur.
*
* @note Following the move, the moved-from object is in the same state as if
* constructed using the @c basic_writable_pipe(const executor_type&)
* constructor.
*/
basic_writable_pipe& operator=(basic_writable_pipe&& other)
{
impl_ = std::move(other.impl_);
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destroys the pipe.
/**
* This function destroys the pipe, cancelling any outstanding
* asynchronous wait operations associated with the pipe as if by
* calling @c cancel.
*/
~basic_writable_pipe()
{
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return impl_.get_executor();
}
/// Get a reference to the lowest layer.
/**
* This function returns a reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A reference to the lowest layer in the stack of layers. Ownership
* is not transferred to the caller.
*/
lowest_layer_type& lowest_layer()
{
return *this;
}
/// Get a const reference to the lowest layer.
/**
* This function returns a const reference to the lowest layer in a stack of
* layers. Since a basic_writable_pipe cannot contain any further layers, it
* simply returns a reference to itself.
*
* @return A const reference to the lowest layer in the stack of layers.
* Ownership is not transferred to the caller.
*/
const lowest_layer_type& lowest_layer() const
{
return *this;
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @throws asio::system_error Thrown on failure.
*/
void assign(const native_handle_type& native_pipe)
{
asio::error_code ec;
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
asio::detail::throw_error(ec, "assign");
}
/// Assign an existing native pipe to the pipe.
/*
* This function opens the pipe to hold an existing native pipe.
*
* @param native_pipe A native pipe.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID assign(const native_handle_type& native_pipe,
asio::error_code& ec)
{
impl_.get_service().assign(impl_.get_implementation(), native_pipe, ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Determine whether the pipe is open.
bool is_open() const
{
return impl_.get_service().is_open(impl_.get_implementation());
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void close()
{
asio::error_code ec;
impl_.get_service().close(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "close");
}
/// Close the pipe.
/**
* This function is used to close the pipe. Any asynchronous write operations
* will be cancelled immediately, and will complete with the
* asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
impl_.get_service().close(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Get the native pipe representation.
/**
* This function may be used to obtain the underlying representation of the
* pipe. This is intended to allow access to native pipe
* functionality that is not otherwise provided.
*/
native_handle_type native_handle()
{
return impl_.get_service().native_handle(impl_.get_implementation());
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @throws asio::system_error Thrown on failure.
*/
void cancel()
{
asio::error_code ec;
impl_.get_service().cancel(impl_.get_implementation(), ec);
asio::detail::throw_error(ec, "cancel");
}
/// Cancel all asynchronous operations associated with the pipe.
/**
* This function causes all outstanding asynchronous write operations to
* finish immediately, and the handlers for cancelled operations will be
* passed the asio::error::operation_aborted error.
*
* @param ec Set to indicate what error occurred, if any.
*/
ASIO_SYNC_OP_VOID cancel(asio::error_code& ec)
{
impl_.get_service().cancel(impl_.get_implementation(), ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @returns The number of bytes written.
*
* @throws asio::system_error Thrown on failure. An error code of
* asio::error::eof indicates that the connection was closed by the
* peer.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.write_some(asio::buffer(data, size));
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
asio::error_code ec;
std::size_t s = impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
asio::detail::throw_error(ec, "write_some");
return s;
}
/// Write some data to the pipe.
/**
* This function is used to write data to the pipe. The function call will
* block until one or more bytes of the data has been written successfully,
* or until an error occurs.
*
* @param buffers One or more data buffers to be written to the pipe.
*
* @param ec Set to indicate what error occurred, if any.
*
* @returns The number of bytes written. Returns 0 if an error occurred.
*
* @note The write_some operation may not transmit all of the data to the
* peer. Consider using the @ref write function if you need to ensure that
* all data is written before the blocking operation completes.
*/
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return impl_.get_service().write_some(
impl_.get_implementation(), buffers, ec);
}
/// Start an asynchronous write.
/**
* This function is used to asynchronously write data to the pipe. It is an
* initiating function for an @ref asynchronous_operation, and always returns
* immediately.
*
* @param buffers One or more data buffers to be written to the pipe.
* Although the buffers object may be copied as necessary, ownership of the
* underlying memory blocks is retained by the caller, which must guarantee
* that they remain valid until the completion handler is called.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler, which will be called when the write completes.
* Potential completion tokens include @ref use_future, @ref use_awaitable,
* @ref yield_context, or a function object with the correct completion
* signature. The function signature of the completion handler must be:
* @code void handler(
* const asio::error_code& error, // Result of operation.
* std::size_t bytes_transferred // Number of bytes written.
* ); @endcode
* Regardless of whether the asynchronous operation completes immediately or
* not, the completion handler will not be invoked from within this function.
* On immediate completion, invocation of the handler will be performed in a
* manner equivalent to using asio::post().
*
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*
* @note The write operation may not transmit all of the data to the peer.
* Consider using the @ref async_write function if you need to ensure that all
* data is written before the asynchronous operation completes.
*
* @par Example
* To write a single data buffer use the @ref buffer function as follows:
* @code
* pipe.async_write_some(asio::buffer(data, size), handler);
* @endcode
* See the @ref buffer documentation for information on writing multiple
* buffers in one go, and how to use it with arrays, boost::array or
* std::vector.
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteToken,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return async_initiate<WriteToken,
void (asio::error_code, std::size_t)>(
initiate_async_write_some(this), token, buffers);
}
private:
// Disallow copying and assignment.
basic_writable_pipe(const basic_writable_pipe&) ASIO_DELETED;
basic_writable_pipe& operator=(const basic_writable_pipe&) ASIO_DELETED;
class initiate_async_write_some
{
public:
typedef Executor executor_type;
explicit initiate_async_write_some(basic_writable_pipe* self)
: self_(self)
{
}
executor_type get_executor() const ASIO_NOEXCEPT
{
return self_->get_executor();
}
template <typename WriteHandler, typename ConstBufferSequence>
void operator()(ASIO_MOVE_ARG(WriteHandler) handler,
const ConstBufferSequence& buffers) const
{
// If you get an error on the following line it means that your handler
// does not meet the documented type requirements for a WriteHandler.
ASIO_WRITE_HANDLER_CHECK(WriteHandler, handler) type_check;
detail::non_const_lvalue<WriteHandler> handler2(handler);
self_->impl_.get_service().async_write_some(
self_->impl_.get_implementation(), buffers,
handler2.value, self_->impl_.get_executor());
}
private:
basic_writable_pipe* self_;
};
#if defined(ASIO_HAS_IOCP)
detail::io_object_impl<detail::win_iocp_handle_service, Executor> impl_;
#elif defined(ASIO_HAS_IO_URING_AS_DEFAULT)
detail::io_object_impl<detail::io_uring_descriptor_service, Executor> impl_;
#else
detail::io_object_impl<detail::reactive_descriptor_service, Executor> impl_;
#endif
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_BASIC_WRITABLE_PIPE_HPP

View File

@ -0,0 +1,722 @@
//
// bind_allocator.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BIND_ALLOCATOR_HPP
#define ASIO_BIND_ALLOCATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/associated_allocator.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct allocator_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct allocator_binder_result_type<T,
typename void_type<typename T::result_type>::type>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct allocator_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct allocator_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_type {};
template <typename T>
struct allocator_binder_argument_type<T,
typename void_type<typename T::argument_type>::type>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct allocator_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct allocator_binder_argument_types {};
template <typename T>
struct allocator_binder_argument_types<T,
typename void_type<typename T::first_argument_type>::type>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct allocator_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
// Helper to enable SFINAE on zero-argument operator() below.
template <typename T, typename = void>
struct allocator_binder_result_of0
{
typedef void type;
};
template <typename T>
struct allocator_binder_result_of0<T,
typename void_type<typename result_of<T()>::type>::type>
{
typedef typename result_of<T()>::type type;
};
} // namespace detail
/// A call wrapper type to bind an allocator of type @c Allocator
/// to an object of type @c T.
template <typename T, typename Allocator>
class allocator_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::allocator_binder_result_type<T>,
public detail::allocator_binder_argument_type<T>,
public detail::allocator_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated allocator.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct an allocator wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
allocator_binder(const allocator_type& s,
ASIO_MOVE_ARG(U) u)
: allocator_(s),
target_(ASIO_MOVE_CAST(U)(u))
{
}
/// Copy constructor.
allocator_binder(const allocator_binder& other)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy, but specify a different allocator.
allocator_binder(const allocator_type& s,
const allocator_binder& other)
: allocator_(s),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type.
/**
* This constructor is only valid if the @c Allocator type is
* constructible from type @c OtherAllocator, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(
const allocator_binder<U, OtherAllocator>& other)
: allocator_(other.get_allocator()),
target_(other.get())
{
}
/// Construct a copy of a different allocator wrapper type, but
/// specify a different allocator.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
const allocator_binder<U, OtherAllocator>& other)
: allocator_(s),
target_(other.get())
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor.
allocator_binder(allocator_binder&& other)
: allocator_(ASIO_MOVE_CAST(allocator_type)(
other.get_allocator())),
target_(ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct the target object, but specify a different allocator.
allocator_binder(const allocator_type& s,
allocator_binder&& other)
: allocator_(s),
target_(ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct from a different allocator wrapper type.
template <typename U, typename OtherAllocator>
allocator_binder(
allocator_binder<U, OtherAllocator>&& other)
: allocator_(ASIO_MOVE_CAST(OtherAllocator)(
other.get_allocator())),
target_(ASIO_MOVE_CAST(U)(other.get()))
{
}
/// Move construct from a different allocator wrapper type, but
/// specify a different allocator.
template <typename U, typename OtherAllocator>
allocator_binder(const allocator_type& s,
allocator_binder<U, OtherAllocator>&& other)
: allocator_(s),
target_(ASIO_MOVE_CAST(U)(other.get()))
{
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor.
~allocator_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() ASIO_NOEXCEPT
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const ASIO_NOEXCEPT
{
return target_;
}
/// Obtain the associated allocator.
allocator_type get_allocator() const ASIO_NOEXCEPT
{
return allocator_;
}
#if defined(GENERATING_DOCUMENTATION)
template <typename... Args> auto operator()(Args&& ...);
template <typename... Args> auto operator()(Args&& ...) const;
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args)
{
return target_(ASIO_MOVE_CAST(Args)(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args) const
{
return target_(ASIO_MOVE_CAST(Args)(args)...);
}
#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typename detail::allocator_binder_result_of0<T>::type operator()()
{
return target_();
}
typename detail::allocator_binder_result_of0<T>::type
operator()() const
{
return target_();
}
#define ASIO_PRIVATE_BINDER_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BINDER_CALL_DEF)
#undef ASIO_PRIVATE_BINDER_CALL_DEF
#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typedef typename detail::allocator_binder_result_type<
T>::result_type_or_void result_type_or_void;
result_type_or_void operator()()
{
return target_();
}
result_type_or_void operator()() const
{
return target_();
}
#define ASIO_PRIVATE_BINDER_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BINDER_CALL_DEF)
#undef ASIO_PRIVATE_BINDER_CALL_DEF
#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
private:
Allocator allocator_;
T target_;
};
/// Associate an object of type @c T with an allocator of type
/// @c Allocator.
template <typename Allocator, typename T>
ASIO_NODISCARD inline allocator_binder<typename decay<T>::type, Allocator>
bind_allocator(const Allocator& s, ASIO_MOVE_ARG(T) t)
{
return allocator_binder<
typename decay<T>::type, Allocator>(
s, ASIO_MOVE_CAST(T)(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult,
typename Allocator, typename = void>
struct allocator_binder_async_result_completion_handler_type
{
};
template <typename TargetAsyncResult, typename Allocator>
struct allocator_binder_async_result_completion_handler_type<
TargetAsyncResult, Allocator,
typename void_type<
typename TargetAsyncResult::completion_handler_type
>::type>
{
typedef allocator_binder<
typename TargetAsyncResult::completion_handler_type, Allocator>
completion_handler_type;
};
template <typename TargetAsyncResult, typename = void>
struct allocator_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct allocator_binder_async_result_return_type<
TargetAsyncResult,
typename void_type<
typename TargetAsyncResult::return_type
>::type>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Allocator, typename Signature>
class async_result<allocator_binder<T, Allocator>, Signature> :
public detail::allocator_binder_async_result_completion_handler_type<
async_result<T, Signature>, Allocator>,
public detail::allocator_binder_async_result_return_type<
async_result<T, Signature> >
{
public:
explicit async_result(allocator_binder<T, Allocator>& b)
: target_(b.get())
{
}
typename async_result<T, Signature>::return_type get()
{
return target_.get();
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const Allocator& allocator, ASIO_MOVE_ARG(Init) init)
: allocator_(allocator),
initiation_(ASIO_MOVE_CAST(Init)(init))
{
}
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
allocator_binder<
typename decay<Handler>::type, Allocator>(
allocator_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args) const
{
initiation_(
allocator_binder<
typename decay<Handler>::type, Allocator>(
allocator_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
allocator_binder<
typename decay<Handler>::type, Allocator>(
allocator_, ASIO_MOVE_CAST(Handler)(handler)));
}
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler) const
{
initiation_(
allocator_binder<
typename decay<Handler>::type, Allocator>(
allocator_, ASIO_MOVE_CAST(Handler)(handler)));
}
#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
ASIO_MOVE_CAST(Initiation)(initiation_)( \
allocator_binder< \
typename decay<Handler>::type, Allocator>( \
allocator_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
initiation_( \
allocator_binder< \
typename decay<Handler>::type, Allocator>( \
allocator_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)
#undef ASIO_PRIVATE_INIT_WRAPPER_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
Allocator allocator_;
Initiation initiation_;
};
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken, typename... Args>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get(),
declval<ASIO_MOVE_ARG(Args)>()...)))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_allocator(),
ASIO_MOVE_CAST(Initiation)(initiation)),
token.get(), ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get())))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_allocator(),
ASIO_MOVE_CAST(Initiation)(initiation)),
token.get());
}
#define ASIO_PRIVATE_INITIATE_DEF(n) \
template <typename Initiation, typename RawCompletionToken, \
ASIO_VARIADIC_TPARAMS(n)> \
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature, \
(async_initiate<T, Signature>( \
declval<init_wrapper<typename decay<Initiation>::type> >(), \
declval<RawCompletionToken>().get(), \
ASIO_VARIADIC_MOVE_DECLVAL(n)))) \
initiate( \
ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_MOVE_ARG(RawCompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return async_initiate<T, Signature>( \
init_wrapper<typename decay<Initiation>::type>( \
token.get_allocator(), \
ASIO_MOVE_CAST(Initiation)(initiation)), \
token.get(), ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
#undef ASIO_PRIVATE_INITIATE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
private:
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;
async_result<T, Signature> target_;
};
template <template <typename, typename> class Associator,
typename T, typename Allocator, typename DefaultCandidate>
struct associator<Associator,
allocator_binder<T, Allocator>,
DefaultCandidate>
{
typedef typename Associator<T, DefaultCandidate>::type type;
static type get(const allocator_binder<T, Allocator>& b,
const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Allocator, typename Allocator1>
struct associated_allocator<
allocator_binder<T, Allocator>,
Allocator1>
{
typedef Allocator type;
static type get(const allocator_binder<T, Allocator>& b,
const Allocator1& = Allocator1()) ASIO_NOEXCEPT
{
return b.get_allocator();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_ALLOCATOR_HPP

View File

@ -0,0 +1,724 @@
//
// bind_cancellation_slot.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BIND_CANCELLATION_SLOT_HPP
#define ASIO_BIND_CANCELLATION_SLOT_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/associated_cancellation_slot.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct cancellation_slot_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct cancellation_slot_binder_result_type<T,
typename void_type<typename T::result_type>::type>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct cancellation_slot_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct cancellation_slot_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_type {};
template <typename T>
struct cancellation_slot_binder_argument_type<T,
typename void_type<typename T::argument_type>::type>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct cancellation_slot_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct cancellation_slot_binder_argument_types {};
template <typename T>
struct cancellation_slot_binder_argument_types<T,
typename void_type<typename T::first_argument_type>::type>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct cancellation_slot_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
// Helper to enable SFINAE on zero-argument operator() below.
template <typename T, typename = void>
struct cancellation_slot_binder_result_of0
{
typedef void type;
};
template <typename T>
struct cancellation_slot_binder_result_of0<T,
typename void_type<typename result_of<T()>::type>::type>
{
typedef typename result_of<T()>::type type;
};
} // namespace detail
/// A call wrapper type to bind a cancellation slot of type @c CancellationSlot
/// to an object of type @c T.
template <typename T, typename CancellationSlot>
class cancellation_slot_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::cancellation_slot_binder_result_type<T>,
public detail::cancellation_slot_binder_argument_type<T>,
public detail::cancellation_slot_binder_argument_types<T>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated cancellation slot.
typedef CancellationSlot cancellation_slot_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct a cancellation slot wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
cancellation_slot_binder(const cancellation_slot_type& s,
ASIO_MOVE_ARG(U) u)
: slot_(s),
target_(ASIO_MOVE_CAST(U)(u))
{
}
/// Copy constructor.
cancellation_slot_binder(const cancellation_slot_binder& other)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy, but specify a different cancellation slot.
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder& other)
: slot_(s),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type.
/**
* This constructor is only valid if the @c CancellationSlot type is
* constructible from type @c OtherCancellationSlot, and the type @c T is
* constructible from type @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
const cancellation_slot_binder<U, OtherCancellationSlot>& other)
: slot_(other.get_cancellation_slot()),
target_(other.get())
{
}
/// Construct a copy of a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
const cancellation_slot_binder<U, OtherCancellationSlot>& other)
: slot_(s),
target_(other.get())
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor.
cancellation_slot_binder(cancellation_slot_binder&& other)
: slot_(ASIO_MOVE_CAST(cancellation_slot_type)(
other.get_cancellation_slot())),
target_(ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct the target object, but specify a different cancellation
/// slot.
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder&& other)
: slot_(s),
target_(ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(
cancellation_slot_binder<U, OtherCancellationSlot>&& other)
: slot_(ASIO_MOVE_CAST(OtherCancellationSlot)(
other.get_cancellation_slot())),
target_(ASIO_MOVE_CAST(U)(other.get()))
{
}
/// Move construct from a different cancellation slot wrapper type, but
/// specify a different cancellation slot.
template <typename U, typename OtherCancellationSlot>
cancellation_slot_binder(const cancellation_slot_type& s,
cancellation_slot_binder<U, OtherCancellationSlot>&& other)
: slot_(s),
target_(ASIO_MOVE_CAST(U)(other.get()))
{
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor.
~cancellation_slot_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() ASIO_NOEXCEPT
{
return target_;
}
/// Obtain a reference to the target object.
const target_type& get() const ASIO_NOEXCEPT
{
return target_;
}
/// Obtain the associated cancellation slot.
cancellation_slot_type get_cancellation_slot() const ASIO_NOEXCEPT
{
return slot_;
}
#if defined(GENERATING_DOCUMENTATION)
template <typename... Args> auto operator()(Args&& ...);
template <typename... Args> auto operator()(Args&& ...) const;
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args)
{
return target_(ASIO_MOVE_CAST(Args)(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args) const
{
return target_(ASIO_MOVE_CAST(Args)(args)...);
}
#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typename detail::cancellation_slot_binder_result_of0<T>::type operator()()
{
return target_();
}
typename detail::cancellation_slot_binder_result_of0<T>::type
operator()() const
{
return target_();
}
#define ASIO_PRIVATE_BINDER_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BINDER_CALL_DEF)
#undef ASIO_PRIVATE_BINDER_CALL_DEF
#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typedef typename detail::cancellation_slot_binder_result_type<
T>::result_type_or_void result_type_or_void;
result_type_or_void operator()()
{
return target_();
}
result_type_or_void operator()() const
{
return target_();
}
#define ASIO_PRIVATE_BINDER_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BINDER_CALL_DEF)
#undef ASIO_PRIVATE_BINDER_CALL_DEF
#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
private:
CancellationSlot slot_;
T target_;
};
/// Associate an object of type @c T with a cancellation slot of type
/// @c CancellationSlot.
template <typename CancellationSlot, typename T>
ASIO_NODISCARD inline
cancellation_slot_binder<typename decay<T>::type, CancellationSlot>
bind_cancellation_slot(const CancellationSlot& s, ASIO_MOVE_ARG(T) t)
{
return cancellation_slot_binder<
typename decay<T>::type, CancellationSlot>(
s, ASIO_MOVE_CAST(T)(t));
}
#if !defined(GENERATING_DOCUMENTATION)
namespace detail {
template <typename TargetAsyncResult,
typename CancellationSlot, typename = void>
struct cancellation_slot_binder_async_result_completion_handler_type
{
};
template <typename TargetAsyncResult, typename CancellationSlot>
struct cancellation_slot_binder_async_result_completion_handler_type<
TargetAsyncResult, CancellationSlot,
typename void_type<
typename TargetAsyncResult::completion_handler_type
>::type>
{
typedef cancellation_slot_binder<
typename TargetAsyncResult::completion_handler_type, CancellationSlot>
completion_handler_type;
};
template <typename TargetAsyncResult, typename = void>
struct cancellation_slot_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct cancellation_slot_binder_async_result_return_type<
TargetAsyncResult,
typename void_type<
typename TargetAsyncResult::return_type
>::type>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename CancellationSlot, typename Signature>
class async_result<cancellation_slot_binder<T, CancellationSlot>, Signature> :
public detail::cancellation_slot_binder_async_result_completion_handler_type<
async_result<T, Signature>, CancellationSlot>,
public detail::cancellation_slot_binder_async_result_return_type<
async_result<T, Signature> >
{
public:
explicit async_result(cancellation_slot_binder<T, CancellationSlot>& b)
: target_(b.get())
{
}
typename async_result<T, Signature>::return_type get()
{
return target_.get();
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const CancellationSlot& slot, ASIO_MOVE_ARG(Init) init)
: slot_(slot),
initiation_(ASIO_MOVE_CAST(Init)(init))
{
}
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
cancellation_slot_binder<
typename decay<Handler>::type, CancellationSlot>(
slot_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args) const
{
initiation_(
cancellation_slot_binder<
typename decay<Handler>::type, CancellationSlot>(
slot_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
cancellation_slot_binder<
typename decay<Handler>::type, CancellationSlot>(
slot_, ASIO_MOVE_CAST(Handler)(handler)));
}
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler) const
{
initiation_(
cancellation_slot_binder<
typename decay<Handler>::type, CancellationSlot>(
slot_, ASIO_MOVE_CAST(Handler)(handler)));
}
#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
ASIO_MOVE_CAST(Initiation)(initiation_)( \
cancellation_slot_binder< \
typename decay<Handler>::type, CancellationSlot>( \
slot_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
initiation_( \
cancellation_slot_binder< \
typename decay<Handler>::type, CancellationSlot>( \
slot_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)
#undef ASIO_PRIVATE_INIT_WRAPPER_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
CancellationSlot slot_;
Initiation initiation_;
};
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken, typename... Args>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get(),
declval<ASIO_MOVE_ARG(Args)>()...)))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_cancellation_slot(),
ASIO_MOVE_CAST(Initiation)(initiation)),
token.get(), ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get())))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_cancellation_slot(),
ASIO_MOVE_CAST(Initiation)(initiation)),
token.get());
}
#define ASIO_PRIVATE_INITIATE_DEF(n) \
template <typename Initiation, typename RawCompletionToken, \
ASIO_VARIADIC_TPARAMS(n)> \
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature, \
(async_initiate<T, Signature>( \
declval<init_wrapper<typename decay<Initiation>::type> >(), \
declval<RawCompletionToken>().get(), \
ASIO_VARIADIC_MOVE_DECLVAL(n)))) \
initiate( \
ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_MOVE_ARG(RawCompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return async_initiate<T, Signature>( \
init_wrapper<typename decay<Initiation>::type>( \
token.get_cancellation_slot(), \
ASIO_MOVE_CAST(Initiation)(initiation)), \
token.get(), ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
#undef ASIO_PRIVATE_INITIATE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
private:
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;
async_result<T, Signature> target_;
};
template <template <typename, typename> class Associator,
typename T, typename CancellationSlot, typename DefaultCandidate>
struct associator<Associator,
cancellation_slot_binder<T, CancellationSlot>,
DefaultCandidate>
{
typedef typename Associator<T, DefaultCandidate>::type type;
static type get(const cancellation_slot_binder<T, CancellationSlot>& b,
const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename CancellationSlot, typename CancellationSlot1>
struct associated_cancellation_slot<
cancellation_slot_binder<T, CancellationSlot>,
CancellationSlot1>
{
typedef CancellationSlot type;
static type get(const cancellation_slot_binder<T, CancellationSlot>& b,
const CancellationSlot1& = CancellationSlot1()) ASIO_NOEXCEPT
{
return b.get_cancellation_slot();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_CANCELLATION_SLOT_HPP

View File

@ -0,0 +1,770 @@
//
// bind_executor.hpp
// ~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BIND_EXECUTOR_HPP
#define ASIO_BIND_EXECUTOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/associated_executor.hpp"
#include "asio/associator.hpp"
#include "asio/async_result.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/uses_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// Helper to automatically define nested typedef result_type.
template <typename T, typename = void>
struct executor_binder_result_type
{
protected:
typedef void result_type_or_void;
};
template <typename T>
struct executor_binder_result_type<T,
typename void_type<typename T::result_type>::type>
{
typedef typename T::result_type result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct executor_binder_result_type<R(*)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R>
struct executor_binder_result_type<R(&)()>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct executor_binder_result_type<R(*)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1>
struct executor_binder_result_type<R(&)(A1)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct executor_binder_result_type<R(*)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
template <typename R, typename A1, typename A2>
struct executor_binder_result_type<R(&)(A1, A2)>
{
typedef R result_type;
protected:
typedef result_type result_type_or_void;
};
// Helper to automatically define nested typedef argument_type.
template <typename T, typename = void>
struct executor_binder_argument_type {};
template <typename T>
struct executor_binder_argument_type<T,
typename void_type<typename T::argument_type>::type>
{
typedef typename T::argument_type argument_type;
};
template <typename R, typename A1>
struct executor_binder_argument_type<R(*)(A1)>
{
typedef A1 argument_type;
};
template <typename R, typename A1>
struct executor_binder_argument_type<R(&)(A1)>
{
typedef A1 argument_type;
};
// Helper to automatically define nested typedefs first_argument_type and
// second_argument_type.
template <typename T, typename = void>
struct executor_binder_argument_types {};
template <typename T>
struct executor_binder_argument_types<T,
typename void_type<typename T::first_argument_type>::type>
{
typedef typename T::first_argument_type first_argument_type;
typedef typename T::second_argument_type second_argument_type;
};
template <typename R, typename A1, typename A2>
struct executor_binder_argument_type<R(*)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
template <typename R, typename A1, typename A2>
struct executor_binder_argument_type<R(&)(A1, A2)>
{
typedef A1 first_argument_type;
typedef A2 second_argument_type;
};
// Helper to perform uses_executor construction of the target type, if
// required.
template <typename T, typename Executor, bool UsesExecutor>
class executor_binder_base;
template <typename T, typename Executor>
class executor_binder_base<T, Executor, true>
{
protected:
template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
: executor_(ASIO_MOVE_CAST(E)(e)),
target_(executor_arg_t(), executor_, ASIO_MOVE_CAST(U)(u))
{
}
Executor executor_;
T target_;
};
template <typename T, typename Executor>
class executor_binder_base<T, Executor, false>
{
protected:
template <typename E, typename U>
executor_binder_base(ASIO_MOVE_ARG(E) e, ASIO_MOVE_ARG(U) u)
: executor_(ASIO_MOVE_CAST(E)(e)),
target_(ASIO_MOVE_CAST(U)(u))
{
}
Executor executor_;
T target_;
};
// Helper to enable SFINAE on zero-argument operator() below.
template <typename T, typename = void>
struct executor_binder_result_of0
{
typedef void type;
};
template <typename T>
struct executor_binder_result_of0<T,
typename void_type<typename result_of<T()>::type>::type>
{
typedef typename result_of<T()>::type type;
};
} // namespace detail
/// A call wrapper type to bind an executor of type @c Executor to an object of
/// type @c T.
template <typename T, typename Executor>
class executor_binder
#if !defined(GENERATING_DOCUMENTATION)
: public detail::executor_binder_result_type<T>,
public detail::executor_binder_argument_type<T>,
public detail::executor_binder_argument_types<T>,
private detail::executor_binder_base<
T, Executor, uses_executor<T, Executor>::value>
#endif // !defined(GENERATING_DOCUMENTATION)
{
public:
/// The type of the target object.
typedef T target_type;
/// The type of the associated executor.
typedef Executor executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The return type if a function.
/**
* The type of @c result_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to function type, @c result_type is a synonym for
* the return type of @c T;
*
* @li if @c T is a class type with a member type @c result_type, then @c
* result_type is a synonym for @c T::result_type;
*
* @li otherwise @c result_type is not defined.
*/
typedef see_below result_type;
/// The type of the function's argument.
/**
* The type of @c argument_type is based on the type @c T of the wrapper's
* target object:
*
* @li if @c T is a pointer to a function type accepting a single argument,
* @c argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c argument_type, then @c
* argument_type is a synonym for @c T::argument_type;
*
* @li otherwise @c argument_type is not defined.
*/
typedef see_below argument_type;
/// The type of the function's first argument.
/**
* The type of @c first_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* first_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c first_argument_type is a synonym for @c T::first_argument_type;
*
* @li otherwise @c first_argument_type is not defined.
*/
typedef see_below first_argument_type;
/// The type of the function's second argument.
/**
* The type of @c second_argument_type is based on the type @c T of the
* wrapper's target object:
*
* @li if @c T is a pointer to a function type accepting two arguments, @c
* second_argument_type is a synonym for the return type of @c T;
*
* @li if @c T is a class type with a member type @c first_argument_type,
* then @c second_argument_type is a synonym for @c T::second_argument_type;
*
* @li otherwise @c second_argument_type is not defined.
*/
typedef see_below second_argument_type;
#endif // defined(GENERATING_DOCUMENTATION)
/// Construct an executor wrapper for the specified object.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U>
executor_binder(executor_arg_t, const executor_type& e,
ASIO_MOVE_ARG(U) u)
: base_type(e, ASIO_MOVE_CAST(U)(u))
{
}
/// Copy constructor.
executor_binder(const executor_binder& other)
: base_type(other.get_executor(), other.get())
{
}
/// Construct a copy, but specify a different executor.
executor_binder(executor_arg_t, const executor_type& e,
const executor_binder& other)
: base_type(e, other.get())
{
}
/// Construct a copy of a different executor wrapper type.
/**
* This constructor is only valid if the @c Executor type is constructible
* from type @c OtherExecutor, and the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
executor_binder(const executor_binder<U, OtherExecutor>& other)
: base_type(other.get_executor(), other.get())
{
}
/// Construct a copy of a different executor wrapper type, but specify a
/// different executor.
/**
* This constructor is only valid if the type @c T is constructible from type
* @c U.
*/
template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e,
const executor_binder<U, OtherExecutor>& other)
: base_type(e, other.get())
{
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor.
executor_binder(executor_binder&& other)
: base_type(ASIO_MOVE_CAST(executor_type)(other.get_executor()),
ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct the target object, but specify a different executor.
executor_binder(executor_arg_t, const executor_type& e,
executor_binder&& other)
: base_type(e, ASIO_MOVE_CAST(T)(other.get()))
{
}
/// Move construct from a different executor wrapper type.
template <typename U, typename OtherExecutor>
executor_binder(executor_binder<U, OtherExecutor>&& other)
: base_type(ASIO_MOVE_CAST(OtherExecutor)(other.get_executor()),
ASIO_MOVE_CAST(U)(other.get()))
{
}
/// Move construct from a different executor wrapper type, but specify a
/// different executor.
template <typename U, typename OtherExecutor>
executor_binder(executor_arg_t, const executor_type& e,
executor_binder<U, OtherExecutor>&& other)
: base_type(e, ASIO_MOVE_CAST(U)(other.get()))
{
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Destructor.
~executor_binder()
{
}
/// Obtain a reference to the target object.
target_type& get() ASIO_NOEXCEPT
{
return this->target_;
}
/// Obtain a reference to the target object.
const target_type& get() const ASIO_NOEXCEPT
{
return this->target_;
}
/// Obtain the associated executor.
executor_type get_executor() const ASIO_NOEXCEPT
{
return this->executor_;
}
#if defined(GENERATING_DOCUMENTATION)
template <typename... Args> auto operator()(Args&& ...);
template <typename... Args> auto operator()(Args&& ...) const;
#elif defined(ASIO_HAS_VARIADIC_TEMPLATES)
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args)
{
return this->target_(ASIO_MOVE_CAST(Args)(args)...);
}
/// Forwarding function call operator.
template <typename... Args>
typename result_of<T(Args...)>::type operator()(
ASIO_MOVE_ARG(Args)... args) const
{
return this->target_(ASIO_MOVE_CAST(Args)(args)...);
}
#elif defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typename detail::executor_binder_result_of0<T>::type operator()()
{
return this->target_();
}
typename detail::executor_binder_result_of0<T>::type operator()() const
{
return this->target_();
}
#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
typename result_of<T(ASIO_VARIADIC_TARGS(n))>::type operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
#else // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
typedef typename detail::executor_binder_result_type<T>::result_type_or_void
result_type_or_void;
result_type_or_void operator()()
{
return this->target_();
}
result_type_or_void operator()() const
{
return this->target_();
}
#define ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <ASIO_VARIADIC_TPARAMS(n)> \
result_type_or_void operator()( \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
return this->target_(ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF)
#undef ASIO_PRIVATE_BIND_EXECUTOR_CALL_DEF
#endif // defined(ASIO_HAS_STD_TYPE_TRAITS) && !defined(_MSC_VER)
private:
typedef detail::executor_binder_base<T, Executor,
uses_executor<T, Executor>::value> base_type;
};
/// Associate an object of type @c T with an executor of type @c Executor.
template <typename Executor, typename T>
ASIO_NODISCARD inline executor_binder<typename decay<T>::type, Executor>
bind_executor(const Executor& ex, ASIO_MOVE_ARG(T) t,
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0)
{
return executor_binder<typename decay<T>::type, Executor>(
executor_arg_t(), ex, ASIO_MOVE_CAST(T)(t));
}
/// Associate an object of type @c T with an execution context's executor.
template <typename ExecutionContext, typename T>
ASIO_NODISCARD inline executor_binder<typename decay<T>::type,
typename ExecutionContext::executor_type>
bind_executor(ExecutionContext& ctx, ASIO_MOVE_ARG(T) t,
typename constraint<is_convertible<
ExecutionContext&, execution_context&>::value>::type = 0)
{
return executor_binder<typename decay<T>::type,
typename ExecutionContext::executor_type>(
executor_arg_t(), ctx.get_executor(), ASIO_MOVE_CAST(T)(t));
}
#if !defined(GENERATING_DOCUMENTATION)
template <typename T, typename Executor>
struct uses_executor<executor_binder<T, Executor>, Executor>
: true_type {};
namespace detail {
template <typename TargetAsyncResult, typename Executor, typename = void>
class executor_binder_completion_handler_async_result
{
public:
template <typename T>
explicit executor_binder_completion_handler_async_result(T&)
{
}
};
template <typename TargetAsyncResult, typename Executor>
class executor_binder_completion_handler_async_result<
TargetAsyncResult, Executor,
typename void_type<
typename TargetAsyncResult::completion_handler_type
>::type>
{
public:
typedef executor_binder<
typename TargetAsyncResult::completion_handler_type, Executor>
completion_handler_type;
explicit executor_binder_completion_handler_async_result(
typename TargetAsyncResult::completion_handler_type& handler)
: target_(handler)
{
}
typename TargetAsyncResult::return_type get()
{
return target_.get();
}
private:
TargetAsyncResult target_;
};
template <typename TargetAsyncResult, typename = void>
struct executor_binder_async_result_return_type
{
};
template <typename TargetAsyncResult>
struct executor_binder_async_result_return_type<
TargetAsyncResult,
typename void_type<
typename TargetAsyncResult::return_type
>::type>
{
typedef typename TargetAsyncResult::return_type return_type;
};
} // namespace detail
template <typename T, typename Executor, typename Signature>
class async_result<executor_binder<T, Executor>, Signature> :
public detail::executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>,
public detail::executor_binder_async_result_return_type<
async_result<T, Signature> >
{
public:
explicit async_result(executor_binder<T, Executor>& b)
: detail::executor_binder_completion_handler_async_result<
async_result<T, Signature>, Executor>(b.get())
{
}
template <typename Initiation>
struct init_wrapper
{
template <typename Init>
init_wrapper(const Executor& ex, ASIO_MOVE_ARG(Init) init)
: ex_(ex),
initiation_(ASIO_MOVE_CAST(Init)(init))
{
}
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
executor_binder<typename decay<Handler>::type, Executor>(
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
template <typename Handler, typename... Args>
void operator()(
ASIO_MOVE_ARG(Handler) handler,
ASIO_MOVE_ARG(Args)... args) const
{
initiation_(
executor_binder<typename decay<Handler>::type, Executor>(
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)),
ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler)
{
ASIO_MOVE_CAST(Initiation)(initiation_)(
executor_binder<typename decay<Handler>::type, Executor>(
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)));
}
template <typename Handler>
void operator()(
ASIO_MOVE_ARG(Handler) handler) const
{
initiation_(
executor_binder<typename decay<Handler>::type, Executor>(
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)));
}
#define ASIO_PRIVATE_INIT_WRAPPER_DEF(n) \
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
ASIO_MOVE_CAST(Initiation)(initiation_)( \
executor_binder<typename decay<Handler>::type, Executor>( \
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
\
template <typename Handler, ASIO_VARIADIC_TPARAMS(n)> \
void operator()( \
ASIO_MOVE_ARG(Handler) handler, \
ASIO_VARIADIC_MOVE_PARAMS(n)) const \
{ \
initiation_( \
executor_binder<typename decay<Handler>::type, Executor>( \
executor_arg_t(), ex_, ASIO_MOVE_CAST(Handler)(handler)), \
ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INIT_WRAPPER_DEF)
#undef ASIO_PRIVATE_INIT_WRAPPER_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
Executor ex_;
Initiation initiation_;
};
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken, typename... Args>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get(),
declval<ASIO_MOVE_ARG(Args)>()...)))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token,
ASIO_MOVE_ARG(Args)... args)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_executor(), ASIO_MOVE_CAST(Initiation)(initiation)),
token.get(), ASIO_MOVE_CAST(Args)(args)...);
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename Initiation, typename RawCompletionToken>
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature,
(async_initiate<T, Signature>(
declval<init_wrapper<typename decay<Initiation>::type> >(),
declval<RawCompletionToken>().get())))
initiate(
ASIO_MOVE_ARG(Initiation) initiation,
ASIO_MOVE_ARG(RawCompletionToken) token)
{
return async_initiate<T, Signature>(
init_wrapper<typename decay<Initiation>::type>(
token.get_executor(), ASIO_MOVE_CAST(Initiation)(initiation)),
token.get());
}
#define ASIO_PRIVATE_INITIATE_DEF(n) \
template <typename Initiation, typename RawCompletionToken, \
ASIO_VARIADIC_TPARAMS(n)> \
static ASIO_INITFN_DEDUCED_RESULT_TYPE(T, Signature, \
(async_initiate<T, Signature>( \
declval<init_wrapper<typename decay<Initiation>::type> >(), \
declval<RawCompletionToken>().get(), \
ASIO_VARIADIC_MOVE_DECLVAL(n)))) \
initiate( \
ASIO_MOVE_ARG(Initiation) initiation, \
ASIO_MOVE_ARG(RawCompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
return async_initiate<T, Signature>( \
init_wrapper<typename decay<Initiation>::type>( \
token.get_executor(), ASIO_MOVE_CAST(Initiation)(initiation)), \
token.get(), ASIO_VARIADIC_MOVE_ARGS(n)); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_INITIATE_DEF)
#undef ASIO_PRIVATE_INITIATE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
private:
async_result(const async_result&) ASIO_DELETED;
async_result& operator=(const async_result&) ASIO_DELETED;
};
template <template <typename, typename> class Associator,
typename T, typename Executor, typename DefaultCandidate>
struct associator<Associator, executor_binder<T, Executor>, DefaultCandidate>
{
typedef typename Associator<T, DefaultCandidate>::type type;
static type get(const executor_binder<T, Executor>& b,
const DefaultCandidate& c = DefaultCandidate()) ASIO_NOEXCEPT
{
return Associator<T, DefaultCandidate>::get(b.get(), c);
}
};
template <typename T, typename Executor, typename Executor1>
struct associated_executor<executor_binder<T, Executor>, Executor1>
{
typedef Executor type;
static type get(const executor_binder<T, Executor>& b,
const Executor1& = Executor1()) ASIO_NOEXCEPT
{
return b.get_executor();
}
};
#endif // !defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BIND_EXECUTOR_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,328 @@
//
// buffer_registration.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFER_REGISTRATION_HPP
#define ASIO_BUFFER_REGISTRATION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <iterator>
#include <vector>
#include "asio/detail/memory.hpp"
#include "asio/execution/context.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/query.hpp"
#include "asio/registered_buffer.hpp"
#if defined(ASIO_HAS_IO_URING)
# include "asio/detail/scheduler.hpp"
# include "asio/detail/io_uring_service.hpp"
#endif // defined(ASIO_HAS_IO_URING)
#if defined(ASIO_HAS_MOVE)
# include <utility>
#endif // defined(ASIO_HAS_MOVE)
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class buffer_registration_base
{
protected:
static mutable_registered_buffer make_buffer(const mutable_buffer& b,
const void* scope, int index) ASIO_NOEXCEPT
{
return mutable_registered_buffer(b, registered_buffer_id(scope, index));
}
};
} // namespace detail
/// Automatically registers and unregistered buffers with an execution context.
/**
* For portability, applications should assume that only one registration is
* permitted per execution context.
*/
template <typename MutableBufferSequence,
typename Allocator = std::allocator<void> >
class buffer_registration
: detail::buffer_registration_base
{
public:
/// The allocator type used for allocating storage for the buffers container.
typedef Allocator allocator_type;
#if defined(GENERATING_DOCUMENTATION)
/// The type of an iterator over the registered buffers.
typedef unspecified iterator;
/// The type of a const iterator over the registered buffers.
typedef unspecified const_iterator;
#else // defined(GENERATING_DOCUMENTATION)
typedef std::vector<mutable_registered_buffer>::const_iterator iterator;
typedef std::vector<mutable_registered_buffer>::const_iterator const_iterator;
#endif // defined(GENERATING_DOCUMENTATION)
/// Register buffers with an executor's execution context.
template <typename Executor>
buffer_registration(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(buffer_registration::get_context(ex),
asio::buffer_sequence_begin(buffer_sequence_),
asio::buffer_sequence_end(buffer_sequence_));
}
/// Register buffers with an execution context.
template <typename ExecutionContext>
buffer_registration(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
const allocator_type& alloc = allocator_type(),
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
: buffer_sequence_(buffer_sequence),
buffers_(
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)(alloc))
{
init_buffers(ctx,
asio::buffer_sequence_begin(buffer_sequence_),
asio::buffer_sequence_end(buffer_sequence_));
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move constructor.
buffer_registration(buffer_registration&& other) ASIO_NOEXCEPT
: buffer_sequence_(std::move(other.buffer_sequence_)),
buffers_(std::move(other.buffers_))
{
#if defined(ASIO_HAS_IO_URING)
service_ = other.service_;
other.service_ = 0;
#endif // defined(ASIO_HAS_IO_URING)
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Unregisters the buffers.
~buffer_registration()
{
#if defined(ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
#endif // defined(ASIO_HAS_IO_URING)
}
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Move assignment.
buffer_registration& operator=(
buffer_registration&& other) ASIO_NOEXCEPT
{
if (this != &other)
{
buffer_sequence_ = std::move(other.buffer_sequence_);
buffers_ = std::move(other.buffers_);
#if defined(ASIO_HAS_IO_URING)
if (service_)
service_->unregister_buffers();
service_ = other.service_;
other.service_ = 0;
#endif // defined(ASIO_HAS_IO_URING)
}
return *this;
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Get the number of registered buffers.
std::size_t size() const ASIO_NOEXCEPT
{
return buffers_.size();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator begin() const ASIO_NOEXCEPT
{
return buffers_.begin();
}
/// Get the begin iterator for the sequence of registered buffers.
const_iterator cbegin() const ASIO_NOEXCEPT
{
return buffers_.cbegin();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator end() const ASIO_NOEXCEPT
{
return buffers_.end();
}
/// Get the end iterator for the sequence of registered buffers.
const_iterator cend() const ASIO_NOEXCEPT
{
return buffers_.cend();
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& operator[](std::size_t i) ASIO_NOEXCEPT
{
return buffers_[i];
}
/// Get the buffer at the specified index.
const mutable_registered_buffer& at(std::size_t i) ASIO_NOEXCEPT
{
return buffers_.at(i);
}
private:
// Disallow copying and assignment.
buffer_registration(const buffer_registration&) ASIO_DELETED;
buffer_registration& operator=(const buffer_registration&) ASIO_DELETED;
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
typename enable_if<execution::is_executor<T>::value>::type* = 0)
{
return asio::query(t, execution::context);
}
// Helper function to get an executor's context.
template <typename T>
static execution_context& get_context(const T& t,
typename enable_if<!execution::is_executor<T>::value>::type* = 0)
{
return t.context();
}
// Helper function to initialise the container of buffers.
template <typename Iterator>
void init_buffers(execution_context& ctx, Iterator begin, Iterator end)
{
std::size_t n = std::distance(begin, end);
buffers_.resize(n);
#if defined(ASIO_HAS_IO_URING)
service_ = &use_service<detail::io_uring_service>(ctx);
std::vector<iovec,
ASIO_REBIND_ALLOC(allocator_type, iovec)> iovecs(n,
ASIO_REBIND_ALLOC(allocator_type, iovec)(
buffers_.get_allocator()));
#endif // defined(ASIO_HAS_IO_URING)
Iterator iter = begin;
for (int index = 0; iter != end; ++index, ++iter)
{
mutable_buffer b(*iter);
std::size_t i = static_cast<std::size_t>(index);
buffers_[i] = this->make_buffer(b, &ctx, index);
#if defined(ASIO_HAS_IO_URING)
iovecs[i].iov_base = buffers_[i].data();
iovecs[i].iov_len = buffers_[i].size();
#endif // defined(ASIO_HAS_IO_URING)
}
#if defined(ASIO_HAS_IO_URING)
if (n > 0)
{
service_->register_buffers(&iovecs[0],
static_cast<unsigned>(iovecs.size()));
}
#endif // defined(ASIO_HAS_IO_URING)
}
MutableBufferSequence buffer_sequence_;
std::vector<mutable_registered_buffer,
ASIO_REBIND_ALLOC(allocator_type,
mutable_registered_buffer)> buffers_;
#if defined(ASIO_HAS_IO_URING)
detail::io_uring_service* service_;
#endif // defined(ASIO_HAS_IO_URING)
};
#if defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence,
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0)
{
return buffer_registration<MutableBufferSequence>(ex, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename Executor, typename MutableBufferSequence, typename Allocator>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(const Executor& ex,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ex, buffer_sequence, alloc);
}
/// Register buffers with an execution context.
template <typename ExecutionContext, typename MutableBufferSequence>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
{
return buffer_registration<MutableBufferSequence>(ctx, buffer_sequence);
}
/// Register buffers with an execution context.
template <typename ExecutionContext,
typename MutableBufferSequence, typename Allocator>
ASIO_NODISCARD inline
buffer_registration<MutableBufferSequence, Allocator>
register_buffers(ExecutionContext& ctx,
const MutableBufferSequence& buffer_sequence, const Allocator& alloc,
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0)
{
return buffer_registration<MutableBufferSequence, Allocator>(
ctx, buffer_sequence, alloc);
}
#endif // defined(ASIO_HAS_MOVE) || defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFER_REGISTRATION_HPP

View File

@ -0,0 +1,265 @@
//
// buffered_read_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_READ_STREAM_HPP
#define ASIO_BUFFERED_READ_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/buffered_read_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffer_resize_guard.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Adds buffering to the read-related operations of a stream.
/**
* The buffered_read_stream class template can be used to add buffering to the
* synchronous and asynchronous read operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_read_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_read_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_read_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return next_layer_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
next_layer_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return next_layer_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return next_layer_.async_write_some(buffers,
ASIO_MOVE_CAST(WriteHandler)(handler));
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill();
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec);
/// Start an asynchronous fill.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_fill(
ASIO_MOVE_ARG(ReadHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers);
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec);
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers);
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec);
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return storage_.size();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
ec = asio::error_code();
return storage_.size();
}
private:
/// Copy data out of the internal buffer to the specified target buffer.
/// Returns the number of bytes copied.
template <typename MutableBufferSequence>
std::size_t copy(const MutableBufferSequence& buffers)
{
std::size_t bytes_copied = asio::buffer_copy(
buffers, storage_.data(), storage_.size());
storage_.consume(bytes_copied);
return bytes_copied;
}
/// Copy data from the internal buffer to the specified target buffer, without
/// removing the data from the internal buffer. Returns the number of bytes
/// copied.
template <typename MutableBufferSequence>
std::size_t peek_copy(const MutableBufferSequence& buffers)
{
return asio::buffer_copy(buffers, storage_.data(), storage_.size());
}
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/buffered_read_stream.hpp"
#endif // ASIO_BUFFERED_READ_STREAM_HPP

View File

@ -0,0 +1,25 @@
//
// buffered_read_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_READ_STREAM_FWD_HPP
#define ASIO_BUFFERED_READ_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace asio {
template <typename Stream>
class buffered_read_stream;
} // namespace asio
#endif // ASIO_BUFFERED_READ_STREAM_FWD_HPP

View File

@ -0,0 +1,295 @@
//
// buffered_stream.hpp
// ~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_STREAM_HPP
#define ASIO_BUFFERED_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/async_result.hpp"
#include "asio/buffered_read_stream.hpp"
#include "asio/buffered_write_stream.hpp"
#include "asio/buffered_stream_fwd.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Adds buffering to the read- and write-related operations of a stream.
/**
* The buffered_stream class template can be used to add buffering to the
* synchronous and asynchronous read and write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a)
: inner_stream_impl_(a),
stream_impl_(inner_stream_impl_)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_stream(Arg& a, std::size_t read_buffer_size,
std::size_t write_buffer_size)
: inner_stream_impl_(a, write_buffer_size),
stream_impl_(inner_stream_impl_, read_buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return stream_impl_.next_layer().next_layer();
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return stream_impl_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return stream_impl_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return stream_impl_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
stream_impl_.close();
}
/// Close the stream.
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
stream_impl_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush()
{
return stream_impl_.next_layer().flush();
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec)
{
return stream_impl_.next_layer().flush(ec);
}
/// Start an asynchronous flush.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_flush(
ASIO_MOVE_ARG(WriteHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stream_impl_.next_layer().async_flush(
ASIO_MOVE_CAST(WriteHandler)(handler));
}
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers)
{
return stream_impl_.write_some(buffers);
}
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.write_some(buffers, ec);
}
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stream_impl_.async_write_some(buffers,
ASIO_MOVE_CAST(WriteHandler)(handler));
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation. Throws an exception on failure.
std::size_t fill()
{
return stream_impl_.fill();
}
/// Fill the buffer with some data. Returns the number of bytes placed in the
/// buffer as a result of the operation, or 0 if an error occurred.
std::size_t fill(asio::error_code& ec)
{
return stream_impl_.fill(ec);
}
/// Start an asynchronous fill.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_fill(
ASIO_MOVE_ARG(ReadHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stream_impl_.async_fill(ASIO_MOVE_CAST(ReadHandler)(handler));
}
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return stream_impl_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return stream_impl_.async_read_some(buffers,
ASIO_MOVE_CAST(ReadHandler)(handler));
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return stream_impl_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return stream_impl_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return stream_impl_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return stream_impl_.in_avail(ec);
}
private:
// The buffered write stream.
typedef buffered_write_stream<Stream> write_stream_type;
write_stream_type inner_stream_impl_;
// The buffered read stream.
typedef buffered_read_stream<write_stream_type&> read_stream_type;
read_stream_type stream_impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERED_STREAM_HPP

View File

@ -0,0 +1,25 @@
//
// buffered_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_STREAM_FWD_HPP
#define ASIO_BUFFERED_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace asio {
template <typename Stream>
class buffered_stream;
} // namespace asio
#endif // ASIO_BUFFERED_STREAM_FWD_HPP

View File

@ -0,0 +1,257 @@
//
// buffered_write_stream.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_WRITE_STREAM_HPP
#define ASIO_BUFFERED_WRITE_STREAM_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/buffered_write_stream_fwd.hpp"
#include "asio/buffer.hpp"
#include "asio/completion_condition.hpp"
#include "asio/detail/bind_handler.hpp"
#include "asio/detail/buffered_stream_storage.hpp"
#include "asio/detail/noncopyable.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/error.hpp"
#include "asio/write.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Adds buffering to the write-related operations of a stream.
/**
* The buffered_write_stream class template can be used to add buffering to the
* synchronous and asynchronous write operations of a stream.
*
* @par Thread Safety
* @e Distinct @e objects: Safe.@n
* @e Shared @e objects: Unsafe.
*
* @par Concepts:
* AsyncReadStream, AsyncWriteStream, Stream, SyncReadStream, SyncWriteStream.
*/
template <typename Stream>
class buffered_write_stream
: private noncopyable
{
public:
/// The type of the next layer.
typedef typename remove_reference<Stream>::type next_layer_type;
/// The type of the lowest layer.
typedef typename next_layer_type::lowest_layer_type lowest_layer_type;
/// The type of the executor associated with the object.
typedef typename lowest_layer_type::executor_type executor_type;
#if defined(GENERATING_DOCUMENTATION)
/// The default buffer size.
static const std::size_t default_buffer_size = implementation_defined;
#else
ASIO_STATIC_CONSTANT(std::size_t, default_buffer_size = 1024);
#endif
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
explicit buffered_write_stream(Arg& a)
: next_layer_(a),
storage_(default_buffer_size)
{
}
/// Construct, passing the specified argument to initialise the next layer.
template <typename Arg>
buffered_write_stream(Arg& a, std::size_t buffer_size)
: next_layer_(a),
storage_(buffer_size)
{
}
/// Get a reference to the next layer.
next_layer_type& next_layer()
{
return next_layer_;
}
/// Get a reference to the lowest layer.
lowest_layer_type& lowest_layer()
{
return next_layer_.lowest_layer();
}
/// Get a const reference to the lowest layer.
const lowest_layer_type& lowest_layer() const
{
return next_layer_.lowest_layer();
}
/// Get the executor associated with the object.
executor_type get_executor() ASIO_NOEXCEPT
{
return next_layer_.lowest_layer().get_executor();
}
/// Close the stream.
void close()
{
next_layer_.close();
}
/// Close the stream.
ASIO_SYNC_OP_VOID close(asio::error_code& ec)
{
next_layer_.close(ec);
ASIO_SYNC_OP_VOID_RETURN(ec);
}
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation. Throws an
/// exception on failure.
std::size_t flush();
/// Flush all data from the buffer to the next layer. Returns the number of
/// bytes written to the next layer on the last write operation, or 0 if an
/// error occurred.
std::size_t flush(asio::error_code& ec);
/// Start an asynchronous flush.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_flush(
ASIO_MOVE_ARG(WriteHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
/// Write the given data to the stream. Returns the number of bytes written.
/// Throws an exception on failure.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers);
/// Write the given data to the stream. Returns the number of bytes written,
/// or 0 if an error occurred and the error handler did not throw.
template <typename ConstBufferSequence>
std::size_t write_some(const ConstBufferSequence& buffers,
asio::error_code& ec);
/// Start an asynchronous write. The data being written must be valid for the
/// lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename ConstBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) WriteHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(WriteHandler,
void (asio::error_code, std::size_t))
async_write_some(const ConstBufferSequence& buffers,
ASIO_MOVE_ARG(WriteHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type));
/// Read some data from the stream. Returns the number of bytes read. Throws
/// an exception on failure.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers)
{
return next_layer_.read_some(buffers);
}
/// Read some data from the stream. Returns the number of bytes read or 0 if
/// an error occurred.
template <typename MutableBufferSequence>
std::size_t read_some(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.read_some(buffers, ec);
}
/// Start an asynchronous read. The buffer into which the data will be read
/// must be valid for the lifetime of the asynchronous operation.
/**
* @par Completion Signature
* @code void(asio::error_code, std::size_t) @endcode
*/
template <typename MutableBufferSequence,
ASIO_COMPLETION_TOKEN_FOR(void (asio::error_code,
std::size_t)) ReadHandler
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(ReadHandler,
void (asio::error_code, std::size_t))
async_read_some(const MutableBufferSequence& buffers,
ASIO_MOVE_ARG(ReadHandler) handler
ASIO_DEFAULT_COMPLETION_TOKEN(executor_type))
{
return next_layer_.async_read_some(buffers,
ASIO_MOVE_CAST(ReadHandler)(handler));
}
/// Peek at the incoming data on the stream. Returns the number of bytes read.
/// Throws an exception on failure.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers)
{
return next_layer_.peek(buffers);
}
/// Peek at the incoming data on the stream. Returns the number of bytes read,
/// or 0 if an error occurred.
template <typename MutableBufferSequence>
std::size_t peek(const MutableBufferSequence& buffers,
asio::error_code& ec)
{
return next_layer_.peek(buffers, ec);
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail()
{
return next_layer_.in_avail();
}
/// Determine the amount of data that may be read without blocking.
std::size_t in_avail(asio::error_code& ec)
{
return next_layer_.in_avail(ec);
}
private:
/// Copy data into the internal buffer from the specified source buffer.
/// Returns the number of bytes copied.
template <typename ConstBufferSequence>
std::size_t copy(const ConstBufferSequence& buffers);
/// The next layer.
Stream next_layer_;
// The data in the buffer.
detail::buffered_stream_storage storage_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/buffered_write_stream.hpp"
#endif // ASIO_BUFFERED_WRITE_STREAM_HPP

View File

@ -0,0 +1,25 @@
//
// buffered_write_stream_fwd.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#define ASIO_BUFFERED_WRITE_STREAM_FWD_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
namespace asio {
template <typename Stream>
class buffered_write_stream;
} // namespace asio
#endif // ASIO_BUFFERED_WRITE_STREAM_FWD_HPP

View File

@ -0,0 +1,521 @@
//
// buffers_iterator.hpp
// ~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_BUFFERS_ITERATOR_HPP
#define ASIO_BUFFERS_ITERATOR_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include <iterator>
#include "asio/buffer.hpp"
#include "asio/detail/assert.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail
{
template <bool IsMutable>
struct buffers_iterator_types_helper;
template <>
struct buffers_iterator_types_helper<false>
{
typedef const_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef typename add_const<ByteType>::type type;
};
};
template <>
struct buffers_iterator_types_helper<true>
{
typedef mutable_buffer buffer_type;
template <typename ByteType>
struct byte_type
{
typedef ByteType type;
};
};
template <typename BufferSequence, typename ByteType>
struct buffers_iterator_types
{
enum
{
is_mutable = is_convertible<
typename BufferSequence::value_type,
mutable_buffer>::value
};
typedef buffers_iterator_types_helper<is_mutable> helper;
typedef typename helper::buffer_type buffer_type;
typedef typename helper::template byte_type<ByteType>::type byte_type;
typedef typename BufferSequence::const_iterator const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<mutable_buffer, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<const_buffer, ByteType>
{
typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type;
typedef const const_buffer* const_iterator;
};
#if !defined(ASIO_NO_DEPRECATED)
template <typename ByteType>
struct buffers_iterator_types<mutable_buffers_1, ByteType>
{
typedef mutable_buffer buffer_type;
typedef ByteType byte_type;
typedef const mutable_buffer* const_iterator;
};
template <typename ByteType>
struct buffers_iterator_types<const_buffers_1, ByteType>
{
typedef const_buffer buffer_type;
typedef typename add_const<ByteType>::type byte_type;
typedef const const_buffer* const_iterator;
};
#endif // !defined(ASIO_NO_DEPRECATED)
}
/// A random access iterator over the bytes in a buffer sequence.
template <typename BufferSequence, typename ByteType = char>
class buffers_iterator
{
private:
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::buffer_type buffer_type;
typedef typename detail::buffers_iterator_types<BufferSequence,
ByteType>::const_iterator buffer_sequence_iterator_type;
public:
/// The type used for the distance between two iterators.
typedef std::ptrdiff_t difference_type;
/// The type of the value pointed to by the iterator.
typedef ByteType value_type;
#if defined(GENERATING_DOCUMENTATION)
/// The type of the result of applying operator->() to the iterator.
/**
* If the buffer sequence stores buffer objects that are convertible to
* mutable_buffer, this is a pointer to a non-const ByteType. Otherwise, a
* pointer to a const ByteType.
*/
typedef const_or_non_const_ByteType* pointer;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type* pointer;
#endif // defined(GENERATING_DOCUMENTATION)
#if defined(GENERATING_DOCUMENTATION)
/// The type of the result of applying operator*() to the iterator.
/**
* If the buffer sequence stores buffer objects that are convertible to
* mutable_buffer, this is a reference to a non-const ByteType. Otherwise, a
* reference to a const ByteType.
*/
typedef const_or_non_const_ByteType& reference;
#else // defined(GENERATING_DOCUMENTATION)
typedef typename detail::buffers_iterator_types<
BufferSequence, ByteType>::byte_type& reference;
#endif // defined(GENERATING_DOCUMENTATION)
/// The iterator category.
typedef std::random_access_iterator_tag iterator_category;
/// Default constructor. Creates an iterator in an undefined state.
buffers_iterator()
: current_buffer_(),
current_buffer_position_(0),
begin_(),
current_(),
end_(),
position_(0)
{
}
/// Construct an iterator representing the beginning of the buffers' data.
static buffers_iterator begin(const BufferSequence& buffers)
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
__attribute__ ((__noinline__))
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = asio::buffer_sequence_begin(buffers);
new_iter.current_ = asio::buffer_sequence_begin(buffers);
new_iter.end_ = asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
new_iter.current_buffer_ = *new_iter.current_;
if (new_iter.current_buffer_.size() > 0)
break;
++new_iter.current_;
}
return new_iter;
}
/// Construct an iterator representing the end of the buffers' data.
static buffers_iterator end(const BufferSequence& buffers)
#if defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
__attribute__ ((__noinline__))
#endif // defined(__GNUC__) && (__GNUC__ == 4) && (__GNUC_MINOR__ == 3)
{
buffers_iterator new_iter;
new_iter.begin_ = asio::buffer_sequence_begin(buffers);
new_iter.current_ = asio::buffer_sequence_begin(buffers);
new_iter.end_ = asio::buffer_sequence_end(buffers);
while (new_iter.current_ != new_iter.end_)
{
buffer_type buffer = *new_iter.current_;
new_iter.position_ += buffer.size();
++new_iter.current_;
}
return new_iter;
}
/// Dereference an iterator.
reference operator*() const
{
return dereference();
}
/// Dereference an iterator.
pointer operator->() const
{
return &dereference();
}
/// Access an individual element.
reference operator[](std::ptrdiff_t difference) const
{
buffers_iterator tmp(*this);
tmp.advance(difference);
return *tmp;
}
/// Increment operator (prefix).
buffers_iterator& operator++()
{
increment();
return *this;
}
/// Increment operator (postfix).
buffers_iterator operator++(int)
{
buffers_iterator tmp(*this);
++*this;
return tmp;
}
/// Decrement operator (prefix).
buffers_iterator& operator--()
{
decrement();
return *this;
}
/// Decrement operator (postfix).
buffers_iterator operator--(int)
{
buffers_iterator tmp(*this);
--*this;
return tmp;
}
/// Addition operator.
buffers_iterator& operator+=(std::ptrdiff_t difference)
{
advance(difference);
return *this;
}
/// Subtraction operator.
buffers_iterator& operator-=(std::ptrdiff_t difference)
{
advance(-difference);
return *this;
}
/// Addition operator.
friend buffers_iterator operator+(const buffers_iterator& iter,
std::ptrdiff_t difference)
{
buffers_iterator tmp(iter);
tmp.advance(difference);
return tmp;
}
/// Addition operator.
friend buffers_iterator operator+(std::ptrdiff_t difference,
const buffers_iterator& iter)
{
buffers_iterator tmp(iter);
tmp.advance(difference);
return tmp;
}
/// Subtraction operator.
friend buffers_iterator operator-(const buffers_iterator& iter,
std::ptrdiff_t difference)
{
buffers_iterator tmp(iter);
tmp.advance(-difference);
return tmp;
}
/// Subtraction operator.
friend std::ptrdiff_t operator-(const buffers_iterator& a,
const buffers_iterator& b)
{
return b.distance_to(a);
}
/// Test two iterators for equality.
friend bool operator==(const buffers_iterator& a, const buffers_iterator& b)
{
return a.equal(b);
}
/// Test two iterators for inequality.
friend bool operator!=(const buffers_iterator& a, const buffers_iterator& b)
{
return !a.equal(b);
}
/// Compare two iterators.
friend bool operator<(const buffers_iterator& a, const buffers_iterator& b)
{
return a.distance_to(b) > 0;
}
/// Compare two iterators.
friend bool operator<=(const buffers_iterator& a, const buffers_iterator& b)
{
return !(b < a);
}
/// Compare two iterators.
friend bool operator>(const buffers_iterator& a, const buffers_iterator& b)
{
return b < a;
}
/// Compare two iterators.
friend bool operator>=(const buffers_iterator& a, const buffers_iterator& b)
{
return !(a < b);
}
private:
// Dereference the iterator.
reference dereference() const
{
return static_cast<pointer>(
current_buffer_.data())[current_buffer_position_];
}
// Compare two iterators for equality.
bool equal(const buffers_iterator& other) const
{
return position_ == other.position_;
}
// Increment the iterator.
void increment()
{
ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
++position_;
// Check if the increment can be satisfied by the current buffer.
++current_buffer_position_;
if (current_buffer_position_ != current_buffer_.size())
return;
// Find the next non-empty buffer.
++current_;
current_buffer_position_ = 0;
while (current_ != end_)
{
current_buffer_ = *current_;
if (current_buffer_.size() > 0)
return;
++current_;
}
}
// Decrement the iterator.
void decrement()
{
ASIO_ASSERT(position_ > 0 && "iterator out of bounds");
--position_;
// Check if the decrement can be satisfied by the current buffer.
if (current_buffer_position_ != 0)
{
--current_buffer_position_;
return;
}
// Find the previous non-empty buffer.
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
buffer_type buffer = *iter;
std::size_t buffer_size = buffer.size();
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size - 1;
return;
}
}
}
// Advance the iterator by the specified distance.
void advance(std::ptrdiff_t n)
{
if (n > 0)
{
ASIO_ASSERT(current_ != end_ && "iterator out of bounds");
for (;;)
{
std::ptrdiff_t current_buffer_balance
= current_buffer_.size() - current_buffer_position_;
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_balance > n)
{
position_ += n;
current_buffer_position_ += n;
return;
}
// Update position.
n -= current_buffer_balance;
position_ += current_buffer_balance;
// Move to next buffer. If it is empty then it will be skipped on the
// next iteration of this loop.
if (++current_ == end_)
{
ASIO_ASSERT(n == 0 && "iterator out of bounds");
current_buffer_ = buffer_type();
current_buffer_position_ = 0;
return;
}
current_buffer_ = *current_;
current_buffer_position_ = 0;
}
}
else if (n < 0)
{
std::size_t abs_n = -n;
ASIO_ASSERT(position_ >= abs_n && "iterator out of bounds");
for (;;)
{
// Check if the advance can be satisfied by the current buffer.
if (current_buffer_position_ >= abs_n)
{
position_ -= abs_n;
current_buffer_position_ -= abs_n;
return;
}
// Update position.
abs_n -= current_buffer_position_;
position_ -= current_buffer_position_;
// Check if we've reached the beginning of the buffers.
if (current_ == begin_)
{
ASIO_ASSERT(abs_n == 0 && "iterator out of bounds");
current_buffer_position_ = 0;
return;
}
// Find the previous non-empty buffer.
buffer_sequence_iterator_type iter = current_;
while (iter != begin_)
{
--iter;
buffer_type buffer = *iter;
std::size_t buffer_size = buffer.size();
if (buffer_size > 0)
{
current_ = iter;
current_buffer_ = buffer;
current_buffer_position_ = buffer_size;
break;
}
}
}
}
}
// Determine the distance between two iterators.
std::ptrdiff_t distance_to(const buffers_iterator& other) const
{
return other.position_ - position_;
}
buffer_type current_buffer_;
std::size_t current_buffer_position_;
buffer_sequence_iterator_type begin_;
buffer_sequence_iterator_type current_;
buffer_sequence_iterator_type end_;
std::size_t position_;
};
/// Construct an iterator representing the beginning of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_begin(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::begin(buffers);
}
/// Construct an iterator representing the end of the buffers' data.
template <typename BufferSequence>
inline buffers_iterator<BufferSequence> buffers_end(
const BufferSequence& buffers)
{
return buffers_iterator<BufferSequence>::end(buffers);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_BUFFERS_ITERATOR_HPP

View File

@ -0,0 +1,305 @@
//
// cancellation_signal.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CANCELLATION_SIGNAL_HPP
#define ASIO_CANCELLATION_SIGNAL_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cassert>
#include <new>
#include <utility>
#include "asio/cancellation_type.hpp"
#include "asio/detail/cstddef.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/detail/variadic_templates.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
class cancellation_handler_base
{
public:
virtual void call(cancellation_type_t) = 0;
virtual std::pair<void*, std::size_t> destroy() ASIO_NOEXCEPT = 0;
protected:
~cancellation_handler_base() {}
};
template <typename Handler>
class cancellation_handler
: public cancellation_handler_base
{
public:
#if defined(ASIO_HAS_VARIADIC_TEMPLATES)
template <typename... Args>
cancellation_handler(std::size_t size, ASIO_MOVE_ARG(Args)... args)
: handler_(ASIO_MOVE_CAST(Args)(args)...),
size_(size)
{
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
cancellation_handler(std::size_t size)
: handler_(),
size_(size)
{
}
#define ASIO_PRIVATE_HANDLER_CTOR_DEF(n) \
template <ASIO_VARIADIC_TPARAMS(n)> \
cancellation_handler(std::size_t size, ASIO_VARIADIC_MOVE_PARAMS(n)) \
: handler_(ASIO_VARIADIC_MOVE_ARGS(n)), \
size_(size) \
{ \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_HANDLER_CTOR_DEF)
#undef ASIO_PRIVATE_HANDLER_CTOR_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
void call(cancellation_type_t type)
{
handler_(type);
}
std::pair<void*, std::size_t> destroy() ASIO_NOEXCEPT
{
std::pair<void*, std::size_t> mem(this, size_);
this->cancellation_handler::~cancellation_handler();
return mem;
}
Handler& handler() ASIO_NOEXCEPT
{
return handler_;
}
private:
~cancellation_handler()
{
}
Handler handler_;
std::size_t size_;
};
} // namespace detail
class cancellation_slot;
/// A cancellation signal with a single slot.
class cancellation_signal
{
public:
ASIO_CONSTEXPR cancellation_signal()
: handler_(0)
{
}
ASIO_DECL ~cancellation_signal();
/// Emits the signal and causes invocation of the slot's handler, if any.
void emit(cancellation_type_t type)
{
if (handler_)
handler_->call(type);
}
/// Returns the single slot associated with the signal.
/**
* The signal object must remain valid for as long the slot may be used.
* Destruction of the signal invalidates the slot.
*/
cancellation_slot slot() ASIO_NOEXCEPT;
private:
cancellation_signal(const cancellation_signal&) ASIO_DELETED;
cancellation_signal& operator=(const cancellation_signal&) ASIO_DELETED;
detail::cancellation_handler_base* handler_;
};
/// A slot associated with a cancellation signal.
class cancellation_slot
{
public:
/// Creates a slot that is not connected to any cancellation signal.
ASIO_CONSTEXPR cancellation_slot()
: handler_(0)
{
}
#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
|| defined(GENERATING_DOCUMENTATION)
/// Installs a handler into the slot, constructing the new object directly.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it with the supplied @c args.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(asio::cancellation_type_t); @endcode
*
* @param args Arguments to be passed to the @c CancellationHandler object's
* constructor.
*
* @returns A reference to the newly installed handler.
*
* @note Handlers installed into the slot via @c emplace are not required to
* be copy constructible or move constructible.
*/
template <typename CancellationHandler, typename... Args>
CancellationHandler& emplace(ASIO_MOVE_ARG(Args)... args)
{
typedef detail::cancellation_handler<CancellationHandler>
cancellation_handler_type;
auto_delete_helper del = { prepare_memory(
sizeof(cancellation_handler_type),
ASIO_ALIGNOF(CancellationHandler)) };
cancellation_handler_type* handler_obj =
new (del.mem.first) cancellation_handler_type(
del.mem.second, ASIO_MOVE_CAST(Args)(args)...);
del.mem.first = 0;
*handler_ = handler_obj;
return handler_obj->handler();
}
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)
template <typename CancellationHandler>
CancellationHandler& emplace()
{
typedef detail::cancellation_handler<CancellationHandler>
cancellation_handler_type;
auto_delete_helper del = { prepare_memory(
sizeof(cancellation_handler_type),
ASIO_ALIGNOF(CancellationHandler)) };
cancellation_handler_type* handler_obj =
new (del.mem.first) cancellation_handler_type(del.mem.second);
del.mem.first = 0;
*handler_ = handler_obj;
return handler_obj->handler();
}
#define ASIO_PRIVATE_HANDLER_EMPLACE_DEF(n) \
template <typename CancellationHandler, ASIO_VARIADIC_TPARAMS(n)> \
CancellationHandler& emplace(ASIO_VARIADIC_MOVE_PARAMS(n)) \
{ \
typedef detail::cancellation_handler<CancellationHandler> \
cancellation_handler_type; \
auto_delete_helper del = { prepare_memory( \
sizeof(cancellation_handler_type), \
ASIO_ALIGNOF(CancellationHandler)) }; \
cancellation_handler_type* handler_obj = \
new (del.mem.first) cancellation_handler_type( \
del.mem.second, ASIO_VARIADIC_MOVE_ARGS(n)); \
del.mem.first = 0; \
*handler_ = handler_obj; \
return handler_obj->handler(); \
} \
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_HANDLER_EMPLACE_DEF)
#undef ASIO_PRIVATE_HANDLER_EMPLACE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
/// Installs a handler into the slot.
/**
* Destroys any existing handler in the slot, then installs the new handler,
* constructing it as a decay-copy of the supplied handler.
*
* The handler is a function object to be called when the signal is emitted.
* The signature of the handler must be
* @code void handler(asio::cancellation_type_t); @endcode
*
* @param handler The handler to be installed.
*
* @returns A reference to the newly installed handler.
*/
template <typename CancellationHandler>
typename decay<CancellationHandler>::type& assign(
ASIO_MOVE_ARG(CancellationHandler) handler)
{
return this->emplace<typename decay<CancellationHandler>::type>(
ASIO_MOVE_CAST(CancellationHandler)(handler));
}
/// Clears the slot.
/**
* Destroys any existing handler in the slot.
*/
ASIO_DECL void clear();
/// Returns whether the slot is connected to a signal.
ASIO_CONSTEXPR bool is_connected() const ASIO_NOEXCEPT
{
return handler_ != 0;
}
/// Returns whether the slot is connected and has an installed handler.
ASIO_CONSTEXPR bool has_handler() const ASIO_NOEXCEPT
{
return handler_ != 0 && *handler_ != 0;
}
/// Compare two slots for equality.
friend ASIO_CONSTEXPR bool operator==(const cancellation_slot& lhs,
const cancellation_slot& rhs) ASIO_NOEXCEPT
{
return lhs.handler_ == rhs.handler_;
}
/// Compare two slots for inequality.
friend ASIO_CONSTEXPR bool operator!=(const cancellation_slot& lhs,
const cancellation_slot& rhs) ASIO_NOEXCEPT
{
return lhs.handler_ != rhs.handler_;
}
private:
friend class cancellation_signal;
ASIO_CONSTEXPR cancellation_slot(int,
detail::cancellation_handler_base** handler)
: handler_(handler)
{
}
ASIO_DECL std::pair<void*, std::size_t> prepare_memory(
std::size_t size, std::size_t align);
struct auto_delete_helper
{
std::pair<void*, std::size_t> mem;
ASIO_DECL ~auto_delete_helper();
};
detail::cancellation_handler_base** handler_;
};
inline cancellation_slot cancellation_signal::slot() ASIO_NOEXCEPT
{
return cancellation_slot(0, &handler_);
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/cancellation_signal.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // ASIO_CANCELLATION_SIGNAL_HPP

View File

@ -0,0 +1,235 @@
//
// cancellation_state.hpp
// ~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CANCELLATION_STATE_HPP
#define ASIO_CANCELLATION_STATE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cassert>
#include <new>
#include <utility>
#include "asio/cancellation_signal.hpp"
#include "asio/detail/cstddef.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// A simple cancellation signal propagation filter.
template <cancellation_type_t Mask>
struct cancellation_filter
{
/// Returns <tt>type & Mask</tt>.
cancellation_type_t operator()(
cancellation_type_t type) const ASIO_NOEXCEPT
{
return type & Mask;
}
};
/// A cancellation filter that disables cancellation.
typedef cancellation_filter<cancellation_type::none>
disable_cancellation;
/// A cancellation filter that enables terminal cancellation only.
typedef cancellation_filter<cancellation_type::terminal>
enable_terminal_cancellation;
#if defined(GENERATING_DOCUMENTATION)
/// A cancellation filter that enables terminal and partial cancellation.
typedef cancellation_filter<
cancellation_type::terminal | cancellation_type::partial>
enable_partial_cancellation;
/// A cancellation filter that enables terminal, partial and total cancellation.
typedef cancellation_filter<cancellation_type::terminal
| cancellation_type::partial | cancellation_type::total>
enable_total_cancellation;
#else // defined(GENERATING_DOCUMENTATION)
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial))>
enable_partial_cancellation;
typedef cancellation_filter<
static_cast<cancellation_type_t>(
static_cast<unsigned int>(cancellation_type::terminal)
| static_cast<unsigned int>(cancellation_type::partial)
| static_cast<unsigned int>(cancellation_type::total))>
enable_total_cancellation;
#endif // defined(GENERATING_DOCUMENTATION)
/// A cancellation state is used for chaining signals and slots in compositions.
class cancellation_state
{
public:
/// Construct a disconnected cancellation state.
ASIO_CONSTEXPR cancellation_state() ASIO_NOEXCEPT
: impl_(0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* Initialises the cancellation state so that it allows terminal cancellation
* only. Equivalent to <tt>cancellation_state(slot,
* enable_terminal_cancellation())</tt>.
*
* @param slot The parent cancellation slot to which the state will be
* attached.
*/
template <typename CancellationSlot>
ASIO_CONSTEXPR explicit cancellation_state(CancellationSlot slot)
: impl_(slot.is_connected() ? &slot.template emplace<impl<> >() : 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code asio::cancellation_type_t filter(
* asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li asio::disable_cancellation
* @li asio::enable_terminal_cancellation
* @li asio::enable_partial_cancellation
* @li asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename Filter>
ASIO_CONSTEXPR cancellation_state(CancellationSlot slot, Filter filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<Filter, Filter> >(filter, filter)
: 0)
{
}
/// Construct and attach to a parent slot to create a new child slot.
/**
* @param slot The parent cancellation slot to which the state will be
* attached.
*
* @param in_filter A function object that is used to transform incoming
* cancellation signals as they are received from the parent slot. This
* function object must have the signature:
* @code asio::cancellation_type_t in_filter(
* asio::cancellation_type_t); @endcode
*
* @param out_filter A function object that is used to transform outcoming
* cancellation signals as they are relayed to the child slot. This function
* object must have the signature:
* @code asio::cancellation_type_t out_filter(
* asio::cancellation_type_t); @endcode
*
* The library provides the following pre-defined cancellation filters:
*
* @li asio::disable_cancellation
* @li asio::enable_terminal_cancellation
* @li asio::enable_partial_cancellation
* @li asio::enable_total_cancellation
*/
template <typename CancellationSlot, typename InFilter, typename OutFilter>
ASIO_CONSTEXPR cancellation_state(CancellationSlot slot,
InFilter in_filter, OutFilter out_filter)
: impl_(slot.is_connected()
? &slot.template emplace<impl<InFilter, OutFilter> >(
ASIO_MOVE_CAST(InFilter)(in_filter),
ASIO_MOVE_CAST(OutFilter)(out_filter))
: 0)
{
}
/// Returns the single child slot associated with the state.
/**
* This sub-slot is used with the operations that are being composed.
*/
ASIO_CONSTEXPR cancellation_slot slot() const ASIO_NOEXCEPT
{
return impl_ ? impl_->signal_.slot() : cancellation_slot();
}
/// Returns the cancellation types that have been triggered.
cancellation_type_t cancelled() const ASIO_NOEXCEPT
{
return impl_ ? impl_->cancelled_ : cancellation_type_t();
}
/// Clears the specified cancellation types, if they have been triggered.
void clear(cancellation_type_t mask = cancellation_type::all)
ASIO_NOEXCEPT
{
if (impl_)
impl_->cancelled_ &= ~mask;
}
private:
struct impl_base
{
impl_base()
: cancelled_()
{
}
cancellation_signal signal_;
cancellation_type_t cancelled_;
};
template <
typename InFilter = enable_terminal_cancellation,
typename OutFilter = InFilter>
struct impl : impl_base
{
impl()
: in_filter_(),
out_filter_()
{
}
impl(InFilter in_filter, OutFilter out_filter)
: in_filter_(ASIO_MOVE_CAST(InFilter)(in_filter)),
out_filter_(ASIO_MOVE_CAST(OutFilter)(out_filter))
{
}
void operator()(cancellation_type_t in)
{
this->cancelled_ = in_filter_(in);
cancellation_type_t out = out_filter_(this->cancelled_);
if (out != cancellation_type::none)
this->signal_.emit(out);
}
InFilter in_filter_;
OutFilter out_filter_;
};
impl_base* impl_;
};
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_CANCELLATION_STATE_HPP

View File

@ -0,0 +1,174 @@
//
// cancellation_type.hpp
// ~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CANCELLATION_TYPE_HPP
#define ASIO_CANCELLATION_TYPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
# if defined(GENERATING_DOCUMENTATION)
/// Enumeration representing the different types of cancellation that may
/// be requested from or implemented by an asynchronous operation.
enum cancellation_type
{
/// Bitmask representing no types of cancellation.
none = 0,
/// Requests cancellation where, following a successful cancellation, the only
/// safe operations on the I/O object are closure or destruction.
terminal = 1,
/// Requests cancellation where a successful cancellation may result in
/// partial side effects or no side effects. Following cancellation, the I/O
/// object is in a well-known state, and may be used for further operations.
partial = 2,
/// Requests cancellation where a successful cancellation results in no
/// apparent side effects. Following cancellation, the I/O object is in the
/// same observable state as it was prior to the operation.
total = 4,
/// Bitmask representing all types of cancellation.
all = 0xFFFFFFFF
};
/// Portability typedef.
typedef cancellation_type cancellation_type_t;
#elif defined(ASIO_HAS_ENUM_CLASS)
enum class cancellation_type : unsigned int
{
none = 0,
terminal = 1,
partial = 2,
total = 4,
all = 0xFFFFFFFF
};
typedef cancellation_type cancellation_type_t;
#else // defined(ASIO_HAS_ENUM_CLASS)
namespace cancellation_type {
enum cancellation_type_t
{
none = 0,
terminal = 1,
partial = 2,
total = 4,
all = 0xFFFFFFFF
};
} // namespace cancellation_type
typedef cancellation_type::cancellation_type_t cancellation_type_t;
#endif // defined(ASIO_HAS_ENUM_CLASS)
/// Negation operator.
/**
* @relates cancellation_type
*/
inline ASIO_CONSTEXPR bool operator!(cancellation_type_t x)
{
return static_cast<unsigned int>(x) == 0;
}
/// Bitwise and operator.
/**
* @relates cancellation_type
*/
inline ASIO_CONSTEXPR cancellation_type_t operator&(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) & static_cast<unsigned int>(y));
}
/// Bitwise or operator.
/**
* @relates cancellation_type
*/
inline ASIO_CONSTEXPR cancellation_type_t operator|(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) | static_cast<unsigned int>(y));
}
/// Bitwise xor operator.
/**
* @relates cancellation_type
*/
inline ASIO_CONSTEXPR cancellation_type_t operator^(
cancellation_type_t x, cancellation_type_t y)
{
return static_cast<cancellation_type_t>(
static_cast<unsigned int>(x) ^ static_cast<unsigned int>(y));
}
/// Bitwise negation operator.
/**
* @relates cancellation_type
*/
inline ASIO_CONSTEXPR cancellation_type_t operator~(cancellation_type_t x)
{
return static_cast<cancellation_type_t>(~static_cast<unsigned int>(x));
}
/// Bitwise and-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator&=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x & y;
return x;
}
/// Bitwise or-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator|=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x | y;
return x;
}
/// Bitwise xor-assignment operator.
/**
* @relates cancellation_type
*/
inline cancellation_type_t& operator^=(
cancellation_type_t& x, cancellation_type_t y)
{
x = x ^ y;
return x;
}
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_CANCELLATION_TYPE_HPP

View File

@ -0,0 +1,523 @@
//
// co_spawn.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CO_SPAWN_HPP
#define ASIO_CO_SPAWN_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#include "asio/awaitable.hpp"
#include "asio/execution/executor.hpp"
#include "asio/execution_context.hpp"
#include "asio/is_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
template <typename T>
struct awaitable_signature;
template <typename T, typename Executor>
struct awaitable_signature<awaitable<T, Executor>>
{
typedef void type(std::exception_ptr, T);
};
template <typename Executor>
struct awaitable_signature<awaitable<void, Executor>>
{
typedef void type(std::exception_ptr);
};
} // namespace detail
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr, T); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename T, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(const Executor& ex, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
typename constraint<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
>::type = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* echo(std::move(my_tcp_socket)),
* asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(const Executor& ex, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
typename constraint<
(is_executor<Executor>::value || execution::is_executor<Executor>::value)
&& is_convertible<Executor, AwaitableExecutor>::value
>::type = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, T) @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* [](std::exception_ptr e, std::size_t n)
* {
* std::cout << "transferred " << n << "\n";
* });
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename T, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr, T)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr, T))
co_spawn(ExecutionContext& ctx, awaitable<T, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
>::type = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param a The asio::awaitable object that is the result of calling the
* coroutine's entry point function.
*
* @param token The @ref completion_token that will handle the notification that
* the thread of execution has completed. The function signature of the
* completion handler must be:
* @code void handler(std::exception_ptr); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr) @endcode
*
* @par Example
* @code
* asio::awaitable<void> echo(tcp::socket socket)
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* echo(std::move(my_tcp_socket)),
* asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename AwaitableExecutor,
ASIO_COMPLETION_TOKEN_FOR(
void(std::exception_ptr)) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
inline ASIO_INITFN_AUTO_RESULT_TYPE(
CompletionToken, void(std::exception_ptr))
co_spawn(ExecutionContext& ctx, awaitable<void, AwaitableExecutor> a,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
&& is_convertible<typename ExecutionContext::executor_type,
AwaitableExecutor>::value
>::type = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ex The executor that will be used to schedule the new thread of
* execution.
*
* @param f A nullary function object with a return type of the form
* @c asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_executor,
* [socket = std::move(my_tcp_socket)]() mutable
* -> asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename Executor, typename F,
ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
typename result_of<F()>::type>::type) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
co_spawn(const Executor& ex, F&& f,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
typename constraint<
is_executor<Executor>::value || execution::is_executor<Executor>::value
>::type = 0);
/// Spawn a new coroutined-based thread of execution.
/**
* @param ctx An execution context that will provide the executor to be used to
* schedule the new thread of execution.
*
* @param f A nullary function object with a return type of the form
* @c asio::awaitable<R,E> that will be used as the coroutine's entry
* point.
*
* @param token The @ref completion_token that will handle the notification
* that the thread of execution has completed. If @c R is @c void, the function
* signature of the completion handler must be:
*
* @code void handler(std::exception_ptr); @endcode
* Otherwise, the function signature of the completion handler must be:
* @code void handler(std::exception_ptr, R); @endcode
*
* @par Completion Signature
* @code void(std::exception_ptr, R) @endcode
* where @c R is the first template argument to the @c awaitable returned by the
* supplied function object @c F:
* @code asio::awaitable<R, AwaitableExecutor> F() @endcode
*
* @par Example
* @code
* asio::awaitable<std::size_t> echo(tcp::socket socket)
* {
* std::size_t bytes_transferred = 0;
*
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
*
* bytes_transferred += n;
* }
* }
* catch (const std::exception&)
* {
* }
*
* co_return bytes_transferred;
* }
*
* // ...
*
* asio::co_spawn(my_io_context,
* [socket = std::move(my_tcp_socket)]() mutable
* -> asio::awaitable<void>
* {
* try
* {
* char data[1024];
* for (;;)
* {
* std::size_t n = co_await socket.async_read_some(
* asio::buffer(data), asio::use_awaitable);
*
* co_await asio::async_write(socket,
* asio::buffer(data, n), asio::use_awaitable);
* }
* }
* catch (const std::exception& e)
* {
* std::cerr << "Exception: " << e.what() << "\n";
* }
* }, asio::detached);
* @endcode
*
* @par Per-Operation Cancellation
* The new thread of execution is created with a cancellation state that
* supports @c cancellation_type::terminal values only. To change the
* cancellation state, call asio::this_coro::reset_cancellation_state.
*/
template <typename ExecutionContext, typename F,
ASIO_COMPLETION_TOKEN_FOR(typename detail::awaitable_signature<
typename result_of<F()>::type>::type) CompletionToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken,
typename detail::awaitable_signature<typename result_of<F()>::type>::type)
co_spawn(ExecutionContext& ctx, F&& f,
CompletionToken&& token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
typename constraint<
is_convertible<ExecutionContext&, execution_context&>::value
>::type = 0);
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/co_spawn.hpp"
#endif // defined(ASIO_HAS_CO_AWAIT) || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_CO_SPAWN_HPP

View File

@ -0,0 +1,218 @@
//
// completion_condition.hpp
// ~~~~~~~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_COMPLETION_CONDITION_HPP
#define ASIO_COMPLETION_CONDITION_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <cstddef>
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
// The default maximum number of bytes to transfer in a single operation.
enum default_max_transfer_size_t { default_max_transfer_size = 65536 };
// Adapt result of old-style completion conditions (which had a bool result
// where true indicated that the operation was complete).
inline std::size_t adapt_completion_condition_result(bool result)
{
return result ? 0 : default_max_transfer_size;
}
// Adapt result of current completion conditions (which have a size_t result
// where 0 means the operation is complete, and otherwise the result is the
// maximum number of bytes to transfer on the next underlying operation).
inline std::size_t adapt_completion_condition_result(std::size_t result)
{
return result;
}
class transfer_all_t
{
public:
typedef std::size_t result_type;
template <typename Error>
std::size_t operator()(const Error& err, std::size_t)
{
return !!err ? 0 : default_max_transfer_size;
}
};
class transfer_at_least_t
{
public:
typedef std::size_t result_type;
explicit transfer_at_least_t(std::size_t minimum)
: minimum_(minimum)
{
}
template <typename Error>
std::size_t operator()(const Error& err, std::size_t bytes_transferred)
{
return (!!err || bytes_transferred >= minimum_)
? 0 : default_max_transfer_size;
}
private:
std::size_t minimum_;
};
class transfer_exactly_t
{
public:
typedef std::size_t result_type;
explicit transfer_exactly_t(std::size_t size)
: size_(size)
{
}
template <typename Error>
std::size_t operator()(const Error& err, std::size_t bytes_transferred)
{
return (!!err || bytes_transferred >= size_) ? 0 :
(size_ - bytes_transferred < default_max_transfer_size
? size_ - bytes_transferred : std::size_t(default_max_transfer_size));
}
private:
std::size_t size_;
};
} // namespace detail
/**
* @defgroup completion_condition Completion Condition Function Objects
*
* Function objects used for determining when a read or write operation should
* complete.
*/
/*@{*/
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until all of the data has been transferred,
/// or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full:
* @code
* boost::array<char, 128> buf;
* asio::error_code ec;
* std::size_t n = asio::read(
* sock, asio::buffer(buf),
* asio::transfer_all(), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n == 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_all();
#else
inline detail::transfer_all_t transfer_all()
{
return detail::transfer_all_t();
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until a minimum number of bytes has been
/// transferred, or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full or contains at least 64 bytes:
* @code
* boost::array<char, 128> buf;
* asio::error_code ec;
* std::size_t n = asio::read(
* sock, asio::buffer(buf),
* asio::transfer_at_least(64), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n >= 64 && n <= 128
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_at_least(std::size_t minimum);
#else
inline detail::transfer_at_least_t transfer_at_least(std::size_t minimum)
{
return detail::transfer_at_least_t(minimum);
}
#endif
/// Return a completion condition function object that indicates that a read or
/// write operation should continue until an exact number of bytes has been
/// transferred, or until an error occurs.
/**
* This function is used to create an object, of unspecified type, that meets
* CompletionCondition requirements.
*
* @par Example
* Reading until a buffer is full or contains exactly 64 bytes:
* @code
* boost::array<char, 128> buf;
* asio::error_code ec;
* std::size_t n = asio::read(
* sock, asio::buffer(buf),
* asio::transfer_exactly(64), ec);
* if (ec)
* {
* // An error occurred.
* }
* else
* {
* // n == 64
* }
* @endcode
*/
#if defined(GENERATING_DOCUMENTATION)
unspecified transfer_exactly(std::size_t size);
#else
inline detail::transfer_exactly_t transfer_exactly(std::size_t size)
{
return detail::transfer_exactly_t(size);
}
#endif
/*@}*/
} // namespace asio
#include "asio/detail/pop_options.hpp"
#endif // ASIO_COMPLETION_CONDITION_HPP

View File

@ -0,0 +1,136 @@
//
// compose.hpp
// ~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_COMPOSE_HPP
#define ASIO_COMPOSE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
#if defined(ASIO_HAS_VARIADIC_TEMPLATES) \
|| defined(GENERATING_DOCUMENTATION)
/// Launch an asynchronous operation with a stateful implementation.
/**
* The async_compose function simplifies the implementation of composed
* asynchronous operations automatically wrapping a stateful function object
* with a conforming intermediate completion handler.
*
* @param implementation A function object that contains the implementation of
* the composed asynchronous operation. The first argument to the function
* object is a non-const reference to the enclosing intermediate completion
* handler. The remaining arguments are any arguments that originate from the
* completion handlers of any asynchronous operations performed by the
* implementation.
* @param token The completion token.
*
* @param io_objects_or_executors Zero or more I/O objects or I/O executors for
* which outstanding work must be maintained.
*
* @par Example:
*
* @code struct async_echo_implementation
* {
* tcp::socket& socket_;
* asio::mutable_buffer buffer_;
* enum { starting, reading, writing } state_;
*
* template <typename Self>
* void operator()(Self& self,
* asio::error_code error = {},
* std::size_t n = 0)
* {
* switch (state_)
* {
* case starting:
* state_ = reading;
* socket_.async_read_some(
* buffer_, std::move(self));
* break;
* case reading:
* if (error)
* {
* self.complete(error, 0);
* }
* else
* {
* state_ = writing;
* asio::async_write(socket_, buffer_,
* asio::transfer_exactly(n),
* std::move(self));
* }
* break;
* case writing:
* self.complete(error, n);
* break;
* }
* }
* };
*
* template <typename CompletionToken>
* auto async_echo(tcp::socket& socket,
* asio::mutable_buffer buffer,
* CompletionToken&& token) ->
* typename asio::async_result<
* typename std::decay<CompletionToken>::type,
* void(asio::error_code, std::size_t)>::return_type
* {
* return asio::async_compose<CompletionToken,
* void(asio::error_code, std::size_t)>(
* async_echo_implementation{socket, buffer,
* async_echo_implementation::starting},
* token, socket);
* } @endcode
*/
template <typename CompletionToken, typename Signature,
typename Implementation, typename... IoObjectsOrExecutors>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
async_compose(ASIO_MOVE_ARG(Implementation) implementation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token,
ASIO_MOVE_ARG(IoObjectsOrExecutors)... io_objects_or_executors);
#else // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)
template <typename CompletionToken, typename Signature, typename Implementation>
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature)
async_compose(ASIO_MOVE_ARG(Implementation) implementation,
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token);
#define ASIO_PRIVATE_ASYNC_COMPOSE_DEF(n) \
template <typename CompletionToken, typename Signature, \
typename Implementation, ASIO_VARIADIC_TPARAMS(n)> \
ASIO_INITFN_AUTO_RESULT_TYPE(CompletionToken, Signature) \
async_compose(ASIO_MOVE_ARG(Implementation) implementation, \
ASIO_NONDEDUCED_MOVE_ARG(CompletionToken) token, \
ASIO_VARIADIC_MOVE_PARAMS(n));
/**/
ASIO_VARIADIC_GENERATE(ASIO_PRIVATE_ASYNC_COMPOSE_DEF)
#undef ASIO_PRIVATE_ASYNC_COMPOSE_DEF
#endif // defined(ASIO_HAS_VARIADIC_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/compose.hpp"
#endif // ASIO_COMPOSE_HPP

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,83 @@
//
// connect_pipe.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_CONNECT_PIPE_HPP
#define ASIO_CONNECT_PIPE_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_PIPE) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/basic_readable_pipe.hpp"
#include "asio/basic_writable_pipe.hpp"
#include "asio/error.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
namespace detail {
#if defined(ASIO_HAS_IOCP)
typedef HANDLE native_pipe_handle;
#else // defined(ASIO_HAS_IOCP)
typedef int native_pipe_handle;
#endif // defined(ASIO_HAS_IOCP)
ASIO_DECL void create_pipe(native_pipe_handle p[2],
asio::error_code& ec);
ASIO_DECL void close_pipe(native_pipe_handle p);
} // namespace detail
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws asio::system_error Thrown on failure.
*/
template <typename Executor1, typename Executor2>
void connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end);
/// Connect two pipe ends using an anonymous pipe.
/**
* @param read_end The read end of the pipe.
*
* @param write_end The write end of the pipe.
*
* @throws asio::system_error Thrown on failure.
*
* @param ec Set to indicate what error occurred, if any.
*/
template <typename Executor1, typename Executor2>
ASIO_SYNC_OP_VOID connect_pipe(basic_readable_pipe<Executor1>& read_end,
basic_writable_pipe<Executor2>& write_end, asio::error_code& ec);
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/connect_pipe.hpp"
#if defined(ASIO_HEADER_ONLY)
# include "asio/impl/connect_pipe.ipp"
#endif // defined(ASIO_HEADER_ONLY)
#endif // defined(ASIO_HAS_PIPE)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_CONNECT_PIPE_HPP

View File

@ -0,0 +1,328 @@
//
// coroutine.hpp
// ~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_COROUTINE_HPP
#define ASIO_COROUTINE_HPP
namespace asio {
namespace detail {
class coroutine_ref;
} // namespace detail
/// Provides support for implementing stackless coroutines.
/**
* The @c coroutine class may be used to implement stackless coroutines. The
* class itself is used to store the current state of the coroutine.
*
* Coroutines are copy-constructible and assignable, and the space overhead is
* a single int. They can be used as a base class:
*
* @code class session : coroutine
* {
* ...
* }; @endcode
*
* or as a data member:
*
* @code class session
* {
* ...
* coroutine coro_;
* }; @endcode
*
* or even bound in as a function argument using lambdas or @c bind(). The
* important thing is that as the application maintains a copy of the object
* for as long as the coroutine must be kept alive.
*
* @par Pseudo-keywords
*
* A coroutine is used in conjunction with certain "pseudo-keywords", which
* are implemented as macros. These macros are defined by a header file:
*
* @code #include <asio/yield.hpp>@endcode
*
* and may conversely be undefined as follows:
*
* @code #include <asio/unyield.hpp>@endcode
*
* <b>reenter</b>
*
* The @c reenter macro is used to define the body of a coroutine. It takes a
* single argument: a pointer or reference to a coroutine object. For example,
* if the base class is a coroutine object you may write:
*
* @code reenter (this)
* {
* ... coroutine body ...
* } @endcode
*
* and if a data member or other variable you can write:
*
* @code reenter (coro_)
* {
* ... coroutine body ...
* } @endcode
*
* When @c reenter is executed at runtime, control jumps to the location of the
* last @c yield or @c fork.
*
* The coroutine body may also be a single statement, such as:
*
* @code reenter (this) for (;;)
* {
* ...
* } @endcode
*
* @b Limitation: The @c reenter macro is implemented using a switch. This
* means that you must take care when using local variables within the
* coroutine body. The local variable is not allowed in a position where
* reentering the coroutine could bypass the variable definition.
*
* <b>yield <em>statement</em></b>
*
* This form of the @c yield keyword is often used with asynchronous operations:
*
* @code yield socket_->async_read_some(buffer(*buffer_), *this); @endcode
*
* This divides into four logical steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The statement initiates the asynchronous operation.
* @li The resume point is defined immediately following the statement.
* @li Control is transferred to the end of the coroutine body.
*
* When the asynchronous operation completes, the function object is invoked
* and @c reenter causes control to transfer to the resume point. It is
* important to remember to carry the coroutine state forward with the
* asynchronous operation. In the above snippet, the current class is a
* function object object with a coroutine object as base class or data member.
*
* The statement may also be a compound statement, and this permits us to
* define local variables with limited scope:
*
* @code yield
* {
* mutable_buffers_1 b = buffer(*buffer_);
* socket_->async_read_some(b, *this);
* } @endcode
*
* <b>yield return <em>expression</em> ;</b>
*
* This form of @c yield is often used in generators or coroutine-based parsers.
* For example, the function object:
*
* @code struct interleave : coroutine
* {
* istream& is1;
* istream& is2;
* char operator()(char c)
* {
* reenter (this) for (;;)
* {
* yield return is1.get();
* yield return is2.get();
* }
* }
* }; @endcode
*
* defines a trivial coroutine that interleaves the characters from two input
* streams.
*
* This type of @c yield divides into three logical steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The resume point is defined immediately following the semicolon.
* @li The value of the expression is returned from the function.
*
* <b>yield ;</b>
*
* This form of @c yield is equivalent to the following steps:
*
* @li @c yield saves the current state of the coroutine.
* @li The resume point is defined immediately following the semicolon.
* @li Control is transferred to the end of the coroutine body.
*
* This form might be applied when coroutines are used for cooperative
* threading and scheduling is explicitly managed. For example:
*
* @code struct task : coroutine
* {
* ...
* void operator()()
* {
* reenter (this)
* {
* while (... not finished ...)
* {
* ... do something ...
* yield;
* ... do some more ...
* yield;
* }
* }
* }
* ...
* };
* ...
* task t1, t2;
* for (;;)
* {
* t1();
* t2();
* } @endcode
*
* <b>yield break ;</b>
*
* The final form of @c yield is used to explicitly terminate the coroutine.
* This form is comprised of two steps:
*
* @li @c yield sets the coroutine state to indicate termination.
* @li Control is transferred to the end of the coroutine body.
*
* Once terminated, calls to is_complete() return true and the coroutine cannot
* be reentered.
*
* Note that a coroutine may also be implicitly terminated if the coroutine
* body is exited without a yield, e.g. by return, throw or by running to the
* end of the body.
*
* <b>fork <em>statement</em></b>
*
* The @c fork pseudo-keyword is used when "forking" a coroutine, i.e. splitting
* it into two (or more) copies. One use of @c fork is in a server, where a new
* coroutine is created to handle each client connection:
*
* @code reenter (this)
* {
* do
* {
* socket_.reset(new tcp::socket(my_context_));
* yield acceptor->async_accept(*socket_, *this);
* fork server(*this)();
* } while (is_parent());
* ... client-specific handling follows ...
* } @endcode
*
* The logical steps involved in a @c fork are:
*
* @li @c fork saves the current state of the coroutine.
* @li The statement creates a copy of the coroutine and either executes it
* immediately or schedules it for later execution.
* @li The resume point is defined immediately following the semicolon.
* @li For the "parent", control immediately continues from the next line.
*
* The functions is_parent() and is_child() can be used to differentiate
* between parent and child. You would use these functions to alter subsequent
* control flow.
*
* Note that @c fork doesn't do the actual forking by itself. It is the
* application's responsibility to create a clone of the coroutine and call it.
* The clone can be called immediately, as above, or scheduled for delayed
* execution using something like asio::post().
*
* @par Alternate macro names
*
* If preferred, an application can use macro names that follow a more typical
* naming convention, rather than the pseudo-keywords. These are:
*
* @li @c ASIO_CORO_REENTER instead of @c reenter
* @li @c ASIO_CORO_YIELD instead of @c yield
* @li @c ASIO_CORO_FORK instead of @c fork
*/
class coroutine
{
public:
/// Constructs a coroutine in its initial state.
coroutine() : value_(0) {}
/// Returns true if the coroutine is the child of a fork.
bool is_child() const { return value_ < 0; }
/// Returns true if the coroutine is the parent of a fork.
bool is_parent() const { return !is_child(); }
/// Returns true if the coroutine has reached its terminal state.
bool is_complete() const { return value_ == -1; }
private:
friend class detail::coroutine_ref;
int value_;
};
namespace detail {
class coroutine_ref
{
public:
coroutine_ref(coroutine& c) : value_(c.value_), modified_(false) {}
coroutine_ref(coroutine* c) : value_(c->value_), modified_(false) {}
~coroutine_ref() { if (!modified_) value_ = -1; }
operator int() const { return value_; }
int& operator=(int v) { modified_ = true; return value_ = v; }
private:
void operator=(const coroutine_ref&);
int& value_;
bool modified_;
};
} // namespace detail
} // namespace asio
#define ASIO_CORO_REENTER(c) \
switch (::asio::detail::coroutine_ref _coro_value = c) \
case -1: if (_coro_value) \
{ \
goto terminate_coroutine; \
terminate_coroutine: \
_coro_value = -1; \
goto bail_out_of_coroutine; \
bail_out_of_coroutine: \
break; \
} \
else /* fall-through */ case 0:
#define ASIO_CORO_YIELD_IMPL(n) \
for (_coro_value = (n);;) \
if (_coro_value == 0) \
{ \
case (n): ; \
break; \
} \
else \
switch (_coro_value ? 0 : 1) \
for (;;) \
/* fall-through */ case -1: if (_coro_value) \
goto terminate_coroutine; \
else for (;;) \
/* fall-through */ case 1: if (_coro_value) \
goto bail_out_of_coroutine; \
else /* fall-through */ case 0:
#define ASIO_CORO_FORK_IMPL(n) \
for (_coro_value = -(n);; _coro_value = (n)) \
if (_coro_value == (n)) \
{ \
case -(n): ; \
break; \
} \
else
#if defined(_MSC_VER)
# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__COUNTER__ + 1)
# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__COUNTER__ + 1)
#else // defined(_MSC_VER)
# define ASIO_CORO_YIELD ASIO_CORO_YIELD_IMPL(__LINE__)
# define ASIO_CORO_FORK ASIO_CORO_FORK_IMPL(__LINE__)
#endif // defined(_MSC_VER)
#endif // ASIO_COROUTINE_HPP

View File

@ -0,0 +1,38 @@
//
// deadline_timer.hpp
// ~~~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DEADLINE_TIMER_HPP
#define ASIO_DEADLINE_TIMER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_BOOST_DATE_TIME) \
|| defined(GENERATING_DOCUMENTATION)
#include "asio/detail/socket_types.hpp" // Must come before posix_time.
#include "asio/basic_deadline_timer.hpp"
#include <boost/date_time/posix_time/posix_time_types.hpp>
namespace asio {
/// Typedef for the typical usage of timer. Uses a UTC clock.
typedef basic_deadline_timer<boost::posix_time::ptime> deadline_timer;
} // namespace asio
#endif // defined(ASIO_HAS_BOOST_DATE_TIME)
// || defined(GENERATING_DOCUMENTATION)
#endif // ASIO_DEADLINE_TIMER_HPP

View File

@ -0,0 +1,200 @@
//
// defer.hpp
// ~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DEFER_HPP
#define ASIO_DEFER_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include "asio/async_result.hpp"
#include "asio/detail/type_traits.hpp"
#include "asio/execution_context.hpp"
#include "asio/execution/executor.hpp"
#include "asio/is_executor.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Submits a completion token or function object for execution.
/**
* This function submits an object for execution using the object's associated
* executor. The function object is queued for execution, and is never called
* from the current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns This function returns <tt>async_initiate<NullaryToken,
* void()>(Init{}, token)</tt>, where @c Init is a function object type defined
* as:
*
* @code class Init
* {
* public:
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex of type @c Ex by
* performing @code auto ex = get_associated_executor(handler); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
* @code auto alloc = get_associated_allocator(handler); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code execution::execute(
* prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)),
* std::forward<CompletionHandler>(completion_handler)); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(
* std::forward<CompletionHandler>(completion_handler),
* alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/
template <ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken>
ASIO_INITFN_AUTO_RESULT_TYPE(NullaryToken, void()) defer(
ASIO_MOVE_ARG(NullaryToken) token);
/// Submits a completion token or function object for execution.
/**
* This function submits an object for execution using the specified executor.
* The function object is queued for execution, and is never called from the
* current thread prior to returning from <tt>defer()</tt>.
*
* The use of @c defer(), rather than @ref post(), indicates the caller's
* preference that the executor defer the queueing of the function object. This
* may allow the executor to optimise queueing for cases when the function
* object represents a continuation of the current call context.
*
* @param ex The target executor.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns This function returns <tt>async_initiate<NullaryToken,
* void()>(Init{ex}, token)</tt>, where @c Init is a function object type
* defined as:
*
* @code class Init
* {
* public:
* using executor_type = Executor;
* explicit Init(const Executor& ex) : ex_(ex) {}
* executor_type get_executor() const noexcept { return ex_; }
* template <typename CompletionHandler>
* void operator()(CompletionHandler&& completion_handler) const;
* private:
* Executor ex_; // exposition only
* }; @endcode
*
* The function call operator of @c Init:
*
* @li Obtains the handler's associated executor object @c ex1 of type @c Ex1 by
* performing @code auto ex1 = get_associated_executor(handler, ex); @endcode
*
* @li Obtains the handler's associated allocator object @c alloc by performing
* @code auto alloc = get_associated_allocator(handler); @endcode
*
* @li If <tt>execution::is_executor<Ex1>::value</tt> is true, constructs a
* function object @c f with a member @c executor_ that is initialised with
* <tt>prefer(ex1, execution::outstanding_work.tracked)</tt>, a member @c
* handler_ that is a decay-copy of @c completion_handler, and a function call
* operator that performs:
* @code auto a = get_associated_allocator(handler_);
* execution::execute(
* prefer(executor_,
* execution::blocking.possibly,
* execution::allocator(a)),
* std::move(handler_)); @endcode
*
* @li If <tt>execution::is_executor<Ex1>::value</tt> is false, constructs a
* function object @c f with a member @c work_ that is initialised with
* <tt>make_work_guard(ex1)</tt>, a member @c handler_ that is a decay-copy of
* @c completion_handler, and a function call operator that performs:
* @code auto a = get_associated_allocator(handler_);
* work_.get_executor().dispatch(std::move(handler_), a);
* work_.reset(); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is true, performs
* @code execution::execute(
* prefer(
* require(ex, execution::blocking.never),
* execution::relationship.continuation,
* execution::allocator(alloc)),
* std::move(f)); @endcode
*
* @li If <tt>execution::is_executor<Ex>::value</tt> is false, performs
* @code ex.defer(std::move(f), alloc); @endcode
*
* @par Completion Signature
* @code void() @endcode
*/
template <typename Executor,
ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(Executor)>
ASIO_INITFN_AUTO_RESULT_TYPE(NullaryToken, void()) defer(
const Executor& ex,
ASIO_MOVE_ARG(NullaryToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(Executor),
typename constraint<
execution::is_executor<Executor>::value || is_executor<Executor>::value
>::type = 0);
/// Submits a completion token or function object for execution.
/**
* @param ctx An execution context, from which the target executor is obtained.
*
* @param token The @ref completion_token that will be used to produce a
* completion handler. The function signature of the completion handler must be:
* @code void handler(); @endcode
*
* @returns <tt>defer(ctx.get_executor(), forward<NullaryToken>(token))</tt>.
*
* @par Completion Signature
* @code void() @endcode
*/
template <typename ExecutionContext,
ASIO_COMPLETION_TOKEN_FOR(void()) NullaryToken
ASIO_DEFAULT_COMPLETION_TOKEN_TYPE(
typename ExecutionContext::executor_type)>
ASIO_INITFN_AUTO_RESULT_TYPE(NullaryToken, void()) defer(
ExecutionContext& ctx,
ASIO_MOVE_ARG(NullaryToken) token
ASIO_DEFAULT_COMPLETION_TOKEN(
typename ExecutionContext::executor_type),
typename constraint<is_convertible<
ExecutionContext&, execution_context&>::value>::type = 0);
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/defer.hpp"
#endif // ASIO_DEFER_HPP

View File

@ -0,0 +1,112 @@
//
// detached.hpp
// ~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETACHED_HPP
#define ASIO_DETACHED_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#include <memory>
#include "asio/detail/type_traits.hpp"
#include "asio/detail/push_options.hpp"
namespace asio {
/// Class used to specify that an asynchronous operation is detached.
/**
* The detached_t class is used to indicate that an asynchronous operation is
* detached. That is, there is no completion handler waiting for the
* operation's result. A detached_t object may be passed as a handler to an
* asynchronous operation, typically using the special value
* @c asio::detached. For example:
* @code my_socket.async_send(my_buffer, asio::detached);
* @endcode
*/
class detached_t
{
public:
/// Constructor.
ASIO_CONSTEXPR detached_t()
{
}
/// Adapts an executor to add the @c detached_t completion token as the
/// default.
template <typename InnerExecutor>
struct executor_with_default : InnerExecutor
{
/// Specify @c detached_t as the default completion token type.
typedef detached_t default_completion_token_type;
/// Construct the adapted executor from the inner executor type.
executor_with_default(const InnerExecutor& ex) ASIO_NOEXCEPT
: InnerExecutor(ex)
{
}
/// Convert the specified executor to the inner executor type, then use
/// that to construct the adapted executor.
template <typename OtherExecutor>
executor_with_default(const OtherExecutor& ex,
typename constraint<
is_convertible<OtherExecutor, InnerExecutor>::value
>::type = 0) ASIO_NOEXCEPT
: InnerExecutor(ex)
{
}
};
/// Type alias to adapt an I/O object to use @c detached_t as its
/// default completion token type.
#if defined(ASIO_HAS_ALIAS_TEMPLATES) \
|| defined(GENERATING_DOCUMENTATION)
template <typename T>
using as_default_on_t = typename T::template rebind_executor<
executor_with_default<typename T::executor_type> >::other;
#endif // defined(ASIO_HAS_ALIAS_TEMPLATES)
// || defined(GENERATING_DOCUMENTATION)
/// Function helper to adapt an I/O object to use @c detached_t as its
/// default completion token type.
template <typename T>
static typename decay<T>::type::template rebind_executor<
executor_with_default<typename decay<T>::type::executor_type>
>::other
as_default_on(ASIO_MOVE_ARG(T) object)
{
return typename decay<T>::type::template rebind_executor<
executor_with_default<typename decay<T>::type::executor_type>
>::other(ASIO_MOVE_CAST(T)(object));
}
};
/// A special value, similar to std::nothrow.
/**
* See the documentation for asio::detached_t for a usage example.
*/
#if defined(ASIO_HAS_CONSTEXPR) || defined(GENERATING_DOCUMENTATION)
constexpr detached_t detached;
#elif defined(ASIO_MSVC)
__declspec(selectany) detached_t detached;
#endif
} // namespace asio
#include "asio/detail/pop_options.hpp"
#include "asio/impl/detached.hpp"
#endif // ASIO_DETACHED_HPP

View File

@ -0,0 +1,38 @@
//
// detail/array.hpp
// ~~~~~~~~~~~~~~~~
//
// Copyright (c) 2003-2022 Christopher M. Kohlhoff (chris at kohlhoff dot com)
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#ifndef ASIO_DETAIL_ARRAY_HPP
#define ASIO_DETAIL_ARRAY_HPP
#if defined(_MSC_VER) && (_MSC_VER >= 1200)
# pragma once
#endif // defined(_MSC_VER) && (_MSC_VER >= 1200)
#include "asio/detail/config.hpp"
#if defined(ASIO_HAS_STD_ARRAY)
# include <array>
#else // defined(ASIO_HAS_STD_ARRAY)
# include <boost/array.hpp>
#endif // defined(ASIO_HAS_STD_ARRAY)
namespace asio {
namespace detail {
#if defined(ASIO_HAS_STD_ARRAY)
using std::array;
#else // defined(ASIO_HAS_STD_ARRAY)
using boost::array;
#endif // defined(ASIO_HAS_STD_ARRAY)
} // namespace detail
} // namespace asio
#endif // ASIO_DETAIL_ARRAY_HPP

Some files were not shown because too many files have changed in this diff Show More