c++-annotations-13.02.01/build0000775000175000017500000001017514735537670014701 0ustar frankfrank#!/usr/bin/icmake -t. // /tmp/cppannotations #define LOGENV "CPPANNOT" #include "VERSION" #include "INSTALL.im" #include "compilers.im" list g_log; string g_logPath = getenv(LOGENV)[1], g_logMark, // unique-marker for g_log entries g_cwd = chdir("."); // current WD, including trailing / int g_echo = ON; int g_installing; // set to 1 by install. int g_lognr; // unique-marker number counter for g_log entries #include "icmake/cuteoln" #include "icmake/backtick" #include "icmake/run" #include "icmake/mark" #include "icmake/md" #include "icmake/md5sum" #include "icmake/log" #include "icmake/logzipr" #include "icmake/logzip" #include "icmake/writelog" #include "icmake/findall" #include "icmake/loglink" #include "icmake/loginstall" #include "icmake/clean" #include "icmake/programs" #include "icmake/man" #include "icmake/docs" #include "icmake/latex" #include "icmake/pre" #include "icmake/install" #include "icmake/distclean" #include "icmake/zips" #include "icmake/examples" #include "icmake/verify" #include "icmake/gitlab" #include "icmake/readlog" #include "icmake/remove" #include "icmake/removedir" #include "icmake/uninstall" void main(int argc, list argv, list envp) { string option; if (argv[1] == "-q") { g_echo = OFF; argv -= (list)"-q"; } echo(g_echo); option = argv[1]; if (option == "clean") clean(1); if (option == "examples") examples(); if (option == "programs") { programs(0); programs(1); exit(0); } if (option == "distclean") distclean(); if (option == "pre") pre(); putenv("FORCE_SOURCE_DATE=1"); // to ensure reproducible builds putenv("SOURCE_DATE_EPOCH=0"); // for LaTeX documents if (option == "docs") docs(); if (option == "html") runhtml(); if (option == "latex") latex(); if (option == "ps") runps(); if (option == "txt") runtxt(); if (option == "verify") verify(); if (option == "zips") zips(); if (option == "man") { man(); exit(0); } if (option == "gitlab") gitlab(); if (option == "uninstall") uninstall(); if (option == "install") install(argv[2]); printf("Usage: build [-q] what\n" "Where\n" " [-q]: run quietly, do not show executed commands\n" "`what' is one of:\n" " clean - clean up remnants of previous compilations\n" " distclean - clean remnants of locally run ./bin/ scripts\n" "\n" " docs - construct the C++ Annotations\n" " Run 'build programs' and 'build pre' at least\n" " once before 'build docs'\n" "\n" " examples - compile all examples\n" " install [base] - install the C++ Annotations in the locations\n" " defined in the INSTALL.im file, optionally\n" " below 'base'\n" " html - force the html construction\n" " latex - force the latex construction, (cf 'verify')\n" " man - build the manual page (requires Yodl)\n" " pre - prepare files for independent `docs' call\n" " ps - create .ps/.pdf files afer 'build latex'\n" " programs - build support programs\n" " txt - force the txt construction\n" " verify - run after `build docs' to find overfull boxes\n" " or undefined references in\n" " tmp/docs/latex/cplusplus.log\n" " zips - zip archives (after doc)\n" " uninstall - remove installed files and empty directories\n" " gitlab - prepare gitlab's gh-pages / zips update\n" " (internal use only. The update script also\n" " installs the zips at git/annotations-zip)\n" "\n" ); exit(1); } c++-annotations-13.02.01/changelog0000664000175000017500000007235214771457136015531 0ustar frankfrankC++-annotations (13.02.01) * The Modules chapter was rewritten. * Added a section about classes derived from streambuf used by std::iostream objects. * Repaired typos. * Note: version 13.02.00 wasn't tagged. -- Frank B. Brokken Fri, 28 Mar 2025 09:31:17 +0100 C++-annotations (13.01.02) * Repaired a typo + cosmetics (13.01.01 not tagged) -- Frank B. Brokken Thu, 02 Jan 2025 12:59:22 +0100 C++-annotations (13.01.00) * Section 4.3 (std::filesystem namespace) was reorganized, section 12.3 (Allocators) was removed since allocators were removed from C++ in the C++-20 standard. Added missing examples in stl sharedarrays (18.4.6). -- Frank B. Brokken Wed, 01 Jan 2025 10:49:48 +0100 C++-annotations (13.0.1) * Repaired an error in stl/examples/classtypeplus.cc. * A stronger typesetting is used for the font used for code in the pdf documents. -- Frank B. Brokken Fri, 11 Oct 2024 14:30:10 +0200 C++-annotations (13.0.0) * New major version adds a new chapter about modules, covers name-independent declarations, and upgrades the C++ standard to c++26. -- Frank B. Brokken Tue, 20 Aug 2024 20:45:25 +0200 C++-annotations (12.5.0) * Added a subsection about constructors of polymorphic classes. * Added a section about using std::streambuf in an std::iostream class. * Various cosmetics and typo corrections. -- Frank B. Brokken Sun, 26 May 2024 16:37:53 +0200 C++-annotations (12.4.0) * Added the multi-index index operator, available since c++-23. * Covered std::byte and an alternative implementation. * Updated the description of how to implement class constructors that may throw exceptions. * Typo corrections. -- Frank B. Brokken Tue, 15 Aug 2023 09:39:01 -0700 C++-annotations (12.3.1) * Due to a small oversight, Debian needed a new source archive, hence the minor subversion upgrade. -- Frank B. Brokken Fri, 28 Apr 2023 19:18:19 +0200 C++-annotations (12.3.0) * removed section 'Returning types nested under class templates' (advancedtemplates/returnnested), sf since C++20 * updated the Generic Algorithm chapter: merged the descriptions of very similar algorithms (like 'copy' and 'copy_if'), added the descriptions of several new algorithms, added a section about execution policies and updated the descriptions of generic algorithms supporting execution policies. Added a new section about handling raw memory. * the memory chapter's section about 'placement new' contains a forward link to the STL section about initializing raw memory. * repaired typos * during the 2022-2023 Academic Year many typo reports and suggestions for updating sections were submitted by the C++ course participants Jeroen Lammersma (jeroen at lammersma dot dev) and Channa Dias Perera (cdiasperera at gmail dot com): thanks, gentlemen, for your valuable contributions! -- Frank B. Brokken Fri, 28 Apr 2023 11:42:22 +0200 C++-annotations (12.2.0) * Added new section covering 'std::string_view'. * Added new section covering 'std::osyncstream'. * Added sections covering 'bound friends'. * 'std::iterator' is deprecated: the section about constructing iterators was rewritten. * 'operator[]() const' should return 'Type const &': its section was adapted accordingly. * 'using' declarations are now preferred over 'typedef' definitions: 'typedef' definitions were replaced by 'using' declarations. * Repaired series of typos. -- Frank B. Brokken Sat, 05 Mar 2022 10:42:56 +0100 C++-annotations (12.1.0) * Added __file_clock::to_sys. * Repaired the descriptions of pop*() members of various abstract containers. * Reorganized the description of the facilities of the filesystem::path class. * Repaired series of typos. -- Frank B. Brokken Sun, 20 Feb 2022 12:20:13 +0100 C++-annotations (12.0.0) * Added a new chapter about coroutines. * throw(typelist) specifications were removed from the language, and the section covering throw(typelist) was removed from the C++ Annotations. * Added a new section to the multi-threading chapter about jthreads * Repaired an error in the US-letter formatted pdf document -- Frank B. Brokken Sat, 25 Dec 2021 15:04:32 +0100 C++-annotations (11.6.0) * Added stl/optional.yo covering std::optional * Added generic/iota.yo covering std::iota * The multi-threading chapter covers threads running member functions -- Frank B. Brokken Thu, 24 Jun 2021 10:11:25 +0200 C++-annotations (11.5.0) * Added stl/tie.yo about std::tie * Repaired several typos and added missing code examples. -- Frank B. Brokken Fri, 20 Nov 2020 21:07:49 +0100 C++-annotations (11.4.1) * Updated the descriptions of some functions in the filesystem namespace. * Fixed some typos * Following a fix suggested by Tony Mancill the US variants of the ps/pdf formats of the C++-annotations are now using the 'letter' paper format -- Frank B. Brokken Sun, 30 Aug 2020 13:36:27 +0200 C++-annotations (11.4.0) * Attributes covered in the 'Intro' chapter were moved to the 'Attributes' section in the 'First Impression' chapter. * The section about Concepts (23.13) received a complete overhaul. * Added FORCE_SOURCE_DATE=1 and SOURCE_DATE_EPOCH=0 to latex runs resulting in identical .dvi and .ps documents as long as the content of the source documents remains unchanged. -- Frank B. Brokken Wed, 04 Mar 2020 11:47:30 +0100 C++-annotations (11.3.0) * Added sections covering the three-way comparison operator (<=>) and various predefined comparison classes. * A link to the Annotations's index is provided in the pdf-version of the Annotations (it was already provided in the html version) * replaced string() constructions by string{} constructions -- Frank B. Brokken Mon, 16 Dec 2019 11:31:20 +0100 C++-annotations (11.2.1) * Just one day after 11.2.0 Jurjen Bokma noted an annoying flaw in the description of the move constructor (section ref(MOVECONS)). Enough reason to fix that in this release. * In addition the description of the copy constructor's characteristics now mentions that the CC should shed excess capacity. -- Frank B. Brokken Tue, 19 Nov 2019 21:09:07 +0100 C++-annotations (11.2.0) * The std::filesystem namespace coverage received an overhaul and is moved to the Namespaces chapter * The std::chrono namespace coverage received an overhaul and is moved to the Namespaces chapter * The sections covering error_code, error_category and error_condition were rewritten. They are now covered in the chapters Namespaces, Exceptions, and Advanced Templates chapter. * Added the (internal use) program src/verb compacting verb-macros. * Fixed typos and inconsistencies. -- Frank B. Brokken Mon, 18 Nov 2019 13:29:31 +0100 C++-annotations (11.1.1) * Clarified the use of lower_bound and upper_bound. * The introductory section of Nested Classes was updated * Typo corrections -- Frank B. Brokken Fri, 17 May 2019 14:39:09 +0200 C++-annotations (11.1.0) * Rewrote major parts of the sections covering concepts -- Frank B. Brokken Sat, 09 Feb 2019 10:46:52 +0100 C++-annotations (11.0.0) * New major version covers concepts, modules, and transactional memory * Several sections were rewritten: unrestricted unions, lambda expressions, the std::filesystem namespace, structured binding declarations -- Frank B. Brokken Sun, 02 Dec 2018 16:33:07 +0100 C++-annotations (10.9.3) * Migrated from Github to Gitlab * WIP adding elements of the upcoming c++2a standard. -- Frank B. Brokken Mon, 25 Jun 2018 12:48:37 +0200 C++-annotations (10.9.2) * Modified src/trim so that it can be used as stand-alone program. * Version and year information are now in the file VERSION: build programs updates the file yo/version.yo accordingly. -- Frank B. Brokken Thu, 18 Jan 2018 13:16:24 +0100 C++-annotations (10.9.1) * Various typos were corrected * Removed the nbsp() macro from preamble.yo -- Frank B. Brokken Thu, 18 Jan 2018 08:34:39 +0100 C++-annotations (10.9.0) * Added extensive coverage of system_error (chapters Exception, and Advanced Templates). * Covered the namespace std::(experimental::)filesystem * Added the constructor expecting an initializer-list to the std::string chapter (chapter 5). * Explicit references to the C++17 standard were removed. -- Frank B. Brokken Mon, 04 Dec 2017 17:22:06 +0100 C++-annotations (10.8.1) * Fixed additional typos uncovered by Amazon. -- Frank B. Brokken Thu, 08 Jun 2017 12:32:50 +0200 C++-annotations (10.8.0) * Added a new section (Introduction: upcoming C++17 features) providing an overview of new language features introduced by the C++17 standard * Many typos and suboptimally formulated statements were fixed, many of them very thoroughly compiled by Maurits Silvis. * Coverage of (considered obsolete) binders and negators was discontinued. * Internally, the previously used script scripts/patchlatexidx is no longer required. -- Frank B. Brokken Thu, 08 Jun 2017 09:04:27 +0200 C++-annotations (10.7.2) * The section about implementing binary operators was fundamentally rewritten thanks to suggestions offered by Wiebe-Marten Wijnja. * The section covering the ::template syntax received an example showing how to call a static member function defined in a (base) class template from a class template that is derived from that (base) class template. -- Frank B. Brokken Sun, 12 Feb 2017 14:22:58 +0100 C++-annotations (10.7.1) * The section about implementing binary operators could somewhat be simplified. Also, some additional clarifications were added. * The SFINAE section was provided with explicit links to sections where the sfinae principle is used. -- Frank B. Brokken Sat, 04 Feb 2017 11:34:26 +0100 C++-annotations (10.7.0) * The sections about implementing binary operators received an overhaul. * The section `Adding binary operators to classes' was rewritten. * Added descriptions of operator new[](size) and operator delete[](pointer). * The section about lambda-expressions was extended with descriptions of new features offered by C++17. * The section `Pointer sizes' in the chapter about pointers to members contains an explanation as to why pointers to members are larger than ordinary pointers. * Added preview intro/cpp17.yo on the next C++17 standard. * Added a section about selection statements with initializers to the `First Impression Of C++' chapter. * Added a paragraph about increment/decrement operators being deprecated for bool type of variables to overloading/increment.yo. * Added a section about std::exchange to the Generic Algorithms chapter. * Added a section about `if constexpr' to the Function Templates chapter. * Added a section about folding expressions to the Class Templates chapter. * Added a section about class templates template argument deduction. * The section about using non-default constructors now contains thread-safe examples. * Fixed several typos, processed several suggestions received from readers. -- Frank B. Brokken Sat, 28 Jan 2017 13:05:50 +0100 C++-annotations (10.6.0) * Added new section (Lvalues, rvalues and more, first/lvalues.yo) about various kinds of l/rvalues distinguished by C++. * Added new section (Standard Exceptions: to use or not to use?, exceptions/usestandard.yo) about the distinction between standard and non-standard exceptions. * Section 'Allocating arrays' (in chapter 'Classes and Memory Allocation') now describes how to initialize memory using the 'new Type[size]()' syntax. * Section 'explicit conversion operators' (in chapter 'More Operator Overloading) received an overhaul. * Changed uses of shared_ptr objects to unique_ptr objects in stl/uniqueptr.yo. -- Frank B. Brokken Sun, 30 Oct 2016 10:25:03 +0100 C++-annotations (10.5.1) * Fixed various typos and completed several cosmetic modifications -- Frank B. Brokken Sun, 24 Jul 2016 07:41:38 +0200 C++-annotations (10.5.0) * Rewrote the section about converting time to text, covering std::localtime, std::gmtime, std::put_time as well as the full table of put_time's format specifiers. * Removed the sections at the beginning of each chapter encouraging readers to send in suggestions for improvements. Instead, this encouragement is now shown at the end of the Annotation's `abstract'. * Updated the kindle-book conversion script, so that cplusplus.css is not used with the kindle book construction. * Several typos were fixed. -- Frank B. Brokken Wed, 23 Dec 2015 13:09:08 +0100 C++-annotations (10.4.1-pre) * Improved the html layout, following suggestions by Harmen Stoppels * Removed repeated 'mailus' files from chapter openings. The 'mailus' info is now shown as part of the abstract. -- Frank B. Brokken Sat, 19 Dec 2015 22:19:18 +0100 C++-annotations (10.4.0) * Added a section about reference bindings to the Overloading chapter * Added cplusplus.css which can be used to fine-tune the layout of the Annotatiions' html conversion. * Standardized the installation procedure * Fixed typos -- Frank B. Brokken Sun, 11 Dec 2015 17:12:31 +0100 C++-annotations (10.3.0) * Added new sections about expression templates, about attributes, about shared mutexes, about shared locks, about heterogeneous lookups, about sized deallocation functions, and about moving and swapping streams * Added new C++14 elements to relevant sections * Reorganized the section about lambda expression * Added the file ./compiler.im providing all #defines for compiling the support programs. See that file for specific information. * Fixed a compilation problem encountered with g++-5. * Fixed some typos. -- Frank B. Brokken Sun, 16 Aug 2015 15:21:10 +0200 C++-annotations (10.2.0) * Rewrote the sections covering the regular expression matching classes. * The section about lambda expression also covers generic lambda expressions. * The coverage of binders now concentrates on stl::bind. * Added a section about stl::placeholders to chapter 4 (Namespaces) * Removed superfluous 'return 0;' statements from main functions. * Conversion related stamp files (e.g., html-stamp) no longer used. Build-commands are now unconditionally executed. * Added a section to class templates covering a bare bones implementation of not_fn, which will likely be added in C++17. * Added some notes about C++17. * Several cosmetic improvements were made. * Html files now use html5. -- Frank B. Brokken Thu, 28 May 2015 12:06:01 +0200 C++-annotations (10.1.0) * Typos and added a section about regular expression, moving the topic from containers to stl. * Fixed various typos and inconsistencies -- Frank B. Brokken Wed, 24 Dec 2014 19:54:28 +0100 C++-annotations (10.0.0) * Added new chapter: Multi Threading, containing all previously defined sections related to multi threading. A paragraph about std::distance was added, some typos were repaired, and other cosmetic changes were made to this version. * Redefined the standard verb(...) yodl macro by a version which does not do the extra newlines before and after the verbatim section. * The build script was extended. The support script `pathbuild' is not used, but can be used in cases where an additional element to PATH must be used. * All verbatim file inclusions are now run through the new release of yodlverbinsert. -- Frank B. Brokken Thu, 30 Oct 2014 20:17:12 +0100 C++-annotations (9.9.1) * Fixed LaTex formatting problems rendering (in particular) the cplusplusus.ps/pdf files (note: cplusplusUS) less useful (cf. scythal's user review on http://sourceforge.net/projects/cppannotations/). -- Frank B. Brokken Thu, 05 Jun 2014 14:16:31 +0200 C++-annotations (9.9.0) * STL facilities for specifying absolute and relative time were rewritten and are now in a separate section, instead of using subsections of the section about Multi Threading. Sections about condition_variables were also rewritten. * c++0x has been replaced by c++11 -- Frank B. Brokken Tue, 03 Jun 2014 13:24:54 +0200 C++-annotations (9.8.2) * Extended and completed the list of available type traits (in section `Available Type Traits', chapter `Advanced Templates') -- Frank B. Brokken Fri, 07 Mar 2014 14:49:22 +0100 C++-annotations (9.8.1) * Added explanatory paragraphs about using static_casts to derived classes using shared_ptr or unique_ptr objects holding pointers to base classes (cf. the class 'unique_ptr' and Casting shared pointers) * Added explanatory paragraphs about defining (const_)iterators and (const_)reverse_iterators (cf. 21.14.2: Implementing a `reverse_iterator'). * Added an example showing how to declare a bound friend function template to a class template (cf. Templates instantiated for specific types as friends) C++-annotations (9.8.0) * Added a section about static polymorphism to the class templates chapter * Removed the `text to anything convertor' section, which is now obsoleted by existing std::string conversion functions. * Removed the C++11 labels from section headers, as the C++11 standard has been implemented by g++ 4.8.2. Note that the --std=c++11 compiler flag is still required. * Several typos were fixed -- Frank B. Brokken Sat, 18 Jan 2014 13:55:37 +0100 C++-annotations (9.7.3) * Fixed several typos. -- Frank B. Brokken Wed, 21 Aug 2013 15:00:30 +0200 C++-annotations (9.7.2) * Repaired some minor flaws, which were still waiting to be processed. * Added for internal use steps to create a Kindle version of the Annotations (see also http://www.amazon.com, look for ('c++ annotations') -- Frank B. Brokken Thu, 30 May 2013 12:45:58 +0200 C++-annotations (9.7.1) * Added changes of 9.7.0 to the Annotations' `what's new' section * Release 9.7.0 was not published as a separate release. -- Frank B. Brokken Thu, 30 May 2013 09:43:34 +0200 C++-annotations (9.7.0) * Added several new sections about time specification (stl/time, etc.) * Added new section about 'this_thread' (stl/thisthread) * Added new section about locks (stl/locks) * Added new section (classes/ambiguity) about Ambiguity Resolution. * Added new section 'system_error' (exception/systemerror) * Added new section 'the class `error category'' (exception/errorcategory) * Added new section 'the class `error code'' (exception/errorcode) * Rewrote all sections about multi-threading) * Rewrote the section about lambda expressions * Replaced references to `ascii-z string' by `null terminated byte string' (NTBS), following the C++11 standard's terminology. * Repaired flaws in function names and return tyes of several sto* functions in string/convertors.yo * `0b' constants are not mentioned in the C++11 standard (but maybe compiler supported) * In section references `C++11, 4.7' the `, 4.7' was dropped * intro/main.yo was updated -- Frank B. Brokken Wed, 29 May 2013 20:11:20 +0200 C++-annotations (9.6.0) * Updated the list of C++ keywords * Added advancedtemplates/noexcept.yo covering the noexcept keyword * Updated the string chapter -- Frank B. Brokken Thu, 10 Jan 2013 20:23:05 +0100 C++-annotations (9.5.0) * Updated (to the current C++11 state) the reference of member functions of the Abstract Containers. * Added a new section (Allocators) just before introducing the sequential containers. * Rephrased sentenses like 'this member s' to 's', in particular in the chapter on Abstract Containers. * Repaired typos, reformulated the section about nested namespaces (Meir Shani). -- Frank B. Brokken Fri, 14 Dec 2012 12:53:53 +0100 C++-annotations (9.4.0) * Added new section make_shared in the stl chapter. -- Frank B. Brokken Thu, 28 Jun 2012 20:48:47 +0200 C++-annotations (9.3.0) * Coverage of the static_cast and reinterpret_cast was refined, following a suggestion provided by Gido Schoenmacker. -- Frank B. Brokken Tue, 06 Mar 2012 20:34:11 +0100 C++-annotations (9.2.1) * Starting this release all release tags (using names that are identical to the version number, so for this release the tag is 9.2.1) are signed to allow authentication. -- Frank B. Brokken Mon, 27 Feb 2012 13:42:38 +0100 9.2.0 * Converted scanner generations from flex to flexc++ * Rewrote the Concrete chapter's section about polymorphic semantic values * Rewrote the Containers chapter's section about unrestricted unions * Removed the Concrete chapter's section about unrestricted union semantic values -- Frank B. Brokken Sun, 26 Feb 2012 17:10:55 +0100 9.1.0 * Added sections about features of C++11 now implemented in g++-4.7 * Added a script to create a beautiful C++ bound book * Repaired typos and stuff -- Frank B. Brokken Fri, 20 Jan 2012 11:50:01 +0100 9.0.2 * Removed excessive use of the verb 'will' from the Annotations. * The required operators for each of the standard iterators (input, output, forward, bidirectional, random_access) are now explicitly mentioned in the paragraphs covering them. -- Frank B. Brokken Mon, 12 Sep 2011 16:01:07 +0200 9.0.1 * Repaired some new annoying typos and slightly rephrased some paragraphs of the `Koenig lookup' section. -- Frank B. Brokken Wed, 20 Jul 2011 12:21:33 +0200 9.0.0 * The form of move special members (move constructors, move assignment operators, other functions defining rvalue type parameters) was synchronized with the form proposed by the C++0x standard. This resulted, in the Annotations relaxing the principle of const-correctness, and in modifying the declarations and implementations of move special members in this release. This shift in position (adopted by the Annotations since its very early releases) profoundly affects much of the Annotation's contents, and warrants an upgrade to the next major release. See the remarks in the `what's new' file for more details. * Several sections were added and sometimes moved. The section about 'unrestricted unions' was completed and moved to the `Containers' chapter, and an new section about adding binary operators to classes using function templates was added to the Annotations' final chapter (concrete examples). * Repaired badly formatted LaTeX table of contents: see bin/latexonly * Many typos were repaired 8.3.1 * Many typos, textual corrections and clarifications were processed, almost all were provided by Francesco Poli. * Sections about move operations were split into subsections * The Portuguese translations are lagging too much behind. I've removed them from the source archives, although they remain available at the svn repository. -- Frank B. Brokken Mon, 20 Dec 2010 15:25:30 +0100 8.3.0 * New sections about various (member) function adaptors * Sections about statistical sampling functions added/modified * Sections referring to C++0x elements now assume g++ 4.4 is available and the required compiler version is no longer listed for those sections * Typos repaired -- Frank B. Brokken Tue, 07 Sep 2010 12:12:18 +0200 8.2.0 * Bumped up the version. Should have been done earlier, considering that the 'what's new' file already refers to version 8.2.0. * Added 'export' to the list of keywords * New typos and unclear passages were processed/improved * KNOWN ISSUE WITH THE PDF VERSION: Due to a known bug in the ps2pdf conversion the pdf versions of the Annotations may show multiple Error: Illegal entry in bfrange block in ToUnicode CMap error messages. Once the bug has been repaired a new sub-minor release of the Annotations will be made available. -- Frank B. Brokken Thu, 26 Aug 2010 09:03:37 +0200 8.1.2 * New typos and unclear passages were processed/improved -- Frank B. Brokken Thu, 06 May 2010 19:39:46 +0200 8.1.1 * Many typos and minor cosmetic flaws that had escaped the previous update were processed -- Frank B. Brokken Thu, 11 Mar 2010 21:00:43 +0100 8.1.0 * The text and examples of the Annotations have completely been overhauled. Before this final 8.1.0 release two pre-releases were issued, partially completing the overhaul (see the two entries below) Over the years many inconsistencies had crept into the text and examples, that are now removed; streamlining the text and the examples. All of the code examples have received a work-over, removing endl in favor of '\n', making virtual functions private, etc., etc. Many sections labeled C++0x were improved and sections in the table of contents showing C++0x now also mention the g++ version in which the new feature will be made available, using `?' if this is as yet unknown. No version is shown if the feature is already available in g++ 4.3 (or in one of its subreleases, like 4.3.3). I received a host of suggestions from Francesco Poli (thanks, Francesco (and several others), for all the effort you've put into sending me those corrections). -- Frank B. Brokken Mon, 01 Mar 2010 09:11:21 +0100 8.1.0~pre2 * Cleanup completed until (including) chapter 16 -- Frank B. Brokken Thu, 24 Dec 2009 11:36:44 +0100 8.1.0~pre1 * Removed the 'template concepts' section from advancedtemplates: removed from the C++0x standard. * Started a cleanup operation on the C++ Annotations aiming at improving its internal consistency in examples and text. In this version completed until (including) chapter 8. -- Frank B. Brokken Thu, 05 Nov 2009 21:08:10 +0100 8.0.1 - Added --std=c++0x to the g++ compiler options 8.0.0 - New sections added describing elements of the new C++0x standard New chapters: name spaces, generic algorithm. The Portuguese translation of the Annotations (in the contributions directory) are still at version 7.0.0., Sergio Bacchi wrote that a new version is currently under construction. 7.3.1 - Readers are referred to sourceforge for the C++ Annotations archives 7.2.2 - Textual modifications and minor modifications of the programs due to new Bobcat library. 7.0.1 - Processed extensive feedback received from Eric S. Raymond and Edward Welbourne. Reorganized yo/string/members.yo. See the yo/history.yo file for details. 7.0.0 - Added new chapter (advanced template applications) and changed many other things. See the yo/history.yo file for details. 6.5.0 - Changed all unsigned types to size_t (where appropriate) Added the Portuguese translation to the distribution, since Sergio Bacchi's acceptance was received Repaired various minor problems in compiling/running examples Moved in-class definitions of member functions to below their class Added paragraphs about size_t and other derived int-types and about implementing pure virtual member functions 6.4.1 - Legal restriction leftover removed from Chapter 2's introduction. Portuguese translation and `The history of C' removed from the distribution, until formal permission to include them is received from their authors. Changes down to 6.2.4: see yo/history.yo -- Frank B. Brokken Tue, 19 Sep 2006 13:03:29 +0200 6.2.4f - fixed basic-type counting in par. 3.3 -- Frank B. Brokken Thu, 07 Sep 2006 14:04:27 +0200 6.2.4 - See yo/history.yo 6.2.2 - See yo/history.yo 6.2.0 - See yo/history.yo 6.1.3(-pre) Repaired several textual imperfections and delete -> delete [] where new [] was used. 6.1.2. This file was defined to summarize intermediate modifications. - description of ios condition flags refined - description of string::getline() refined. - open_mode `creat' changed into `trunc' (reading and writing streams) 6.1.1b Minor textual modifications since 6.1.0 c++-annotations-13.02.01/compilers.im0000664000175000017500000000205314735537670016174 0ustar frankfrank// This file was added shortly before the Gnu C and C++ release 5 of the // compilers became available. A new version of the compilers can simply be // tested by specifying the new compilers' version at CVERSION // // To check the software using the 5-version of the bobcat library that // library can be made available in a separate directory (e.g., // ISN // /usr/lib/bobcat-5) and an /etc/ld.so.conf.d/bobcat-5.conf file can be // ISN // prepared specifying /usr/lib/bobcat-5. That directory should then have the // ISN // libbobcat-5.so* library and links, and after `ldconfig -v' the linker will // ISN // detect the proper library. #define CVERSION "" //#define CVERSION "-5" // the used compilers #define GPP "g++" ${CVERSION} #define GCC "gcc" ${CVERSION} // options to be used by the compilers #define COPT "-Wall -O2 -fdiagnostics-color=never -g" #define CPPOPT "-Wall -O2 -fdiagnostics-color=never -g" // extra library for the C++ programs #define BOBCAT "bobcat" //#define LPATH "/lib" #define LPATH "/tmp/bobcat" c++-annotations-13.02.01/contrib/0000775000175000017500000000000014735537670015310 5ustar frankfrankc++-annotations-13.02.01/contrib/concrete/0000775000175000017500000000000014735537670017112 5ustar frankfrankc++-annotations-13.02.01/contrib/concrete/refcountautoptr.h0000664000175000017500000001172314735537670022533 0ustar frankfrank#ifndef INCLUDED_REFCOUNTAUTOPTR_H_ #define INCLUDED_REFCOUNTAUTOPTR_H_ #include // Implementation of auto_ptr using reference counting. // This implementation was provided and offered for inclusion in the // C++ Annotations by Jesse van den Kieboom (jesse at icecrew.nl). template class auto_ptr { class auto_ptr_data { Type *d_ptr; size_t d_refcount; public: typedef Type element_type; auto_ptr_data(element_type *ptr = 0); ~auto_ptr_data(); element_type *get() const; // Refcounting size_t refcount() const; auto_ptr_data *ref(); bool unref(); element_type *release(); private: auto_ptr_data(auto_ptr_data const &other); // NI void destroy(); }; auto_ptr_data *d_data; public: /// The pointed-to type. typedef Type element_type; explicit auto_ptr(element_type *ptr = 0); auto_ptr(auto_ptr const &other); ~auto_ptr(); // Assignment operator auto_ptr &operator=(auto_ptr &other); // Dereference operators element_type &operator*() const; element_type *operator->() const; // Get and release element_type *get() const; element_type *release(); void reset(element_type *ptr = 0); private: void destroy(); }; /// auto_ptr_data template auto_ptr::auto_ptr_data::auto_ptr_data(element_type *ptr) : d_ptr(ptr), d_refcount(!ptr ? 0 : 1) { } template auto_ptr::auto_ptr_data::~auto_ptr_data() { // Destroy our pointer if (d_refcount) destroy(); } template inline size_t auto_ptr::auto_ptr_data::refcount() const { return d_refcount; } template inline Type *auto_ptr::auto_ptr_data::get() const { return d_ptr; } template Type *auto_ptr::auto_ptr_data::release() { // This function releases the pointer so it's no longer // maintained by this object. if (!d_refcount) return 0; --d_refcount; Type *tmp = d_ptr; d_ptr = 0; return tmp; } // Refcounting template typename auto_ptr::auto_ptr_data *auto_ptr::auto_ptr_data::ref() { if (d_ptr) ++d_refcount; return this; } template bool auto_ptr::auto_ptr_data::unref() { if (!d_refcount) return false; --d_refcount; if (!d_refcount) destroy(); return d_refcount != 0; } template void auto_ptr::auto_ptr_data::destroy() { delete d_ptr; d_ptr = 0; } /// auto_ptr template inline auto_ptr::auto_ptr(element_type *ptr) { d_data = new auto_ptr_data(ptr); } template inline auto_ptr::auto_ptr(auto_ptr const &other) : d_data(other.d_data->ref()) {} template inline auto_ptr::~auto_ptr() { destroy(); } template auto_ptr &auto_ptr::operator=(auto_ptr &other) { if (&other != this) { destroy(); d_data = other.d_data->ref(); } return *this; } template inline Type &auto_ptr::operator*() const { return *d_data->get(); } template inline Type *auto_ptr::operator->() const { return d_data->get(); } template inline Type *auto_ptr::get() const { return d_data->get(); } // Warning: when releasing a refcounting auto pointer the data // itself is released and no longer maintained by any of the // auto pointers. All these auto pointers will now return 0. // It's your responsibility to handle this properly (and to // free the released pointer of course) template Type *auto_ptr::release() { Type *ptr = d_data->release(); return ptr; } template void auto_ptr::reset(Type *ptr) { // Prevent creating a wild pointer by resetting if (ptr == d_data->get()) return; // Unref current data destroy(); // Set new data d_data = new auto_ptr_data(ptr); } template void auto_ptr::destroy() { if (!d_data->unref()) delete d_data; } #endif c++-annotations-13.02.01/contrib/classtemplates/0000775000175000017500000000000014735537670020334 5ustar frankfrankc++-annotations-13.02.01/contrib/classtemplates/cloneable.h0000664000175000017500000001022014735537670022424 0ustar frankfrank/* Cloneable template class protects a derived object from slicing when used with stl containers Author: Jesse van den Kieboom Jesse provides the following example based on his class template Cloneable: vector > vec; vec.push_back(B()); vec.push_back(B()); Cloneable a = B(); a->(functie op A/B) Cloneable b = B(); a = b; */ #ifndef __CLONEABLE_H__ #define __CLONEABLE_H__ namespace jessevdk { template class Cloneable { Base *d_base; public: /* Default constructor */ Cloneable(); template Cloneable(Cloneable const &other); /* Specialisation needed to override default copy constructor */ Cloneable(Cloneable const &other); template Cloneable(Other const &other); /* Deconstructor */ virtual ~Cloneable(); /* Public functions */ template Cloneable &operator=(Cloneable const &other); /* Specialisation needed to override default assignment operator */ Cloneable &operator=(Cloneable const &other); template Cloneable &operator=(Other const &other); /* Operators */ Base &operator*(); Base const &operator*() const; Base *operator->(); Base const *operator->() const; operator Base&(); private: /* Private functions */ void destroy(); template Cloneable &assign(Other const &other); }; /* Constructors */ template inline Cloneable::Cloneable() { d_base = new Base(); } template template inline Cloneable::Cloneable(Other const &other) { /* Clone other */ d_base = other.clone(); } template inline Cloneable::Cloneable(Cloneable const &other) { /* Clone other from cloneable */ d_base = other->clone(); } template template inline Cloneable::Cloneable(Cloneable const &other) { /* Clone other from cloneable */ d_base = other->clone(); } /* Destructor */ template inline Cloneable::~Cloneable() { destroy(); } template template Cloneable& Cloneable::assign(Other const &other) { /* Assign other to this cloneable with self-destroy check */ if (d_base != &other) { destroy(); d_base = other.clone(); } return *this; } template Cloneable& Cloneable::operator=(Cloneable const &other) { return assign(*other); } template template Cloneable& Cloneable::operator=(Cloneable const &other) { return assign(*other); } template template Cloneable& Cloneable::operator=(Other const &other) { return assign(other); } template inline void Cloneable::destroy() { delete d_base; } /* Operators */ template inline Base &Cloneable::operator*() { return *d_base; } template inline Base *Cloneable::operator->() { return d_base; } template inline Base const &Cloneable::operator*() const { return *d_base; } template inline Base const *Cloneable::operator->() const { return d_base; } template inline Cloneable::operator Base&() { return *d_base; } } #endif /* __CLONEABLE_H__ */ c++-annotations-13.02.01/contributions/0000775000175000017500000000000014735537670016552 5ustar frankfrankc++-annotations-13.02.01/contributions/FAQ0000664000175000017500000000217014735537670017104 0ustar frankfrank1. Too many consts? -------------------------------------------------------------------------- 1. Too many consts? > int compareWrapper(void const *p1, void const *p2) > { > return > Person::compare > ( > static_cast(p1), > static_cast(p2) > ); > } > Isn't it const *const * one const * too much? To answer your question: well, you could omit one const, but it blurrs the intention. Person::compare's prototype is int Person::compare(Person const *const *p1, Person const *const *p2); which mentions two consts: the parameters are pointers to pointers should not be modified nor should be modified what these latter pointers point to. Hence two consts in the static cast. The last const matches the const in void const *, and the first const matches the intention of Person::compare's function. Leave out the last const and the compiler complains, leave out the first const and the compiler will pass a non-const pointer to a const * parameter, which by itself is OK, but blurrs your intention. c++-annotations-13.02.01/contributions/porter.scobey0000664000175000017500000001174014735537670021276 0ustar frankfrankFrom porter.scobey@SMU.CA Sun Sep 17 16:54:15 2006 Received: from smtp1.rug.nl (smtp1.rug.nl [129.125.50.11]) by suffix.rc.rug.nl (8.13.7/8.13.7/Debian-2) with SMTP id k8HEsFqe020630 for ; Sun, 17 Sep 2006 16:54:15 +0200 Received: from smtp1.rug.nl ([129.125.50.11]) by smtp1.rug.nl (SMSSMTP 4.1.0.19) with SMTP id M2006091716540904671 for ; Sun, 17 Sep 2006 16:54:09 +0200 Received: from mail3.rug.nl (mail3.rug.nl [129.125.50.14]) by smtp1.rug.nl (8.12.11.20060308/8.12.11) with ESMTP id k8HEs7ba029629 for ; Sun, 17 Sep 2006 16:54:07 +0200 (MEST) Resent-Message-Id: <200609171454.k8HEs7ba029629@smtp1.rug.nl> Received: from by mail3.rug.nl (CommuniGate Pro RULES 4.3.9) with RULES id 26722890; Sun, 17 Sep 2006 16:54:07 +0200 X-Autogenerated: Mirror Resent-From: Resent-Date: Sun, 17 Sep 2006 16:54:07 +0200 Received: from smtp1.rug.nl ([129.125.50.11] verified) by mail3.rug.nl (CommuniGate Pro SMTP 4.3.9) with SMTP id 26722881 for f.b.brokken@rug.nl; Sun, 17 Sep 2006 16:54:07 +0200 Received: from smtp1.rug.nl ([129.125.50.11]) by smtp1.rug.nl (SMSSMTP 4.1.0.19) with SMTP id M2006091716540704669 for ; Sun, 17 Sep 2006 16:54:07 +0200 Received: from HUSKY0.SMU.CA (Husky0.smu.ca [140.184.1.100]) by smtp1.rug.nl (8.12.11.20060308/8.12.11) with ESMTP id k8HEs5Hr029615 for ; Sun, 17 Sep 2006 16:54:05 +0200 (MEST) Received: from [140.184.170.51] ("port 1263"@[140.184.170.51]) by HUSKY1.SMU.CA (PMDF V6.2-X25 #30841) with ESMTP id <01M7AU3VD1VW8ZFLAU@HUSKY1.SMU.CA> for f.b.brokken@rug.nl; Sun, 17 Sep 2006 11:54:04 -0300 Date: Sun, 17 Sep 2006 11:54:04 -0300 From: Porter Scobey Subject: Re: java_cpp_keywords.html In-reply-to: <20060916171615.GA16340@rc.rug.nl> To: f.b.brokken@rug.nl Cc: George Danchev , Tony Mancill Message-id: <450D618C.7070206@smu.ca> MIME-version: 1.0 Content-type: text/plain; format=flowed; charset=ISO-8859-1 Content-transfer-encoding: 7bit User-Agent: Thunderbird 1.5.0.7 (Windows/20060909) References: <20060916171615.GA16340@rc.rug.nl> X-Spam-Flag: NO X-Scanned-By: milter-spamc/1.4.366 (smtp1.rug.nl [129.125.50.11]); Sun, 17 Sep 2006 16:54:09 +0200 X-Scanned-By: milter-spamc/1.4.366 (smtp1.rug.nl [129.125.50.11]); Sun, 17 Sep 2006 16:54:07 +0200 X-Spam-Status: NO, hits=-4.80 required=4.00 X-Spam-Report: Spam detection software on "smtp1.rug.nl". Questions: postmaster@rug.nl Content analysis details: (-4.8 points, 4.0 required) FS_GAPPY_2=0.241,USER_IN_WHITELIST=-5 ____ Status: RO X-Status: A Content-Length: 2373 Lines: 65 Hello Frank, Thanks for your e-mail. Please accept this reply as permission to perform the two actions you mention below. To be more specific, you have permission to use my file at http://cs.stmarys.ca/~porter/csc/465/notes/java_cpp_keywords.html for inclusion in your site at ftp://ftp.rug.nl/contrib/frank/documents/annotations and also in your Annotations package to be offered to Debian. Furthermore, you may use this file with or without acknowledging its origin, you may modify it in any way that you deem necessary or convenient for your purposes, and you may pass along this permission to subsequent users if required. Best regards, Porter Scobey +--------------------------------------------------------------+ | Porter Scobey | McNally North 104 | | Associate Professor | (902)420-5790 (voice) | | Mathematics and Computing Science | (902)420-5035 (fax) | | Saint Mary's University | porter.scobey@smu.ca | | Halifax, NS, Canada B3H 3C3 | http://cs.smu.ca/~porter | +--------------------------------------------------------------+ Frank B. Brokken wrote: > Dear Mr. Scoby, > > I am the author of an Internet-published document called the `C++ > Annotations', which have been around for about a decade (currently: > http://www.icce.rug.nl/documents/). People who want to have a copy of their > own may download the document in various formats from > ftp://ftp.rug.nl/contrib/frank/documents/annotations. > > When they do visit that ftp site, they also find a copy of a page I downloaded > from your website: > http://cs.stmarys.ca/~porter/csc/465/notes/java_cpp_keywords.html > containing a list if C++ and Java keywords. > > However, I'm in the process of offering the Annotations to the Debian-Linux > distribution, and by doing so I think I should obtain your permission to > include your html file in the package that's currently being built for Debian > > In order to avoid embarrassment caused by improper handling of publication > rights, I'd like your permission to: > > - Keep java_cpp_keywords.html on > ftp://ftp.rug.nl/contrib/frank/documents/annotations > - Include the file in my C++ Annotations package as offered to Debian. > > Thanks in advance for your reaction to my request, > > Kind regards, > > [Cc: George Danchev, Tony Mancill] > > c++-annotations-13.02.01/contributions/GGD.algorithm0000664000175000017500000000314614735537670021067 0ustar frankfrankFrom d.j.heijs@wing.rug.nl Tue Jan 30 02:10:13 2001 Received: from oosix.icce.rug.nl (root@oosix.icce.rug.nl [129.125.14.80]) by suffix.icce.rug.nl (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id CAA11404 for ; Tue, 30 Jan 2001 02:10:13 +0100 Received: from dep.cpedu.rug.nl (dep.cpedu.rug.nl [129.125.28.200]) by oosix.icce.rug.nl (8.9.3/8.9.3/Debian 8.9.3-21) with ESMTP id CAA25169 for ; Tue, 30 Jan 2001 02:10:15 +0100 Received: from skylos (client44-109.kabelA.oprit.rug.nl [129.125.44.109]) by dep.cpedu.rug.nl (8.9.3/8.9.3/Debian 8.9.3-21) with SMTP id CAA31441 for ; Tue, 30 Jan 2001 02:10:13 +0100 X-Authentication-Warning: dep.cpedu.rug.nl: Host client44-109.kabelA.oprit.rug.nl [129.125.44.109] claimed to be skylos Message-ID: <000701c08a59$d376baf0$0201a8c0@skylos> From: "Dirk-Jan Heijs" To: Subject: Gave ggd functie Date: Tue, 30 Jan 2001 02:13:16 +0100 MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit X-Priority: 3 X-MSMail-Priority: Normal X-Mailer: Microsoft Outlook Express 5.50.4133.2400 X-MimeOLE: Produced By Microsoft MimeOLE V5.50.4133.2400 Status: ROr Hoi Frank, gisteren hoorde ik van een vriend een mooie functie om de grootste gemene deler van twee getallen uit te rekenen (het grootste getal waardoor beide getallen deelbaar zijn). Hier is hij: // Copyright by Gerton Lunter int ggd(int a, int b) { while(a ^= b ^= a ^= b %= a); return(b); } // Copyright by Gerton Lunter Gaaf he? (Heb je er nog leuk commentaar op?) Groetjes, Dirk-Jan c++-annotations-13.02.01/contributions/README.makebook0000664000175000017500000000262214735537670021223 0ustar frankfrankThe following recipe was provided by Jurjen Bokma (j dot bokma at rug dot nl) for creating a neatly bound C++ Annotations book. He gave me one as a 2011 X-mas present, and I think it's a great gift. Thanks, Jurjen! The recipe then, is: - gunzip makebook.sh.gz - Call the script like this: ./makebook.sh --t7 -p2 cplusplus.pdf (t7 is for 7-sheet signatures, see below, and p2 is to prepend two empty pages, which you may or may not like/do) - Have the output, cplusplus_book.pdf, printed. For normal-size output, you need A3 paper. I use 60-gram paper, so I can keep all in one book. Print double-sided, short-edge-bind. - Separate the printout into bundles of 7 sheets. Don't mess up the order. - Fold every bundle neatly in half. - Take these folded signatures to a book binder, e.g. http://www.boekbinderijerends.nl and wait a few weeks, or try to DIY. Background: A bound book is made up of signatures, stacks of a small number n (e.g. 7) of sheets double the size of the book's page, folded in half. Each of these signatures gets sewn into the book casing. So the A4 PDF being processed must be reshuffled so that the pages are printed on A3 paper, in signatures of n sheets formed by 4*n original pages. That is what the script does. This results in an A4 sized book. If you need other sizes, adapt accordingly. c++-annotations-13.02.01/contributions/makebook.sh.gz0000664000175000017500000000502314735537670021315 0ustar frankfrankbNmakebook.shYmWK#ȨII=FXA&f 1ߧ{r,ѡ^jq cZC1Q IDO4ȡ)t,\/Bw9x+zҡߩ`44q"ě@D z%~{rb2b]C'loOJV37jNX "M;#!}C0rC5t=,a|xQP]ah\/[g[FZ6eO[I'ѽV O1^ϸ5S9Ijω?1]8" zm"QL\FJt~EجW塻^8o[!1svx0qP^p#$ClA濧nK;LCw30ߢ!\)Y.477Bxa, #tcCbI'>\/ =})hN8f? ay@׉͛z0^yAI^ݑ8KMꛎo~6zrǻAnɶҟp(.Wy kPq^J/d辂QH6*H'$cvߖ_; Y=lt-;oto=> 'P&Su2D|ع́C;2Ǚ -[L1rQOX<%R )WYQ8B|uب](LW;ê}Qvyơ$n}عE^7k0J,ƅ[`I@j_avR`+SLrEJSB2xo8LI~< Jz3Y9JI87dhA"4KcTbK,1x vDm.ezbH\9gniOG=(r$$2&g,˂@"$ݤD%{&x<="ȝW1R XI+O!&df.mY`841j%[K L% |{U.4đnWށK폱1~X1 s-v[;!5&4藃5+bAN {+Zmo ~q}fByYٻfjjĹ% DrhB)C6A`XPك(6Zd{'<8m2Өl= *ӫ9Jl]4VOokd'z%ov< ȪZkp蝞Q?P?9 PԍdÆ Nі禌h2P VI'$ddzg7i[,įy&72gӚՃ4]F[ئ2n~dRc.o|zt‘>68cjKtpTH_B2"b쉲N].w#ܒ F$j۲+3CZ䶚yYW \R=ʨt9lY<_|m%`X4t3SH&ޱMn}Rn?}G+LRBAAEc++-annotations-13.02.01/contributions/sator.proton0000664000175000017500000000242014735537670021143 0ustar frankfrankSubject: Thanks for the great book Date: Tue, 19 Feb 2013 03:26:06 +0900 Hi Frank, First I want to thank you for the excellent work you've put on the C++ Annotations (v9.6.0) book. I read it to refresh my knowledge on C++, and I can really feel it's a great book, especially for someone who wants to get a deeper knowledge on C++. I'd also like to tell you that I have converted the HTML files into MOBI book. I did it so I can read the book on my Kindle apps, and I should tell you that the conversion works without much difficulty, with the result looks really great on Kindle. I don't know if you've tried the conversion yourself, but as a token of my appreciation for your kindness to share the great book, I'd like to share the OPF file I had used to create the MOBI version. If you find the idea for MOBI conversion is good, please feel free to use (and reuse) the file. (It's just an XML file containing the metadata for the book, which you can inspect and edit for yourself.) To create the MOBI book, you just have to put it on the same directory as all the HTML files, and feed the OPF file to KindleGen tool (which is freely available from Amazon). Also, if you wish I could provide you with the MOBI file. Thank you, and please keep up the good work. Best regards, Sator Proton c++-annotations-13.02.01/contributions/java_cpp_keywords.html0000664000175000017500000001514214735537670023155 0ustar frankfrank Java Keywords and C++ Keywords

SAINT MARY'S UNIVERSITY
Department of Mathematics and Computing Science

Language Reference Material

Java Keywords and C++ Keywords

This page contains a table of both Java and C++ keywords, showing which are common to both languages and which appear in one language but not the other. Within each column of the table, the keywords are listed in alphabetical order.

C++ only Common Java only
    abstract
and    
and_eq    
asm    
    assert
auto    
bitand    
bitor    
    boolean
bool    
  break  
    byte
  case  
  catch  
  char  
  class  
compl    
  const  
const_cast    
  continue  
  default  
delete    
  do  
  double  
dynamic_cast    
  else  
enum    
explicit    
    extends
extern    
  false  
    final
    finally
  float  
  for  
friend    
  goto  
  if  
    implements
    import
inline    
    instanceof
  int  
    interface
  long  
mutable    
namespace    
    native
  new  
not    
not_eq    
    null
operator    
or    
or_eq    
    package
  private  
  protected  
  public  
register    
reinterpret_cast    
  return  
  short  
signed    
sizeof    
  static  
static_cast    
    strictfp
struct    
    super
  switch  
    synchronized
template    
  this  
  throw  
    throws
    transient
  true  
  try  
typedef    
typeid    
typename    
union    
unsigned    
using    
virtual    
  void  
  volatile  
wchar_t    
  while  
xor    
xor_eq    
Total = 40 Total = 33 Total = 19
c++-annotations-13.02.01/COPYING0000664000175000017500000004310314735537670014704 0ustar frankfrank GNU GENERAL PUBLIC LICENSE Version 2, June 1991 Copyright (C) 1989, 1991 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This General Public License applies to most of the Free Software Foundation's software and to any other program whose authors commit to using it. (Some other Free Software Foundation software is covered by the GNU Lesser General Public License instead.) You can apply it to your programs, too. 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 this service 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. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must show them these terms so they know their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. Finally, any free program is threatened constantly by software patents. We wish to avoid the danger that redistributors of a free program will individually obtain patent licenses, in effect making the program proprietary. To prevent this, we have made it clear that any patent must be licensed for everyone's free use or not licensed at all. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any derivative work under copyright law: that is to say, a work containing the Program or a portion of it, either verbatim or with modifications and/or translated into another language. (Hereinafter, translation is included without limitation in the term "modification".) Each licensee is addressed as "you". Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running the Program is not restricted, and the output from the Program is covered only if its contents constitute a work based on the Program (independent of having been made by running the Program). Whether that is true depends on what the Program does. 1. You may copy and distribute 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 and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and give any other recipients of the Program a copy of this License along with the Program. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Program or any portion of it, thus forming a work based on the Program, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) You must cause the modified files to carry prominent notices stating that you changed the files and the date of any change. b) You must cause any work that you distribute or publish, that in whole or in part contains or is derived from the Program or any part thereof, to be licensed as a whole at no charge to all third parties under the terms of this License. c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the most ordinary way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this License. (Exception: if the Program itself is interactive but does not normally print such an announcement, your work based on the Program is not required to print an announcement.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Program, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Program, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Program. In addition, mere aggregation of another work not based on the Program with the Program (or with a work based on the Program) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may copy and distribute the Program (or a work based on it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you also do one of the following: a) Accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, b) Accompany it with a written offer, valid for at least three years, to give any third party, for a charge no more than your cost of physically performing source distribution, a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange; or, c) Accompany it with the information you received as to the offer to distribute corresponding source code. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form with such an offer, in accord with Subsection b above.) The source code for a work means the preferred form of the work for making modifications to it. For an executable work, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the executable. However, as a special exception, the source code distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. If distribution of executable or object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place counts as distribution of the source code, even though third parties are not compelled to copy the source along with the object code. 4. You may not copy, modify, sublicense, or distribute the Program except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense or distribute the Program is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 5. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Program or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Program (or any work based on the Program), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Program or works based on it. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties to this License. 7. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), 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 distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Program at all. For example, if a patent license would not permit royalty-free redistribution of the Program by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Program. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system, which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 8. If the distribution and/or use of the Program is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Program under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 9. The Free Software Foundation may publish revised and/or new versions of the 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 a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of this License, you may choose any version ever published by the Free Software Foundation. 10. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, 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. 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE 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. 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 convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 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 General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) year name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (which makes passes at compilers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice This General Public License does not permit incorporating your program into proprietary programs. If your program is a subroutine library, you may consider it more useful to permit linking proprietary applications with the library. If this is what you want to do, use the GNU Lesser General Public License instead of this License. c++-annotations-13.02.01/html/0000775000175000017500000000000014735537670014614 5ustar frankfrankc++-annotations-13.02.01/html/annotations.gif0000664000175000017500000000772214735537670017650 0ustar frankfrankGIF89a{!!!"""###%%%&&&+++,,,...///000222333444666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFHHHJJJKKKLLLMMMNNNPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~!,{ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻx˷߿ LÈ+^̸ǐ#KL˘3k̹ϠCM4 0uװW D-چ70`뚨wnta ޼ҪW)7{;O{Jۧaj襷<_X_$GAב)T%R@ʇqY'P aF68Ryف!pQj*}IH^wwA֢{8{>zDy":U^Baw(xߒ P.H%Z@&"w[rvdw##a,k"AevإF@}hXJDbl$e xIt~*HZ鐕\jRjQ[ @vP&kB:+scrwl PD+5,M6dS.(Ftd,W™gum0&nok:s { Vnݾl [k [”}iqE݆t*رV^iGino-S¼u/e(wʳ/ [* a]/ۜ,kgsI]of~lQ mD*#VN ʦr,puW=7Bo8H_ߋ#wrq=A x؄=.ox%]Ћ&f`:7"XЉ;oW `$f 7'﫳gNvɶϦc۹o ߽ zdsL(M2 u ۥH>n{;UAX(|` U ЅTaȷFoēİ` L|h<񲇺p*7h uR<*+7ɰP,JmWטYj=_qw͆7v虲~4| Hl8KͿ!Dp,d)ga[ M?S;(Or;^^ 8EA~Бe4R.K8H*:#2=vp{~J$MhNlڞ٠MjЖ, IR'jO,Tjqq#+w*dzE'wK`>vD!{uTh0kZO|3+eBF4P(?;bzxӎP*Y'~O MsǢ:?i‡Sa si`s7V:YS_J˛@%a9sQyqxy.e$XRj1U"aeՏye,ETL*ZzP!V!=_qBW12{E>)ao$py􏬘U"&8p{[j5 [UvU+ s /pli J["CϾ߁W!&`!gv 0ŵ5tʢNn!e {16a`ΡA/ (uL0m-j+c8^#ԫmIU.єHI2 GA.(gT'M8"Iaٓ?S*L ii4 -YI^"Xq&(פgl}5Gd?C sfчFt!E@[Д뜺;WS Pz'mOj4iy[Mkl#w^MbNf;{WM%g5d`}{#l\ ,LFp+lQI"nmoIIДfY&̑ISF 94,o3im"ȴWsۗW)*Eŕub=؀/zKj.e!3ǙrT"} <<Ȕsz9Dr>sA77[r{5VC^4uIG}76MUu"wvAEkZJ ڣ{nodKzqPX=4kxmE6'^C~]DTh,mŔ+^j.ĆGtn5+Hՙ0ہjr4x:=}ޟB{uNWNoҪ-=zaЃs|Ko]ZAWfOtvp#V&9tA҅qOv"eCa9BV31򀖳*,FGe#uG>!A5Ve4]q+u"x[er2%2XAZ҂WWyf;Xa:DhBHbesK!D pr|dd.S@ȢZK1##`M:tp"Le5G*kV_#WvR;TPXbu;V'@X>E_(2%S4O #ug'Yh(_Å?qeX}'toз$W2u(H*hHC$U1B|؇H6[X'sHi38M1xx3߲?hhBu̱qݸ`U҉Bu옍*$w`JP:X#"0؏(Y*$S5[v(YIqhIfu#y Y5x?-.ᆊYQhűLAXFOwF9.&F(H[4H T&6oOҋu~AޔSӓSPgIA'ZL9/5E^c68lQHScUb\#_^]a%zٗ{qQ!;]wg-"X}G|[[ZOl[{I^5~G#b!*^s8x!J"4mFR^㛩Yb֜{#uhaVSffQhiFyx8ĞI9Mh1RG'G 6GwrH-X]7r rV:X**ڢ.02:4Z6z8:<ڣ>@B:DZFzHJLڤNPR:T;c++-annotations-13.02.01/html/first/0000775000175000017500000000000014735537670015743 5ustar frankfrankc++-annotations-13.02.01/html/first/datahiding.gif0000664000175000017500000001621714735537670020535 0ustar frankfrankGIF89ay """222333777888;;;@@@DDDPPPUUUXXXfffqqqwww!!4 Image generated by GPL Ghostscript (device=pnmraw) ,ydihlp,tmxypH,Ȥrl:ШtJZX7PxxL.zn|N-y?|{С׃~ ,h(0> f-0{z.> J ̛o2vR &AD!(VuqK? yR@:  a`f}+ƨ4XҟB5q0OAX}klwa=& r5&w23H~k`YLȀӠBI {pPu}笕:w@ y !mDxZa \0 o]ŗ"ˡZLrG-X7^z0l@f8O lGf`>4@6O= `=hAuUgA77uyAA|,@ bфuDE68@۩yTK] R~00319E ه|G OhJ=V9GUMOu#-Pm܃AC ]drCgO6D%T[ ik&J"ncmΩAIgUiL IG2EKfɇO'* z&h_e |!!R~ n0e$55 )g maQ0AlH#P tT"ⷬF+ 6EQ PHË7R 9# !TFOFZ$uIZ$&7IB (QQP$*Wʜ\e)cIKIβ.q]"sE/I `;S`B <<ێF5ͦn+dUlm(@" ND('jx10Cp)u窱!&-1,P{2Ph* p,^ oP co!MjM(m욨"דW˗@62E&sEjʝ*H\`@z6ёzX"B$mjUQ;(ґ%[]'6Z~*8 *@>Fu'0T/3^8Ɠ)'KX(: eRPDo滺%HhZ bNp͞(elKۆ= eq?9$4C09->S6s3?ϸ̃=C?k$0:'V7ω.uo=]vv4 gmiOaɂTH1>zOƿ! (,Ȑ|((oyEb~Ub:#A=O/x9_=#z[^v7}14}k'o|J> GC>m|Gڿ4,-0~2߉\L~#b] 7_I p B*LzW rCXUQ @p*?6 # R1#*SR+UZ$!?R"QA">_Mz'DaC**\)+b֢]ޡC!%XKQ(|( 3XZ,a*jItU <,3/CE"5v/x|G 3(_h}PSR >33?*RpmKo}'}UXO#g!21p?.OVW0Tsc֔׈(٢b<2A* =mR+O0K|~H]Ȍ^;+bA2$?p2H,6X40:Q$Gv"aTdG!GD>!8l2{FdW"|q &yڔВ.p'@594w8 :@BI7YwI D9F H7PV)t=IS(NٕaɒcId/akzJ} z* Z=MJkJъNe L/ͺ~I:*+ݺ*Z% Ji)PJ*y[-0Z 1 $xU+LjJfԕ@` .l4%NfGqG0cOu$=.Հd;[+PIVU),#0uXj4g\00##EXѓf+ fkz0uCp@1(Bl!eΊʘXX%!1w]1X<"-ɻ\ -yO~y" Y]zIV`dk kڱvf D:B[Kl̻, zkBx UƂWX|j|5_uCEXo l ߂M fMu"ݳUk!",o ;-. -"'L;YB/2VE;>!|utSadwk@x OTE[_} ޫ3K^]`̼uaS^*]&xw4X02] e0M NFl^BFV Q!CvU=,ߒP Vᄐg-=⌎2c.FX'rT[#' A`D]q857f 9elO'pK'ݨQ=8"~_>D%*)-N@Q>0]K6 ȶW!XZ{>D5Lv$`!cj3|\^kk8'C'!Pz>j2M6 U'!JQaI5\\&VSZn-Jx. ] %^|w+jn WŪ׶-jS.:Js z fߴx вrE;9_$TՐ*oӜOբ?Y֨?M x pO{+9v?Vm o " qgИSt" A"TƐn+ "DuF0a8rߘ. 0 l4EP`(i5n\5Hڨ 5r Gj5phL"uțXmrz1*XR@̘FFD CMZKC\ @΢Meأ DW@P1rr@pž€I֍p%RC!7Lo^ //J)@F>vFbIuoC.Ao x A#Ae+Bzi$!g.,R^,a-Rׄ#;ԑiذ`=( *\-ɖ5H*PKepw ,U <6ZVAYA="ҡ.m$Bo_=^DA{6( 0"ՁmW7tV/Yڷ7w tYWءY!164X8OJ{l'aQ{C5Gg 8x X d+܇mj٠t6ap_cρYMiqu|fYl :\34rI"c"r߃Y2biI(HyW̜@m fD$*̵e`y#C׋gTx*狀4KyY ,?JL 9xpVAcaTlmj JZZi*ފ@PT*q"=ڐARjLy Ëai"8)N:.Gñ܊*! D'Rfe _ʭ*!&.薪g@WhҦw-bndOAWbbz7c宱0>nI.ЕfEDt} "|9S7!v`Bf@ZXoTҀ6ASbYz#ذrM Sv_@^STc$]*<%y-'tN|&u({|8`P D9=.FA Dtqu$=cؗwKt&?B.[a<'܌f3(: !Y8 % <&12XX i::O|`wB. XX1,pO@֌VeE 18xdXOp,BX@ڐ!X)O 2>#'C/!1X,r^"K1cܢӨ5Nl|#s Mv D<D)Ak!E2̠##)IR򐐬$&3M$(CHO<+*|%,c)YҲ%.s]򲗾%0)aR:&2e2|&4)iRּ&6MhZ%&8)q<':өu|'<)yҳ'B;c++-annotations-13.02.01/html/advancedtemplates/0000775000175000017500000000000014735537670020300 5ustar frankfrankc++-annotations-13.02.01/html/advancedtemplates/concepts/0000775000175000017500000000000014735537670022116 5ustar frankfrankc++-annotations-13.02.01/html/advancedtemplates/concepts/nested.gif0000664000175000017500000002030714735537670024071 0ustar frankfrankGIF89ah          #&*+-0".3& !*!#*%).'(+)-+*.4 !6*,?,.7.064:;7::8>G47"=D3>B,@F-AG+LU3IP9QY3\f?[d8epELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,hq&&/1 H({*LjÇ#CgÈŋ3jȱǏ -2 e(S\ɲ˗.L4e8sɳϟ@ jdf&T*]ʴHP&4Jgц6jʕQLH{駨dZz0ڷpr nP%{TͽD7a8x;=up#7u 6佉JXYw vNrN{.韻3]lP{Vm}(>Ko+ -DQIs'ҁϚ4g/F7S!dV 7 N*$~gt.Ly թt9-s蒳ߡq!"|HD,Um38f`D xQ@BJ Id`)DJr:o%(M27' J 6|$ G)RBRd6JFD2jI%qHI\p*q]’9NI`*1)˧ҕ&c'L3012 *P IP9v<͙$@} X}C}cVf܆f_'u]F{7.{{n{ x(pz4;JX}(xZvhx7pDŽQ]ڵ|] wx9}~'~g_~W~q` 7>Ѓ7xx~aЃ7gh~ApGJXxH 5(ZF}f0H & {H(Aȃ>G8EHe8 ɨaƌ Ϩڧf:xthqkXpѸ؃X};H]8h@' )f  9w`e ّ )DW Az(eXp"0y 2ّ4 68ٓB9 D9Fo&`R9TYVyXY9V@$Д 0 Q &)-*Tc)sefZ`{{I%s 8E*p9Y4Py gGh9)UhwٙPUřI 9UFc SUaaYhy 9)v) ʉXٜƜ҉bKyUۙW9TYW)X晞ưU䀞T`9 j g퉝 J٠:T z*00R#!*Q.0G<6*Z8Z:oգN@UBZDZEuؗJʣ,YɤTJVVXNo_.exc fgIo)eb0X\X{^{^f]ʦ1o'}g7F'~7~;e 'zhW} e؁Y6؁|z,zU0Ux6h}rh*~D*ZzZֆoej(u؍9٬ZVxv菬y ) >Z% |J' PzHQ*DD z8 C{wKGtpT k'Ա;(u*k(dltLaW4HdAkv>J{-[I @2t"8d W-,s"H 'Y˵B,}B7Ck#24"Rh:RR &[hHR:ƶOp;[59+S&8"o""DhaᴍQ vvdCjv+Sp+*6;0/۸ Д 2 /F[/ZH5k;k\5!RB2*4hj&))"$A'>s;rΰl PeaCMR n"30aNH [u kGm[b$k>!%L#'tgd*9N:B7:IVm..0.t=@QI 7m9ޠ;r|6 ZuGվJeL^Nu_?AT^WYqYRUka_>ckmuR6[M:ïְؐh|~~~voZesJ} fͅXezze޳(>꘻׺ّ~wUꈤ-wڔڊן {zɎ ۾خ j~8}۸=xj׍Z~oW}>ܺ}mОeH੸޷}. oZvV$h,.08 [68/:b@=_D_(/`JGN_6TQV&PѢ1b?/^>glnpr?t_vxz|~;c++-annotations-13.02.01/html/advancedtemplates/multibase.gif0000664000175000017500000001461114735537670022757 0ustar frankfrankGIF89aJ          #$%&')*,,0"""+).;()>++333:7=K::DDDHEMR@DWGLYIIYLL]LRUUUWS\gXXfffealtdmto{wwwp{ww}!K,K $1' Ÿܭ1J;ᚦH H ?*b\#JXnK jȱG/9!œ(SBHRRƏ0cʜ/d˛ ɳgEz8I6*ӧӧY.]4ի3N:)ԯ`Iz*ֳh j%˖װpÎm;lڻxݻmܿNݵ|G Jt 5eh+̈!0C~m #Wk@Q͜5Gs(yQsr6I֡E!H]h _ FHLCD55&܁T 6Ip9!0!&Br!":QXzB|A !}9PF0Ce$?3Y!p0 9%btJ@BEȰa$C B#ăϽ CGÕCZ0QS&O*9(0 PiD"(p>JAoܗyj J ɖ؀"B PD+ i #9GT{-9G (WE|6&>"h) 1"@e&Ppk>{O35(pj3#9bh-OBRW%]*3KFsD=qnl)>g 3 jF̰jj;dz0?5rYΊ2ۼ@'(C.9I|;}9(#Rsno-0 +<XMj mb>x}WE4,Aȡ> uq(+袧QgAyt6O"/GG`%#PuR#6`Hgxa7* "8C@ HGMx`bɠp\90!Y:)9E0@i;ާ:đ(U _H.MD S$j7(pG⁜WQD{(,xH+`@p}G0_dn $UI//…a`CbcfE&6Yej~:ݧ49Yt&N~ꅞa%>}ބL( Ж4CߩЊj C!N'F3zr4(ECR 1IR|)L!әNY)N=i\jZRuF=*S05'N}jK*`$`jLՐr*X"քܴi9+ZmAյ<%+\*׹'؁`KMb:1*z@Zͬf7z h3;¯M)" "E´P܆p ;W9r{2w}tk6"ͮp]C`5w;nzޝrwm|Iwk}{WpGݯ'<gT0Ak^D ^WJ,b`tqUoK!DNRt$+8aT *,-\sBe3'Ԍ6g#a 2_CtsgՅpZz.ġTTmeCOZnc7N{ӐŴ[A@ ԨNWVհg jO S`uϜk]ם5+*D밑 _/;v  -վ6fnw$Klk>nwT- e6ݓtۃƦo'^Ex1D;8QӜ\aGw4,s *;/pł(d! Qn'647Pϲ*z~U4MjbSt9N(8cx EAt}R'%.G~%R{I@R<9d61%VR7ɔD<&| h/%wCy7d44yT2AGAgsBAr2F]J=@wC2Px8o*H6SR$9)5*374C7`1wH5yLJg ѕ2F)ne8y>ʴ,O97yX!9tՙib?ኳWYb՛@yIl !@y)f̉ɩPyؙaY E嶝iv4Vy)A 7Ja0  * -P 9pVZVj֡ fkbhPP&E Ƣ6Z.fg9fx v֣[;&%Jif9mJZbNQ 6QfTZ[$꩸ 7 PFz[BYuJZ8\(z%G,@ڬ:Zz8YƺvFيĞ*:Rjܪ\pz\ZڜzV[ٯ Eg߉!ư>Ffݚzl oYuq(p#4#'Z*+1! |(|4w!U"=g"?p,rY% D`Ftftf&mBuru=}y(3."+rI/L/I)u@!|ӘD!|WRBJ{gȗ"0wp,wu-w-]xtuSvv?Pz2+?vQ*7DDa0`X<:)@)FF)t)y=2/ysz2ziFcU,ׁ609hT|6AԈ$]`GXA岄I "d%T,[XLcB:ྚǸ2R ÈĽKŠR?w?rIH_VܔѬ@0E%æ%aGsiԉ(C˅$|Gq0N1:  ;(hIc;t)i͕\D+[[`0ɲ#"@Gp0S ,Vp.UCaI3GLJwI1#,lD+Ь 2w@r|~yYUU Ջ!LEs0Am/}=Ʊ&AC;RُpBR}Tm Ma<(1۴ ڵL`m=ý S]]$܇ ]W{I %v5TaڷݰyZ] >+=`V >^ Jl]H, ZEe~ Zթ&'N`)^cd0N^/N\2^|z%:~^9NA! F_\45:jP7T> W^V.Z>`Y aaJ_^N6攰h>aj^\gr>v>ey~nG|/FPN~a^_Fa9>d-^` 0ꤞW~p.š5na :욵~e>b=$N/bٮT^}hޮ^x1h~﬽Nt?/6eތ Xz&з+)01*ѷ[L0 "){KJ22P?j`QK7;vH5ȻO <@#FHV)<") 9/17+ayԋԃ )/ D{o&ݼ{ċ;7=ț[ܻ{\=;m>˻?k?O~ H`\`ԁP`:7N^߁n!gbbyvHb,}b؍hb.n26#@c>dBIdFdJ"N>0RNIeV^eZne^~ &PIf7afj&eiW ;c++-annotations-13.02.01/html/inheritance/0000775000175000017500000000000014735537670017105 5ustar frankfrankc++-annotations-13.02.01/html/inheritance/hierarchy.gif0000664000175000017500000000304414735537670021553 0ustar frankfrankGIF89a+++:::HHHVVVeeesss!,`$dihp,tm| Ȥrl:#0Zl pxxL.Un).zN~?vx|%~bo}],g.eik„f`ba̔pű cgܖyd_   ^HG 92@xAz AP/f!PD rp~ \$2nb:[2#s(9F .B'[E8u*Uс^(| P $@pu!%u (QؾT6-ȱx*iޱM" p5q?tdƔ+yfF9LhH&s0իvH۸sBo ѻxƓB9&Σ.ֳ; O+MϾaߘ~m侔84N_A .֠ 8߆84x0ۉ(&Khm0F09ꘋR>q$$FFBV~"YQeCr Jyǖf5el_injm9Fvzewɧ@)ۜ)Agh"Fi( xр] ؤ-"v)%Αe3J F:^pB,T$v*#ެR=CO6$ꙗ?IңQ*YZ)d=ܚ",PQ;(v t AF}@VW6ۉAD{r.`4`@Kn]L&٪" Pd ٞ!@􌽠k hs\G Up2VoE3Ĥ.0Q+3G>E\<^- ˌsfzg>Y:l'ڹW:w;?V{[yCzC93|h*Ji=C!#"w/~$/beD.O?#j(29|r"(AP ] b}`!h4*{"lg yi Cp/\!ZCdnG< j 1:91q;ItH"TDb'0dnY^+`L1:|݊Or9)ug ؎b*W+#Fs&@%IbxQ?_~r|0^G=Yle \ޣb,3y[F?1]^h"o?Rť.A* v!}z ȝ [e^ERCBXÅ݆ $Ma}8b(nhbV+Yƌ4r2=r;?BdFdJ.dN> eRNIeV^eZne^~ fbIfffjfn grIgvމgzg~XJhh.h> iNJiRgni~ jJjjj kJkފkk lK-xñA栬"4pH12#_2'۟2+2/cnzW`W8 id@ڎC`!@ hA ~PaJЁaOA z l0>ǻT 9x-Th$ :\x'AP*/I{+ybHE1KhL=5:kz(u~$xY1t"YIRrYK$呓sd&C)UJ[%*E$W,_F^rd ^:/0-PKMD&dǔ&xgQLc7^~ L(sfsl; xs=|s? Ѐ t-AЄ*t 9 шJtE/ь*G? Ґt$-IOҔt,mK_ Әt4MoӜRo|bF' Q} ژ6$%hpۙ_!NuT*U6SjX{U. jjVQHP:EU<,VW_[ X9˛,1cY&J.5,g,^Y9-j kZ= ㍫h+Zp6mc\obSlR{BDs:]PCYi=eSUb5N w}w x.U;c++-annotations-13.02.01/html/containers/queue.gif0000664000175000017500000000227714735537670020604 0ustar frankfrankGIF89adర!,dڋ޼H扦ʶ L ĢL*̦ JԪjܮ N6Z&8p)9IYiy Gfx *:JzJ&P (J8[u;L\ %l< },M]d ]-~l~?J^?.kO/@z (0>@0:Cč(n" J<2J4r|yeK4k)͝+G N $y-94燢Gy&3]O65ZUǫN}N3#םYf`:g`ۺ*mZpK.nW݃S]ׯbO;8$^yReˏocHnHf>JɁU#d&N9& Bv4vǵDe2F3nrx9'WЇSa2 ~j%7+s{^}utbtr֜|卧ށՆE؞ X'o}Z~:깗b6آ ᝉGjv0"=*c"A"2);x$zhcQx"|Ȣ0RQ!/)bݔTHpjA~YOW&g&G|'@祜 F(MQ| *z!#a1ɡ݀XA}2ziク7&BaE]dVA.ܮck&~KjAκ-.m~kʴn+{m㒻Vޢ[|r^U,-[뮿  /spoS.UodRY1slp&1ʵr<-L 133ͩ|s89 =tCKsA 0I;tMMuVuACu)zaw5ٿdwPMurMwv wzw~ xNxx/x?yWzPAڎG 9 K@|+ʆ U^9}7;z"rm+~Vʾ%/z;3>:*_ȻGZ'jٟs>,b=b̓>>Oߏ p,P;c++-annotations-13.02.01/html/containers/list.gif0000664000175000017500000000234314735537670020425 0ustar frankfrankGIF89ad!,dڋ޼H扦ʶ L ĢL*̦ JԪjܮ N xgxH8PXxi@biH Y:* k'Zikz{J+kLG[{ڻj{) -y͖Lk,m|9-]-/_o~N<}~Bڵ}Zh0=|+@q01xcڨ̙,!IW7T"'eU1g/{@ CJ4E)ԀSNC*VYZ:+b)k{lۺEKܹSѽ+PZ 8 > ;~LXƐ+[.,U/{ @3ʠK7ɴję7/%:vdeFխ]6mU JylЋKLuսv٫2wN1H?[|$dNtU_;X91Y.D 5a(5aV_Db'~ȅT 8[H`+:#f0 !=hcx<IdLF҇d`/vM&V$qSRW-jyWy]*d2if*[ry&iBS։#xӛx~y %mJ)z'm2Y ~6i}yj{JJPj{x+Κе(x+h$Y.Aì|Yz# &l7E+ Ύϰ(v^~rֺn^r oO׵ܦ+yj;Z:2n"mu 0(;>oX7S/… 5b1B~ܒջpG )%'8cdHA21;5/i24=e0jcBkT9I:\XtkbÔK,Zk m.M]c:Wn8+1Z>xiČo0ɔ+[9͔R9љ=g%:沦JV ;vcF={ݢYClp͹?nȑV0.)ǟCWj}usE>{=k6O/[tI MZq`",^7.M4)=ءQXᅉ8bca↉ACƘ EciiՎ78v42D^ơCS/:$fFyJVYm%QVOx%feYfޙ8iqY̞|Ι~'m?h5#`rh6 ()mVץqv4s*d2:j2lbjJa z(k"*hklVp.,uuNlR-JޒYfn[nfe&iW6r/[WL%'DzC< 0C;k[LB a<*:KRƋs,[op׾lk0Jq7ϜtMxNM)A0[GFRf?ʲuSݬ07 V wL9TŽd枧(mi7s%G}E그NMNy]REM8S.O¹O»Wq:dS:0eckp~)9osƈ'pL+ȼt1[ |NQ "'- !Cw|C/Ph`I\ g0\b0Ҁb, h40T'h[;]yc=820~BV"񑸈dHHI@1d%4H v,k'%/Xe\JT^r %$jYYv)]D/pb""V`2"LdF@f3IA8LQ-@l6L9-sʤ29)pi'SGLy24> Oӟd(<jL*u'C-Z{^T}(D:e8hIz҅fԣ}ȶ R3hMIjN4PpR :@{"U7hAjCp0L]RU2QC ԪfUL<ʼ4VeX*VW=ב浩 \6%:Whho-lcۉj0,cŊY9O0(,l ) Ѧv5<˒umk3ֱ-Mm{[=ַmX %q*}nsVN7-weR]ml;X=j5@w5ooTwe}ޅok\B7*܃QgX (9awPp&51)`a [5.po8uo>.,6+N0#Or"+ky\ 0yd.<_x{C3HAHFͲ)c*ġL~{œPh+y WH) S4F>TDeH/gnt{i΄61JSV@h0ֲnE]>?ƈ Yd+{n hK{Ԯlk{ p{.ύt{nP;c++-annotations-13.02.01/html/containers/dellist.gif0000664000175000017500000000324314735537670021112 0ustar frankfrankGIF89ad!,dڋ޼H扦ʶ L ĢL*cfXJԪɈFA(lMvn|6Fe892g'Ɇ؉a():eəyʧw%I9JZx K֘KyZFz|-=M]m}{8,= [Y:]l̴NN n~oTf tBAc4x% qQFyhlQGh TXYHZ+մ#<}b!8SK+;SDPr97sG0MI#SRmZHV"[*l@za-ֵgsWOqN Ů^fx{ >8 (pW'Ŝ;{>͟KFYKvMe٘an՘ξ'im_'_銋#xiyɏ'B1ۿg$~vWyݤ|w|n`Sn)' 8!f5ŃE`,ԇԁF"H$H(!J4gcB;3[7.E-ҶUAdQFj$ 3H%S_iZZ]alFzf^xϩsrNDߟY%z≦xJY |rJZy(RȑfJi)X2zfV(JκVk~ꞦZ觔J,w:,vzP>[jNlRKڂm[Ƶz*D[z{+*K.Rl.Eo{K/&*x pʪfƨv\1_&2$hX#b%}+zÉRb8+@2)c#]E4QtÂJEJ,\7IN,J V MɿX / ` s,1d*sl3 hJ,ww7rDBՉS=,Qpa*6OM4=ASt,0Ç/ATdCO[tt"7@ȥ!딅'Qɍ$>/BJ4JYRc~,S)F@A)iL'F^C"&~O ըJuTUլju\W ְudA;c++-annotations-13.02.01/html/pointermembers/0000775000175000017500000000000014735537670017647 5ustar frankfrankc++-annotations-13.02.01/html/pointermembers/personfig.gif0000664000175000017500000000314114735537670022331 0ustar frankfrankGIF89aT!,Tڋ޼H扦ʶ Ls ĢL*̟ JT)=q\ zT7{ĵH3PhHph#@iai))y yFfJ6zX깪նP * *pKQ\{lG} ,mKWD nP-qn.*u_-ʛ0~w:iB/!fI`GopbQd ,eDM9#̔!#RK1e^O3I:4gĜ_teGT+S95+4ϯ`O%+*Y.,˶(TqY[7V׫yӚW][k?α^;Rf/ipe*\OGk͔E7ϪU8 ;GٴiwHkn7'ڕz̗e籯'HZ``|t{_swj"-X`~Uuy}qtagX*r%"@̉zഁngnDǢd ?ܰhBZdK>OvDDSBJW]jZ} fUff=iffm~曧StyHvI%gcAJbPr9*9i FzTjfզVj%v483Gx䪫k,l!4,1rʩbfj3, Z]׷fKnaje[n`鮺8%,ὔVmfлP{/'\3OR8Llb *)gbh!^/Lr ?c/#yLBϫRRg[+Vw۔X{FώQl[&wY,co{zMڂ8זag\yR=7yՕyڟzc5U:^*-~4ZI[ZcgwDزϻ]<׼s{ǷhA2)^ RϽ.g}# t 2J}觩zj*_ƿi^&yNC\Pvd( R0< 'yf$ 9/ǁq*X¬u3Cp<O$bK.KT"D'T,jXD(N1dlbx1qhd8qt kx7!>͈h/PSd?DFң?F d JP2$ =yGPђdI..`bYJWeoF\R̥/w^s,fHcRdf-KhS(eHB0@e9 SlD1IDTg:yFR^<'Nt6Sg49MVӝ$h? OTg>N38G(:ӄ`y Q  (/4^vԤGB@  s.|@l*%۠n1s JFDƙ)`E. 8H0xIf4-D0H.W*;'޹M*)NvSi%*Xfv$?Q'K!GGV3iFy,Ƶ,Y'hI @;DiXLt>nQSFLϥ`mBw+LjhgZ4>ըIPwM]Y_GA]iQC 4S CK"Ѯ^Q\.u$pk:Z_49!uzm_/Bv-i,־ݰPs[6!-nUcq:w-1SY&3ly۸Z7LM1{Ao=n#^}Wq2+n^jϼ|.yk|q_<ێG5pѓ6uO۟W9hzg_hux%Q 4 8,p"ׁ ,7z'"@~*,~sMq#74X6x|x׃z:Q[WP7P7"SkxIQKZMAWoGULWgAs_5f:PhRH!`?p4lhy{ȇ(凼v(nxkhhX{~,rU8(|bS8XSJXz7WO8mȊVC?muXxp؅ M8lhXQ8wZ0%8{V(vh$Gޘ̸zXx(8g7' ǐWͨmy 'BґiHБ`gtȒ7 D|i4x69[fІb9$256A!9i=l#١UVO4QS)3MHꢕБ P>#?>>H&?T?/UYq@CF@|@ Jaa9!UgI5jy):dSTE 5YEOE*%FddFFkmFq4G%eGrGG鑘07;c;K;;cCpYlY%]tC^SM"N@cCeTQ TQsH)Gqu Eȕd2\%5eI ^ 'rdW~L3_}X1X_cm8LX!Օ&L&`*`tae4ava>Zx:Ţۊ;e[uTܺ_YՕC6E&dKFE eĺiy%]^4^u^^y2%C5_5;Jبj•gJfgv泤)[b1bjfTcB[,^cD)T7vZħЈyf]f`&fAfFSe&":<vHJˊs+ ukuwkf{`}bdˍ{k}tˆ tK :ꎗyKsKk+K+;"ԸK[`+ފ{oɫKkK+{{p++x닙{+{w{+ v k߻i᫻'9X{67X;ly٫̠r\%q')<+ܒ-q/\1,yk Ç{.á+tLر5y$QV|XmdMA<9*>h|\|2I)+ np%pI)؂xyp~,ۍ~<Ȁ|XȹлȐ|̎쀒 wɚs,| Xd p<+ahIAԫX̯@+SͦlBAl,s,,63,p, <Aʼ["0(,)@)ρB= \}}3Bm"A$(Hзq%ph*)g|^$KnM#0M▱ ԷA~9=~7Nx;=~@.BGI K>fa$#:1+=ߜGmG`MAh>6L:.m>~%I@Ep^ ga!^ъ1bƮ^N™^^ =>a֞aNnZ!fެϞ1a!,..jn^욃4n)&-$̢? ?R3oڏA^]M%-\q]ٮV=,0Bu)13_Wr<o _F@AC)A3Aޜ.!OqߜKN-B -upO%c/Q!n}M}'QO#$1ͥ- ⫿ݥE0]~=i\l O|nǟϏ׏Oۏٯ?oO909+6b6A\"@ET. NUin]eUmm{_}IOp1K2RrRsT235upT6U6w6xؘjXyYW:Z3y:;j[|:<]v=^~^Q`@A4'A 000111222333555888;;;<<<===???:BNAAABBBFFFKKKLLLMMMNNNFO]GP^PPPRRRSSSVVVYYYZZZ\\\]]]___MWgR\m]j|bbbdddeeeiiikkkmmmrrrtttzzz{{{iwo~p~uʘˣٯ!! ICCRGBG1012 mntrRGB XYZ acspAPPL, desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km, '! H*\ȰÇ#JHŋ ȱǏ CIɓ(S\0cʜI͛8s"ϟ@ JѣH*]ʴӠDtJJիX'|ʵׯ`Ê5ٳhӪ]Kpطpʝk,ۻxݫ-ݿ FjÈ;p +L坐3kTϠC_@3ӨS?,0I.X"Q4nIYNxF!{FX@LG'k׋Oyz6-nү=_"x\q`WT߂xB޵T#nhgsƇxh#p!ԈT!QXcO-<H'hD$J4f`FD:#4X_?R9HA\{[ǡO6H"fwFA"H8Tn'Pİ <#TP!hB,Zꪥe1Đ#F[ҺE%z[nON o|9+BvZ4e7KYd6[[pF?CB%ʈ6c+A.p&$GslYܾOJ "6,bd#*F̺tzlU6R(~=PѭfR&!{́a z(BcSC?͡T0kL\cz3Qs12\! >*6fAD#8w6ܸ%797dܓ~Gs֚^*XeŰLZ[8՟"TgS gp5kOJVgx-ꘐӤk*: וp!3-\h >&vXJa 2&+2 dz?6]bC5z}RՓ^iNe 'W" ҽ MVɔ!.'<5FհgMZָεw$zdhLqraj'0p8|v R$bZn{w}]=AhCqh1ubm`{V5A-~&7n"oLcr8'N[ |Y8E S|fuW_\ƥh;+a@.+yηȉHO:_똻zHLUX'~<~+`5aCR9G{zE}춆)v9r+Ww{g9kw:\)LvϼOƣk)uO9?kKq7߭Ͻw{D?@̮|BOn#Ͼet?ïmo=x4(uO7ǹ7@WWq`({ j(sG%.׀jt؁gⷁ`~xVd!(z}(4w,(2)+XzdȃF؃@y$hGFKMVP>8|x`H^Yw}#ŁaN4dX}UpH1l؆GxAsHAkՁ7Xxi{ȇLk'vPx؉_`pXՁ^P8Xx؋h6}kw(ʸ،؋x8DRxؘڸ؍A긎؎˜1{x?Cf9ȏ>h^I ِh W y8 !S 1h"I႒I>*ɒ4.I@1i3Y<7A9 RJHvv?yXVyXZ\ٕ[9??p(Q7p(7_Jɐw  ;h7aJP?Ўdy^p)(ȗh8mIؘx j^# ahJm _`J0(P9mp^mR wp#pmYI? 9ipwy^p@~ q0MH#Н7)qYYv 8 RpxY٘_`)9  QR0`Дɡ ٢0ږ ٖ_0%zjp ڡ!#mwY7^ 0X.]@@B;D[F{HIʰxjTkW:Z)Ęz$8Oۓ+ocKf}}P2*nbpWgɒ}+g 'H_[!kw͘rV۸s*w`u|{=v;+5Id{w[:/ t iЋȋDH׼qcb۱Pqثxë CZ!rKݛN94;A7Wː뷇 (F;l Lq% }gkj"\1x(̉k,™XǿWPlk(=< A C^9D1\.km2ڑJ||[Gꬑ''UyW\E\m>4 A_ n+w}w*d imkPDpsļFĶylV({ku !yw<\ȹF Ȏlqa;AɕL~} ˑɳɤlQʦkīʯ쀗pm>p&ɶ|̯g||˱mܑ܁i<\,͕6iY̴,z/L|Ϊ\7jh\~7C5 [<}<<7W8EnK}jQLq<*HEԤzCPwh0qZ-.HEե1Zf`-ovnMŔ@SJEEgSGu}'FMI=nLT4p@vT-o<ًqΣ,tEqGerNˢئ=uq֨]t=ImӨе|P*+@|BDtR m' ݒ-U-1}^]SޔM61߉,im߯b ?\5i. n;hǫlAm=V5խ&:-WE}*ܧ  *nR0NhH׎Z->s3O><ݾw츭W0-ln>ߧ>n?'.~~s8;n L6^V<]JX֋^.mA/Wo <(>De">f' ^r~1\?JC}T,7bQ(@h|c>fr=>bAoX|>/ć(jt>@?a(ښt~[^/ˢLޟ>,`?_ȑˣ2~&-.@'lsӐ > j{O+'چ}jYDqf   $ DPB @Æ)^Ę"Í vB%MDRJ-MN`L5m RN=5JSЊEbЃG>%ySԔvPŚueΧ]ZȡCXe͖( =ruG\9ޭKݼ{E!r޸sаV~%|侎n"]og@a`g|ldǫ]@TgJ*WR9\pŋ:ǀȍ;7]tsrBP"k`]xѷP1g-~"рKA[~w7 ;c9dp:D:CA /.6D1E[@320E0mdp /  xDRJ>РHK2^2KbKjD @ҾC>C 240rP4$ACV2PAKCz<C1>mPN>,,@J(O R4UUU*PW J@0U: )Zw=nKOu<@WI/~@ֶV_=4bMG4׆vZTkSqBfzZ/GsWKjZ ̵ͪXPw^}<ӣ4T[okJB"7Kلmjaň3ҵ2eh2erc:&KRC )c%m)&( %L9(׎hdVUe{Vbbސ%[Q⹐/. %{B&rP7`DC [R7Ӯe&Zj}̦ETk߿ 濒P{&]!fBL OL e8õς [F(wC/!v3 g% f;(/n q #xhЋ_ q<( xk?ܠy  g&;s^" HB |RHF0hX"m4DKy+YXi6Det|\Fb/3Y&⃡ʒIa0hʛ5384f6,'.'gLol&1qS! 8#>zANiMlSk'i;dϟ-t#/Bat%=iJWҗtK|hE9njR4fԧFIj-.Y=kZךk3[drֿv_{ɛlG-z'H@vmnwwŽ]_ѽnv(~r=F[KwLg߈ CD/+ O\gpC<wAqRq}+Q"B}OxOODg:8tFYr}|vqtG])zn{dz:]ϝw|9W{G9_.xF;c++-annotations-13.02.01/html/threading/time.gif0000664000175000017500000003555614735537670020224 0ustar frankfrankGIF89a             $% "$&''(("-003""*+ 0033 , "#%0&""&&++ &"(#); %??-).6$?3-?6*08,1:.3=/5>-??1>85>>D(6C%D%N+B+U.@0V0^4?D8f8l;DDUU@@ffww6=G8?JDDUU;BM:BNwAffww@IVBJWFO]nnNll\JS`MVeP[kQ\kR\m\le]bkW`rWctZfx\h{^i|]j|cfkckkkkkHJKMQSUXX]^_foxerfriwo|n}uȡׯ!,`H*\ȰÇ#JM ŋ3jȱǏ C iqɓ(SLɲ˗0cdr͛&kɳϟ@+J΢H*]:(ӧ/BJՉRjݘuׯ`v5`lتfϪ]6gŲp8״vP`Yu{/È-obK``ʕ1kެU5-6vl`MVM.Ϯ%:!ءY̻7SϬG|1cݸN}pƗ~K\:u껻e4M>Yˣ?>}#cxh{ui ya7 ngWڀBHBa2'" m"GAr7XclH|UgًDa'&HcF9:d]VzPFf_Kw#V>%Q9IlJd 1f}*蠄Nq)<% B V0t駠fvN$rqVY@"RjgqꮻZFrh\yus)\s%&^thm+w~1xbɟ#֭.ʻ$"̮v.:0i,wgmT&"]bL2!k1lL0+2*L67\4M>wΝ}t5O bȾPMgnZfb;H2]eIvܙ1 L22p܂B1"Oa'+2Hdvbq>+l:{Lz~S/<+0[{1Pzjc-kJZ l]u[J f1eV(Hj[vYʩ3VGrs U0Ghv+5Lp9bB*126N-HN8 ` x'PQ U0[z!r~'&a3|Rr׮ -YbG[=^yc= rhxXϺַ{`{ו!H{!@?Nxϻw_=dn >UJՋDXe񐏼w`삯m\!H&hnQӑɛ{^t̻^jPZ+/}w{ȯ=A{C#_$}?jT}/ߥssEQT>ϯ(w 'wҗ~հ~~sG'#b&wsvGW ( @ wn 0 ( pW 'Aa"g"+L7uၽr $X Fh~ (nx--qt\Ԃte,f'@ׄpՀsׄ tWfh8gh{MX 70 !X 8T8wxhRm8Eyч0w7 o~Ԁ0 vX~(ogDwT7tddհ (n TS֊ *wsk8F8 ЀgG8XKʸ{(wPt{ysxHwx|E$$kb#gwt9Yyy o PqD &y(*,ْ.0ҀEyH7A7t.5xO<r>HEٔsH9%$#V "Z\ٕ^`] fy` 渖l9AVoX).b yxY yٗP hYyَoM9"!xwؙI/pi {G/8 vx9xY9tY*{|8LQwPwGvٝ9Y 4/{z̹ɏ yXXuwqDjP :Zz vYIמw~9JQxʟv Z&z(H (~P0 H(`~ Ԡ @ FJ$IWj L~7pnX 7x` "ZA):PJ Ġ%Ԣyڄ8 @ ʄ* Xm')yRTZ~x L( H o#X'+؂/3qjBsꧯpp~Jw:..*yp!Lh`_HsG:9yZ:}Z rZw zIHpQZ~$~ʧv j, y8w*wʡ9 jzڭ I걷mʆ rzJʯ0& I*y ۬ج::늂ڳTx L{ZHC) t0Pw@@H H@ Hq[ im6+ X rԪʂ(JDGH I˹rw(w؍J-۵~ J3[ 0t@ P t [›+}ۻz:z8 `n ~,8 AK0 IJKpFWʋ ; ЂmZ>^[z; tP;0+ H0H@u* (y茝uµ+4L"|8yJ{ty+*\{ ȍ"lR\ƻ9, \A\%Cblwț/wTL ͫ > [ ~@yLw 1)zvǪѹYw TywIw Mwo2,}m]wpLuG dƨ% '~wݪҼ,><>@B=D]F-iP}: l8 w(8zS=w8 t)w1s PWw إϠ^ʤN1jPvW;h=wrMwl Mqxg*SMu (&t]vͥ[ZaO<"w`u%(2} } { S PNXȄzzʳ׃H۳=wj۸w"H&׻-(۱zE{Jܧު ʍ΍ FY֮MwHJ8ڋmՠk˪*(͉n zgJRXww(x ڮa]i)ڿasXug/sGn; $;kWk~IB΍Ҵ-*}@޸(}k؆Aj<Ρ%~-. M gL޸hNF(njoxcά(ͪ3h=8}{y.wV }?Zn揜ήYkNr~[ap+xmޫΉ'ތܔ{gݞ*n~߶޸X샘Ξ.xx'%+N &q~F d݋(rW {׿ؾ(ի+nn">?A y" njK{/߿ی1Nu^qCvn.w0*Էʟ _wE?[wژ,K6*ҕPYLωd{yj ~?_J--y*-,8؎,M耇绷C_ jPmlz?_?|l~ 0I)؟ڿ? o?h PN?P/pB DPB BQDQ#Y<~%H%MD2-=ҘL5m@N=}ΡEET)ХMbԘcIA\^jǬ&afTlNc hٳmݾ}܉PN-i[]ǯ=+qܴk?bfnyG^M`=zwwbr߁?|o~6G_zbH:\={׶h?w 1';>"v@+h'?Я~|? VP|D=(@̉UaP2t_"?W A`wPD +)(V 3 5VъsadG(" ?p=:@A Ke QvuK<ʬH84#3őv(GT.+fD' HN",cwI:R\;Ώ6|ENo& ;Spg1t)RnGg5hv!֩ 4S^;?T 1z0@"~3%lV>ݤQD!عgdԥ5H7;'E)FRqL?Qԡ6UEIRzNfLuPS ZU^}*7Vur[}LWխo[)WMumK[Wƕs_6El632ֱ=c+YBqf5{n6ڗgE Ž,D i=YRh-:[Їlq;ַ;o?6S5no\ ent'Z`Mnvmۨ*>Wjk >r{\3 ě^&Y%P%-Y0B<`X@З.tG55`-ow\ꄿ Ն򅬖Xv_pd!,PBVtCޱ%Fqk_o-aBOnш3)'Yυ=Xgy3M8DQ% (68;cΧ+yJezD\b0{T wS"f.vnvw=ozm\F[F_3 bN&M NA5$>qWx5qwm-֝aJ \|p(LIΎnAs?"6GGzҕt7Js2Dv"^A|qutgs[OͦykNVs,b|pǎvW;ia ߙЅ:9Yhqps~xҗ2nzr4i؋;x;G}uz+ܲ<٩Agovyc߅_ fx0~wם};x7T@1>|ڇ?Ϲ݃_-_ 7dՏĽ/0+bT8ڂћ8@Dp2 J2p\#D]Jp̾h#@isAi@i8?f?f0?TAcAk87)4AA@p?$Ծ%l'tB3|jD2B1TD4É;;4-822P?>=2@d?D$djCC:gB;AۅBDӳDMKıAGLC{$H@ tCDJ@x?f@4?D{t=lʪ|J @ KJ3870Aj`iKRD=8?5;j6D;LTDT 5ReTyQPɲ[QgPӓՌjزԲ{N=^-=`Uųkc=1(9sWmFkUQx\(ۢriMp]$Z'ZUKb#eI,JDpJxR,?DS@D{Iy5zWc#\]VVP%E-WF=qTJp_ 嵸蛸՜ͫj`diWLLD4쿫Mfݫ$ՠn*;)6ʮ6;nGc 4k NLD E,l8,dCuK8ώjV>XWkϺGj;C$Y.^j;<,k H4Q̄ 1mEmjնG[K I$Q'f4tLTHD'EFGӫs;2Kt“?t>DQWRSGTdVGL@\]^=0`a'b7cGdWv3P%pgvg7Zg1jG Hlmnopl'Lo;k 0uG 0EPwvp:Wxy w|a} ~ u$?،3g xuj7xX?`xp萎 ! ɍ('7Gzggz1a/Q  izE r1B޷{ : ܙSw7 Yqtqw"*,!?Yg!{{N4w/ ^QY8% `{N|{L[E1S 5|t|^?| Vi`П|gs`cF}}SR5hvpaPpIY(7 ww~|[=J&sU/j „ )!1b'Rѡ+W7rx!Ue!ʔ*Wl%̘2gҬS$,~l"ǖ,~T-X$ WS>{tT\EthѣZs*-JBČ@x/޾s lH1Q+nܑqW=(Jd.̚7sТqݺ5z@W^3lr :S%d< Q%DznTvQ6']0!, ?L $ByS|} +t$rD𝗞)wP  J!hY-r!6alUÌ#VRwUC Wqǡ"'oLSM'%Rs@WtWC}P EM:$|@Id%FVe &q&TauR-vՇrf&3(Xd5`ָh5ÑX y(^VII"dNҠCHRXc*Ŵ)=ǗD>t+\t+kM"*)Ahv:ZX]4N3z-6=df"JDfCG+ǤhVdC/"k d슈,9'6:У=6\-zj.{e.i01 5Z̲06Zco K'ϋF;%NwFd%q]f޼Ug]9=fK(p7y7}7],أm;:܎e0-4@'N ."{_h5xYt_Iq_*= t" )Ř{~+Ą9Q"Ow[="|1{=a1PeHeٻ>Ǵ}0>ç*ɯ< wFRfƠ_y,xQ u@.#AiplҰ6KC>bfx!.dDx"()RV"h#r^T!(1f4Ψ5n|#%ɱv#7C<~)A{,$"r|$$ HR$/Mr&$(C)֍'OU"2|%,XҲ_-srz aSn+&2iLp)䗦)i)Լ mr,.|uv@Ҷ"]Lb\2.gE>y"pH8BO{2t| *Ҫ}oG;JF3φ}Q&Q|XhF5qi$`BKSԅ*m%s29eӝ25~OWpCJ2mrϙp H`P"?!DUdM+VXJPzU3seکDA $Òu*-)sdƬxl^)Jl{JO=DT)+#Bln3ov-pe?QN"VOSVmçJն'{WZ*Ʒ.xfq͕td`CZ񼱝M^Anjֳp&y$F}Ie5XBd W"IzĀl![:l_:F" ╌K*^aw0܃&ɮ=kzZ5:VhUb,_$ww<:$N1sY!'e'Ͽor0|HSZ a#6Ykn3Lg!)TS9Ў^cRbϐR6ў`a2ilTK7-Jdծ~5c-YӺֶu`ez \N_/ժe3~6-iSmkTZ&^}qm)mrg&8/QM<':ө]M}KDBh(f.,rqv&#B(G;\dԄ~ M@ .j.i&wrpR]Dhi$K «>;rQ[O 56#4,59(5{pAǣQobgw hhE3٩176o}S&ܠ89.7^xt#]o8q*5Rg-S^$3!dn߯hMo|;cо=s z̟/_(T _^ |7 @bB@ZtZ?/f;}u'Fъ@<OV}DLT*I,F^]Q HFEARq)]*OTƁGUVVeTU~GT͇e [[db|t0`Et_tXnbI mIĊ eY֗X٘IK Α gPhָ8ii!GTVVIXn~JnJ1cV"@!0I!eW}!v8OX f zv zRʡf@G$z)^l "ʼ wH29"šbV؁a(XnDqC~CD  EOFz.$JJ$KdBtH$F2/mF~L$O"` &NdJdOdIDN-% %JETN%UVed."9)%RVre)yU %ZZ%Zn@YBX1VQO bm\R]!ᥣ=+h@xAd_"]& Mg1CAxDDf Qf(Y&+f:`cCD_.>>ibffՁGkf eR* q-Ds: Q#EPLBCo&pp&)Msx2ify'.i(UYq%U z{!hV:Dw~Ѕo:gqd>肦gJcMX ^FlUVIf"gˁ"&愊)o*' z9ɆFB}yD!a\h(sY#]yhhhV}6^}9dv i%h%&`ez6Ji(V*ʊjb- pb rnx){JfsFKrkbqT5V :#UۜhR1),*8*y(HmN;>"ϨX?bwi:),jt"mgEoj>R&jj^BgNE)+zf ܔcPQj*.wbҕy&RJk6+kҺF+kkҼFl1hNŒ*R.l11133355566626:15<888===06@3:D4;F8?J:BNELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,uuüϨDŽŭߩՍðƾֈ *\xqSǰŋ9 &4j2I,I(ɗ0c%m͛8sɳeiJ詠F*] )SY.JYo`5N ֯~]N,h^ o7xs+ FT"hBX9H㉓4IY rHX2^!( ʬܚ09nѐ06p9>cܟ$9s`f&C>3!=rPuS>}Q02\';32Pl&>ѹU "FJQ6͠DЋ44wT28ndfTyOrԥ2|@B-jPUUCQԣ"UF]S*բFTSԭ:uVŝdSmEGȥ J~_C,rSaN)ą1 ! 3Qj " x+F X\FqXhR@ 5d1y+GF2h` TPex)B2G 2IZРMﱹn.D>gLF;R8n3@C_)DycecĖIMlٴC}+SqקYMd2LRɎ{T-PZ9Vih biVdžvq݋~rFMR1EO^wtTyMnw[JN!]uv^c^Űp'f͸7qհߣ"QƲQ(KRnG0aTsIG9z\DV'N_2CdGlDK#MНY#u>=SF;P@ 37S~ƚmרtlX}BgqHT"ݬ Ixx7?4$ }0Mfqw@ J]Zjʹտ:V _&O0eʜZ%%c|]_>{ͣGAtou썏4Я+;@\mwk#W~L& e ݧvgg 'kV0chz8ǀW(`a|rNjy!#g!?rVx8+Xtߦ1`󷃭g, u.KG(C.X R4?NȃU0WxWRJXlօzY {acch f(Ӆ\dxx|ag (|Q~p؀?Gܷ~vXsDdw]v݆xlxupd38v~(=f\wyXzx}Ȋ>ч }Ftq7z(wL{hш[i#aWq&4 eߘixZNpYyșʹiМ9ԩIؓnjxhН9YyaMIIXٙoEޅ"X@qP8]9X{E1{jȟѵF"`P`5׋&;v]OKul7&(! ]K P̓iY3: 9=(A:_`0P߅⸡ѠSPV:TpZ\*Tʥ`^djZ- %Uep TqZP sPU:usڧ\J& 0N'yC,s:Zz:i *@r:ZJx<`ڪeI6ʄ8*zr01 ګZsƺfXuʪRЩ0ZF: SddZZ`dPگm <f[[k[;:;$+{ [;%;'1;)ˬ^B0E(r N DN*!+MPPa@ƺвO[G+[KT9KBM_@c- s zLKl{{F>۪ 3й+]FËXZKqGKK4DJdVk þZ뺵{`7[XFVkNtS75FLdMKL#Hc*ڴ꾅FSZDF`iDFa¡QI5P`9<|&>=@L| ӳƢĄ+YZpExQY]lOi a,5FԺ Ɩ୑ļJǃ`,n5WX̟Z\:R4[R9Ssp,=r,B\D :,Þ;%WUtoLGop[W``EuW[9ܶJɕ`E|`Ǽ;i` p ЋH)uSlåuZ͐lL ˒lŜ}F\Mkm OVvؗhqh39SMc܊yܱ|S=έ53^~ >^~ h$(=p$nZ}{|'㇁1{ )9yxwk)<>#a7:(]䋘6ݨN~#~(ixzLT=nS'8;c++-annotations-13.02.01/html/polymorphism/0000775000175000017500000000000014771007032017336 5ustar frankfrankc++-annotations-13.02.01/html/polymorphism/multivtable.gif0000664000175000017500000001640314735537670022401 0ustar frankfrankGIF89a O  !!!"""$$$%%%&&&'''(((***+++---...000333555666777999:::<<<===???AAACCCDDDKKKNNNPPPUUUZZZ]]]fffjjjkkkooowwwxxx~~~!P, P)2+!#"#±ц")%=@HJMON&0@D* :ߌy>}Gŋ 0n8)Hɓ DQ )܌|sLaj0c*]ʔitիr`t"hf1U ֳhiMʝ)C&L˷Iu@f!]x\%K% ¤(!).> uc'H8KڵoMp4m Fx&w9eسoҌ8&ӽ?n>`@\@GqKI5 <:%5P%#@~O41r|1A *@!VgC'$8hQbA8g`V!d9F@P؂D (2.fL^#S6*^@8M~<1B cթiďYx5Ԑ,ĎmYrCP{D*vP})Np#'v7^gIj~(n%@i̽8rIQ[NH] kU#tDJub~eǡF+վeګjӁk|hP69m /9˧ H ~$Q51"O8DURY-*za7b'138_\3K>I_[]D:ی9tḘ̇3 =4|eȍSC=g W?`D\y/.Dw"/-9S+7xHx]0Z!Mrj4{NhoD; ɗ8͛=GXY0@'p~@`$D`NU,xEj pt0 c d`g,4'2Aec H!y Vt 9Ț0sV9D,'k#.!p6,@@~>qyE1O0C qẍf@E2=G+s hމd_5$-H I>A\`*O#@%Ȥ,lj `@p &f6%,@$wZ"$QWQBfD1s)  @lґ'7񙠬7((J.h>@v脤y7brreAKgɋO m⊦6uKE8d0'*XN  @aXMZֶp\J׺xͫ^׾^F `KMN:dc eЕeeflVͬ,?.p5hڷ6ukWضu-[qKvo*mi-.&US̽s-]NEKK .Uw ^I7 ovX6½LzqYm~+b/kߥx~]\De¾0%Wa 3eKp"@|\{&֗bħ]e cس7qvs㺮Xy~l!g@DB,YONr%&Ų#e]ry0bfˮ9#&3l g˼2hĝ: M4}6s~ ZIJ3cgE/3-O zx.%6Nn_MVcDӳ4l}\ZME|f`_8דv]cf׃؏6vm^jKjkCٻ hWۤvnC{nw߭x{fQ۳.;<oa{p.meV\Wf|lȩqܯ'nɉrܼ+O:oǼ5k|s|^=]EGzA{8n:uRW~ekV׿~5{jǾhOwwߎ ۵l>پ{O?YAH b1RbȽs߃@P-z33׀j &U@eŷ?=b,1 mXi%:I@$+9-.@!/ݢ-jTaX'B1@.$D@S/:ЉUϖ_"@8X2t脤5a1nD875df2islӍf ) Lh2C88F7=SS;cӏ Uek%I#@㐗1#@C<3<`(<tiL)k] G8>30;֘g[yF`ГLf^[/7Ox!&U6\B PVaKwDZdյO`.H`9EAַ5neU 4|:[O*Nڤ6gTvNƤZZpmMX1Zv[l*zl:uYVzvt*muRmoqZ&>c_:bEZCY |iFWz`zک `_::j:Zxtqjazi^a)yګxyZz9[i u{ʝE@瓜@ Pjx D +;0J8BTb*fs `@+0>PEKаIJ Zg@@ &{( E4 t @$C)@G8` ЌvVg @;PA[VJ+p"gh:i4 +WjJ`gƴ{ʭ;;k۷~G./egt wN+9 P4Aq;mlv)9PtzŨtJ40;[֬awws7|K EpGdZvwj[;  { Ƽ禧˻Eb JpnDBKC۷E`1lpڻv{>A~- ,tlڡ{+@{E ˾bpNfipzG{4@+`I@yK$J;9|{Kp;: Dܰ4p >'LE0VQq'{ {  I `z,kQ<|;rlEPaLJ@f g:k([ Ŏ_4+oª<*[K0&ʴ˾0J|ɖ"L ǣJ0 {ZN&nUnW;[-? WKe@HL kU]Mu^ڜ+` @V`^n">㈞b(;Xg~ cWqA:æ ّ jK簮~ oKnk\]փ^`>!AZm>a<~7L޻Aׇn\Mbk ).l^YʊnM ?$۴/ ]0OB~Z8c/__/}+Ho類аR޷68ö˲> BYlH P,hݰVEAŇ?<]>xn,tlxɞwJ0LJ,찋MHMP_fo l\,4R48Xsx(y$yə*:J ZJz + ZZ;ۋ `ٹ2D"sX$(ixT PxyQlξ#1k*/\o|Koo߿XʵTt) J!mfKXLI#.@2ɐ,[rK4kʜi ͝<i6ܖAA@rHF+)h@OilkZ -05l;Iܹ|K7o?4KT `w/%!6ČzK496NƊ>z\!g~M 'gشsMsA%0:pIpו\;y,ƕ;&1;Z=ܻ{8;tvnnv;R(?`Aa`r܂ x ^ana~b"؎r5"z4D6ވc:jH";p-*ɽHuRN> e=0Bl0bY-E_QIfNi ffH>o4ifzވ&'re)dsfgg(!'+ hbFtJhIu¤Zj+Kf¨I*&V:ϖemDcL. eDdA=+Wv骰4(&2 bByz-SGzɷ ^ p&plpqP֢ qlI"ni|Sz [!5tDDkbqˑz$|7d{ tڌ(%8 0C)y%pIo}! ٹP-d_jukI48Mʓtv-hz!@5t+@t۝1y+$-/XHxzk?45Nz馟zꪯz뮿Nb 8yczm-JI1|O||?'њRYI@:m}&>K*\ZOuJW=]M¸OT !l,*p*ƿ+ jpr4`},!'Ps]~һ d@&,a0^A(̪ JͅJ @3"P!kC,Rk@ ($a 0A1]XK A*׸;q.!Dؖ1eerȌqj! 71G `K$,>f1$):n\B|P'ŔU-5ր:.`4!JvPA{EhiLX`PHw-%KL!3j`lI0`曶3w`dZV," G:w `NЄ2p,$ {j%C/@;c++-annotations-13.02.01/html/polymorphism/buffers.gif0000664000175000017500000000665214771007032021472 0ustar frankfrankGIF89a  !!!"""###$$$%%%&&&'''((()))***+++,,,---...///000111222333444555666777888999:::;;;<<<===>>>???@@@AAABBBCCCDDDEEEFFFGGGHHHIIIJJJKKKLLLMMMNNNOOOPPPQQQRRRSSSTTTUUUVVVWWWXXXYYYZZZ[[[\\\]]]^^^___```aaabbbcccdddeeefffggghhhiiijjjkkklllmmmnnnooopppqqqrrrssstttuuuvvvwwwxxxyyyzzz{{{|||}}}~~~!!4 Image generated by GPL Ghostscript (device=pnmraw) , H*\ȰÇ#JHŋ3jȑCBIɓ(S\ɲ˗0cʜI͛8s܉.; JѣH*] qOLJJիX1:ׯ`Ê+p+ThӪ]˶?nʝKnFC˷_x:KDǐ*|'3]OmyKg".%rn ޛn{<[pvl*Z. nvٮ{.|xo<~9IOY{irykOc^VQOHُCT A[s朲9Gm\ݚ%4俤2Ģ1fuld`ȚEYG2cnƙ "e;s)P64|ܜC@*oa!f\x fY`>.``O&Ѝ0B ŮĦ"a.+dĊj$C1%"Q"$"(V@< #ǡ|Q,wlc(Q( K DЌD$'IJZ̤&7Nzd"gFv VҔ6+gIZzp^ %WG~e#_E3Ӈv2슞ta Oqs*rTdE,uPX19L2?akMr'g *X(`z*dnF0}V.&bSYMgiHxH4j!ѿhU)GՂ`to[]A6\ٶ"D(}E!eR- <(Ѿ HGm3v1^nXWi%/ۡiM-t{ RƢ0wawjҖԥ^%o%9 !sb_n0߁iz+':taAq!T7w0?#fc@C]&뗾wѲ@}yF}@"(E1TeT;%gdN;ykHOmS"wxNj}t3BPSAV :}E;dNT1D6YBRGF")6RHg9yEK\xf:{M nȳMmLڴ!ۿW>y(8nOȌ{Ω;˵52n06fH-soi):zTլh=x[f%*| @%ԠW RX p/:"QYK>ʠi4];me3"d3ӌQsg $?k#s bD|Y3N?fFL.E-Z(.u2: R#هU6(GQb68~b.] Tm"+ NrGHx:~b|~`ow."p[dRT^|8cz$<||r|FЁ;*^0>Y|u4G=c{>][/aIWxo~o 7rK52}U6uZE&/yXw]~(vcwc8ãH(rf(Pq$jw(5 #*Hj,nTu{,ZTbig1iucrB(:.XW1O9QxYqkhU9W)]hc8_x]jl؆pXmr8Vvlxɶ|Xl.Rxe8tXYHHl.zlXHk8A?xh(l؊ Xx؋l;c++-annotations-13.02.01/html/polymorphism/virtbase.gif0000664000175000017500000000236614735537670021673 0ustar frankfrankGIF89af """&&&''')))+++---333<<߭_$|xP  \tۦRb[] N+;9 ײyW`Bؽe Jx-C$ P„ L}dkU-vW|ceF,ͻoT"mvgvT Or !t꿵n߿+p ȟO׋97uHpr]m'X?7`AX`yXC wjz-Q&.^"H$w 8~%@(d!/>ȊA&eT:ieRѤE2Xc2gMZ!]%K֩pydu2Ddr'tVjD"ٍ2֙E:&o^iۜ褶T*fi(v)6Nꧪ ꞷk'+馱 Nb#"X*Bk>;GʫfKmȢ.26 &cȱjߊǗ2j: X|rHwg{kP\1h*sl!'{#82g3-K;/rLPLut-9~ bvIKx*ۙ mww-|l4|K7zs6 ʤ%r̖8! _>u㓿Cʡwm8:l`')w/|A;c++-annotations-13.02.01/html/polymorphism/implementation.gif0000664000175000017500000000524714735537670023102 0ustar frankfrankGIF89a """%%%&&&***333<<<@@@CCCMMMZZZ^^^fffsss!, 'dihlp,tmx|pH,Ȥrl:g/*ZID5J)iw,ԘՖ]{eYX6c YTQss]Il_c{l T"Y^" ]"sq#T#U#  Lv֗h" zWqvakhik^a?e]@ni@4x0[ ]X!E8 ۣ _yɊ_*fYK'pD FTL 5$,deHR `&S[a*ӧMGbmԩWq A ӠAPAb$Vƀw!Զ8rkb uؼٰ#z)RJ34,0٠)36`WJelnc}[ .N7r0ՕY9ϫ_{#{OϿ(hgǂ 6F(Vhfv!($h(,0(4(c8<@)DiH&L6PF)TViXf\v`)dihlp)tix| @i")":&:h)vਢ.ڔ JZ( X ꨤjꩨjAVMd i;ꭸʪʄ@rڪk쨻j*˺l*hfkLjv.B*m(ljkv{授z+nK+Z0D={/+p{r00;1[o\, ,t=s<\1<*ݯ8RuHZBQҖ5&ԬF>˜7j˰@7=Ѝ>tŸJp. G"7ɍ>pb}GkH;$ȆH#BPE997ާ/ lQ,PJBIy1(4k | Gx@kŔSo/[ܫz -3YLdv'ɍk?ٍrp27+_v X̠7N, w1JH W0tB(B3f&ܘGFC]Їbbh6шRgCrEjQ$U>΋e@!~_H&ZMRۢF1aX23>. 8EnbG9ղVà4t*6RFIRL*1̑\"UHqRMKɰZ j}$[bL2LWeVč͌`$Y6Zjdd)M:}|,Ǩ8ȵf pd=)rҜy#uɠję@HPF_G4,n[&·*HRG ɀzc iFΒLJ89,@UN8$NFdLQoȢ:PxBS*2Uu3꘴U$r5L_*R5v"YO֕ (\V.u𚥥QT"鵯&J 6Bl)a6,!`lg=F6NūiZPvm* DmKWH+Hߪ 0Kh{ڴJJeH h"dtukde+0@w$%h h։oh\, ;>owK :[W փOaAeXxm4VQb X+b^(mm 2Q@r+:_LL"3Ȇ]CRR."m+_t2e0#%s-f?'5˧AM?:wh枟lbBNtA3ک~tV%HSګ>3"?.B!A"+JԡFQ"&93Oot]fGYw>+|k:ޓiC?&ڟ?|vo+lEV^3kسx.orggQZ5Ss&gR)gm (uj%<";c++-annotations-13.02.01/html/polymorphism/internal.gif0000664000175000017500000000243614735537670021666 0ustar frankfrankGIF89af """&&&+++333<<<@@@DDDMMMUUUZZZ^^^fffooossswww!,f dihl0tmx|pH,#)l:l$ZX2zۯx,Oskw-Cv+={L~NJuT`;:=8A36S@g~þƎ(Ⱥ%?Ϫ HwI^1M3"\p&I#|/]'j.j\1afI^ɏ+cӠl0MΘYMGpTS6,Zȣr iOEE,jdۺ 4`AU{ ADh"V (A% P( ê Y& 5@`) PKmp-@  dPYBw[y P@ 5浥=dt A 5TP@{} ^/votdao |aiS@tEAw#A GF i=@PhvN#$h`b-́DUŗUMe%8Q?J%SOj#4U9!}38f˽eYhUn;rvyfy@l 4裐F*)) :馜v駝ԥp'^ x ŒlX+רl k|:"kG~rq+lkijFv/Ѫ)TE HnA˸b 4;Ȱ*#üI,kf/R\ﱄ  Xۄ>bƵ"LֿXpmd$ |J.4w+;k۳*;csv jʴ Ӯt NB"D_+eY'foh]ݶgj!owNM/Zm~!^Zw0u~F h"O+ 2埌Œz.6ζ݈L筻.ߋVbu/?r/x~<ѫ}%; wNpT0S#;G>'`+KKk/94ֿ\Owd` Z B;c++-annotations-13.02.01/html/polymorphism/ambiguity.gif0000664000175000017500000000267014735537670022044 0ustar frankfrankGIF89af """&&&+++000333<<<>>>@@@DDDMMMUUUZZZ^^^fffooossswww!!,f@pH,ȤRj:hsIZvzܰXȘznt~nkpr_t}zoq~djQxmf jii`{ uyxv m ff fՂN{ vu \@x `,]0 tT<!B _ [f%?Npi!P3PPVpA :4L" 4<=7GOW yܠ(X_)M 6FnfŅpᇗ(b#ax&~b,Zb(!/h8#T;XcBX$D2&ɤL^%{VYĉVfYZr%Q1*ID)&P&:j&efr)"wgmfh b?2񧗂™4:YTŢR6:)^I9iRɨZ饞!Z*&2jkx+jk [ i))~:r-RrmhزeŎkV芮%ֺ#kok,.o"nڹ.l"?j*rܰ#q^iƹ(l߯b2w'Yr! <ܧƦ*{sG!t; N[=sW)Oma3Lrjcvn o)v]wAw{mوu[NEUnL9IwKN疇<7:{:﹞yv T^,gRA 0@  AkXAg@D`0;ĀpAK9eO_/ٟ < 6CJ!CT#"hV"mƌ`U U4/izdْKgRΜ^E!dIGk:mTTԍTLUhVs"* 3رvMkiҩ+ٶew޼ -\0bK%.Gm&LY f3+NRgC6SϪz ;٩/оM*Cj3 _ cE~_5ݒύ3bj9=pM4gĶ2|UC|zeD]YEG ]Ju]L@2AIS=ǡνeZx졨֭!D=@ԉ@T߀8_Fc3X [R8lNδ!uXYfGb\%WY+2I1*W|^>>݄ˏ@⨐Z;Ҧg~6aPIt68hߐDfrkJp}I~ =h(ITJwre`p+W$*f뒤uGU.ˬH4 -CV lRbm{rk6* x&} W;o%njnAJ5U~j-osibi Xo ENK91-$qI"kn6̰>d |X˜ ./Wl.fҸ܁L,uTGu$?_صA[M[#_sk%/m,>usK=7ځ#^ۊ/9!AH.+X~?3xKk-{|lf ٫D;C1;d78ۧ}h'Jćz[dŢڋ_)|:E!BF@]aCԃRfdU3ZZ0)|_Q%kqa7*)i ;.Uӟ|0~# Xs!a h e+2 kE Q QD%^0,u!ꃭ[#TFꑉclA<vhE-ad H1^1\0$REґc< N}#:)BQBwTe6I"L풓\F3mVH^j,AL w$V+dPbDHUgaK#ȶԵsh(uKEiU5Tᴰ%-}W\=7ɭHcՅד9F/EٴlD> ]wЩn-ʈ N(37˨~L.X\@DG2#xBcUQCFV^9a..a!0H;=iڢFq9'Bks" 5C{A4b]n\^Eް̠Mq_CRdFd)tx} P۬ZSjj4DsІ4}ELU}tXmq6T賧PzԤ.OTzլn_ Xzִo\z׼ ` {.d+{n =;c++-annotations-13.02.01/html/classtemplates/0000775000175000017500000000000014735537670017640 5ustar frankfrankc++-annotations-13.02.01/html/classtemplates/notfn.gif0000664000175000017500000002443414735537670021462 0ustar frankfrankGIF89a    """%%)""-3.316 !!!###&&&'&'#(/+*+,,,---///%33/5>(88-??000434555777;;;=D=DLULUNWNW1DD:BN=UU>WW[f\fjwkwp}@@@AAAGGGFO]PPPRRR^^^R\mIff]j|Uww```jijpppuuuvvvyziwbgujnuz}ʣْ̔Οݯ!! ICCRGBG1012 mntrRGB XYZ acspAPPL, desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,IIHGGFʳ̻~; H*oÇ#JHbD,jȱǏ a Iɓ(Sk˗0cN)͛8scϟ@A Jѣ"]ʴSrJJJ5gԪXj%y8`ÊKٳhӪ5f۷rݻx˷߿{UF+^̸`ֈ˘>̹d3ۥDFѨn犡A|G %o[ b컷P7YF37؉g y.W;;5 ^f F=qA=wx!Ci%~ Ѓ7 zu{w|u1Q_^5rDG߅!3j 24m/vW.F)!^7N 1Dv)v !y%`L$-d]7ܕϭ ^ֹܛ~bhi]U\urENCz*FɦeL' P}7q`]6ѣ27%u@ ߏszm<`A]1aJBzfVkz-Z]Pܖ(*$nBjkкɫ/C`~d/z{п+0 cA' WlE,ZI 1Aoegqjf43V3׬7W@/4rN?m=SUL'TK7-u>CXSMWg;[dTcv9aהpӶLoǽ1mwxC`Qބ}vSE&Q8} ŏ7J}`D&d*>n7)j7( |7(KL_'G!Wog}PL[Gw }觯g?~^?)?˟}P0^ =`P2D kư~PV@Yɠ@9aA wP}8G= e\MdX~իlˀ0LXܠW&jzU n- $ Z8JpG,  HL"F:l$*T5X@_P NX .Mӳd*oO! +%1IS~JADIJ! j2@ҳcjZf"-Gnz{,X s7(\wE顳 WO݀U% "_G8$G&< hz h:D|abJzOq'UOJN`\:Q] % IՎ=tQc_)M} *4{NyyTTQ6;jz>`D}T)0[1so8ϹwppH!.5jqmXϺַ2yTy<~YpNxϻ]6sW$aR̗#ϼ7y)(8v =J?z698:TLIw{Yh`Ќ}XHY9w)dB x{jYd'sJ|zx~ڦutq=D`x;=:@ǙEʉe(:NڍPK9X3ځq6Жqgګv.`oXwo wIh$*[wo٧ `ࡣ' wjwӺwx)Z /ZBPDڪF$ْLO)i:/8z ؁zx:w8ޚf@h8`*wʦ{%vfъ;rߪw ZfQڂ:ɁꚯY,و3 [p xڤȊzyBQ;9ȥY .+d),`y"`+w)v q+IȭYvတ"H AYDБ"k+ Cځw!u"03؎;u1@N+^[X_V&[h)LoW; k`Vk{zwwOwo. {[Kk+oywI;+صom. 9`nljۖH8ٿ+jtpl#ɋ`8K0Q3\؟V m)+,ti*:\=kE>X0O6<0$>.4umDn< J&MEw}K~,-\>VbM;h]G0=c)X8 8jJ .B.è熎y|:Շn1o.&y^k~>=0(.^m>X̴>ϟ.߸.*mSHul. >>{w,ЮԞ|>w_ xN^{ȶwފHv&釀)ږo z,imfhQiyh 2|2 ,S=6-4}1m["N(ڡz k}FwʞR Xqiuhb½*z^˽-Ȝ_[Ւ 8(L|PZͻa۱|k٘G`mmYnPkٗ;-IYvxOjڬ/[wb;wª ,{dzԭz퉣ǘO~mv [w閎xw\/ zyP=_ڭ́ǝ'hp[}`eFCHp Eh%(I(b%Hi69(:JiYʺ+;K[Pw ,!(q3MB,GT} YQ7c$n*r%h Kf6(f(S~rœ [.{K>ݱ/գu~]VrG ֬ح(2?.nPa7OyUv[`),fc51ܿ#Jiz{E lD4D䁌u׭]|D!R.tDd<IHbW}F G[b3w(FFhbJ.$E(Υb,, Dh!s.!BxED`aqqch$,Ō!DYID^"#n੧jeD0W(聿Pعd~'E17ʋyE[pqcz! BʦʋwHtڧmc/;Cwk,*\D /[| 8\Hnr&IN) +hZ/"BW ([\AAs7 })$/l`'Ljg|ڹ람rʨ[һ,W8k33L_ BČRKG-<]\)rbEidL4u۫2keym[7ڇ-Dl톋8?C >+Dź#⊫܏ mҖnѬ/wwBzcκeK2uƐ[:`P~{0'/;4D| f<4g+|s}LJ%7?'!? /ֈ&+ o`Wt:B*#2[@[>w?x;>P$yp 0eEV:G<t%   """""!% ## $$%*(-).,--3/0.133398=9=855515=87888899999:;;;;;<>>>=D>C>>A??BDDCCLUUU-NN:@@:AA:BN8HK>EP[fffjwwwBBB@FGEEEFFFEGKFFJ@HI@KLFHLGHL@LLJIJLKLBHSILPLMQDLXFO]DPQDQRERTESTEVWNQULSTNPVEWXORXIR_GZ[IY[I[[QPQPSYSV[XWXT^_^]^_^_T_`X\cR\mKabKbcUbdUcdPlnPno]j|VwyVyzdcd`eoihiiozyzntiwqx[[azuaffklqqqvw{|ɂʥɭԣفӂԆޯ!! ICCRGBG1012 mntrRGB XYZ acspAPPL- desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,>H*\0Ç#JHb xiȱǏ Cz@ɓ(S\ɲ˗0cʜIfDɳϟ@ *HAVHʴӧP"mSիX&5煮`ÊAUhӪumǯnʝ,ݻx 7߿cLQK +^T0ǃ eT/k+9n͠;M:lgK;z먧צ~M[mڸV;;o 7|Ro@Nر/Q;mo%ӫ_Ͼͻ~x[>|iu}%r G])haH՟?^ g>H Z,~!]]zH$WK{#GCIQbz'X$~uH !z@`> YKSKc)VJ\],+L "K$"U`qAg4tGpyy`V(Ef)Wy2+`0(RKb g.X*h{""\򊲥fnd^=iBD.wGU2&J@^`yBJ'׊^i\)l^0@.3H2񽮸ҠBrI S^(IBΙ_~muY=in']BzX\b#y yRӯMXbiP\PRckwe]IȎ@ryNw.4oz@ty (y$ǿi5Oh\m/zVR]kW }ĎjjCl髇,BJ J-Q졜a (!̚B%mCq ñC ;̋} RЃ5ϯQs?_xQ6دk@SFp6^,Sˆ6V7r- $Bd)V@~/ae1 XfI<K@|ioxn#N̡Olt=*( zqWlxupE :؟>80q8"7 y鐈2 eIT#I$hA6n$3FJӡrcaABO+C#2jk 7Af~Ќ%iZts`-@af5(Kc͖ KӲ^@J0RD#k_92$7cYlf9yҜ`DRHgV晕z i"/p PA)C7Rj#/x`J&eKնdž%0Jh+ŊGwτq$ȋD")O?VӪ7mFtZAH(p&#)smph &k;$X|S1],9Xt e_^*R{̼_e>0~V^2̙Qp S&hRGόM"$OFzjG1giiP $VyA wHGGGgtB?2zVc==j^Q b%*%@)L!ۏp|e[^*m msZ|8 GFKѴg1 &@b, f7EhZv7wjn7WwRo{ܦ&P72aS"6YА/<yWr[{$Lp0 S7fAaNskYn#(w,I7bҘB._5̩-lUۺsY& Yw:춍U iScWO=jgE8= wЅTRwoM%UƙleXMnOJeAϒwDi:@mG29rxlO Jkq )={e~-/!=]o0U t;/|ѽkD ~nh~)!Al^ b6Q*Q؁ ")g*,؂&!284X6x8`~}$V0>H@XceRr&GNH-PxqRhcqrv-ed[gȃ!1CQKBZv(^Xz"r|x"jHx~ȅbш@ar׆f" $M (ъ'GX~h8oX0"(6X-xx~\HDψ8Hh( s,8Xx(LNAg0Yy ِkY<ыM  "9$Y&y(&? Ƿ04Y6y8:<ٓ>@BrP? LٔNPR9TYV9В29`b9dY@Y;@WٖnpK.ɕfx y{ٗc5=:Lr٘WI[ H9 Ix`p50 铈) )P<7i :isٜZYvgM2I :@5XP_q 49񙓴@0Yx @YX0PZx^9 ɞ{@@ڡ yy@p>PYx^٠4i  J 9PJ0 9   )Dj7X`  VZZ@ jʞsʠk C Ypx`P{i {: Ex0 kɛ4y ?UI @ mj Nѣ:@ Př 0@)I %ʥ:ZpIP :@ X଺@ڞ)ϊ : 5PMZ`rrTI>LJIL Ki .ʯɪM"_٤3٤*!+ t5YP[6% '+ٲ1 ˱Tp13 j)J* 0 `Y]+ 𩏠D `PɣI\?8HK{ J/` cjYij 튜U:% F˗ߩ :5px5>1Q K;KY +OIДU;&ڷʫ۸{ q@kʓдj{6뫬Z)ZT: qᛴԫp:9)Ca @/ pۻJ `K ,NLp{kRQZ )0{Y0Y{'l*|j[ô@ ZZ29 |EZ!KY+£; <|ˡK8 !BAOi N)    pr< "L`^Y١4*Y0p𕊜i̓@ɚc9 q@dДJ̛i 5 q?\j۔KIܔ ̔<[<[I)j\L , ` ̔~lʵ KKi3dgۜ1i|=firkYǑI%$u$uK&d {* M ]MNm@BMT]F]|cx\iHU]E^n` Smv͔WH$ ==΂;?K>bwͣX7Y@5 +7IƊݓMzÞz MXbsu e@oTJн4雄Կ Z@Y@JZљJ9zMinMԴǗ|幠y:eJ  i@۟l]]7 ܯ߷l-]ʡ*_z]]&Ly͔ 64!Chۦ6 r*u:gp` Pgkj<@pދ㠻}@Kq@"{N \Wj3~NJ =t]Ty̼L@ =k&nnT]J=9싫495ԛ79ܺIʌΗ I[iLLٶ/ {v {Ϲv<k ˰n3yj}Y͗3[;~66͞> M@ T Ÿ+^0iꪲhr>f[.t{>аb D` {_e{i˵Jɶn .ˇsюk)q` 9n M^-j i򋛴+P-Rǻۻ UҽO,û 's6쉇b;qΒnN==^;y |ɦqコɾ";nllYϔU ͢,PGLq|T@C<6IJBLAm=D Vô a:ȿ_|i-k-P܎I0;/;x}<! G"@PH?x=QD_,QF.tPxtK"\$Y֐3Γe(H,NYC%R]AgTXs'8@5 5ҨNK JQ3idY"3uJU8H F' I uG OF% G6qGPhbB'?#NPpNjmx["}\pōG|ou?Htæ"p΢%\2ŦL wT219(S"4&U" gfO!٠6AޔcA0/: Q!F ڣl?@-<E$qCʼn8?V4!;T^Ѱ/@"u@A dI'p# - 2K-p r$\I3D(5j.٬2N9Kt,3M?532O3QEС#4=3PK/ tЊ t#D5,<N39,`UW_5VYgXU rW_/NSQEVHG4؉Ru6Z v6dTvLnϭ8.ŖsWQ]K\~ _gT`a8b'v7X$[h Ζ$(6j ;wl ]HShKB V0[$(}͹i7ht۪/DxNB6ltzݵ[`عݔnh@kP4Xm#zquqdkqxHZs6 (羜XSHzh)(P(AY_;Sg/#(A xo3:5 _H'9s??x _(4{Ag0"#b@ jq1[ٜ)uBxƙl 6HUPL AQahh(Z yPWx-dќx!橄."2HeHaEtIa5D3qk_)4~XǢuMn%>ьEs!~>@ۤ /E4JD$RS>*ʈr,'RK^l` ?'Q! y7]zFIiF/`2;L$ϜDg:չNvӝl9OzӞg>{hӟwqHDhBP6ԡhPV^F5QvԣiH9ʅk\@DnHlZI;B葓"TAR"h2I-hӉSD)0Ev@LDu թ6`\ShM"URTдxQN U&jJ?Ҏд PQ:AuOm5;Ng jiTƲՙkE*<6{5]Wev%`gURNVkǖYiv՜hUV"o ܝVvݪ 'Y1wq%qg\h~]uZXrlǖލx^`7DXp5aw Vp'LGm4]/qeS`nw*V"X7Sq&LBrOFh|ީxB, ȻO: .N6ל6TnPe=  C'QN;X:ӏ(p#OFDndJ(]؄mamz5.nu ()>rV!54!>EQ8bG1H$hBF1b-ﳽÄo1=ʪAܓ L<;.Jb@a/k@ Ub2ad69&;w8ߛ#W$: .ßO?S=):"r=(P'J]X\@'#;=#P$$[N[ A\= t2u벌k?.9IRAe+HHe[y+'4@G)<6@ T@%ۄ=pOh2O LMh:±$#;3# q # LYAG㵊4Lu#= N(+@Fc8?nI?fd.#=p9;9 `;z2,|ल5TJ7TNzq͞N'@(N;DVkN`=I^p4Or3HN|  J%؄U'R?hN>2WW%P,E$==JPԃ*uiM=81K8KWwK?eu]vw]4QR݈:ŵC#Q=ߛʁ섿ETJ|)˕`"y{޾KDKm̓ P[?SM\E Plշ%LΤLLdVFv4$ JN ASsN2 ֈdK69\d e匐䎈S LdU`NneG~ep[&fDNM^fƫbF;JfYffv_ %ap@X)ffmDguZgSNe]e^VfxyFŖtdt0gPz豉h茶#uRfbvr牘e(t闆阖陦隶ɛ靮Jez¦s旔<>Pj>pj^nꨦꪶj~v;ꮶ>jfjk6>ԣAio2f"-$ί%jy ,4.ש.F6!*)il EM,rlhl ʦb ' mFNvs*Nh~hm.,֜ Xikxmmv%M- f^Vno&oA֠^N>ŹnN* `oooCy.>1ofOG nֳ p)q_ O*7p7ל qH"Po %Sqq ?a'rt1'' .r,MBg3G4Ws(r(9:(?t}"B7C1 FO gpJq r0&.O$XS nRN62"QnWw6OY 9Rp]eub['$Z?jfwvPdw eqQ+kvh'Un_o?wl_o__a^&swY"ig)f{A.kHYX$ygr؀)`xmSGwEw( H)HrDbр`%jo, IP XxX_@h~zz)@( ܸV_xR]`y]Bg۶Hy{^ zjG1kz j ( x"O 8 |[*e |%煮1Qϖo!aXay1iϿmȁnR/|s}ar}lRʍW~RA}laya}/w=_ f~[LJ=(PO|(o}z/wڹ~^,h „ 2$@Ä0 2 G,XAŋ7j$H0c8%8J&/9#.|!(Ҥ(2m (L1>jO/h)PG xz1SY^7 К(e D@Z^gGJG <}U[鋰X]LʛȒ'Sl2fed3ОqKS8(  楡1pj8;(KƏٵ _ԨMS;Ǔ/o<׳i֓j`?_dl`̴A @^+qt @ `ƋB|֜F0_Renܵ"18cڊ9Vv="bx$I*y($U?" MYI}M.di! WNfEB5'0i^{٧zh ZIfzfb%R(i jh'ޟ3zhwhĢUhj*Bf*X'_ RC(5wD {2-j`r^ɮw Kǂ,&I}zGrɪU:/WͪiW ^{h*P;mI(뎩 !ѭx0k0j ä&ޅI( J(Hp" c2A P ,A=c㽔 Ծ{+f۩ӋF-;mzj񰗔|-M.\-#UɋeoCu/ Ti&-iL5} '5*k֍G yֻ‰FrB KI 7ZI#z_KB]M`EdpӰF Xbnpx$ĞN+{4t #퍸#~||1Oe`٣O;9=~\o]H\h`[h :Y0؜XPhXx(!rhT1mr ɝc ;A# Cp$,E* I$1Me Up%ٸ2&&됙e"pYb%瞀ify fP ('虉&:椟ae~(^J䣛頨jZ)E*묢Z뢙J[i(J뭸}z졶!:[Z,R;rق;ۚ j.Z[5ڻҘo,{!{溢*NqoKqpGQ1rCsW"%)HFt 2*;yrFr(.BS",L%B̄Bp;/tD/a4״OLLQJߚf 3vc p#]n=]nΫ(v6wxupgt)ί_jiޮ->\=9эy斟|.x{d~ݕn]n:ikv;8g1/zyKoB}:m?|ѯ&Z|z{νԙ_Cu}9r>a|sߒ=On,x *.| l hv} 8B}4MHAw3D=+ lA$*qLl(JqT,jq\0qd,ψ4;c++-annotations-13.02.01/html/iostreams/0000775000175000017500000000000014735537670016622 5ustar frankfrankc++-annotations-13.02.01/html/iostreams/sbbuffers.gif0000664000175000017500000001461114735537670021275 0ustar frankfrankGIF89a X؀!, XH0I8ͻ`(dihlp,tmx|pH,Ȥrl:ШtJZجvzxL.zn|N~|KeHVIFG4E"Cı ޼ڼ Wql!p HqTBr 8|(0#=VID EFH#0c*:1%ȏZ|)O@49ReПH9&Ħ9T7LC:%e8WÊ%!U7~:[.eJZsmڷxR"ӍP ,oT;'K o*ǘ3ґ%9ɻҒD*1yG A\d$Iѕz^.4]0Q7Lu4e/5{t1WQVSD]2vJVқc4#JYƲld6UͺuS7DN2\'릩@li^הv``7Xt4 B+=TFk8ۺYv\Yku?;>b8,OaNնLmb]X6:mSi[&Ը`E.4 ӹ.!Y٠Zwحnv[&ջKV ^ֲ U.YqkvկtAE}^!2n=;_ٷ5-{^0L_ X &mo6zݍolE\7o0U,X qG<pZ8%\a";w` {YCrE1`a\{\1ms27q>t=/Gߏ^4=AOM53%,6ULYu__zإ>v3{ׁ..4o'{5GX?o8 G*3~Yw9<x<6^7OxrV6Wkyt^oj>AXTV}INF?;h{>`}t">{?b/nOw~Կ w*Ax  x  5bw$4h)[0{Ò0A}a(O+y5'fb+uB,")"H; $(8H-j)Ѓҁ^!68%"|aPqr+W/yZԢ)C(it.FHB'*G)f Xy8e%Axr,wcHLH+R؅5l{ ؄S*[҂Pp^xp&HX Hzgz}N7@8XxȘʸ،؋Pq-g/X#UqK"/--( 0Ȃ,cw2~w!+9s2)&x_Pݢǐ 99Hx(H8&%*b#38w:*g07ؑٓJ)+KXȑR$Ti5IL[ "!fɕSinq$jk ^ɒLW0s/"@B:DZFzHJLڤNPR:TZVzXZ\ڥ^`b:dZfzhjl:/a"Ѧ0}(X/r0x: .|Iy~:3מ~¨PqQ,ىSj ,O7"xB|)AZ*$(uzZ 8º Īʬʬ*͊ JNJ\q,:ʭѪj*犮jJ ǚ"Z@%1JY੗Q˰  9rbXພ {/x⭼:zڭwuQ+' tz8wLwj ʳYF{L۴;RK[XZ\۵^`b;d[f{hjl۶npr;t[v{xz|۷~;[{۸;[{۹;[{ۺ;[{ۻJ};[{KrSCe4dnkqqCSomkSkDD[9lklۋG{l=;q7Y;l<Ľ{nnږq?{nhg|Ŀ+ [ ,9|f{˾߻EE|q!\9fH < \T,qlJ 4,AL6m^ pOnTG,pULp*i ?2 ę=TvF- y=]_,a?vwȈ+,:mLlj&bk ɏsȍZȚ|[āÅLȒ ƥ@Ɍʝh6Ll|ʢlʞɬ˻ʨ6˲\˴qL8xl͌ż\<ȷ|Bl̪L ̪#&lŌA ϭ:ŕ׌ټ[7ƟLN \N= L<լosl^Ϳi]M!dS g|;(,};|60 1M3M5Ϛ+):2mF]|<}$=֡[ F - ֠L̀ѓ|^=w"Q&]q}sm5iMOa-צؤ MO}هȍ-؏ّٓMky pjd -԰]Ǥ>ЉmۋmMoہM ܌kMz}xm/TMKmōݪػ-րS=ԗ\ݸ}ݺ=׮ĭ m6RMmޭD]- m:]Ԣǭܨ^ʓW -Ն%}SM#2q =~B@=6< ? -M:GI/~#MmN:8C.TNqnn>l]}N1N3(ޭ D>Au~V{ynݗʌ.>塎ߔJmZ`^.hj晞;>^f>W~Kb&.>^gNN[~؞nruG}l. Q Tz W{랎.| Nht@uT8x|>K t /v 0r_}/vxWw~ 9x(?02˕1_}(uؘhy=TA`yFLO%Gi7 VXC/#4K!~M]/prZivOs7.^k]e_Rߎݗ0 ֗X:Ggos!?,H0|ɲ |i*8`,'g0 oot$),?HWhhB*hOyXx9 7/&_-*C;ʾ^ڋ޼AH扦ʶ.(L=ŸGMƄANK*W J&֬_K ZW;}8W߹'8ChxXبIy7Yvٙ**ZjBzZ +;K[k{ ,N^n~/?\֔J?)S@@ F:8 D`F)al#EFY{d~7 iNJi^ini~ jJjjj kJkފkkN lKll.l> mNKm^mnm~ nKn枋nn oKoދoz;c++-annotations-13.02.01/html/iostreams/ioclasses.gif0000664000175000017500000001434314735537670021303 0ustar frankfrankGIF89aXX!,XXڋ޼H扦ʶ L ĢL*̦ JԪj Nm '8HX!ȸh))hy8U):yzJg*;Kz[[š+k|L<\ \X,=Km .m;NyV-D_~0`~0T1b =1r^}wQȑtxɕ,CPd]Ȗ4kN;b4hti3)MjB0SSαzҭ#9IQʘ&ǒ-UVgr}kVb!j2M*7``ୄIY:n)œ^43f{Sѵ Q\Ɵ[K\e vjXE]V0K .q̑!Ojy齞_CP:;^P;C%zvU|{L#oɯ5 x * Ja-! :xW2!&]<za}h&^!b)8T2p3޸ċ5cFdBId>H.)L>yR6e 9ie`epe)ffinf)g.ډgyy9 |I.Z> N^jniBh*jʘj@ꫯ*+֚ꭸ뮢bj챔&,6"*Vk-fv+販i뮙+ziZ櫯;C)0#)/ԁCRQgi(o,R΀$K)2}'lL|.C~3>܈: ij?3="82ȹ^05a,`ϙjwZR[6좮avjB_DP^OI S]x]#;#?xՒN5gw,CvG@9˽Ky 4BX3^u<zY}{Khú޻O|o.}'[|,_ľ=dmK9?d? tžuQFw@}t׀BP|$a=r+Yl(& j{kW F/ro8;΃׳_D-^4&L\ Ґw#^?N3 (.r(~"HlvS&s'̨Ґ7bاQD|{ݦ?rFC1"A22z(y!KBd_8I`{<"S-<5"gbSF&خal89sB\g:Nq~F;HusD r@7< E`mA qX(|Y4t3D(GaQ`7@E/шmc8 b:,|7%FPb14\tDΧ(M1J3P=Sѵ=^T V:p_"Sֳ2̩jNѪUNqMkAfӹudM"_ʋ>ƭK$j^W9T2֭e/_"1gzА}EaTЩtMbk]j^–l_KdCJmVprQXS,kMܝt2֍bBn ^Ծ7̭dne/G^vMXӖ׾A.7iS&شt wW ,e_>4EYK]8+UxׅXĠ}1ZVXx%_E.1 dzS4ݙv D^!Z.rQ|]&m0(ĜgfFAAf6 ssPg*Ywϛg;Cn9htm}֢EZYg*"LwHT!U2!LnGcz~`LezAl.ʵr*<tLկg M;^-w9piO;N\ ~;c]*>bnOWQ2AWh6}Wo~Tջ;.xBBF;\N\!͋N4ml2$kM#9.{sFc9;G͏tr4zS[տ4u?]'zٕ~v@aoKbAWL].Rv-ƲIXR֖]?ċcjnz|d/vQZWm_q1\W oܤtuu[aPƼ_N>NtRĹ. ,!g:^p6 OCh_1׿o6}ysg}igcxd'AL7GH{w~L!wwBg~q}zq6xё(KXmHs6WQTwUl(;r{v1x5yuؽ{t<H[{9f1{{aG쫿'v\Y (~h< 97ڪ{ w{-`zCPz 9%x˽CRVc{GG4ďxE\ yt$C13|G};ziܿؗ}ʷ],hILme[Ŧ‚q,#\zLl:h}{,& {ƹzjL'E辡 ɝ[P\ʒȟ<(MʜT Ø[ KǚˌBɟ3s'Ȉ ?\D<%Uƫ\F\QX ΪǺ,~RhSlBی DZl¸ EH]6 [ } "Ƹ\%L|{Xʋ(*&| <+}_r}(} lR-͈ =}{b,Ӧ܈&u[#Kk[ȪaiMp=r-֑8rxk kl}jv[p{ؿW\{؍Hu- {ٗmيٝ<ءPiؠm: ٫}V= ۱=7=յMўMگ]s ض Hĝ۰].i٫c]Нܕ8ݦzƝ}ݡʭMt=ޜ]ֽ]ݰޗߞ̝߫ܝ|Y# --߬ū0ndk0Q5j$5R⮑u⸲X5R/u㳲㮒~p1qrR\[J䀑26q5KQ奲2S’r+oO,huQ熦{n~;}.&^dnw6~茮NNBnn䍮RNn\^ꩮn..$赎屎 뻎hNN%N슚yn뽮1>Nh΋ٮ@@M.gx$ Ngnz PJ?O ?Ϻ"_VU[ ́Mh5-ЋNOl̹,- ŃX68\;4Їζ-OH4 JM[vӬkL$lP]R= Yo#.Euopw{(} o qOyo/?oO-&F2__/?ȿ"үԏoO/_/o?OSF9igy ő,31Еm噮R]T.M3sNUH]cV_ks}/gqёCQrR23S3rT3ԴiTu56V!7WwW6X-9Yy9u8:[{z<[|>~[ޞ]^_|aB 6Ԫ[]jkX$qiVkTekKlq%ޒs}3PWy`ح~ =odM&|.ˊ73|RrhJwӑ{l鼂IvVtlG:Iƪ_c,!ܵU}2fΫ{e+;c++-annotations-13.02.01/html/intro/0000775000175000017500000000000014735537670015747 5ustar frankfrankc++-annotations-13.02.01/html/intro/objects.gif0000664000175000017500000000341314735537670020070 0ustar frankfrankGIF89aؠ,ڋ޼H扦ʶ l" " hL*L JϩuܮWT0ޙkK]koXh ub)9IYiyii():JZjٹBx* k{k+{%S ELX*< jL0" FL=,< Fw^˽^ξ]>[~ iwmpx)C(N]@mDRx erMVx#l#QpJ\n@v nfsYlIgy^ h~Y.h2jM@'@i2饟*ѩQꠧ*hΪH*D1ځK,RXbR΂-$Nܭf,V{U-96MLyeOAt;o 5ˎ1poI4B.ƄG!-eG` !\zsoI54]Jy 3hn \q|ƴpiK帶=5M VafpPniu[φl J1+5gWqY4]FC.6vetҍ6[Ӷ 7d3TAv_=&P>a228d*v8 *Rzt.\H/{s{4_>ϔyzS_8}z/%_Qr [lMKnh@߄ xT*V<@J1P,+-yit7 V)4!aB 1$ wU0979Cn?aC_0ITbeቒ:" 8)Vd"ɳDCmW]HEWegF:ciU~{@GH`QQK" y%9r\&I>zl^ԏ]Jhn,+(Մd$rq$:Y-A1\ + 4LV&Cl *򂹜mm23[$ 0|YCLJ&s8-RKvs3x'V0Iқ g(7ʥ-E9ur[[^7A33K_z%=iOנ32TZ)ǚcبlʔjIm9/ؽr`%uPw:vNwJΗ\jJe_'#:@QS4 *- ""33 #$$$)))((+)).3""1++3++)3"7ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km, H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟ@ JѣH*]ʴӧPJJիXjʵׯ`ÊKٳhӪ]˶۷pʝKݻxk~ ,p0a]8a‡ Ƒ+ùϠCs6X1҉z既cLڴfʦni¶':5ᙇ6,A wqسknp'{'`5~wNO/%th`C)w|d܁Vn߆Eax Z(A&yq8!0ƨ2hJ4^Ec Ax 񸗐1מᦠHVr*JNca灉^{ h噤6ߛp:`r,ɗ|矀ʧWZAũ(N(fbhs j}Z&nf=NJi ide]F){Z {YY뮼+XZk̺B6+W=J[JfN˛+-\ꉞ'ޒɻ+vw>&5,h/܋U[b,MgZ Gp_ElϭZF{~ܢLey3ZM~\-7{+?#mL7PG-TWmXg\w`-dmhlp-tmx߀.n'|+G.⌣Y/gw砇.2L[^ꬷ릣n;9\qNK"?<-Oι$†;cHp0 C\!>0}9".tBCx=W8A9@/׽߳x>s+_-}zRlf smH!jabha8#a"̡P` Iȿ"2`o=a暷EZ\\1g q/V xEj9[pRb.Mh0Ld!1O! e:E-Fσh"9: ?%ΰW0*XTRvt(YIeo9p]NnN}3=L҂P{f ;f9^RDt:wG[x_ιuvWW!hΜP:+PM(@j&:`r( `@4JҒ? ҺT,mhS23=MF?KB;[Oust95*O/ԥFBe*TӧNnUU*խ-IТJֲhMk Aj\J״5*n]S'׾ `KM,`uzצ5Mb"L,f7+X6v)C"C`e FH"bٿjm$15},LJ7p@ -: E!/@NB|u.t[X/P_ XxAB@ /hoAXC!hm΋~7-yW"aXCV!tWUGB6{ WߒUW( H'nz< CX@ eZ:liZIX0ilc+B}!I`!5D㾪.+589ęDcbPKEdF=zW9$Tlτo`BDXq[ _8,󻌐#Y^0$hbF05V=Y t2k BīhBW_l[zl/7a3;*NĚ^x%Ҭn5?,ݝXw'41#D%`mz{^%./x+ׄ ~p>5$IYؽsh|qK[5} C8xAK8fD~ܖ XqZOue#I(ѓJ` %Fmtw $ӡ.ux%a&-AZR:NtF_; .aOKLT8%B'1qL톀Ɣ>x JneX~~;n_~qFQ^-1K_% kKݙ aS7=wޗs͓|_e~qCx!F—vvkv&/vGt.I7~ɵkw5sA~ Epx>wXYWQG؂ww/HȂH6uw姁Uq!X[:wLX)N+8/<ȃ77F0H}o_w g.j /SvFwpghw";a~zUM؇~Ȅc#AgnQ4t$0'{8 I@@GfNgGv0{${H@jҗvw䗇DYqf0h2xzYbUW(Wx @(b%9nH9׌Xq|0}P਍(h˒Lð Hxk))'_ȏ,2OÎ혐+[YŐNEbV zW4i/DYZ5[E_}([\|%4')#~ee`F^^^WH9`0^s_)XU^_]x_Ey}` `%f]֓E15[6dd]v]9c4iClW9 EvdIr~dtfSvhWe[f7!pui&iՔ$c)h̆z m>hh.gv^vhig$Ù|!eU&s~FcesfmÉ%X&yW0IV|5s/rU]Js;w[)rƉsrXhNqvo'Q 68_9~i;3H /H,-8WLxue@k ;mn\T(xʰL<ͷ4xQ<:,|h(]._8VxpX(W֬vϪhjܛ UB; >S?$@_@=֔9= Tԣ,v}׉r9A$BLDF$C+TL/LMCpDڣDA4.^ q gAgePWP !,..>@>j!Sh- ?`L&qM6olTeV. >Cb9c?@4>V?>?Fg}. O,@P NʿPPPӯL_D, , f ۿC ,0,O , Qƫ]łfp‚ -(0LF=~RH}DRG?~V #/^8ТI^98آ'M6pjPALf-E&E3(648ϞdsyQJF@ub7 ~.%ADž<9Xe~-l) |胱&΂58 օ_Sj0vӞ;7r/M6et"g ͑gNզE Ot|;?>z <_r~ 05*b@ (J B H@740@ C, DS1EJ2螳1Ǎӱʋ/(;DR!4X>O?Qƃ< [Ĉb1D/#Ž$8O|3FU,PC741Pp: m&(Z ## (Ly &jRnNP-UrMk|Nl(4+ĵ54۴L7^a>֢ݬc5³WhsOf5vσE[C]:rp` 8p6;2(w9{կβ+#mr!W&XOW ,.p S0苅+d D>6" c5beVcu+"ca inY%Qpi\,^:jj՗k;lux'xG>y协ny矇>z駧ݫپz_'|Ϗ^OR?ۇ?~秿o}ԧ?ЀD 86Ё=FЂ`þqOaE8A zP'Da HB Ѕ/aXx І7afHЇ?WC ш>xD&6QIT 8E*[b^Rbh@/.cDcwWF3Qo#83юw  XG<я̙#GB9!Hqdd$%Dq$%Lv'EIHPDeKiT$)]9K2m8Yҗ'ezKbj0„d1iM"p˄f!f6Mnvӛg89NqFs~T3ENvӝg}ow-vB=ivAob 8BNCŷIp7EmC*Ut"ZrA|)_yɶ t*lj({yA_+ZeT/ i.׌wVavUun%{.=cm>P$'>S3pt**(UCxab]g< ɃG8ճAx ޟO}GV_ֶ[PEd/}7ߧ{+~VGJL?Q8~W?/ -}p?={?#$TTԼ 3kL* > \< @4῎@S?HAh@AArYA $#ASB`p~AA*A? r•(žA0#BJ-9:;L,,$ȚJk4qEHH]a{*;-,[u4+۵Y(2!Inlʥ(142D-D>e4'ɲ|F#HTgI4o Ǥ$ʤ4FKI49H֒4HNYb?&LЄMtFǜLhFDŽLLlD˵lLMKL$jlK$w+wsԺˤH{-L4DSLhbN#4# $0Ngf4#NdN#` Mi(NԄ#0##0DOLh4$#@NfNHMɏ`MF1̳֤&T5S-]5M[W8cLKH܄fJ(N0Qi \܄̈́EɄ LQuNuO Pj)uQ^c֟^A?x-3ݼzs b"-]Bh;(=)9*"6o `G`cc#R05&aF78&9:.a?a^ܭ⤹b#($Vb?`b'F*)<`GH$Aۅ-b^O=PI>c5\@CUD@f1Q9B.(\pD3 &6i0fbmfK:i.iNi\*li >3p袞蚾hX_8ShhXjfja8XjUw$IΑ֠&h.jahkNnk.h R؀h hSnYh&hfPhh0˶v# h0ŎjafmfR mnmmn>Rhnnk?8iaxn.kmfVj~k^ooafong͡Y8Pvhgpoh o~m N Ơ.`gm mRqYpmi%,pBhj*_*kmhsfo l/&'Z6+^~q?tsVfNq< h@HoA'pD)nIiP^7Mf;WBPWuNtw.SW!zVZmY v^OL(/ dO(Ux1vv$mY_k7qTvtW MpW+lgr9Q|/wZ _yq%{ 0ttWIxy41vvO}ߚwWf"x`S`4' h xԐypHhgWRh` hww?1G00 P ƨ { 7`0Ո ׀{֐[ٍߌߖ7dgg/ɍIYθ  і|y j7\H51!<3Y'O8 xOEzŇY^ ] Ϳb/av_ gh~?D/0zOJ~٘(˨9 Ňi`BC D. jtQ 5 E@a"G,i$ʔ*K"@%̘2gҬi&Μ:w9ʠB-j(ҤIAl)ԨRRj*VJm+ذbdž+ڴjײ+ܸrҍ-ޖz/.l0Ċ3&'Y*ɖ/WۘТG.mԪW}5t=m6ܺw#7‡/n8ʕn9҅.n:CN;Ǔ/o<׳o=ӯo>? 8 x * : J8!Zx!j!z!!8"%x")b;c++-annotations-13.02.01/html/sigfrank.shtml0000664000175000017500000000023714735537670017473 0ustar frankfrank c++-annotations-13.02.01/html/coroutines/0000775000175000017500000000000014735537670017006 5ustar frankfrankc++-annotations-13.02.01/html/coroutines/coawait.gif0000664000175000017500000001660114735537670021130 0ustar frankfrankGIF89a %%%---...555===MMM\\\kkk{{{|||..==MM\\kk{{ĩ˸!'! ICCRGBG1012 mntrRGB XYZ acspAPPL- desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,@pH,Ȥrl:ШtJZجv]xL.zn|N|Y|ntqvڄp& xo co*|oÇ{ŋBD619RcǓ? IR! -1DIs5,cs:ͬIM59VA龡E:&iF+\ Bhu]`ݍ7"-!ȭ-7TxAQEcÄ,ta0H0 Dqg*fǕ/_KD ML@0qL?W8w7L{$pD&JPuk M$\㪫+ 9Dt~⵹ڷKm&g+O*>:45AO8Nc\Wy%AaAi!bI$߈Cp0Άeubx /^]8d sfe`@A8$;(%""zCNA5^8/ yhp/]w99(N(@Y唀BWf&i}Wى%X)9,gtZ ~j"``Y:B[WVڭ&p*a}֬-'Xnz굃:FN#X_gvhXvUVhn:+L!쇶bX¸mɉX0{3=#JaL/d>' MW=rPG5_VwY,T{m:O]S`1em8i-0wNzc˷߄w^&3N}S^cn曏عnz|nۖE8@R zx^ "8TTռ9 ,&8Aу֗ٛ {8@՗/><>@$ : @}.yE\@L` 4`}A;p`"؀9<\o3  ^~\ >58>8o9v*L sXwpA+.0$횷'6: gCI5nS &El 0H-6Z4 8d2da:!pI:ꩰzGJo#ɱD<+rdmRKNq(Sy U`L2[X&[06pL:xγ>πԦ`P-R `C'Ѿt=CCtUZL{nĤaOZrfĨS+'1EN$}kO`l29[ס\֨9,@P,HR:8n:iRLh#BT9[. U({ :"ƎY1$ ; M"ًlIbDҗtvMwiZ 82, hL)$g0'=pf^̨\xVC~(`{o `$9@p^)T"lPPѼi):@8(mNwp8Pwۏq@'I{ώ“fqtn'! r֣8u?|>]+EƲz$e DhJF쨨xe< & -A9Iv 5|vTXoJ6cs~#Zy9^ Ph[U?2).jt4B*#A2$Do@:" &@#629s<3a( ֱ$8/rx)GG,]$!8BGODTPq+dTpJs{hȑl&jr/a"!A&`&r&M~m~B|_R&P}bwQw~%{"2&'RNWaWpFxpvXU?(wD(fwGS"w(/~&prq㠁W&7}≺Vw"Eϖk$l;HOf7F/sQ+́+Ķ!sAvkk߷2!,&Nnj #~݈Fiv8+8BohҊpUETj%UDY0wFJ׋p!(/?g#r(#.+Miq./r"'*.qbV:Jh}B'ARU^BCB> CՇ'q9' @pPofAꀖ:kaQ_0 }#g  $}Y@Bxj9 _Yy7-wr38*ӘlDcޠ9㙀 $PjB@L%R-~IB@T}ś AS>u&}` lj TUyjЩҹRd؉cGy81Wy0xU睦mYzWIOwW綟> Q[ɞ@sY It :~xZEj?gjz Pe'Uy:z+Z @ʣڐ#FPCEzLj{6Z8ڤR]{SSڡ=j?;Х^z`Jqb:Zfd^Цr:tZvzxzj_ef:բQ9JŨDeTd:3i QI::`c#7֪A8aSj bR]AĪ|pj9YfjdsbƊcɔr*qdGPڭ:5ac׊cePî!jJdՊezjQ:dS:Z+a `|!jPZ[,[6ڱ &Kf5ѰXq.+frDʲq)+'<ղ8Z=˰:K%1KP?IK+\B M 6*Q\OUY[0[;]W3Tb:P꫔F(#"#`qKsAu[y;5_Y7jcBfZ&{ ;+H!s[w4芰{ˊ J @dn+((Kr{ quK bp+˻˵$ jɻ"˶Z%ػҵ|+ѫcPK{+k۾k[ 4ˋiqc!&ijV|ۮ۽:պkK$[kū雿,kl!&ꮨ1'ǿK{w^ܻ+~ š+ "Ȃ\.l\2̴ƧC˗Ycd+ańEKGˡ̟ %rͽ||Ɵy8LZ |ZÐߜἶ ̹ T{lmL`ۯ 2v-3|c - %m]*/3 3<9e*}JKɍ \Ն'M)}< ՘Ъ`] bmQd]ݜ_n/=pXgi= ~{תׄ}fO-؈ˉ؎͏!ٔҕ}ٜٚԛMy ڕ٢=w]ڂSتڬڮ A;c++-annotations-13.02.01/html/coroutines/awaiter.gif0000664000175000017500000002432114735537670021133 0ustar frankfrankGIF89a4E  %%%(((...333666<<<===DDDKKKMMMUUU[[[\\\fffkkkpppwww{{{""..33==DDMMUU\\ffkk{{wwęę̩˪ոһ!! ICCRGBG1012 mntrRGB XYZ acspAPPL- desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,4 EEW^*\ȰÇ#JHŋ3jq!n'ɓ(S\ɲ˗0cʜI͛8sLqP$w JѣHTPPJJjQ>ʵׯ`wb@سhӪ:VT٩&N-wQ6|A$^EaeZ?AmEi"Ct.))[i#^t>:Z e'Ȭ?- oΙ{wMN` G.Ӄn>UyxS᷵Urg9Qn:CxyMƏYe}*m" }ygB_I <_Jֱt(o.('g'֗ AeB4I&x> "'b%H7b#n%cI)v^I-($x ~ȁWZdBe.p@&Oā $IgI%D"҄Tr4pXI'jBq>X( J IZpP:Rg>(j"dy6I.p(Ĭx: 8^bi@N Uœ #*9NIDQTzF4pZۆ9>j'F)$QSI*%gINC#ř$_cDL`UEd.{D%"!SQ1Q#i{W=5m~B9yxsDך>%~U-BΈ-B3Cq4'IS34aUNCX@FMRԨ 8հ 0Yָεw^Mbر[y8 * j[> pn{[Mr#];+nw%ηQ {|Eps'B oĻBE|vy{f?Ns|#/qrhyaNjȼUιw@ЇԼ̕d;6k{饐A( _S*n.{]g6 "8׫1\p(R0! `:X@N{0\ˮO]i[]ܥ: )( "`N(@!bߺ'ؓba> ⯾uC {"Pw8@w5Y0/V~|Sn `B^[pg|8Wz@|Z- -3 FxGzuzgH| ؀Ewg{t=r00uЀ*f ǃFo ChVx|*`}+d-rևx@ȅj|hz(ex@gyFrH 2hUj̶o@׃mhR RX}E0g5 ~DŽh`{;Ppև| :PR'gC@{?Ѕȅ`~~#Xk ֊󗉞 Ѕ"Ȃ pdž͘hWHtt`׍dpT،27jkp똇z [fרQW hQȁuumX'\V(`xrn 0v (Hבm7+xr }^'}|z'~19P}#8췆2ɓׅhpoXF{2qX"(4Y)&{KRI h_@g jM o@kPs1dᖺ(i`w֗juv0i WYyWhiREЉz)Yv N Pk&؅.9 ,Pk)pȌMoWw) Iu [9,Hv Pw k߹Zrp%9 Im :7|p qF8VĐ`* % e5ڡ,* .(!@@P00 YD=: 79 05EХc %PD@!00XeYڂ?u8 zڧE@ su ܅\^9@Ed +ꞎzdz]J] jw :{5PC P@b z 00PNZDw:{dY pwѰJj mHz .IxEgJ{ڪX< ?p:z z{Z8p" ;@ *nhl8 :Ѕ J`Iع 5, n Nj9r)j 209s;[ VG Cp4&״O @+ /0XmZ۳P+{|gi@p[wIl 0۸rik8;0]szP'@;;Jw 0 * 8 m۫ 2ж|I9 : {n눷: ʐ k(; E!P@Ep!#P*6{?㼧yq 㩼(;p 9dbbzis7}ߠH [<7 *[ vgC '~/\tǓw/97 5P@0z%|(!8uFZɁA- mQډ#8H`0 is!7f0x ;:(ln\uЫ<{s/Pݍεov|];vuvc״0]n&meRW/ 1 Mەۄbx 3q=my3*(>ܢ9 K H K} ;w ÅbM; \xFxwpr@ ƈȯ,kyGda<קgX)Ƈ]]G*gǥ'{Lٖsj qIzom{ǩ-(F4m{l)q4[ٜ8n<v4xnj]գa=xJ08\S͎~ٮq.ůp jEpznյ%>K~p~w ,cqM} FNr]rޕg)U.T /np ?߅ٟ{)Zރ78j kp^OэMJ*E-bqunx>}: :q|||Y$Y*$HƜnO&`n脙 g}/hXz_٫~Yꢞ` <]*q|`u?)݋DnuDf`{ğop+&/oqsж0GO@ڏp 0P2TDH SH8IYi(yIx *Jy0Zpq*00x8 jhH[ډʩ ,XZ:S)ܘ+<YH݈=.k:ʌ9B`c^c`2M8a?r0"ұaTT`b v_6J2bЩN-*'&!rЂP]S,~ETD(SVYP':s`?TD-׎JkkHG9dڢ*\o{ɥ[ײEvj.2m5hn- \ȱcevOք ݝV"~wּiʀ<\⓵_z,ʷW[0ǪB-$ 7a Bz*rBY|.6^+3KBUބta"e8! v!(yX㉨"l%~rbHc6ވc:c>#w-'1'CJ.dN> eRNIeR3wEjrd^~ .[^ef&1Bani昖 gvZ(g%tgIIh:h)!k:Ji@ꈤn)(62J#3>t(- z*s7f5l}K) p^^f($~-G4m^j[ЌE+K/ r oN m pYE@% V> qOLq[muq r"j*r.Ljm*c._X Vy)Iit#Jtӄ]sHM8JHL֍ו=re]4W7NPFg@ 4!6@B,YT|n~Ap7V7pI^AԇwQETzޢ>Q R)G|J!/|$s@N(#Zmgz'Qov5 l7M| "R-PB(m `B1C˓R+̓W:4qJX#!UMOx 9?m"pjc,29eҒS*8aEYK$T t#8 (rG"cyFAp[$:71-e.u.13pb8^Q<z`Vt,y8Qg$-IgQc}m1 p$҂,e$%{$R3_YTR=uK0M̫RJµτ jGg37Dh g/V=ŝ}oBSYGLiJkkj|Ԇ; b 8$pO xŕ@O!x4ox< yD.gL@;c++-annotations-13.02.01/html/coroutines/context.gif0000664000175000017500000002522314735537670021165 0ustar frankfrankGIF89a<$ """---...333666===DDDMMMUUUWWW\\\fffkkkwww{{{!%! ICCRGBG1012 mntrRGB XYZ acspAPPL- desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,<pH,Ȥrl:ШtJZجvzxL.zn|N~ H*\ȰÇ#JHŋ3jȱǏ CIɓ(S\ɲ˗0cʜI͛8sɳϟTP@ѣH*]ʴӧPJJիXjʵׯW0ٳhӪ]˶۷pʝKݻx˷߿e0È+^̸ǐ#& ˘3k̹gɔ_YLӨSհc˞M6֭^ͻߠ Nmq}vУKNسkνËOב'A˟OϿ(hzl) sf1Vhab ^!{iI W: $xh$0(4hc#E&) DiH&L6PF)TViXfrhae,`hlp)tix| yg1"4裐F*餔Vj饘f馜v駠*ꨤV@:h)Fh*무j뭸zoJ᪥$k&첝"2kf:ۥ$ܖk覛#[aIPH@ヘr[++bgZCBpq1+Bn o0\Ѐ#]/aw-p-_>vo<ᓚl)y)d^zrnn`L+uT} _@nKmĹc\A`ogɹ 6p; m |tc@7O-3 yݚ'$w$7 *PtAs@x4Ҏ(źN=\v3Q:= c&1h1\+\@nEl& t> QDd_@mh$1d&.yQ&$ ocrFh,FM+T# HBw\"$cjȖ"'!6@ (bƲZSGǭQ[+Ɣe()Lb{&LVk\<7qf@1U&3͉=mӜ1 j¤'<(|Mա]*{Z5;- D-k[)QwB" &V X$`8`cꔀF,N jQ+Z^rw0U`R#σr;iI9%SiUӺP~HΔ-b|P%IT)TIFkYIQ ݪ%NsL| >f)eJZV+z^_X,YekaM3g(Z״<-B-?`lZRRԣ0kwښQj;# 3Pju%sηղ㕔8N}kEVw/}KZSZ˶BoaF_jjqnh<}ۨ p( * N-9. n h@3?-g/47~-aCgZ֏?gxM ֺd%YdlØeu9Ke_!Ӳ:ipq( 7cy?bLH8NcYȳ^R!SPB͘>'OTA6߉rhnn C %p`P( ҭ^l3Wҧۛq։vkH-z&;K r25Ek Jݥ*vݕ]=;[7){ s3Mт`#Mn&oR_t꧚-1|6,r"_BxhڶWyҮ}lgۜ6wgf9pp HO:N0ҧNL{"J`қF62Lwo bm9[Rx/WE ;nR=޵n\rF7V)tM߃<&͕ dm pai97K2vRXJh`<ش"Pd/{IQHHLhY/v'jZ=Z_ןT%ڀHS~BX2 ";1PuMzb>8*%wLN QdQeV (Q1]|7C5դ/ѧL82R&gZGd-V+(5J`b30XR73C$ׁ‘FG#7cybUoW"yTY@aB&DIe_ l$kG|3}B/Wl *3v5N$HgtTdF6?UPHcԖ,WgYy([ɊSCz6(Q/c65/$Yٙ,'Rёvi$5DVƧq(srIicuNj$xX/WYvؖg_cI ]<鋟`ÙYol :M@2Uecz)MXf.GAiCδTkGfE@)|ٝvoj ,/m9QpʒZZJ :*zYs,I+:Rq4b<:آAIL)>*@ BڤT)OQ SZ\q}/E٥dj%lڦnpr:t*giuڧ~:Wrə˹"!j睂ب:Jѩzj7ڪZz1$ǫȑP2DPD C*uAXj 0!@Ϫ@xv!p qɨz! z*f19ڰg!kKfA$p ! [x[ bXM7&JT1+paڰ|/BBf *$`5ZD5$JL;Q $M *-!#\P֤t:K"Dfѳ9X9nfaAT PȺg!twKI` $@kc`j2*x,+"K;$a}KV90۬{kگkUDհ#*Z{  غ!_sDk$1;Qb2+$RhK$";& ;!Kgs{[ ". ~ۿ57!NҬDrbKK˭« ,߻# `gXA^;6&үc˻ 0ċ"+9"1k$lP\)˶+붮#DeL[q;fa #W˼- 08cel{9zеʿ{"<+1\Z| !е̹ Bb{M+1|K@|B$3 D;]kj5}@=CӄD0mԃJԂP],@VՀ\֗b}jK~`hּ}n=ׯ | tעj{zיz׀]،*y@؆؈ 1j m(-T-̼ KiZk!va#u]ͬh!TKڑ}poLfwفn㚱z&z"![!oAݞZȟaquamA@rd:-k0Ľެk =i+l芳\ߑ#˯:!+fe\aN|.i!0[QJL~7KXYo>ɜc>xngt5\ + XF븈knj(.cKz Lu;[[ 1+!;웻.[Ǭ$=ǝΎff|K\Km~U=K{[~Nʸa(vܰ<h+QK)OrʛЋ2[7\^:9ݼ<%,@ΰ=?!k$f0%oի+-iD% [MKYJ!fڑj [NK*C. BBe(o&;0>SP/.A*PS8+)2"kp >s["=y;  "H=4Ap:쬼K& 8p(/K(B/ K0Ǵ49u93ͤ䴳M;?$3L7SO"<LqIveFG5e@ iw:B #r=?wpv "<\ \Od>$S.(>Vgs E$=y @ѱ"A}2V> $7 a9"~@" t( Cu!o@̐Pb*`A3< 1y 2 @Dh? !@!tԅxBHd9 CœI0AĈ*!lBha`" $F |UxB)Xxi ̀aУBX.†}|p x ,=0CFqTA<>tejž%04A*M""8Al$yى?O 9%;5H`jYh.[2-r(\6!&)q \_4oSLe~d+s A@e|@VKuV9f>(2+ޜ'p2RD;y`CbJQDTj&EuyS m5ݼG`"(1<\2EIWNd&*,E)YR@UTPjjX.)8b؉:U$PD_r5T V: a\Ø8e /&"Q.XSYV;U<.ƵKfؐc mܐ =Lh h*ADŽ,N${@C|Qv4A32 - %!mC RfЪ1m v+-GBI}%4x}>i[r@8Ҥ;P,oضŭJ"'J gB.fcB0H sc]ʄ\!~އxjxճh)`?MQgo,jc~dQߔ\Oάr%@:USCEřё5hGg Ҕ9}*K_]I]Q}ɴYR:Yi]H:ykM:=]l;۵!;ٷ]mxE\mo]nsVnw]o{o[ ^p Wp?)^q_9q!I^r)WYr1i^s9ysAЉ^tIWҙt?Qԩ^u_Yֹua^viWvq^wyw _xWx?)_y_9yI_zӟWYz׿i_{y{_|A;c++-annotations-13.02.01/html/coroutines/awaitable.gif0000664000175000017500000001417614735537670021437 0ustar frankfrankGIF89a6...===MMMOOO\\\kkk{{{..==MM\\kk{{ĩ˸!"! ICCRGBG1012 mntrRGB XYZ acspAPPL- desc|cprtx(wtptbkptrXYZgXYZbXYZrTRC gTRC bTRC desc"Artifex Software sRGB ICC Profile"Artifex Software sRGB ICC ProfiletextCopyright Artifex Software 2011XYZ QXYZ XYZ o8XYZ bXYZ $curv #(-27;@EJOTY^chmrw| %+28>ELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,6@pH,Ȥrl:ШtJZإhzxL.znxX(~~[qYueErdǾib !g` tV5*\ȰÇ :&!ċ3jhN\,4a S\ڼ-R\0SΈne>hDB4 3r4 cJ*D_*!Nʎ*9t~C .*́-4ɹ0t^pp Ջֺ!0rl $^,ܞnx*@ px{ WDitiRL46Y6C!  A͟YpC8؇ p5JYr߿)(.2! Y{W@|YUXədI!P8 {!:5_` TO3kx%} ]c&b-q A !n @7Ydq術DE΋Fpo 0!h6^Ex#G>b$-G֎V8zSj zـ-"v ]QufUqР=k8*@^f @y8[)j|]պ)K~-07IZ*n8&,`_2;Nӡi3j5Y )O5%y_׎Ce~cC;/)} O`Ė/> 'D68'D]/\W1⛑llu_3YAd;+zS/ ,_ :zy 'GB '0<1<] ICFxCR̤9(H/2Qp$+-J*rG8`d$r<;GJ~΍\\f$Iքű#ռb6Cpmsp8hv^ +=9gtwe[ bbV d0I3/sa|g7nHGJEaAAq 4&Kۋi].0)n"(š/"oiKQ %(G[(U%EAx0hб)g}9oDk@>N rm[t0}`i=Uդ# '9L=7iV#ZEjr8َB7+w]lUpdT7)8lBְ%_oJ*j;.2pYqq}|SVss,i!*]:hˀD>tl@R;G9]m_Xxށr3Dm]cfzі6ؤ>{fGF߸ci)mx3զ0A^}] LEK_SJf>bi>z ];<:Sȳ\|nݱ&nGp0VJ9@txtZNԘ~5ynւӟ7U|m~8aǭ%;+n⬰XX ¸`7텼-˞mhCRM! (Hmk=)KH#01 g: <$G7Lu?EJp0o8@TmS7n7D'd_D!wy?`޵c{ juk|?rqC21/Gΐ0iNM.uO<`YWg{_7~ժmC;Nx" | p{P}՗BHs[ {`[ "`?rȁ uфqr2tHst!u`wz@bH9eȈ\Ȇ(KX6WQЅq)؉؅؄8HG89J֖k( 8 s8ȋ|KxwH;ȅXȉXרRXhcP(-&|x脤ڈx8FɈɌYXHx(8(LJ菂 ~8ȏ`Ȍ|88gC)/9x84y6i{8):i<@I8ȍ׃Li'}Q؏MYVGh6SY@ Gghri ȋ yx/(n 閽hhȖK(y8X"yy9BɘO((y_Ii (o醚ɚٍHX' 障)I0) ه雕)xdֹu(OY,I^)z9YII}\ِ rHk܈~]~ٛiHx6~{Iמ)7|9 z5Y01JI/Ȣg:ڣד>BZ@FJڤN)Tz8zXZjA;c++-annotations-13.02.01/html/coroutines/fsa.gif0000664000175000017500000001575414735537670020262 0ustar frankfrankGIF89ak ""##""")))---)33-223333666661==8888>>===6DDELRY`gnu| &/8AKT]gqz !-8COZfr~ -;HUcq~ +:IXgw'7HYj{+=Oat 2FZn  % : O d y  ' = T j " 9 Q i  * C \ u & @ Z t .Id %A^z &Ca~1Om&Ed#Cc'Ij4Vx&IlAe@e Ek*Qw;c*R{Gp@j>i  A l !!H!u!!!"'"U"""# #8#f###$$M$|$$% %8%h%%%&'&W&&&''I'z''( (?(q(())8)k))**5*h**++6+i++,,9,n,,- -A-v--..L.../$/Z///050l0011J1112*2c223 3F3334+4e4455M555676r667$7`7788P8899B999:6:t::;-;k;;<' >`>>?!?a??@#@d@@A)AjAAB0BrBBC:C}CDDGDDEEUEEF"FgFFG5G{GHHKHHIIcIIJ7J}JK KSKKL*LrLMMJMMN%NnNOOIOOP'PqPQQPQQR1R|RSS_SSTBTTU(UuUVV\VVWDWWX/X}XYYiYZZVZZ[E[[\5\\]']x]^^l^__a_``W``aOaabIbbcCccd@dde=eef=ffg=ggh?hhiCiijHjjkOkklWlmm`mnnknooxop+ppq:qqrKrss]sttptu(uuv>vvwVwxxnxy*yyzFz{{c{|!||}A}~~b~#G k͂0WGrׇ;iΉ3dʋ0cʍ1fΏ6n֑?zM _ɖ4 uL$h՛BdҞ@iءG&vVǥ8nRĩ7u\ЭD-u`ֲK³8%yhYѹJº;.! zpg_XQKFAǿ=ȼ:ɹ8ʷ6˶5̵5͵6ζ7ϸ9к<Ѿ?DINU\dlvۀ܊ݖޢ)߯6DScs 2F[p(@Xr4Pm8Ww)Km,  0ká˛ҧ޴IP 2˞'*\د dPHHŋ32)(T CH!#SNWY$13sZl%:NiSN:y (RD;TRVL8*3T_T0a" Ϧ*V*~E @{~%f*d`2;UPuLD5rDu\| ze^RY9ec_PXExdh8^^f̲33A8r؜8 wS ؀fnY=CKVR[E1\|p( ~$Cxp^*)$wWEHXthq_~17)[p(@W}!MD>)D9$F 0yM> MFdTJ9\v%^ Pd6(W؊Y(, jNx=H㎊u@* Aj衈&袆J*Ђ7gy.G[}`@g|a ى')5p!*>0@ h ]i^*Z"٩*E;JT謥Ez8>,`d}lW*bqۗc.y FP[ed b|>NlXAְr<޵xQo+TdbNQ(rQpF_țpCdq #{RrJ^FVE)\3s(Kr*'ZFL4'[sc3kP`{3':wT&q)-4jQCٜؐ~t_)%NL4 el'eC';.4yFY]lѴ4`ts9E\@H6N輬, *H(jw0 X [=EKw> _DբG@]\a@nS^3̀geؙ tPO!АN+ <#+H]|h(NHo4m[Cl0,ly~S/sai"zCsҳ6a5,rD"x Ulľq6L)O-0 .˄31PL_0yf&U9#Hx eSΨ5 huJ`t= m E['śh[2:~.~guTzh>ŧs׬rN|1jl~GqF:[=0._;qkz$CXN>GALl3>]hW(I m"p}- 1=<۳ƮM^S{:rFq5ؼ01D{uB3ƒanRP\ L-5*ݢ096+Zs7 |FνWy0λ]cխQeWQU]MQ#OK纘[P. p;!j ),)EX P@W%Z)  5^0/8 j1 2w#4z;.1yt+(G "~a#)Ã#,xڥrTj1Uz 7*9(d01 /),\ !B*~a\z4HJ#ʨ)g-b_P x@V0ZzZgԴڬκ:Z_2J!gBvzs\)!,!GZAگD@)a*{" ~iJ:Y [*&@ ۮK ,@EBOBpB2-aL`;g`Lj ,=" pbHAZPs "B&p&Tc٪VS;"4k|/P;,"ВM;,˴Hq<0_yK*A3?j7ڷ}~{Y뢹!GG{k+~k5ۺ ٺІQ#HK|˻j7XV5|ɫІNWiwث{j 9u0Z+ !34_ȾE|k }x@80XkBT'l|\WM<$&|…/*,0LO2<„$:<>@B'^NX~ 雦n%8Ej>Ɗh 뮼믽 pk;)SXԳОkfD&[Bφ۷榫 +Rko+LOkp 7ܨGWGp߻q qk$|6,rj1ì ;3ECY&nL<Ӈ,4T`Xg Aw5SL?РG[e׉=6BΉrfz{wI!$bV$Eux֋e(&eNuӈdZ8j+v[oELܥ瞖C@`]!#%Sݹ1yjls^|Kb^tХ_4j}~Xyeע>rxc A*(sZ(v 騤 *\gbҹW~Ҫeڧj֪p%nꭿXl1̎,J)GaQ`8V:T$L`HN~Qn%*qθY(- ?C=Cni!D8"wϼwǞ0FAuHˈD|ɰJ-)dZFE 5Eur5z7w34 4x 46A)8VYΡ5guVB1(ivY4bS Cs[/Wy],R`]OE%7?}ߍxn5[pm gB\AI%د'\>'?)i#ەh."kR@g5T`7A NyUҟ[PA VOCpQ'|`R$BT 98̡w*$3C?D,"$*>Lďث(~bT|=,^hKq8b)3T^gDe؋t@mP_[B!eTG~ X+dH,T&e*a)IFKbh3SB0vaòӜ%bLMI)YmNI2Hf6ӊce}IY7 S]BfW`ݔ o~K|;i<=yO퓔D:#&T HBw*(p(B;c++-annotations-13.02.01/html/memory/0000775000175000017500000000000014735537670016124 5ustar frankfrankc++-annotations-13.02.01/html/memory/fswap.gif0000664000175000017500000000675614735537670017751 0ustar frankfrankGIF89a """&&&222333888DDDHHHUUUXXX\\\fffhhhpppwww!, $di%lptmrv_㻠GȤrTBPYsJ]>VuKfܰfp9Bw{-x}ߟo}~/x|iyf_{j0Xs,QB;ǝū9˥vבգ:σpӢ:"ݽA,4' ;\P.(0IQoTbbLP!@raxd%DE$!@v!6H5ojidA" /iGeAUYsװA$,r*D (ȝKݻs (!AL8޾A.HhOpv&wl׹ugL@Zg"aA RLZj Si hx0@ڴޮ='"Rx>Iz݈r$` `@f0T`p) dvȂ2 IƷBv-\JA+-X@NC DP>"DO@Q"g6hC\b[=6l=- _`i-w-@7Zp&W*tH^tTp.Tp`S9Л(8½+@ȅn+ Bо= XN`w1Hxc‡on £hOel @L@ As1'iTrT'.[_xF(6X%W`N`f6EqjcW1PY"D I3-gx{G(W98$ H`d(9B8ʕ0,% 9Ea65 'T>TV'AHᏖ]ptCxđɾеCn3lCS$zlXt$qf!@s# \v HEc$;fN'uxmez+&RPodiAIR./<(P0mF'lRtۦ>&@y3RԕE_Q^ Ǐ2X<'J!aYBt mY%%+- OOJX3/5LV3Zϊ!ȇP d z hGKҚMjWֺlgK6nw[K}(Z&/j1 siel]XQ fw_Uf 㽆Հ㦷ms߫*6KFuuYOh Ac#*B OAMuבdv I$>a TګCxH24(O7c?},ĉ[Lb.NCd8BG/|pY/sk<ƿ}G_o۞w}_" W\~|0Exw8\aL0azh e_ R&***-.80x4 7X$EփuY:X+fq5rAxHJL؄NN.*b."2}/jQ`///~0`TPN,3:i1fwql sH,02!d2͢98.L}&3xH+6H$ O,eWӶ4[=t4V7R|Y#61^6[7es6i#6(scF#0xC 4Q#@QSscRF(,e:49C5%809g::l=s#=3;0U=ijƃ<1B%;H=sMC>#Sɂ_sA&>^PM2cߤ:M%3C>4@NKj)G8N OxC?v,"ƓOStm,E%4!C,PCpCxkDœDyK;N$E?U,#+c4^.pFqFmdQtPNFtz$dPGbyq兽-`<^B,INr),PI3Kid u42}8$J@ cf+:OTM#ryHt3dpS?MrSӔ9Hp)6۴ryQ,t 䡉2gO?cRZOOɱ 5dCiIP7"%iK:~(,!/H k#3S(tx9t̓~gw+^|$ 5m H A(]9  ~bt` JRݖw!b6Gg_HqBMh߆7IA#$7N\QGdu'åflR 'V}] 3Rm>&xĉsv6hg.栅h#.ʨņii)V)u kBjӕF8i>7kdZ>\ ,,rylƀ,^mféY--*+n&ZUu{k q;1/\:N]k(׿m TKqt1XeP(7Z˱ a<lrJzź0(g҅8చmrKsd|sQ{sH+ So[q9I蚨dg5!M6P/tz7$2`GgW7Fk%>ʎG>}饥:w> P%]ڇMI'5L{؅U;T^СP{*^.&2I2bjS. XymwO>5?x ;/)tׁo㓟6Pڃo٫ ;!~?h+af*'3no2L Yh*oAP6 UO:CH'tT#-s4+N&l4gQ•e1qhܜٸq$4-2ы ̣0ɑ=lO!f:,cG[U<"7EbCxԘtJP"r&I!c T͜jlrzJY.G´_ 1ìׄYdQ&hvnilfpn%2ωtsl;xs= {s?ۙ t-AWS3 ]&7 Q3-D+5Q%h _c,M R^1H^L?"LVc iHdYC@e '1\T^d#GXhHM$#yH@TnP[9`Nƥ KUZ0Ce=jLjWB3b9yNrՓ(lZjAZ78UW5TJvEBZUγl(A"جER!|eBVO 3R^1xq*\]s}JӭnkB7ڕnqwk7]/{7(}י0_׸Aq٭|a N [92^3?.ĥ-hxbplIIq}V lH@э% xِkİ.K1Zk Ϊl< Y(&A>@w\pa%\:en(gs\6ֱlt:(DgqG>͝㖎yKNRC~fc$Ct ,IZ\,F{+7)|^gľF#Jp]>ĶalLtoi蹎w 'VSy1ξNk7[gg )uj3T~ي6S/sz[XcSsv _jgLvB zqfn7[/h{YimxZނ3Yo?+;Ϋ6Go\O֩?2`?U?~6eQ3{t\:gKW8[׀|rR3Rrҁ_zkqq"X~l GK81@#|$5z>(3/X{WJoCȃ$烛biFbOx8~';oQĄ)h9W}1@h~uwjNa0sGHvړ'}xN$9s:syƦjBy{vByX8cu_Xm8*4c"JSh=DGqHٗ8wX(3{z9}g)(2H;xlH~8~ahh(􌹷X\nĨ9X{WV؉TXHVoXDs7xs( DqxNNe`- uYNIdM Đ )MHiPɑ4 !) #i'+M1yU^#'e_J0XRp6Vy-0ղ|0TP7YX(A.S`V9+iM []YW*aT'@Q^ieZXe3;UX^XiXcjz9 +tVBYeZc [Xw4|X1|<9)XlQyyb~VuxY YW73d k$Rs>L%SQUyZ ]aiMŔْR}f4]ڹ ՂɝSoH\_):" )N/eT T98_WɟXsJd9Ġ9pP3cD^q詠 7!jV"JE&@ԠU\.ڎ9M6 ߕwʄxr=i[XqWxu^ |q]Uf4')tnu ;ˎN ۷yC2úKtx~x[ Zm0{|yꛎ\|wIAJB\xhh,óF hbH[싴j_e~hۛC݋d \B8TKj6[L(2hD^,3 ȗ[LJ[ .)U F;L|ͺ1̬;lה<8 HܑiƯh8 |Bhσ {l5ͥQ >>???CgC66D44C;;D<<\==u66DUXfw.D.DDUUXX9DBffwwDDDHHHJJJKKKPLLSLLVOOPPPVSSUUUXQQXXX[[[]ZZ`HH`\\c\\DfDPwPVfc```fffhhhmkkmmmrlldwspppqppvvvwww  '..''  ??..<<>>N ~__ll}}__NN^^nn~~2!}}C̍сș̦!, Hi(3ȰÇ#JHŋ3jȱ-1 rP3@:\ɲ˗0cR$ڴ;&H2USϟ@ j@%ʴӧP'.u5ek!I 13v5_HBUkRk~Jݻ& X5kዚ26Õ>òĮ]vځ] ZⰘc˞qz}&Uo̽ m˄ y؍9i{v%b.ugnv*I?*DU$e=BS| 6F(gUhfv.8!$h(j("Eb0(4h8cV@)DأE?L*yLI6)T$.\vY.^ ӏZzihE?)Jm/͉dt։{ɒzWk'k$zD"$X6h}B)XzDڧ2kj(=zjDB'U-*d'p+D&(g똙k,6,:cH,d/ E;дV{mW֭ր됝x,\i*n𪅮@2d B򻬞,BܯAvv<lp)M@IfE`/[œH T 7 2fb(CjZcl{WNˊB;p[[\-fÙdۘz}vk[wnmt-jrύ~8څSD!|6>ge[.vW)y .Ž:1误.~ή;Ȅ(a/o'|:n{ܾWogwO N觯E<㞐 ?+#>Tt '7Ӆ#?7?Odg ..Z Z H*A }xPȂ HpQG8~{2\2axE+7 r:(rDP;DZA  @O(x$DF78\ؾU`_"H2Fq2 3f#):j2"#ԧ5,S`X," :P*g2҆5򯞐*%k@8nOreݔ K](*RQT(0E z`[20czD*yM > t< Nf:wع'%+*KLCyTҜDv=> (H|I?;$< )$䣨"$VQSdNE 甩< ` 6!ϓrV1Ag44TCj:.|EZq(@: Jِp=N')pRԫ_ R'R*Qf7{rLEWTt|i>Rn~5!l.hLSIخB5aXG S%V4u=_+` p+Zgf%(wRָ`r_Kوbw_ 5d>Pq9 $h83*}_, C\AI؂DK0.I@NVD&ڀ&Ű*KkE*XbsXQxńa"Sob/n jL:Ϲy&$ܺyπg뾻%Zv气E|]UwBpӜ-9. W]25Q6WN5'=/[Wak_7jPv3MCNիuq-c:ɮlnztmх_tRS(68`Hmg/H,I5P2@0 8hU sQS`-PSP `aaQ!67 Z̀Iy17d /$0:C)66q (P@R1Hp@clu_A"! & F dsYAk /Q/b&Z" sz>ٯBDmЧm?&آҬc"Z۱ ihY"(k! Y9Ph8O(6kb278K_;8;)"6A{HG*?7G熭vTr'lq>16;,bS`PK֒-iہ>3.b.u  b XY/@0ۦ0P1K&Y+s-U;2k2;336SL@l.TI9?H2Zh>jlToL@dLZLLYjv+lK} ?J$Kb!\*HLTUUOtaYHGD>?Mޔ>Nc&1{PhʊLRAR+eX”|t\(>PQ Q Z PN p|U@̽5uS %#UTXWU[Xu J܁>VݴZ|WK i\g^Q^ y  7=.2ͯ@]u]Z۵_3,AN5 F af6 Ŕmƀ q=b>u>B-`dMOA6c:VRt$G.c%^|qٚ"Fb&E(*f-ĔhVeeSt-AJdT=3%Aٛ} νx ~= < rNL,c9<#\>$~:5n1 0r '.q#V;껾nP;@ގf½2-2~Q 9nLJB]rWkn Q MOP Q 1'KKN H`QCC1"Ymmp`'[΁>OM  @p@ C.l 9^0= "r \@a mľo֍.#P.^rg^(D>y Xn 3Gd׊f Нhw8֎3 v.}duSt!ҁq(%{')ρv j;~W6*@πJӞg@Ht9;ZN7P4'KYy[^||b/sd iM'8Xw18V}=X1I{/rkOm,Iw?#TT;y?Xe4/Y-Ore_W&Oo$#[J 6MЯuF*zX u-8gψ4H.!M@B Tذᢅ4I|PF3BRH%MDRe-;fQL0%NF#B]}TP5tّ5ꜙqU^ŚUV]x(THǖ mݾW\uЦҊE0#B… FXbƈc}^_ƜY3Ȃ3\rgɃ7F5ʕɶvm:lڎ_~놶\pōG^i®;tխ_nv5Sݣ5nɗG~2~=7W_~ǟ~n/C@vC @'\@D{6CCODD{6_ʓ-Fo|q-ñGQѾ$1Y\Hd߲OI'rC(7ڑB-K/9K1$L43M5TM6߄3NݔUN;tN.j׀ .s[oR{FoL򱽻˛? _۫7-Z?~BWz'8!%<aNHa^anȡ^}]A\f!@2Hc6WFn*6ލJ.dpbT%N~ f"R"j]ZiN(fvI&nYjƥo'ht9* 5ygboty[-0IH'>X**iMR0 ec '*u|h6ůjKŠdvΙjF*^%PV败mcTˮRɪ'o N`/3o|Wku KTſLqoq)9U (X0mW$?Wz}.43=',3BLt"UV_-qN:m

4~/Ka y^J.㎋*ᆎ90IC.?x~;좓^R>^󾃀T|K{񋮮;˃<5~ONe^݋U3~~c~vbOPc` wk`ՑiLO( ^%4!NPBЅ]Y@pm1$ >=kA MYGZ -hOlSE Mq 6 YEqJb|(5 BKka0Q~`<ԁo{cr QX^ˏreH.#ֽ[},$%C)gd: E<_oά, iZ҄*'/{Qp[H3T)FLR3_ޗ6A_lJ){5\(?jԛPzKؔ2a. 14-o NT1wƈ-nAQ7XW};|@ޣF(`Y`JEF'1RrߪZ! ^b%͸@gd$ӕOZ>VgJW[޶m.Z-i}H5y+y b9Dv '$~OȄ$0OVNCՉ&߬An~|,ɼ.D*J-oG[|o _9Iz݀BY4#߮t-GWv,Gn?h ǵ0z}QNqto6ta{F*ss;.wgw*-pW|`Ѿ>܎?w0 Fl㧌[پ\|tyAyWa;]C}BCB\=O|F:??IKί|!u<:&wz7SW~ f)USU%6Su@X,A[X7UHb>UZPUYYXWX#ϘXW\ Z}٤PcYZYvȐVY]I4UgHUZ匠ōI% gl8iHEiGɓ0hO/e0@iaaNYP X #F~]^)` ^u#mA+Q"{gBjv+/"a$'6va{9 MoY6%6_bK#e 6hNzƘ?2iҕ`h'a^ْ7a3_ɓ֎tvqG`o™z&qK)絚Vd|y]`g~pNIyUjQW(Be rWkEC7 #Sٓm9vUÝs؞ 9=V&T;7tyylY# {fK)mdö h)ʡ*$&  #'ڢ):+:,"plA'Z\֕<*3;j^9jy67L 246%:5WN*\:9ޔzU(o zEiɖiJv4UڤrVYz[J]T y }9nt@li`]jdɨmJhojN󧂪vsuڤ2ag3eykP`V&qj ]گ{ʯ0 !k 2 K'nYmZ:+ʱa ۳%`\*ˉsz619b8미Q0W+Y& W+QWG[SaV0)d<˵lKn52/'sd[d}5m۷oq۵Z{9DxKzukK; ;[K3f8Kk{ uKĹ1K~oA :XT[ATqXe2"kP#5+Y. H̨F˲(obcRzVV( ÉM֘뛼7uFV~KS4+KtpȴO2Kz;z[Gĺg۹lk[M#׿FK 4);+,ʿk8w+#ƀM,Nܱ8נI<և'ޛ6.U  ךWPܧfzJk]ԯ~_zR{گTk'՚rtU4o~Һ|=ǐ ǎJkܟ2l3K@w C++ Annotations Version 12.0.0 en-us EA989A949A Frank B. BrokkenThe University of Groningen9036704707Computing, InternetDec 25, 2021 annotations.gif c++-annotations-13.02.01/html/modaye0000664000175000017500000000010514735537670016011 0ustar frankfrank c++-annotations-13.02.01/html/functiontemplates/0000775000175000017500000000000014735537670020360 5ustar frankfrankc++-annotations-13.02.01/html/functiontemplates/selection.gif0000664000175000017500000004337614735537670023051 0ustar frankfrankGIF89a|    "" "2   """ #'#(/3"!3'&(+0+-1.05.38/5?222333346888;>_16T86_?=g*)!C)Tp+D"2D,-S)6D22F92E<*]2%m$1d #z#9u&aIreat65:@9P몾y <%X;V]%EZ.X.k .k 1YB:+z>jk@Ǻb@Kb1Z^+9dɻ<-Y @^H=VEiP|J5c24jżp @ؗ ģLlba|bq,T'(qn Hͫ3c~{6s`W<\CJiaִ BVJ4@?[C9!iKk%ҖkZp"͋ipM@uW ̍p,Rht%T{v)$Ưr#KͪIlrlRHesI#ȦF8R0? ߇>+]  yMff`2H3JWej1קʇ%uвe]NT3ZJ?(OՒէ1]:әLIWv]%[ ъnc2=8N :a/hܱɘɦYTB3LeF(qθBoJ,jd:wqHjrT| (U(eqhDә-4¨ ѣgaf.$[DprB(KgNaifRjL)l MIg=!YNuXERR[ES'=7ѧ~4j5@UzS?I <ҵ-lI!:**iiB3S#V;ƨU#VE*Ɩg-kCIы~MIwacבW`ȥ P$8c6ʱ=BA bjwZyC-˕ERSUnqWJt!ja 5VUYsk\@+UB BL*l1@8Wvbx >R- xKb 6UaKW*p x \JZӕ#) 4] 'l͵sov$EW,aOl4l9C]@6TTdOvD6rVܖ_mZxVzgb]`p[ dq a6gh@;.K bH6>48̞nKuo7ѯx3b8L^\WIXRgT9v˨cd;o]vT}brǢfk[ʱkh~v_t;{\Ab{xwKڍ|s0Z#l Zf g% ko*Yq@|c! +t%/9zN>\f"W>q|aL\rs8Kr'}*D.} š硓F_3Y2wL.+ao&\dMb'ozޒEr|)M&kFL@~Ao(ٻ$nO;H+=GS!zЉk%K_uÄmaYk\ywޘGPDyʑHL]d^%0fqx/4/arW}{λV#y/^1tsÖ΋mx˩G+GCU\"5e:59N}H0$<!& 9 MG}f}"}3ga{Vq/"<#ģ& 4,?5)&F;i'm' TJ4>a;FU5Q,&om7%5TxC<u%cS2T#!e6hA>G'z$XgBYX= ?T5ZcDU6"7b@?xI'g_XEτ?bM5N8EuA0؉X8 PSn5GĒ.PM.ƔA^S$iԊU548!_wx@ 8XxpTX\|r8xKE؎艝(Cuu؈B%Ex|gJ2PY]T`\YUOTqO ֑ AąJeh3Nm&$ D{ҋ+}bY/IHVX@"YF JQ0I`L %]YLdVX@qL4VSO26*Hx~6YSa’@9/1"9Ӹ xQ@QiHŨJKbFX1z" -`EpF[TEd7Cd/I3C(rcpabYe7}qmuuW5TRișƩ(8cb'03cwcbӁIJkakpb!6RHd$ NcteZZ[a3eeX!$)5f>X E4Y7aiiV\ J!Ra!EVk&h6Xla.2i3[R&2Pz!0r/;]-j#z"0;祆rȑv¥gJ&pzqfʐ¦5vs,uzuQ~)q_0ZI:cC5.b~[ q:aѩ)R, \ǪzrA21Q̚j~nZ71Z=YΚz9VUJn꫙Z2҃U;)ʮrٚixe*٥:cqƷc:ʬ[1v @I:pQ@V-"Ȍ*ڱ)$-0K>qs3𮷡2#2l6myJ7&% F SXB[e8,)B{Xvٷ.p8sKg'Y041'K(iG2 GH4Uسh2=sUz(kʪ=K"%NsH4_4iT"cCbzR!%c3@5A3lJ{)dU!&ZTdG!b1,µR_W&gmrQRZ] /oI#+W$;B2bC*r!G###Lbr/u!#/γ}pZw- R`O+)SUW*&ho0XR` C<@BDt3UͿa*f/CP6!u3O5bDՌ"? Zjx\aSB(>F U/R ]DGɺJiX\}do6eYqZΥ *g?Nݧ#颸uր:-!a,`kdi&cI 7V?*aBZaݙ} q&pqHN*P/KSΣA3itY>^^_Bd: dRFmn^p%{RU~Mmyn]~v>Vw1^芞v)1^ꦮ hsꮎ޿We뺾R>^~Ž =0^~؞ھ^~^T=T;~)ߨ_? ?_s " ?&(%,.+2?4o1_8:;>B?Do_HCJN/LR?4TXoV\^b`?f^hljpr_v?tz@~֘ 9G{}_?` _h_08OoCP oUoH@ȟ ˿uR֨?osCP!z_G?LQO5yo1@ DPB >QD-^ĘQF=~RH,RJ-]SL5USN=}TGCETRMiuUTU^ V]~TkXe͞EXmݾ([uśW#]}o`… :bƍTXdʕ)FYɘ9ZgѥM.Kj֭v[읡PƝ[MR"\pōG\r͝?=ҭ_Ǟ]vV ^x͟G^!>_Dp_~0@$@D0A'b%0B '9 e%vC?1DG$DOD1EWdq'2 gFođOTi2H!|Q!D2I%C,2%2w4RJ+&S1K/TrˏdL33dE1IM9dFȤ3,j|)B jZGt1wu4=MKpX T:cZ6bGֳv-d[^ԴnZ!& G>'lަ"*7 &"x`Cp7 WC<( N%y#q#@ǒmtn˺!DW!,$fOHU: V]\Jt؈./bhypIϏ~oG 7ZT/w9kۇڙMtCDLrJ@tizdQ1" :bc %)f16(-1@eP('1Q1l ~@,2b\? @Ù12j? T kR$[!:; ^{BiP0  )*"% oɚ»Z3BêbPhA% 5i*9 aPpK0C*/D0tџB= 5d"gU(C0* {A?>)A?fɉ+!ѦJX1QB,@cQ)n*y(!sɟF1? t_tˮ5|* /΢ٻҹD},y$r-.J&Qi#<B<>J,/A-~0K yB#jQ҅O(+=RI4I~ rGƅDC" ѯ?0"31E9DJSC;<}G 1\dH,J(̣,I;\(Fcbǡأ$9 =&R9ɼ"(૬µLD³tѴ7z!tʊiKI KHC˗4KjͬKY"˶̕:MNd)k@ɖ?1@*EjlOHN4%wyrOLjJO, !_LqLdy%eA&qI쒢Ъ޼6N -N۱޽|؄x]sOc=W[ֻ-3q?1,DXS5Q_9=/iP-m2 ?)VmT0>ZYu! f Qkጡʋa ~a` លaWaCk !B#6n"Vb_'$vV,>=+6\'bb,c3UcI)6n5@5];<=>?@A6CFDc(cuGHIJKILNd(bO&R6SFTV"% bP)Z[\]^_[N/X`6cV.)@fvge=ic}Xލ3PmNE XgP3s q r sfgP0y w x yg{gg灶WUP(8hH臦 Uhhƈh/~ 6i0(閎v i2vn Hu.j > e 9jXhjxg.ejj_S@(>vnhFl8/xkÐ릠wk0in}~lV좮ll63^bXE@.fmj|.[@EX>F[(e ^ ؎h;ھގZ(c8 V .nkPfnn N f(b@FX?hE@gF .oPlPo՞X6i> xiaЋn'j7 _XoYIp /bm  p8jWm6S R Su,`o~Z7 Y ZuDJ(pfGb _/`hvgOn knp_g׉hsq"vFP` ww"/b@hzo7r~7rnt{|O7s2OTwx@A/gx'xs8ޞ픏oUyByPkyxxXV^?sz(z^gkz_hzxz v zpr_v {0{@{kv  {o t}rG|{{`"rhF_o |/j|}}E~G>?t?t{_LjxI}=i~}y7! -؂'7GWgwȉzPG*pd710R,h „ 2l!Ĉ'R(ƌ7r#Ȑ"=S4enŊh^?P¹`r%;l&wrl7+Iş (NK7 {Ϯ">f>Tp%=^Np|;  ;@'LOes=UŠ`P$  \]x{ U E|NX?ʬGt'8`|r&Ewoaԅ@@!a@ ɦI `C.tA2ls]&ACN&؉bߠ@DۅE980PvtQ `Qu$(&F06M8^O =wJ.s‰͢=OT.2GhΜLl"'L\hڜBteAO!R%Fюr4diE}ȓb(Y)Ks4 :#S| " FD5*T-ӟWKuMԨr5bSI?*f]=+þeI!knֹ̊'u}ju ֈW6|դ h\w}uR29. JLh{Է( l},ênTkE{E=jOsMGNi[V=5aX\ز~psⶩ/'>@ g*!JA|\8KBD gi NsNh?~c`s f7JYqK*W~c. )|D_,3 D!ŰχU8SgA ȃ.{3Əu]4[RENL*y!tmb- *?+E&ȦE:q![m~CJ=^ٱY,}Xf[监 ;mWp|2Y4&¡as:ZYtƣbwG+ SJh.vz̄Yh@Ӓ>.[gZz]I=7 fEmSδHlMK0veJO~||.Y&nsȴ'QCd=b$nԝ.ضc+Kэ kMn S.^Zwx>r8y|\_1^lx>N[ 2+[%¬lsqkAWB^?IG#ݶ/q:RIdZf񡝞h랡c.[Ѹ~Hƹ@aܯNѵs}{/xzه 7OLyL.'Q/Eǭ; r-?2@̷'ԋYpy2ԡOԢ?Gӯ~ZЂB8@39h s@.Q,בuB@ @!pH8^A2 'tB/0OB I_5Kr#B22B8 8@\ -p#` '`Y*d ~ߗU~ *!!!0'؂1̅2Ba[m!Q\ z_!F/A6I`ɡQ__m*:IOan&uB>`iIi&'F ~џ_  ta 0BHU/n/.0>a/``.6j z߈dCVE@+Rd,c@$j_%2GDD02,F ))J.3FD#M#Ԣ ⟃ODH68=&1>`H7$#F%M]Fj Rn "(V:?cMdE&[FV>ڇٌ4%S\~I^BNb[GF4ڤ"rG)_P6f5>$JNJ~፥<%9r%_fTn_U^RbefV֣9H-"s`kY#Z%m#;UeEep.Wf# fEbsE:gc60dv] FbR!(PRy:Fa.ixdxigh@)Nfd4#Peg%!!k\&2>6ycfmnq_p;tg:c<F\gufD}`wEInDzeZghF&hY!h~n_(Qd)钂J_%ncST VH@j>ņޗimΟ BNha|V֩)dtA)@*&.*@yVV^*fn*v~**B <*\Hj*ƪf'Ϊ**S ++&.+6+@ 8N+V+檯n+v^*. H+++ƫ+JIN+Rk,,f>,Z*&^,fl.,jkvXȺǦ,N,QTƾ,Ƭ̚+iê.T),f*ά-kk,,ö4-Omn-v+ެV^u+B*X@Վ:zޭ.m-Jm, + ,(Zͦ m)@Ԓl-ކ^6R*涮@*PjԪ@릂@FB)L*tR*Dݎ.Fnp,.v/v..+(/+$*6oO=r_o˲ 4@s Z7 7yZH`x#/̺?¶G s3W:9Bo5{Jŋ>اn}<.>;lgmKJ,Kv36n_b{/ .@(a5p,9X2@%Z"cGA鱄3'QT I/aƔ7qԹ'LH lgћ4U)OF:jUWfպkוUތ;lYcbQ};WlI*]eA#pKH,ذAA/hPI}30 &@$}Wy_@+ 6p0Y0a{Q8fྉ#ALJޕ>zuױOK{wDo7oz^`a/Llk @Fod $^/' %˯"!NB`!HVp 9IO.iq4i;x1$7h J @.b:a d 9BIl+1,wK L`De/L{M,J TAݑC{l"%Hh&' 7@)!s͗2ud`NI6TLP%q=ܓ)_I-XcRԄCg)SVs$#TLU:qVUYڗ$ &]y3w፷a{)nnc MM]4wԘY V\>a"DlbxA^|I.dVn_s9%iˮrS͚xfHX]Cn駯䩩F4V\-雘Vy`AjsŘ@C݄mOdAE]Ojn*ksmKs@7$3 0t E#/tgKQg1tX뱗ǹᆴJ _/8u{eg_ʭoi> q7- A e%1A nAB%4M@)vq a@N5 =D!P:MtRLUE-n]F1 јF50 ;c++-annotations-13.02.01/icmake/0000775000175000017500000000000014735537670015101 5ustar frankfrankc++-annotations-13.02.01/icmake/examples0000664000175000017500000000341314735537670016643 0ustar frankfrankvoid tryCompile(string source) { string obj; obj = change_ext(source, "o"); if (obj newer source) return; if (strfind("koenig4.cc" "personconstr.cc" "stringsmove.cc" "binarystring.cc" "stringconversionerror.cc" "binaryambigu.cc" "binary1.cc" "virtconsorg.cc" "refwrap.cc" "ambiguous2.cc" "ambiguous.cc" "buffer.cc" "perfect.cc" "basename1.cc" , source) != -1) return; system("g++ --std=c++0x -c " + source); } void compile(string dir) { list sources; int idx; chdir(dir); printf(dir, "\n"); sources = makelist("*.cc"); for (idx = listlen(sources); idx--; ) tryCompile(sources[idx]); } void examples() { list dirs; int idx; string cwd; cwd = chdir("yo"); dirs = strtok( "intro/examples:first/examples:namespaces/examples:" "string/examples:iostreams/examples:iostreams/cc:" "classes/examples:memory/examples:exceptions/examples:" "overloading/examples:containers/examples:" "containers/queue:containers/set:inheritance/examples:" "polymorphism/examples:pointermembers/examples:nested/examples:" "stl/examples:generic/examples:functiontemplates/examples:" "classtemplates/examples:advancedtemplates/examples:" "concrete/examples:concrete/examples/monitor" , ":"); for (idx = listlen(dirs); idx--; ) { compile(dirs[idx]); chdir(cwd); } system(P_NOCHECK, "find ./ -type f -name *.o -delete"); exit(0); } c++-annotations-13.02.01/icmake/pre0000664000175000017500000000051014735537670015606 0ustar frankfrankvoid pre() { string files; programs(0); files = stringlist("", "yo", "*.yo"); cleanup("paren", files); files = stringlist("", "yo", "*.cc") + stringlist("", "yo", "*.h") + stringlist("", "yo", "*.ih"); cleanup("tab", files); cleanup("trim", files); exit(0); } c++-annotations-13.02.01/icmake/programs0000664000175000017500000000271414735537670016662 0ustar frankfrankvoid programs(int docs) { if ("VERSION" newer "yo/version.yo") { printf("updating yo/version.yo to version " VERSION " and years " YEARS "\n"); system(P_NOCHECK, "rm -f yo/version.yo"); fprintf("yo/version.yo", "SUBST(DOCVERSION)(", VERSION, ")\n" "SUBST(YEARS)(", YEARS, ")\n"); } md("tmp/bin"); if (docs) { if (!exists("tmp/bin/htmlindex")) { chdir("src/htmlindex"); run("./build"); chdir("../../"); } if (!exists("tmp/bin/rmindexlines")) run(GPP " " CPPOPT " -o tmp/bin/rmindexlines src/rmindexlines/rmindexlines.cc -s"); // // only used in 2024 // if (!exists("tmp/bin/celeb")) // run(GPP " " CPPOPT " -o tmp/bin/celeb src/celeb.cc -s"); return; } if (!exists("tmp/bin/paren")) run(GPP " " CPPOPT " -o tmp/bin/paren src/paren/paren.cc -L" LPATH " -l" BOBCAT " -s"); if (!exists("tmp/bin/trim")) run(GPP " " CPPOPT " -o tmp/bin/trim src/trim/trim.cc -s"); if (!exists("tmp/bin/verbnrs")) run(GPP " " CPPOPT " -o tmp/bin/verbnrs src/verbnrs.cc -s"); if (!exists("tmp/bin/tab")) { chdir("src/tab"); run(GCC " " COPT " -o ../../tmp/bin/tab *.c -lfl -s"); chdir("../../"); } } c++-annotations-13.02.01/icmake/latex0000664000175000017500000000043214735537670016140 0ustar frankfrankvoid latex() { md("tmp/docs/latex"); system("rm -f tmp/cplusplus*-stamp tmp/_cplusplus*-stamp tmp/dvi*-stamp " "tmp/docs/latex/cplusplus*"); latexdoc("", 0); latexdoc("us", 0); printf("the log files are in tmp/docs/latex\n"); exit(0); } c++-annotations-13.02.01/icmake/logzipr0000664000175000017500000000071614735537670016516 0ustar frankfrank// names may be a series of files or directories in src that are zipped into // dest/zip. dest/zip is logged. // src and dest do not have to end in / void logZip_r(string src, string names, string zip, string dest) { list files; int idx; string file; chdir(g_cwd); dest += "/"; md(dest); if (src != "") chdir(src); backtick("zip -r " + g_cwd + dest + zip + " " + names); chdir(g_cwd + dest); log(zip); } c++-annotations-13.02.01/icmake/findall0000664000175000017500000000107414735537670016437 0ustar frankfrank// assuming we're in g_cwd, all entries of type 'type' matching source/pattern // are returned w/o final \n list findAll(string type, string source, string pattern) { string cmd; list entries; list ret; int idx; chdir(source); cmd = "find ./ -mindepth 1 -maxdepth 1 -type " + type; if (pattern != "") pattern = "-name '" + pattern + "'"; entries = backtick(cmd + " " + pattern + " -printf \"%f\\n\""); for (idx = listlen(entries); idx--; ) ret += (list)cutEoln(entries[idx]); chdir(g_cwd); return ret; } c++-annotations-13.02.01/icmake/readlog0000664000175000017500000000023214735537670016436 0ustar frankfrankvoid readlog() { list line; while (line = fgets(g_logPath, line)) g_log += strtok(line[0], "\n"); // add logfile entries w/o \n } c++-annotations-13.02.01/icmake/log0000664000175000017500000000014214735537670015602 0ustar frankfrankvoid log(string file) { g_log += (list)(g_logMark + " file " + md5sum(file) + " " + file); } c++-annotations-13.02.01/icmake/man0000664000175000017500000000061414735537670015600 0ustar frankfrankvoid man() { md("tmp/man tmp/manhtml"); if ("man/c++-annotations.yo" younger "tmp/man/c++-annotations.7") { chdir("man"); system("yodl2man -o ../tmp/man/c++-annotations.7 c++-annotations"); system("yodl2html -o ../tmp/manhtml/c++-annotations-man.html " "c++-annotations"); chdir(g_cwd); } } c++-annotations-13.02.01/icmake/writelog0000664000175000017500000000034114735537670016656 0ustar frankfrankvoid writeLog() { int idx; if (g_logPath != "") // do not store uninstall info { for (idx = listlen(g_log); idx--; ) fprintf(g_logPath, g_log[idx], "\n"); } exit(0); } c++-annotations-13.02.01/icmake/verify0000664000175000017500000000057114735537670016333 0ustar frankfrankvoid verifyrun(string file) { printf("\n" "checking tmp/docs/latex/" + file + ":\n"); system(P_NOCHECK, "grep -i \"overfull\\|undefined\" " + file + " | " "fgrep -v polymorphism/undefined"); } void verify() { chdir("tmp/docs/latex"); verifyrun("cplusplus.log"); verifyrun("cplusplusus.log"); exit(0); } c++-annotations-13.02.01/icmake/mark0000664000175000017500000000012214735537670015751 0ustar frankfrankvoid mark() { g_logMark = backtick("printf '%3d' " + (string)g_lognr++)[0]; } c++-annotations-13.02.01/icmake/clean0000664000175000017500000000054614735537670016113 0ustar frankfrankstring remove1; string remove2; void setRemovals() { remove1 = "tmp ../sf/index.html ../sf/cppannotations"; remove2 = "o indexentry/o aux/o"; } void clean(int stop) { setRemovals(); run("rm -rf " + remove1); chdir("src/htmlindex"); run("rm -rf " + remove2); if (stop) exit(0); else chdir("../../"); } c++-annotations-13.02.01/icmake/uninstall0000664000175000017500000000144014735537670017034 0ustar frankfrankvoid uninstall() { string key; int idx; int nDirs; list entry; list dirs; string dir; if (g_logPath == "") // do not store uninstall info { printf(LOGENV " environment variable not available\n"); exit(0); } readlog(); for (idx = listlen(g_log); idx--; ) { entry = strtok(g_log[idx], " "); if (entry[1] == "dir") { dir = entry[2]; dirs += (list)dir; chdir(dir); } else if (entry[1] == "file") remove(entry); else if (entry[1] == "link") run("rm " + entry[2]); } for (idx = 0, nDirs = listlen(dirs); idx != nDirs; ++idx) removeDir(dirs[idx]); run("rm " + g_logPath); exit(0); } c++-annotations-13.02.01/icmake/cuteoln0000664000175000017500000000023314735537670016473 0ustar frankfrankstring cutEoln(string text) { int len; len = strlen(text) - 1; if (text[len] == "\n") text = substr(text, 0, len); return text; } c++-annotations-13.02.01/icmake/run0000664000175000017500000000015114735537670015625 0ustar frankfrankvoid run(string cmd) { if (g_echo == OFF) cmd += "> /dev/null 2>&1"; system(0, cmd); } c++-annotations-13.02.01/icmake/zips0000664000175000017500000000237514735537670016020 0ustar frankfrankvoid zip(string dst, string src) { system("zip -r cppannotations/zips/" + dst + " cppannotations/" + src); } void zips() { system("mkdir -p tmp/docs/zips"); system("rm -f tmp/docs/zips/*"); system("ln -sf tmp/docs cppannotations"); system("cp README single/legal.shtml cppannotations/txt"); zip("cplusplus.txt.zip", "txt/*"); system("cp README single/legal.shtml cppannotations/latex"); zip("cplusplus.ps.zip", "latex/*.ps"); zip("cplusplus.ps.zip", "latex/legal.shtml"); zip("cplusplus.ps.zip", "latex/README"); zip("cplusplus.pdf.zip", "latex/*.pdf"); zip("cplusplus.pdf.zip", "latex/legal.shtml"); zip("cplusplus.pdf.zip", "latex/README"); system("ln -s ../../../contrib tmp/docs/html/contrib"); system("cp README cppannotations/html"); zip("cplusplus.html.zip", "html/* -x *.svn*"); system("rm tmp/docs/html/contrib"); system("ln -sf ../../yo tmp/docs/yo"); system("ln -sf ../contrib yo/contrib"); system("cp single/legal.shtml changelog README yo"); zip("cplusplus.yo.zip", "yo/* -x *.svn*"); system("rm yo/contrib yo/legal.shtml yo/changelog yo/README"); system("rm tmp/docs/yo "); system("rm cppannotations"); exit(0); } c++-annotations-13.02.01/icmake/removedir0000664000175000017500000000137114735537670017022 0ustar frankfrankvoid removeDir(string dir) { list parts; int idx; int dirIdx; list entries; int warn = 1; if (!exists(dir)) // directory was already removed return; parts = findAll("d", dir, ""); // if there are still subdirs if (listlen(parts) != 0) // then remove at some later stage return; chdir(dir); parts = strtok(dir, "/"); for (idx = listlen(parts); idx--; ) { entries = backtick("ls -A"); if (listlen(entries) != 0) { if (warn) printf("not removing non-empty dir ", dir, "\n"); return; } warn = 0; chdir(".."); run("rmdir " + parts[idx]); } } c++-annotations-13.02.01/icmake/md0000664000175000017500000000153114735537670015424 0ustar frankfrank// md: target should be a series of blank-delimited directories to be created // If an element is a whildcard, the directory will always be created, // using mkdir -p. // // uses: run() // if the target directory does not exist it is created and its realpath is // logged. string g_lastLogged; void md(string target) { int idx; list paths; string dir; if (!exists(target)) run("mkdir -p " + target); else if (((int)stat(target)[0] & S_IFDIR) == 0) { printf(target + " exists, but is not a directory\n"); exit(1); } if (g_installing) { target = cutEoln(backtick("realpath " + target)[0]); if (target != g_lastLogged) { g_lastLogged = target; mark(); g_log += (list)(g_logMark + " dir " + target); } } } c++-annotations-13.02.01/icmake/gitlab0000664000175000017500000000027014735537670016265 0ustar frankfrankvoid gitlab() { run("cp -r yo/version.yo tmp/manhtml/c++-annotations-man.html " "tmp/docs/zips ../../wip"); run("cp changelog ../../wip/changelog.txt"); exit(0); } c++-annotations-13.02.01/icmake/remove0000664000175000017500000000042014735537670016315 0ustar frankfrankvoid remove(list entry) { int equal; string file; file = entry[3]; if (!exists(file)) return; equal = md5sum(file) == entry[2]; if (equal) run("rm " + file); else printf("not removing modified file ", file, "\n"); } c++-annotations-13.02.01/icmake/backtick0000664000175000017500000000016014735537670016574 0ustar frankfranklist backtick(string arg) { list ret; echo(OFF); ret = `arg`; echo(g_echo); return ret; } c++-annotations-13.02.01/icmake/md5sum0000664000175000017500000000015214735537670016234 0ustar frankfrankstring md5sum(string file) { return substr(strtok(backtick("md5sum " + file)[0], " \t")[0], 0, 5); } c++-annotations-13.02.01/icmake/install0000664000175000017500000000221714735537670016474 0ustar frankfrankvoid install(string base) { g_installing = 1; #ifdef DOC logZip("", "README README.papersize COPYING README.legalese changelog", base + DOC); logZip("tmp/docs/txt", "cplusplus.txt", base + DOC); logZip_r("tmp/docs", "html", "cplusplus.html.zip", base + DOC); logZip_r("tmp/docs/latex", "cplusplus*.ps", "cplusplus.ps.zip", base + DOC); logZip_r("tmp/docs/latex", "cplusplus*.pdf", "cplusplus.pdf.zip", base + DOC); logZip_r("tmp/docs/latex", "* -x cplusplus*.pdf -x cplusplus*ps", "cplusplus.latex.zip", base + DOC); #ifdef MAN logZip("tmp/manhtml", "c++-annotations-man.html", base + DOC); #endif logInstall("contributions", "*.zip", base + DOC "/contrib"); logZip("contributions", "GGD.algorithm " "chist.html chist.pdf chist.ps " "java_cpp_keywords.html", base + DOC "/contrib"); #endif #ifdef MAN logZip("tmp/man", "c++-annotations.7", base + MAN "/man7"); #endif printf("\n Installation completed\n"); writeLog(); } c++-annotations-13.02.01/icmake/loglink0000664000175000017500000000012114735537670016455 0ustar frankfrankvoid logLink(string file) { g_log += (list)(g_logMark + " link " + file); } c++-annotations-13.02.01/icmake/loginstall0000664000175000017500000000155514735537670017202 0ustar frankfrank// source and dest, absolute or reachable from g_cwd, should exist. // files and links in source matching dest (if empty: all) are copied to dest // and are logged in g_log // Before they are logged, dest is created void logInstall(string src, string pattern, string dest) { list entries; int idx; chdir(g_cwd); md(dest); src += "/"; dest += "/"; entries = findAll("f", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " + src + entries[idx] + " " + dest); chdir(dest); for (idx = listlen(entries); idx--; ) log(entries[idx]); chdir(g_cwd); entries = findAll("l", src, pattern); for (idx = listlen(entries); idx--; ) run("cp " CPOPTS " " + src + entries[idx] + " " + dest); chdir(dest); for (idx = listlen(entries); idx--; ) logLink(entries[idx]); } c++-annotations-13.02.01/icmake/logzip0000664000175000017500000000134514735537670016333 0ustar frankfrank// names may be a series of files in src, not a wildcard. // if it's empty then all files in src are used. // the files are gzipped and logged in dest. // src and dest do not have to end in / void logZip(string src, string names, string dest) { list files; int idx; string file; chdir(g_cwd); dest += "/"; md(dest); if (src != "") chdir(src); if (names == "") files = makelist("*"); else files = strtok(names, " "); for (idx = listlen(files); idx--; ) { file = files[idx]; run("gzip -n -9 < " + file + " > " + g_cwd + dest + file + ".gz"); } chdir(g_cwd + dest); for (idx = listlen(files); idx--; ) log(files[idx] + ".gz"); } c++-annotations-13.02.01/icmake/distclean0000664000175000017500000000114614735537670016774 0ustar frankfrankvoid distclean() { list extensions; int idx; clean(0); run("rm -f script.log yo/legal.shtml latex/legal.shtml html/legal.shtml"); run("rm -f html/cplusplus*.html"); run("rm -f html/target.shtml html/contents.html html/index.html"); run("rm -f html/cppindex.html html/cplusplus.index zip/cplusplus.*.zip"); extensions = strtok("aux dvi idx ilg ind latex log out pdf ps toc", " "); for(idx = listlen(extensions); idx--; ) run("rm -f latex/cplusplus*." + extensions[idx]); run("rm -rf src/*/*/o src/*/o"); run("rm -rf zip/cplusplus.txt"); exit(0); } c++-annotations-13.02.01/icmake/docs0000664000175000017500000001442114735537670015756 0ustar frankfrankstring stringlist(string path, string subdir, string pattern) { list lst; string entry; int idx; string ret; path += subdir + "/"; chdir(subdir); lst = makelist(O_SUBDIR, "*"); for (idx = listlen(lst); idx--; ) ret += stringlist(path, element(idx, lst), pattern); lst = makelist(pattern); for (idx = listlen(lst); idx--; ) ret += path + element(idx, lst) + " "; chdir(".."); return ret; } void cleanup(string task, string files) { list filelist; int idx; filelist = strtok(files, " "); for (idx = listlen(filelist); idx--; ) system("tmp/bin/" + task + " -q " + element(idx, filelist)); } void txtdoc() { if (!exists("tmp/docs/txt/cplusplus.txt")) { md("tmp/docs/txt"); chdir("yo"); system("yodl2txt --no-warnings " "-o ../tmp/docs/txt/cplusplus.txt -l3 cplusplus"); chdir(".."); } } void htmldoc() { list htmlList; int idx; string html; md("tmp/docs/html"); // cp necessary files for HTML if (!exists("tmp/docs/html/annotations.gif")) system("cp -r html/* tmp/docs/html"); // convert .yo to .html if (!exists("tmp/docs/html/cplusplus.html")) { chdir("yo"); system("yodl2html --no-warnings -l3 cplusplus "); system("mv *.html ../tmp/docs/html"); system("cp cplusplus.css ../tmp/docs/html"); chdir(".."); } chdir("tmp/docs/html"); // // only in 2024 // system("../../../tmp/bin/celeb cplusplus.html"); // index.html is the file holding the // c++-annotations-13.02.01/single/target.shtml0000664000175000017500000000447514735537670017502 0ustar frankfrank C++ Annotations

Table of contents:

Contents

Title Page

  1. All Chapters
  2. C++ Intro
  3. A First Impression
  4. Name Spaces
  5. Strings
  6. IOStreams
  7. Classes
  8. Static Data And Functions
  9. Memory Management
  10. Exceptions
  11. Operator Overloading
  12. Abstract Containers
  13. Inheritance
  14. Polymorphism
  15. Friends
  16. Pointers to Members
  17. Nested Classes
  18. Standard Template Library
  19. Generic Algorithms
  20. Multi Threading
  21. Function Templates
  22. Class Templates
  23. Advanced Template Use
  24. Coroutines
  25. Modules
  26. Examples

Index

Index:

c++-annotations-13.02.01/single/legal.shtml0000664000175000017500000000215114735537670017265 0ustar frankfrank Legal considerations for the C++ Annotations


Legal considerations for the C++ Annotations

The C++ Annotations are distributed under the GNU General Public License version 2 or later (See the file COPYING distributed with the C++ Annotations's distribution).

You are encouraged to read the C++ Annotations and to share the C++ Annotations with others. You are also encouraged to include links to the C++ Annotations in your own WWW documents and you are allowed to publish the C++ Annotations on your web-site.

If you intend to use the C++ Annotations for educational purposes please let me know: the more people tell me they use them, the easier it becomes for me to continue and maintain the C++ Annotations.

Direct all correspondence concerning suggestions, additions, improvements or changes in this document to Frank B. Brokken.

The document itself starts here. c++-annotations-13.02.01/src/0000775000175000017500000000000014735537670014437 5ustar frankfrankc++-annotations-13.02.01/src/tab/0000775000175000017500000000000014735537670015205 5ustar frankfrankc++-annotations-13.02.01/src/tab/fname.c0000664000175000017500000000042514735537670016440 0ustar frankfrank#include #ifdef MSDOS #define SEP '\\' #else #define SEP '/' #endif char *fname(char *prog) { register char *cp; if ( (cp = strrchr(prog, SEP)) ) cp++; else cp = prog; # ifdef MSDOS *strstr (cp, ".EXE") = '\0'; # endif return (cp); } c++-annotations-13.02.01/src/tab/flex.c0000664000175000017500000013710614735537670016317 0ustar frankfrank#define YY_NO_INPUT #line 2 "flex.c" #line 4 "flex.c" #define YY_INT_ALIGNED short int /* A lexical scanner generated by flex. yyunput not compiled: by Frank */ #define FLEX_SCANNER #define YY_FLEX_MAJOR_VERSION 2 #define YY_FLEX_MINOR_VERSION 5 #define YY_FLEX_SUBMINOR_VERSION 33 #if YY_FLEX_SUBMINOR_VERSION > 0 #define FLEX_BETA #endif /* First, we deal with platform-specific or compiler-specific issues. */ /* begin standard C headers. */ #include #include #include #include /* end standard C headers. */ /* flex integer type definitions */ #ifndef FLEXINT_H #define FLEXINT_H /* C99 systems have . Non-C99 systems may or may not. */ #if __STDC_VERSION__ >= 199901L /* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, * if you want the limit (max/min) macros for int types. */ #ifndef __STDC_LIMIT_MACROS #define __STDC_LIMIT_MACROS 1 #endif #include typedef int8_t flex_int8_t; typedef uint8_t flex_uint8_t; typedef int16_t flex_int16_t; typedef uint16_t flex_uint16_t; typedef int32_t flex_int32_t; typedef uint32_t flex_uint32_t; #else typedef signed char flex_int8_t; typedef short int flex_int16_t; typedef int flex_int32_t; typedef unsigned char flex_uint8_t; typedef unsigned short int flex_uint16_t; typedef unsigned int flex_uint32_t; #endif /* ! C99 */ /* Limits of integral types. */ #ifndef INT8_MIN #define INT8_MIN (-128) #endif #ifndef INT16_MIN #define INT16_MIN (-32767-1) #endif #ifndef INT32_MIN #define INT32_MIN (-2147483647-1) #endif #ifndef INT8_MAX #define INT8_MAX (127) #endif #ifndef INT16_MAX #define INT16_MAX (32767) #endif #ifndef INT32_MAX #define INT32_MAX (2147483647) #endif #ifndef UINT8_MAX #define UINT8_MAX (255U) #endif #ifndef UINT16_MAX #define UINT16_MAX (65535U) #endif #ifndef UINT32_MAX #define UINT32_MAX (4294967295U) #endif #endif /* ! FLEXINT_H */ #ifdef __cplusplus /* The "const" storage-class-modifier is valid. */ #define YY_USE_CONST #else /* ! __cplusplus */ #if __STDC__ #define YY_USE_CONST #endif /* __STDC__ */ #endif /* ! __cplusplus */ #ifdef YY_USE_CONST #define yyconst const #else #define yyconst #endif /* Returned upon end-of-file. */ #define YY_NULL 0 /* Promotes a possibly negative, possibly signed char to an unsigned * integer for use as an array index. If the signed char is negative, * we want to instead treat it as an 8-bit unsigned char, hence the * double cast. */ #define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) /* Enter a start condition. This macro really ought to take a parameter, * but we do it the disgusting crufty way forced on us by the ()-less * definition of BEGIN. */ #define BEGIN (yy_start) = 1 + 2 * /* Translate the current start state into a value that can be later handed * to BEGIN to return to the state. The YYSTATE alias is for lex * compatibility. */ #define YY_START (((yy_start) - 1) / 2) #define YYSTATE YY_START /* Action number for EOF rule of a given start state. */ #define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) /* Special action meaning "start processing a new file". */ #define YY_NEW_FILE yyrestart(yyin ) #define YY_END_OF_BUFFER_CHAR 0 /* Size of default input buffer. */ #ifndef YY_BUF_SIZE #define YY_BUF_SIZE 16384 #endif /* The state buf must be large enough to hold one state per character in the main buffer. */ #define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) #ifndef YY_TYPEDEF_YY_BUFFER_STATE #define YY_TYPEDEF_YY_BUFFER_STATE typedef struct yy_buffer_state *YY_BUFFER_STATE; #endif extern int yyleng; extern FILE *yyin, *yyout; #define EOB_ACT_CONTINUE_SCAN 0 #define EOB_ACT_END_OF_FILE 1 #define EOB_ACT_LAST_MATCH 2 #define YY_LESS_LINENO(n) /* Return all but the first "n" matched characters back to the input stream. */ #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ *yy_cp = (yy_hold_char); \ YY_RESTORE_YY_MORE_OFFSET \ (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ YY_DO_BEFORE_ACTION; /* set up yytext again */ \ } \ while ( 0 ) #define unput(c) yyunput( c, (yytext_ptr) ) /* The following is because we cannot portably get our hands on size_t * (without autoconf's help, which isn't available because we want * flex-generated scanners to compile on their own). */ #ifndef YY_TYPEDEF_YY_SIZE_T #define YY_TYPEDEF_YY_SIZE_T typedef unsigned int yy_size_t; #endif #ifndef YY_STRUCT_YY_BUFFER_STATE #define YY_STRUCT_YY_BUFFER_STATE struct yy_buffer_state { FILE *yy_input_file; char *yy_ch_buf; /* input buffer */ char *yy_buf_pos; /* current position in input buffer */ /* Size of input buffer in bytes, not including room for EOB * characters. */ yy_size_t yy_buf_size; /* Number of characters read into yy_ch_buf, not including EOB * characters. */ int yy_n_chars; /* Whether we "own" the buffer - i.e., we know we created it, * and can realloc() it to grow it, and should free() it to * delete it. */ int yy_is_our_buffer; /* Whether this is an "interactive" input source; if so, and * if we're using stdio for input, then we want to use getc() * instead of fread(), to make sure we stop fetching input after * each newline. */ int yy_is_interactive; /* Whether we're considered to be at the beginning of a line. * If so, '^' rules will be active on the next match, otherwise * not. */ int yy_at_bol; int yy_bs_lineno; /**< The line count. */ int yy_bs_column; /**< The column count. */ /* Whether to try to fill the input buffer when we reach the * end of it. */ int yy_fill_buffer; int yy_buffer_status; #define YY_BUFFER_NEW 0 #define YY_BUFFER_NORMAL 1 /* When an EOF's been seen but there's still some text to process * then we mark the buffer as YY_EOF_PENDING, to indicate that we * shouldn't try reading from the input source any more. We might * still have a bunch of tokens to match, though, because of * possible backing-up. * * When we actually see the EOF, we change the status to "new" * (via yyrestart()), so that the user can continue scanning by * just pointing yyin at a new input file. */ #define YY_BUFFER_EOF_PENDING 2 }; #endif /* !YY_STRUCT_YY_BUFFER_STATE */ /* Stack of input buffers. */ static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ /* We provide macros for accessing buffer states in case in the * future we want to put the buffer states in a more general * "scanner state". * * Returns the top of the stack, or NULL. */ #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) /* Same as previous macro, but useful when we know that the buffer stack is not * NULL or when we need an lvalue. For internal use only. */ #define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] /* yy_hold_char holds the character lost when yytext is formed. */ static char yy_hold_char; static int yy_n_chars; /* number of characters read into yy_ch_buf */ int yyleng; /* Points to current character in buffer. */ static char *yy_c_buf_p = (char *) 0; static int yy_init = 0; /* whether we need to initialize */ static int yy_start = 0; /* start state number */ /* Flag which is used to allow yywrap()'s to do buffer switches * instead of setting up a fresh yyin. A bit of a hack ... */ static int yy_did_buffer_switch_on_eof; void yyrestart (FILE *input_file ); void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ); YY_BUFFER_STATE yy_create_buffer (FILE *file,int size ); void yy_delete_buffer (YY_BUFFER_STATE b ); void yy_flush_buffer (YY_BUFFER_STATE b ); void yypush_buffer_state (YY_BUFFER_STATE new_buffer ); void yypop_buffer_state (void ); static void yyensure_buffer_stack (void ); static void yy_load_buffer_state (void ); static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file ); #define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER ) YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size ); YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str ); YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len ); void *yyalloc (yy_size_t ); void *yyrealloc (void *,yy_size_t ); void yyfree (void * ); #define yy_new_buffer yy_create_buffer #define yy_set_interactive(is_interactive) \ { \ if ( ! YY_CURRENT_BUFFER ){ \ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ } #define yy_set_bol(at_bol) \ { \ if ( ! YY_CURRENT_BUFFER ){\ yyensure_buffer_stack (); \ YY_CURRENT_BUFFER_LVALUE = \ yy_create_buffer(yyin,YY_BUF_SIZE ); \ } \ YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ } #define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) typedef unsigned char YY_CHAR; FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; typedef int yy_state_type; extern int yylineno; int yylineno = 1; extern char *yytext; #define yytext_ptr yytext static yy_state_type yy_get_previous_state (void ); static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); static int yy_get_next_buffer (void ); static void yy_fatal_error (yyconst char msg[] ); /* Done after the current pattern has been matched and before the * corresponding action - sets up yytext. */ #define YY_DO_BEFORE_ACTION \ (yytext_ptr) = yy_bp; \ yyleng = (size_t) (yy_cp - yy_bp); \ (yy_hold_char) = *yy_cp; \ *yy_cp = '\0'; \ (yy_c_buf_p) = yy_cp; #define YY_NUM_RULES 5 #define YY_END_OF_BUFFER 6 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info { flex_int32_t yy_verify; flex_int32_t yy_nxt; }; static yyconst flex_int16_t yy_accept[9] = { 0, 0, 0, 6, 4, 2, 3, 1, 0 } ; static yyconst flex_int32_t yy_ec[256] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 4, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 } ; static yyconst flex_int32_t yy_meta[5] = { 0, 1, 1, 1, 1 } ; static yyconst flex_int16_t yy_base[9] = { 0, 0, 0, 5, 6, 6, 6, 6, 6 } ; static yyconst flex_int16_t yy_def[9] = { 0, 8, 1, 8, 8, 8, 8, 8, 0 } ; static yyconst flex_int16_t yy_nxt[11] = { 0, 4, 5, 6, 7, 8, 3, 8, 8, 8, 8 } ; static yyconst flex_int16_t yy_chk[11] = { 0, 1, 1, 1, 1, 3, 8, 8, 8, 8, 8 } ; static yy_state_type yy_last_accepting_state; static char *yy_last_accepting_cpos; extern int yy_flex_debug; int yy_flex_debug = 0; /* The intent behind this definition is that it'll catch * any uses of REJECT which flex missed. */ #define REJECT reject_used_but_not_detected #define yymore() yymore_used_but_not_detected #define YY_MORE_ADJ 0 #define YY_RESTORE_YY_MORE_OFFSET char *yytext; #line 1 "rules.lex" #line 2 "rules.lex" int column = 0, nspaces = 0; FILE *yyout; extern int entab, minspaces, tabpos; void process_spaces() { register int ntabs; if (nspaces >= minspaces) if ( (ntabs = column / tabpos - (column - nspaces) / tabpos) ) { nspaces = column % tabpos; for (; ntabs; ntabs--) fputc('\t', yyout); /* put out a tab char */ } while (nspaces--) fputc(' ', yyout); nspaces = 0; } #line 482 "flex.c" #define INITIAL 0 #ifndef YY_NO_UNISTD_H /* Special case for "unistd.h", since it is non-ANSI. We include it way * down here because we want the user's section 1 to have been scanned first. * The user has a chance to override it with an option. */ #include #endif #ifndef YY_EXTRA_TYPE #define YY_EXTRA_TYPE void * #endif static int yy_init_globals (void ); /* Macros after this point can all be overridden by user definitions in * section 1. */ #ifndef YY_SKIP_YYWRAP #ifdef __cplusplus extern "C" int yywrap (void ); #else extern int yywrap (void ); #endif #endif #if 0 static void yyunput (int c,char *buf_ptr ); #endif #ifndef yytext_ptr static void yy_flex_strncpy (char *,yyconst char *,int ); #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * ); #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void ); #else static int input (void ); #endif #endif /* Amount of stuff to slurp up with each read. */ #ifndef YY_READ_BUF_SIZE #define YY_READ_BUF_SIZE 8192 #endif /* Copy whatever the last rule matched to the standard output. */ #ifndef ECHO /* This used to be an fputs(), but since the string might contain NUL's, * we now use fwrite(). */ #define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) #endif /* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, * is returned in "result". */ #ifndef YY_INPUT #define YY_INPUT(buf,result,max_size) \ if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ { \ int c = '*'; \ size_t n; \ for ( n = 0; n < max_size && \ (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ buf[n] = (char) c; \ if ( c == '\n' ) \ buf[n++] = (char) c; \ if ( c == EOF && ferror( yyin ) ) \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ result = n; \ } \ else \ { \ errno=0; \ while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \ { \ if( errno != EINTR) \ { \ YY_FATAL_ERROR( "input in flex scanner failed" ); \ break; \ } \ errno=0; \ clearerr(yyin); \ } \ }\ \ #endif /* No semi-colon after return; correct usage is to write "yyterminate();" - * we don't want an extra ';' after the "return" because that will cause * some compilers to complain about unreachable statements. */ #ifndef yyterminate #define yyterminate() return YY_NULL #endif /* Number of entries by which start-condition stack grows. */ #ifndef YY_START_STACK_INCR #define YY_START_STACK_INCR 25 #endif /* Report a fatal error. */ #ifndef YY_FATAL_ERROR #define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) #endif /* end tables serialization structures and prototypes */ /* Default declaration of generated scanner - a define so the user can * easily add parameters. */ #ifndef YY_DECL #define YY_DECL_IS_OURS 1 extern int yylex (void); #define YY_DECL int yylex (void) #endif /* !YY_DECL */ /* Code executed at the beginning of each rule, after yytext and yyleng * have been set up. */ #ifndef YY_USER_ACTION #define YY_USER_ACTION #endif /* Code executed at the end of each rule. */ #ifndef YY_BREAK #define YY_BREAK break; #endif #define YY_RULE_SETUP \ YY_USER_ACTION /** The main scanner function which does all the work. */ YY_DECL { register yy_state_type yy_current_state; register char *yy_cp, *yy_bp; register int yy_act; #line 32 "rules.lex" #line 637 "flex.c" if ( !(yy_init) ) { (yy_init) = 1; #ifdef YY_USER_INIT YY_USER_INIT; #endif if ( ! (yy_start) ) (yy_start) = 1; /* first start state */ if ( ! yyin ) yyin = stdin; if ( ! yyout ) yyout = stdout; if ( ! YY_CURRENT_BUFFER ) { yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_load_buffer_state( ); } while ( 1 ) /* loops until end-of-file is reached */ { yy_cp = (yy_c_buf_p); /* Support of yytext. */ *yy_cp = (yy_hold_char); /* yy_bp points to the position in yy_ch_buf of the start of * the current run. */ yy_bp = yy_cp; yy_current_state = (yy_start); yy_match: do { register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 9 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; ++yy_cp; } while ( yy_base[yy_current_state] != 6 ); yy_find_action: yy_act = yy_accept[yy_current_state]; if ( yy_act == 0 ) { /* have to back up */ yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); yy_act = yy_accept[yy_current_state]; } YY_DO_BEFORE_ACTION; do_action: /* This label is used only to access EOF actions. */ switch ( yy_act ) { /* beginning of action switch */ case 0: /* must back up */ /* undo the effects of YY_DO_BEFORE_ACTION */ *yy_cp = (yy_hold_char); yy_cp = (yy_last_accepting_cpos); yy_current_state = (yy_last_accepting_state); goto yy_find_action; case 1: YY_RULE_SETUP #line 33 "rules.lex" { column++; nspaces++; if (!entab) /* write blank if detab */ fputc(' ', yyout); } YY_BREAK case 2: YY_RULE_SETUP #line 41 "rules.lex" { if (entab) { process_spaces(); fputc('\t', yyout); } else { do fputc(' ', yyout); while (++column % tabpos); } column = 0; /* as we are at a tab-position */ } YY_BREAK case 3: /* rule 3 can match eol */ YY_RULE_SETUP #line 56 "rules.lex" { fputc(yytext[0], yyout); column = nspaces = 0; /* process spaces are ignored */ } YY_BREAK case 4: YY_RULE_SETUP #line 61 "rules.lex" { if (entab) process_spaces(); column++; fputc(yytext[0], yyout); } YY_BREAK case 5: YY_RULE_SETUP #line 67 "rules.lex" ECHO; YY_BREAK #line 773 "flex.c" case YY_STATE_EOF(INITIAL): yyterminate(); case YY_END_OF_BUFFER: { /* Amount of text matched not including the EOB char. */ int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; /* Undo the effects of YY_DO_BEFORE_ACTION. */ *yy_cp = (yy_hold_char); YY_RESTORE_YY_MORE_OFFSET if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) { /* We're scanning a new file or input source. It's * possible that this happened because the user * just pointed yyin at a new source and called * yylex(). If so, then we have to assure * consistency between YY_CURRENT_BUFFER and our * globals. Here is the right place to do so, because * this is the first action (other than possibly a * back-up) that will match for the new input source. */ (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; } /* Note that here we test for yy_c_buf_p "<=" to the position * of the first EOB in the buffer, since yy_c_buf_p will * already have been incremented past the NUL character * (since all states make transitions on EOB to the * end-of-buffer state). Contrast this with the test * in input(). */ if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) { /* This was really a NUL. */ yy_state_type yy_next_state; (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); /* Okay, we're now positioned to make the NUL * transition. We couldn't have * yy_get_previous_state() go ahead and do it * for us because it doesn't know how to deal * with the possibility of jamming (and we don't * want to build jamming into it because then it * will run more slowly). */ yy_next_state = yy_try_NUL_trans( yy_current_state ); yy_bp = (yytext_ptr) + YY_MORE_ADJ; if ( yy_next_state ) { /* Consume the NUL. */ yy_cp = ++(yy_c_buf_p); yy_current_state = yy_next_state; goto yy_match; } else { yy_cp = (yy_c_buf_p); goto yy_find_action; } } else switch ( yy_get_next_buffer( ) ) { case EOB_ACT_END_OF_FILE: { (yy_did_buffer_switch_on_eof) = 0; if ( yywrap( ) ) { /* Note: because we've taken care in * yy_get_next_buffer() to have set up * yytext, we can now set up * yy_c_buf_p so that if some total * hoser (like flex itself) wants to * call the scanner after we return the * YY_NULL, it'll still work - another * YY_NULL will get returned. */ (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; yy_act = YY_STATE_EOF(YY_START); goto do_action; } else { if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; } break; } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_match; case EOB_ACT_LAST_MATCH: (yy_c_buf_p) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; yy_current_state = yy_get_previous_state( ); yy_cp = (yy_c_buf_p); yy_bp = (yytext_ptr) + YY_MORE_ADJ; goto yy_find_action; } break; } default: YY_FATAL_ERROR( "fatal flex scanner internal error--no action found" ); } /* end of action switch */ } /* end of scanning one token */ } /* end of yylex */ /* yy_get_next_buffer - try to read in a new buffer * * Returns a code representing an action: * EOB_ACT_LAST_MATCH - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position * EOB_ACT_END_OF_FILE - end of file */ static int yy_get_next_buffer (void) { register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; register char *source = (yytext_ptr); register int number_to_move, i; int ret_val; if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) YY_FATAL_ERROR( "fatal flex scanner internal error--end of buffer missed" ); if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) { /* Don't try to fill the buffer, so this is an EOF. */ if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) { /* We matched a single character, the EOB, so * treat this as a final EOF. */ return EOB_ACT_END_OF_FILE; } else { /* We matched some text prior to the EOB, first * process it. */ return EOB_ACT_LAST_MATCH; } } /* Try to read more data. */ /* First move last chars to start of buffer. */ number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; for ( i = 0; i < number_to_move; ++i ) *(dest++) = *(source++); if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) /* don't do the read, it's not guaranteed to return an EOF, * just force an EOF */ YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; else { int num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; while ( num_to_read <= 0 ) { /* Not enough room in the buffer - grow it. */ /* just a shorter name for the current buffer */ YY_BUFFER_STATE b = YY_CURRENT_BUFFER; int yy_c_buf_p_offset = (int) ((yy_c_buf_p) - b->yy_ch_buf); if ( b->yy_is_our_buffer ) { int new_size = b->yy_buf_size * 2; if ( new_size <= 0 ) b->yy_buf_size += b->yy_buf_size / 8; else b->yy_buf_size *= 2; b->yy_ch_buf = (char *) /* Include room in for 2 EOB chars. */ yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); } else /* Can't grow it, we don't own it. */ b->yy_ch_buf = 0; if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "fatal error - scanner input buffer overflow" ); (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; } if ( num_to_read > YY_READ_BUF_SIZE ) num_to_read = YY_READ_BUF_SIZE; /* Read in more data. */ YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), (yy_n_chars), (size_t) num_to_read ); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } if ( (yy_n_chars) == 0 ) { if ( number_to_move == YY_MORE_ADJ ) { ret_val = EOB_ACT_END_OF_FILE; yyrestart(yyin ); } else { ret_val = EOB_ACT_LAST_MATCH; YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_EOF_PENDING; } } else ret_val = EOB_ACT_CONTINUE_SCAN; (yy_n_chars) += number_to_move; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; return ret_val; } /* yy_get_previous_state - get the state just before the EOB char was reached */ static yy_state_type yy_get_previous_state (void) { register yy_state_type yy_current_state; register char *yy_cp; yy_current_state = (yy_start); for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) { register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 9 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; } return yy_current_state; } /* yy_try_NUL_trans - try to make a transition on the NUL character * * synopsis * next_state = yy_try_NUL_trans( current_state ); */ static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) { register int yy_is_jam; register char *yy_cp = (yy_c_buf_p); register YY_CHAR yy_c = 1; if ( yy_accept[yy_current_state] ) { (yy_last_accepting_state) = yy_current_state; (yy_last_accepting_cpos) = yy_cp; } while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; if ( yy_current_state >= 9 ) yy_c = yy_meta[(unsigned int) yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; yy_is_jam = (yy_current_state == 8); return yy_is_jam ? 0 : yy_current_state; } #if 0 static void yyunput (int c, register char * yy_bp ) { register char *yy_cp; yy_cp = (yy_c_buf_p); /* undo effects of setting up yytext */ *yy_cp = (yy_hold_char); if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) { /* need to shift things up to make room */ /* +2 for EOB chars. */ register int number_to_move = (yy_n_chars) + 2; register char *dest = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[ YY_CURRENT_BUFFER_LVALUE->yy_buf_size + 2]; register char *source = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]; while ( source > YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) *--dest = *--source; yy_cp += (int) (dest - source); yy_bp += (int) (dest - source); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_buf_size; if ( yy_cp < YY_CURRENT_BUFFER_LVALUE->yy_ch_buf + 2 ) YY_FATAL_ERROR( "flex scanner push-back overflow" ); } *--yy_cp = (char) c; (yytext_ptr) = yy_bp; (yy_hold_char) = *yy_cp; (yy_c_buf_p) = yy_cp; } #endif #ifndef YY_NO_INPUT #ifdef __cplusplus static int yyinput (void) #else static int input (void) #endif { int c; *(yy_c_buf_p) = (yy_hold_char); if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) { /* yy_c_buf_p now points to the character we want to return. * If this occurs *before* the EOB characters, then it's a * valid NUL; if not, then we've hit the end of the buffer. */ if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) /* This was really a NUL. */ *(yy_c_buf_p) = '\0'; else { /* need more input */ int offset = (yy_c_buf_p) - (yytext_ptr); ++(yy_c_buf_p); switch ( yy_get_next_buffer( ) ) { case EOB_ACT_LAST_MATCH: /* This happens because yy_g_n_b() * sees that we've accumulated a * token and flags that we need to * try matching the token before * proceeding. But for input(), * there's no matching to consider. * So convert the EOB_ACT_LAST_MATCH * to EOB_ACT_END_OF_FILE. */ /* Reset buffer status. */ yyrestart(yyin ); /*FALLTHROUGH*/ case EOB_ACT_END_OF_FILE: { if ( yywrap( ) ) return EOF; if ( ! (yy_did_buffer_switch_on_eof) ) YY_NEW_FILE; #ifdef __cplusplus return yyinput(); #else return input(); #endif } case EOB_ACT_CONTINUE_SCAN: (yy_c_buf_p) = (yytext_ptr) + offset; break; } } } c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ *(yy_c_buf_p) = '\0'; /* preserve yytext */ (yy_hold_char) = *++(yy_c_buf_p); return c; } #endif /* ifndef YY_NO_INPUT */ /** Immediately switch to a different input stream. * @param input_file A readable stream. * * @note This function does not reset the start condition to @c INITIAL . */ void yyrestart (FILE * input_file ) { if ( ! YY_CURRENT_BUFFER ){ yyensure_buffer_stack (); YY_CURRENT_BUFFER_LVALUE = yy_create_buffer(yyin,YY_BUF_SIZE ); } yy_init_buffer(YY_CURRENT_BUFFER,input_file ); yy_load_buffer_state( ); } /** Switch to a different input buffer. * @param new_buffer The new input buffer. * */ void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer ) { /* TODO. We should be able to replace this entire function body * with * yypop_buffer_state(); * yypush_buffer_state(new_buffer); */ yyensure_buffer_stack (); if ( YY_CURRENT_BUFFER == new_buffer ) return; if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } YY_CURRENT_BUFFER_LVALUE = new_buffer; yy_load_buffer_state( ); /* We don't actually know whether we did this switch during * EOF (yywrap()) processing, but the only time this flag * is looked at is after yywrap() is called, so it's safe * to go ahead and always set it. */ (yy_did_buffer_switch_on_eof) = 1; } static void yy_load_buffer_state (void) { (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file; (yy_hold_char) = *(yy_c_buf_p); } /** Allocate and initialize an input buffer state. * @param file A readable stream. * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. * * @return the allocated buffer state. */ YY_BUFFER_STATE yy_create_buffer (FILE * file, int size ) { YY_BUFFER_STATE b; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_buf_size = size; /* yy_ch_buf has to be 2 characters longer than the size given because * we need to put in 2 end-of-buffer characters. */ b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2 ); if ( ! b->yy_ch_buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); b->yy_is_our_buffer = 1; yy_init_buffer(b,file ); return b; } /** Destroy the buffer. * @param b a buffer created with yy_create_buffer() * */ void yy_delete_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; if ( b->yy_is_our_buffer ) yyfree((void *) b->yy_ch_buf ); yyfree((void *) b ); } #ifndef __cplusplus extern int isatty (int ); #endif /* __cplusplus */ /* Initializes or reinitializes a buffer. * This function is sometimes called more than once on the same buffer, * such as during a yyrestart() or at EOF. */ static void yy_init_buffer (YY_BUFFER_STATE b, FILE * file ) { int oerrno = errno; yy_flush_buffer(b ); b->yy_input_file = file; b->yy_fill_buffer = 1; /* If b is the current buffer, then yy_init_buffer was _probably_ * called from yyrestart() or through yy_get_next_buffer. * In that case, we don't want to reset the lineno or column. */ if (b != YY_CURRENT_BUFFER){ b->yy_bs_lineno = 1; b->yy_bs_column = 0; } b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; errno = oerrno; } /** Discard all buffered characters. On the next scan, YY_INPUT will be called. * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. * */ void yy_flush_buffer (YY_BUFFER_STATE b ) { if ( ! b ) return; b->yy_n_chars = 0; /* We always need two end-of-buffer characters. The first causes * a transition to the end-of-buffer state. The second causes * a jam in that state. */ b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; b->yy_buf_pos = &b->yy_ch_buf[0]; b->yy_at_bol = 1; b->yy_buffer_status = YY_BUFFER_NEW; if ( b == YY_CURRENT_BUFFER ) yy_load_buffer_state( ); } /** Pushes the new state onto the stack. The new state becomes * the current state. This function will allocate the stack * if necessary. * @param new_buffer The new state. * */ void yypush_buffer_state (YY_BUFFER_STATE new_buffer ) { if (new_buffer == NULL) return; yyensure_buffer_stack(); /* This block is copied from yy_switch_to_buffer. */ if ( YY_CURRENT_BUFFER ) { /* Flush out information for old buffer. */ *(yy_c_buf_p) = (yy_hold_char); YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); } /* Only push if top exists. Otherwise, replace top. */ if (YY_CURRENT_BUFFER) (yy_buffer_stack_top)++; YY_CURRENT_BUFFER_LVALUE = new_buffer; /* copied from yy_switch_to_buffer. */ yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } /** Removes and deletes the top of the stack, if present. * The next element becomes the new top. * */ void yypop_buffer_state (void) { if (!YY_CURRENT_BUFFER) return; yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; if ((yy_buffer_stack_top) > 0) --(yy_buffer_stack_top); if (YY_CURRENT_BUFFER) { yy_load_buffer_state( ); (yy_did_buffer_switch_on_eof) = 1; } } /* Allocates the stack if it does not exist. * Guarantees space for at least one push. */ static void yyensure_buffer_stack (void) { int num_to_alloc; if (!(yy_buffer_stack)) { /* First allocation is just for 2 elements, since we don't know if this * scanner will even need a stack. We use 2 instead of 1 to avoid an * immediate realloc on the next call. */ num_to_alloc = 1; (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc (num_to_alloc * sizeof(struct yy_buffer_state*) ); memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; (yy_buffer_stack_top) = 0; return; } if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ /* Increase the buffer to prepare for a possible push. */ int grow_size = 8 /* arbitrary grow size */; num_to_alloc = (yy_buffer_stack_max) + grow_size; (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc ((yy_buffer_stack), num_to_alloc * sizeof(struct yy_buffer_state*) ); /* zero only the new slots.*/ memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); (yy_buffer_stack_max) = num_to_alloc; } } /** Setup the input buffer state to scan directly from a user-specified character buffer. * @param base the character buffer * @param size the size in bytes of the character buffer * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_buffer (char * base, yy_size_t size ) { YY_BUFFER_STATE b; if ( size < 2 || base[size-2] != YY_END_OF_BUFFER_CHAR || base[size-1] != YY_END_OF_BUFFER_CHAR ) /* They forgot to leave room for the EOB's. */ return 0; b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state ) ); if ( ! b ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ b->yy_buf_pos = b->yy_ch_buf = base; b->yy_is_our_buffer = 0; b->yy_input_file = 0; b->yy_n_chars = b->yy_buf_size; b->yy_is_interactive = 0; b->yy_at_bol = 1; b->yy_fill_buffer = 0; b->yy_buffer_status = YY_BUFFER_NEW; yy_switch_to_buffer(b ); return b; } /** Setup the input buffer state to scan a string. The next call to yylex() will * scan from a @e copy of @a str. * @param yystr a NUL-terminated string to scan * * @return the newly allocated buffer state object. * @note If you want to scan bytes that may contain NUL values, then use * yy_scan_bytes() instead. */ YY_BUFFER_STATE yy_scan_string (yyconst char * yystr ) { return yy_scan_bytes(yystr,strlen(yystr) ); } /** Setup the input buffer state to scan the given bytes. The next call to yylex() will * scan from a @e copy of @a bytes. * @param bytes the byte buffer to scan * @param len the number of bytes in the buffer pointed to by @a bytes. * * @return the newly allocated buffer state object. */ YY_BUFFER_STATE yy_scan_bytes (yyconst char * yybytes, int _yybytes_len ) { YY_BUFFER_STATE b; char *buf; yy_size_t n; int i; /* Get memory for full buffer, including space for trailing EOB's. */ n = _yybytes_len + 2; buf = (char *) yyalloc(n ); if ( ! buf ) YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); for ( i = 0; i < _yybytes_len; ++i ) buf[i] = yybytes[i]; buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; b = yy_scan_buffer(buf,n ); if ( ! b ) YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); /* It's okay to grow etc. this buffer, and we should throw it * away when we're done. */ b->yy_is_our_buffer = 1; return b; } #ifndef YY_EXIT_FAILURE #define YY_EXIT_FAILURE 2 #endif static void yy_fatal_error (yyconst char* msg ) { (void) fprintf( stderr, "%s\n", msg ); exit( YY_EXIT_FAILURE ); } /* Redefine yyless() so it works in section 3 code. */ #undef yyless #define yyless(n) \ do \ { \ /* Undo effects of setting up yytext. */ \ int yyless_macro_arg = (n); \ YY_LESS_LINENO(yyless_macro_arg);\ yytext[yyleng] = (yy_hold_char); \ (yy_c_buf_p) = yytext + yyless_macro_arg; \ (yy_hold_char) = *(yy_c_buf_p); \ *(yy_c_buf_p) = '\0'; \ yyleng = yyless_macro_arg; \ } \ while ( 0 ) /* Accessor methods (get/set functions) to struct members. */ /** Get the current line number. * */ int yyget_lineno (void) { return yylineno; } /** Get the input stream. * */ FILE *yyget_in (void) { return yyin; } /** Get the output stream. * */ FILE *yyget_out (void) { return yyout; } /** Get the length of the current token. * */ int yyget_leng (void) { return yyleng; } /** Get the current token. * */ char *yyget_text (void) { return yytext; } /** Set the current line number. * @param line_number * */ void yyset_lineno (int line_number ) { yylineno = line_number; } /** Set the input stream. This does not discard the current * input buffer. * @param in_str A readable stream. * * @see yy_switch_to_buffer */ void yyset_in (FILE * in_str ) { yyin = in_str ; } void yyset_out (FILE * out_str ) { yyout = out_str ; } int yyget_debug (void) { return yy_flex_debug; } void yyset_debug (int bdebug ) { yy_flex_debug = bdebug ; } static int yy_init_globals (void) { /* Initialization is the same as for the non-reentrant scanner. * This function is called from yylex_destroy(), so don't allocate here. */ (yy_buffer_stack) = 0; (yy_buffer_stack_top) = 0; (yy_buffer_stack_max) = 0; (yy_c_buf_p) = (char *) 0; (yy_init) = 0; (yy_start) = 0; /* Defined in main.c */ #ifdef YY_STDINIT yyin = stdin; yyout = stdout; #else yyin = (FILE *) 0; yyout = (FILE *) 0; #endif /* For future reference: Set errno on error, since we are called by * yylex_init() */ return 0; } /* yylex_destroy is for both reentrant and non-reentrant scanners. */ int yylex_destroy (void) { /* Pop the buffer stack, destroying each element. */ while(YY_CURRENT_BUFFER){ yy_delete_buffer(YY_CURRENT_BUFFER ); YY_CURRENT_BUFFER_LVALUE = NULL; yypop_buffer_state(); } /* Destroy the stack itself. */ yyfree((yy_buffer_stack) ); (yy_buffer_stack) = NULL; /* Reset the globals. This is important in a non-reentrant scanner so the next time * yylex() is called, initialization will occur. */ yy_init_globals( ); return 0; } /* * Internal utility routines. */ #ifndef yytext_ptr static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) { register int i; for ( i = 0; i < n; ++i ) s1[i] = s2[i]; } #endif #ifdef YY_NEED_STRLEN static int yy_flex_strlen (yyconst char * s ) { register int n; for ( n = 0; s[n]; ++n ) ; return n; } #endif void *yyalloc (yy_size_t size ) { return (void *) malloc( size ); } void *yyrealloc (void * ptr, yy_size_t size ) { /* The cast to (char *) in the following accommodates both * implementations that use char* generic pointers, and those * that use void* generic pointers. It works with the latter * because both ANSI C and C++ allow castless assignment from * any pointer type to void*, and deal with argument conversions * as though doing an assignment. */ return (void *) realloc( (char *) ptr, size ); } void yyfree (void * ptr ) { free( (char *) ptr ); /* see yyrealloc() for (char *) cast */ } #define YYTABLES_NAME "yytables" #line 67 "rules.lex" c++-annotations-13.02.01/src/tab/tab.c0000664000175000017500000001036614735537670016125 0ustar frankfrank/* TAB.C 92 11 24 Ported for Unix KK 94 04 06 Port and maintenance for ELF: FBB 96/08/xx Skipping symbolic links: FBB 2001/07/22 Repairing EOF swallow: FBB 2001/09/09 */ #ifdef MSDOS #if !defined(M_I86SM) #error SMALL memory model expected #endif #endif #include #include #include #ifndef MSDOS #include #include #include #endif extern int yylex (void); extern char *fname (char *); extern FILE *yyin, *yyout; extern int column, nspaces; int quiet = 0, entab = 0, minspaces = 4, tabpos = 8; char version[] = "1.41", tempfile[] = "tab.tmp"; int main(int argc, char **argv) { int piping = 0; char *progname; struct stat fileinfo; progname = fname(argv[0]); while (argc > 1 && *argv[1] == '-') { switch (argv[1][1]) { case 'd': entab = 0; break; case 'e': entab = 1; break; case 's': if (!(minspaces = atoi(argv [1] + 2))) { printf("%s: missing or illegal space count at -s, " "assuming 4\n", progname); minspaces = 4; } break; case 'c': if (!(tabpos = atoi(argv [1] + 2))) { printf("%s: missing or illegal column count at -c, " "assuming 8\n", progname); tabpos = 8; } break; case 'q': quiet = 1; break; default: if (!argv[1][1]) { piping = 1; break; } printf("%s: unknown flag '-%c,' ignored\n", progname, *(*argv + 1)); break; } argv++; argc--; } if (argc == 1 && !piping) /* error */ { printf("\nTAB Entabber/Detabber V%s\n" "Copyright (c) GPL 1989-2006. All rights reserved.\n" "\n" "%s by Frank B. Brokken (f.b.brokken@rc.rug.nl).\n" "\n" "Usage: %s [-d | -e | -snnn | -cnnn]* file(s)\n" "where:\n" " -c - entab at / detab to multiples of nnn columns " "(default: 8)\n" " -d - tabs in file(s) are removed (detab)\n" " (default action)\n" " -e - spaces in file(s) are changed into tabs (entab)\n" " -q - quiet: less output than otherwise\n" " -s - entab/detab a minimum number of nnn spaces " "(default: 4)\n" " file(s) - file(s) to entab/detab (are overwritten)\n" " use - to filter stdin to stdout\n" " non-regular files (e.g. symbolic links) are " "skipped.\n" "\n" , version, progname, progname); return (1); } if (piping) { yyin = stdin; yyout = stdout; yylex(); return (0); } for (++argv; *argv; ++argv) { if (lstat(*argv, &fileinfo)) { printf("Can't stat %s: skipping\n", *argv); continue; } if (!S_ISREG(fileinfo.st_mode)) /* not a regular file */ continue; /* skip it silently */ if (!quiet) printf("processing %s\n", *argv); unlink(tempfile); if (rename(*argv, tempfile)) { printf("%s: can't rename %s\n", progname, *argv); return (1); } if ( !(yyin = fopen(tempfile, "r")) || !(yyout = fopen(*argv, "w")) ) { printf ("%s: cannot open in- or output file\n", progname); return (1); } yylex(); fclose (yyin); fclose (yyout); } unlink(tempfile); return (0); } c++-annotations-13.02.01/src/htmlindex/0000775000175000017500000000000014771045033016416 5ustar frankfrankc++-annotations-13.02.01/src/htmlindex/build0000775000175000017500000001461314735537670017465 0ustar frankfrank#!/usr/bin/icmake -t. #include "../../compilers.im" string CLASSES; void setClasses() { CLASSES += " aux indexentry"; } #define ECHO_REQUEST ON // Extra libraries required. Remove lib and .a from the library names. // E.g., #define LIBS "m Xt" to link libm.a and libXt.a explicitly // Specify libs from the most specific to the most general one. #define LIBS ${BOBCAT} // Extra library-paths required. // E.g., #define LIBPATH "/some/path /some/other/path" to search these paths // apart from the default paths #define LIBPATH ${LPATH} // DO NOT ALTER THINGS BELOW THIS LINE string // contain options for libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" lopt, libxxxa; // expanded lib-name string ofiles, // wildcards for o-files sources, // sources to be used wild, // wildcard of extension current; // contains name of current dir. list objfiles(list files) { string file, objfile; int i; for (i = 0; i < listlen(files); i++) { file = element(i, files); // determine element of the list objfile = "./o/" + change_ext(file, "o"); // make obj-filename if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } list altered(list files, string target) { int i; string file; for (i = 0; i < listlen(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type files = objfiles(files); // remove if younger .obj exist return (files); } void link(string library, string exe) { exec(GPP, "-o", exe, ofiles, libs, "-L.", libpath, lopt ); } void c_compile(list cfiles) { string nextfile; int i; if (!exists("o")) system("mkdir o"); if (listlen(cfiles)) // files to compile ? { printf(current, "\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) { exec(GPP, "-c -o o/" + change_ext(nextfile, "o") + " " CPPOPT + " " + nextfile); } } } void updatelib(string library) { list arlist, objlist; string to, from; objlist = makelist("*.o"); if (!listlen(objlist)) return; printf("\n"); exec("ar", "rvs", library, "*.o"); exec("rm", "*.o"); printf("\n"); } void prefix_class(string class_id) { list o_files; string o_file; int i; o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); } void std_cpp(string library) { list cfiles; cfiles = file_list(wild, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } void cpp_make(string mainfile, string library, string exe) { int n, index; list classes; string cwd; setClasses(); // remaining classes cwd = chdir("."); ofiles = "o/*.o"; // std set of o-files classes = strtok(CLASSES, " "); // list of classes if (n = listlen(classes)) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use wild = sources; // make library name libxxxa = chdir(".") + "lib" + library + ".a"; // first process all classes for (index = 0; index < n; index++) { current = element(index, classes); // next class to process chdir(current); // change to directory current = "subdir " + current; std_cpp (libxxxa); // compile all files chdir( cwd); // go back to parent dir } current = "auxiliary " + wild + " files"; std_cpp (libxxxa); // compile all files in current dir for (index = 0; index < n; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. chdir(cwd); // go back to parent dir } current = ""; // no class anymore if (mainfile != "") // mainfile -> do link link(library, exe); } void setlibs() { int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = listlen(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); cut = strtok(LIBPATH, " "); // cut up the paths n = listlen(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); } void main() { echo(ECHO_REQUEST); sources = "*.cc"; setlibs(); lopt = "-s"; system("mkdir -p ../../tmp/bin"); // make destination if it doesn't // already exist cpp_make ( "htmlindex.cc", // program source "htmlindex", // program library "../../tmp/bin/htmlindex" // binary program ); } c++-annotations-13.02.01/src/htmlindex/htmlindex.cc0000664000175000017500000000245014735537670020737 0ustar frankfrank/* htmlindex.cc */ #include "htmlindex.h" HashString indexHash; vector indexVector; vector filenameVector; string lastFilename; char indexSection = 'A' - 1; int returnValue = 0; int main(int argc, char **argv) { Arg::initialize("", argc, argv); Arg &arg(Arg::instance()); if (isatty(STDIN_FILENO)) usage(arg.basename()); getKeys(); sort(indexVector.begin(), indexVector.end()); head(); unsigned n = indexVector.size(), halfway = (n + 1) / 2; cout << "\n" << "\n"; // left column as a table for (unsigned idx = 0; idx < halfway; idx++) // print left column { cout << "\n"; display(idx); cout << "\n"; } cout << "
\n" << "\n" << // left column done "\n" << "\n"; // right column as a table for (unsigned idx = halfway; idx < n; idx++) // print right column { cout << "\n"; display(idx); cout << "\n"; } cout << "
\n" << "\n"; // right column done tail(); return returnValue; } c++-annotations-13.02.01/src/htmlindex/indexentry/0000775000175000017500000000000014771045033020607 5ustar frankfrankc++-annotations-13.02.01/src/htmlindex/indexentry/operatorless.cc0000664000175000017500000000065414735537670023662 0ustar frankfrank#include "../htmlindex.h" bool IndexEntry::operator<(IndexEntry const &other) const { if (isalnum(uppercaseKey[0]) && !isalnum(other.uppercaseKey[0])) return false; // alphanumeric entries after special chars if (!isalnum(uppercaseKey[0]) && isalnum(other.uppercaseKey[0])) return true; // special chars before alphanumeric entries return uppercaseKey < other.uppercaseKey; } c++-annotations-13.02.01/src/htmlindex/indexentry/showrefs.cc0000664000175000017500000000062314735537670022774 0ustar frankfrank#include "../htmlindex.h" void IndexEntry::showRefs() { for ( vector >::iterator it = labels.begin(); it != labels.end(); it++ ) cout << " second << " target=info>" << it->second << " \n"; } c++-annotations-13.02.01/src/htmlindex/indexentry/indexentry.cc0000664000175000017500000000056414735537670023331 0ustar frankfrank#include "../htmlindex.h" IndexEntry::IndexEntry(string const &keystring, unsigned filenameIndex, unsigned labelNr) : key(keystring) { for (string::iterator it = key.begin(); it != key.end(); it++) if (*it != ' ') uppercaseKey += toupper(*it); labels.push_back(pair(filenameIndex, labelNr)); } c++-annotations-13.02.01/src/htmlindex/indexentry/indexentry.h0000664000175000017500000000000014735537670023154 0ustar frankfrankc++-annotations-13.02.01/src/htmlindex/man/0000775000175000017500000000000014735537670017206 5ustar frankfrankc++-annotations-13.02.01/src/htmlindex/man/htmlindex.yo0000664000175000017500000000531214735537670021554 0ustar frankfrankCOMMENT( Leave a definition of a label empty if not used. E.g., if you don't have other programs related to this one, use: SUBST(@SEEALSO) () Use bf() for items that should appear literally in commands, etc. use em() for formal names, that should be replaced by actual values in real life. ) SUBST(@SECTION) (1) SUBST(@DATE) (2003) SUBST(@AUTHOR) (Frank B. Brokken (bf(f.b.brokken@rc.rug.nl)).) SUBST(@ORGANIZATION) (Computing Center, University of Groningen.) SUBST(@PROGRAM) (htmlindex) SUBST(@PROJECT) (C++ Annotations Software) SUBST(@DISTRIBUTION) (htmlindex-X.YY.tar.gz) SUBST(@SHORTDESC) (Create html index from Yodl index entries) SUBST(@SYNOPSYS)( @PROGRAM < indexpage > outputpage ) SUBST(@OPTIONS)( startit() it() tt(indexpage): file obtained from Yodl-html pages containing lines like verb( ) which can be created from Yold-macros like COMMENT(Make sure a blank is written behind the backslashes in the following verb()-block.) verb( NEWCOUNTER(htmlAnchor) def(hix)(1)(\ IFDEF(html)\ (label(an+USECOUNTER(htmlAnchor))\ htmlcommand( )\ )\ (IFDEF(latex)\ (latexcommand(\index{)ARG1+latexcommand(}))\ ()\ )) ) using lines like: verb( hix(http://www.xs4all.nl/.../yodl/) ) it() tt(outputpage): indexfile written as a html-page to the standard output, as a two-column table, sorted, clickable entry file, referring back to labels defined in the pages where the index entries were found. E.g., the table contains entries like verb( http://www.xs4all.nl/.../yodl/ 4  ) endit() ) SUBST(@DESCRIPTION)( See the description of the options. The conversion of index entries in the html file to labels within files may be performed by a simple script, like: verb( #!/bin/sh cd ../html for x in `ls cplusplus[0-9][0-9].html` ; do grep -v '^ ${x}2 mv ${x}2 $x done ) ) SUBST(@FILES)(-) SUBST(@SEEALSO)(-) SUBST(@DIAGNOSTICS)(-) SUBST(@BUGS) (No Documented Bugs.) SUBST(@COPYRIGHT)( This is free software, distributed under the terms of the GNU General Public License. ) COMMENT(Do not modify from here) INCLUDEFILE(/usr/local/share/makemanpage/executables.1/pagedef.yo) c++-annotations-13.02.01/src/htmlindex/aux/0000775000175000017500000000000014771045033017213 5ustar frankfrankc++-annotations-13.02.01/src/htmlindex/aux/getkeys.cc0000664000175000017500000000456114735537670021220 0ustar frankfrank#include "../htmlindex.h" void getKeys() { string line; Pattern pattern("([^:]+):"); unsigned filenameIndex = 0; while (getline(cin, line)) { try { pattern.match(line); } catch (...) { cerr << "Invalid entry at line `" << line << "'\n"; returnValue = 1; continue; } Pattern::Position pos = pattern.position(3); if (pos.first == pos.second) { cerr << "Missing key at line `" << line << "'\n"; returnValue = 1; continue; } string filename = pattern[1], key = pattern[3]; unsigned labelNr = atoi(pattern[2].c_str()); if (filename != lastFilename) { filenameIndex = filenameVector.size(); filenameVector.push_back(filename); lastFilename = filename; cerr << "File " << filename << " at " << filenameIndex << endl; } /* hash indexHash contains the key and an idx in `index' where IndexEntry objects are stored. vector index; IndexEntry: contains the key (and for comparisons speedup the lowercase key, and vector of unsigned label numbers. First hash (and index) are filled. */ hash_iterator it = indexHash.find(key); if (it != indexHash.end()) // key already available { //cerr << "duplicate key: " << key; indexVector[it->second].push_back(filenameIndex, labelNr); } else { // new key: add to the hashtable //cerr << "new key: " << key; indexHash.insert ( //hash_map::value_type HashString::value_type ( key, indexVector.size() ) ); //cerr << "..."; // and add to the `index' vector indexVector.push_back(IndexEntry(key, filenameIndex, labelNr)); } //cerr << " inserted\n"; } } c++-annotations-13.02.01/src/htmlindex/aux/usage.cc0000664000175000017500000000113014735537670020636 0ustar frankfrank#include "../htmlindex.h" void usage(string const &basename) { cout << "\n" << basename << " by Frank B. Brokken (f.b.brokken@rug.nl)\n" "\n" "C++ Annotations html index page builder, V. " << version << endl << "Copyright (c) 2001-2006 Frank B. Brokken. GPL.\n" "\n" "Usage: " << basename << " < indexpage > outputpage\n" "Where:\n" " indexpage: file containing `' index entries\n" " outputpage: file to write the index page to (e.g., " "cplusplusidx.html)\n" << endl; exit(1); } c++-annotations-13.02.01/src/htmlindex/aux/head.cc0000664000175000017500000000042614735537670020442 0ustar frankfrank#include "../htmlindex.h" void head() { cout << "\n" "\n" "C++ Annotations HTML Index \n" "\n" "\n" "\n" "\n" "

Index

\n" "\n" "\n" "\n"; } c++-annotations-13.02.01/src/htmlindex/aux/display.cc0000664000175000017500000000106214735537670021203 0ustar frankfrank#include "../htmlindex.h" void display(unsigned idx) { IndexEntry &ie = indexVector[idx]; if (ie.firstChar() > indexSection && isalnum(ie.firstChar())) { indexSection = ie.firstChar(); cout << " \n" "\n" "\n"; } cout << " \n" << " \n"; } c++-annotations-13.02.01/src/htmlindex/aux/tail.cc0000664000175000017500000000015014735537670020464 0ustar frankfrank#include "../htmlindex.h" void tail() { cout << "\n" "\n" "
 

" << indexSection << "

" << ie.getKey() << " \n"; ie.showRefs(); cout << "
\n" "\n"; } c++-annotations-13.02.01/src/htmlindex/version.cc0000664000175000017500000000011714735537670020426 0ustar frankfrank#include "htmlindex.h" char version[] = "1.13", year[] = "2001-2014"; c++-annotations-13.02.01/src/htmlindex/htmlindex.h0000664000175000017500000000275314735537670020607 0ustar frankfrank// htmlindex.h #ifndef _H_htmlindex_ #define _H_htmlindex_ #include #include #include #include #include #include #include #include #include using namespace FBB; using namespace std; void usage(string const &basename); void getKeys(); void head(); void display(unsigned idx); void tail(); extern char indexSection, version[], year[]; extern int returnValue; extern string lastFilename; extern vector filenameVector; extern HashString // hash_map indexHash; typedef HashString::iterator // hash_map::iterator hash_iterator; class IndexEntry { public: IndexEntry(string const &key, unsigned filenameIndex, unsigned labelNr); void push_back(unsigned filenameIndex, unsigned labelNr) { labels.push_back(pair(filenameIndex, labelNr)); } bool operator<(IndexEntry const &other) const; string const &getKey() { return key; } char firstChar() { return uppercaseKey[0]; } void showRefs(); private: string uppercaseKey, key; vector > labels; }; extern vector indexVector; #endif c++-annotations-13.02.01/src/verb/0000775000175000017500000000000014735537670015375 5ustar frankfrankc++-annotations-13.02.01/src/verb/usage.cc0000664000175000017500000000170214735537670017010 0ustar frankfrank// usage.cc #include "main.ih" namespace { char const info[] = R"_( [options] file(s) Where: [options] - optional arguments (short options between parentheses): --help (-h) - provide this help --version (-v) - show version information and terminate --replace (-r) - replace .yo files by generated '.yo.vb' files. file(s) - names of files where verb(...) macros must be compacted. Processed files receive extra .vb extensions. Use file:filename (no blanks) as single argument if the files to process are read from lines in 'filename' (empty lines, lines starting with # are ignored) )_"; } void usage(std::string const &progname) { cout << "\n" << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n" "\n" "Usage: " << progname << info; } c++-annotations-13.02.01/src/verb/parser/0000775000175000017500000000000014735537670016671 5ustar frankfrankc++-annotations-13.02.01/src/verb/parser/parser.h0000664000175000017500000000320414735537670020335 0ustar frankfrank// Generated by Bisonc++ V6.03.00 on Fri, 08 Nov 2019 10:01:15 +0530 #ifndef Parser_h_included #define Parser_h_included #include #include #include "parserbase.h" #include "../scanner/scanner.h" #undef Parser // CAVEAT: between the baseclass-include directive and the // #undef directive in the previous line references to Parser // are read as ParserBase. // If you need to include additional headers in this file // you should do so after these comment-lines. class Parser: public ParserBase { enum VerbContext { NO, BEGIN, END }; VerbContext d_verbContext = NO; std::string d_blanks; std::ifstream d_in; std::ofstream d_out; // $insert scannerobject Scanner d_scanner; public: Parser(std::string const &fname); int parse(); private: void outBlanks(); // collected blanks to d_out void out(); // d_scanner.matched() to d_out void blankOut(); // outBlanks + out void error(); // called on (syntax) errors int lex(); // returns the next token from the // lexical scanner. void print(); // use, e.g., d_token, d_loc void exceptionHandler(std::exception const &exc); // support functions for parse(): void executeAction_(int ruleNr); void errorRecovery_(); void nextCycle_(); void nextToken_(); void print_(); }; #endif c++-annotations-13.02.01/src/verb/parser/parser1.cc0000664000175000017500000000027614735537670020562 0ustar frankfrank#include "parser.ih" Parser::Parser(string const &fname) : d_in( Exception::factory(fname) ), d_out(Exception::factory(fname + ".vb") ), d_scanner(d_in) {} c++-annotations-13.02.01/src/verb/parser/lex.cc0000664000175000017500000000111414735537670017765 0ustar frankfrank#include "parser.ih" int Parser::lex() { int token; while (true) { token = d_scanner.lex(); if (token != WS) break; d_blanks += d_scanner.matched(); } switch (d_verbContext) { case BEGIN: if (size_t pos = d_blanks.find_last_of('\n'); pos != string::npos) d_blanks.erase(0, pos + 1); d_verbContext = NO; break; case END: d_blanks = '\n'; d_verbContext = NO; break; default: break; } return token; } c++-annotations-13.02.01/src/verb/parser/parse.cc0000664000175000017500000004557514735537670020332 0ustar frankfrank// Generated by Bisonc++ V6.03.00 on Sat, 09 Nov 2019 12:08:40 +0530 // base/comment // $insert class.ih #include "parser.ih" // The FIRST element of SR arrays shown below uses `d_type', defining the // state's type, and `d_lastIdx' containing the last element's index. If // d_lastIdx contains the REQ_TOKEN bitflag (see below) then the state needs // a token: if in this state d_token is Reserved_::UNDETERMINED_, nextToken() will be // called // The LAST element of SR arrays uses `d_token' containing the last retrieved // token to speed up the (linear) seach. Except for the first element of SR // arrays, the field `d_action' is used to determine what to do next. If // positive, it represents the next state (used with SHIFT); if zero, it // indicates `ACCEPT', if negative, -d_action represents the number of the // rule to reduce to. // `lookup()' tries to find d_token in the current SR array. If it fails, and // there is no default reduction UNEXPECTED_TOKEN_ is thrown, which is then // caught by the error-recovery function. // The error-recovery function will pop elements off the stack until a state // having bit flag ERR_ITEM is found. This state has a transition on errTok_ // which is applied. In this errTok_ state, while the current token is not a // proper continuation, new tokens are obtained by nextToken(). If such a // token is found, error recovery is successful and the token is // handled according to the error state's SR table and parsing continues. // During error recovery semantic actions are ignored. // A state flagged with the DEF_RED flag will perform a default // reduction if no other continuations are available for the current token. // The ACCEPT STATE never shows a default reduction: when it is reached the // parser returns ACCEPT(). During the grammar // analysis phase a default reduction may have been defined, but it is // removed during the state-definition phase. // So: // s_x[] = // { // [_field_1_] [_field_2_] // // First element: {state-type, idx of last element}, // Other elements: {required token, action to perform}, // ( < 0: reduce, // 0: ACCEPT, // > 0: next state) // } // base/declarations namespace // anonymous { char const author[] = "Frank B. Brokken (f.b.brokken@rug.nl)"; enum Reserved_ { UNDETERMINED_ = -2, EOF_ = -1, errTok_ = 256 }; enum StateType // modify statetype/data.cc when this enum changes { NORMAL, ERR_ITEM, REQ_TOKEN, ERR_REQ, // ERR_ITEM | REQ_TOKEN DEF_RED, // state having default reduction ERR_DEF, // ERR_ITEM | DEF_RED REQ_DEF, // REQ_TOKEN | DEF_RED ERR_REQ_DEF // ERR_ITEM | REQ_TOKEN | DEF_RED }; inline bool operator&(StateType lhs, StateType rhs) { return (static_cast(lhs) & rhs) != 0; } enum StateTransition { ACCEPT_ = 0, // `ACCEPT' TRANSITION }; struct PI_ // Production Info { size_t d_nonTerm; // identification number of this production's // non-terminal size_t d_size; // number of elements in this production }; struct SR_ // Shift Reduce info, see its description above { union { int _field_1_; // initializer, allowing initializations // of the SR s_[] arrays StateType d_type; int d_token; }; union { int _field_2_; int d_lastIdx; // if negative, the state uses SHIFT int d_action; // may be negative (reduce), // postive (shift), or 0 (accept) }; }; // $insert staticdata enum // size to expand the state-stack with when { // full STACK_EXPANSION_ = 10 }; // Productions Info Records: PI_ const s_productionInfo[] = { {0, 0}, // not used: reduction values are negative {260, 1}, // 1: startrule -> inputtext {261, 2}, // 2: inputtext -> inputtext input {261, 1}, // 3: inputtext -> input {262, 1}, // 4: input (TXT) -> TXT {262, 1}, // 5: input -> verb {263, 3}, // 6: verb (')') -> verbTok content ')' {264, 1}, // 7: verbTok (VERB) -> VERB {265, 2}, // 8: content -> content info {265, 0}, // 9: content -> {266, 3}, // 10: info -> openPar content closePar {266, 1}, // 11: info (TXT) -> TXT {266, 1}, // 12: info -> verbblock {267, 1}, // 13: openPar ('(') -> '(' {268, 1}, // 14: closePar (')') -> ')' {269, 3}, // 15: verbblock (')') -> verbNest content ')' {270, 1}, // 16: verbNest (VERB) -> VERB {271, 1}, // 17: startrule_$ -> startrule }; // State info and SR_ transitions for each state. SR_ s_0[] = { { { REQ_TOKEN}, { 8} }, { { 260}, { 1} }, // startrule { { 261}, { 2} }, // inputtext { { 262}, { 3} }, // input { { 257}, { 4} }, // TXT { { 263}, { 5} }, // verb { { 264}, { 6} }, // verbTok { { 258}, { 7} }, // VERB { { 0}, { 0} }, }; SR_ s_1[] = { { { REQ_TOKEN}, { 2} }, { { EOF_}, { ACCEPT_} }, { { 0}, { 0} }, }; SR_ s_2[] = { { { REQ_DEF}, { 6} }, { { 262}, { 8} }, // input { { 257}, { 4} }, // TXT { { 263}, { 5} }, // verb { { 264}, { 6} }, // verbTok { { 258}, { 7} }, // VERB { { 0}, { -1} }, }; SR_ s_3[] = { { { DEF_RED}, { 1} }, { { 0}, { -3} }, }; SR_ s_4[] = { { { DEF_RED}, { 1} }, { { 0}, { -4} }, }; SR_ s_5[] = { { { DEF_RED}, { 1} }, { { 0}, { -5} }, }; SR_ s_6[] = { { { DEF_RED}, { 2} }, { { 265}, { 9} }, // content { { 0}, { -9} }, }; SR_ s_7[] = { { { DEF_RED}, { 1} }, { { 0}, { -7} }, }; SR_ s_8[] = { { { DEF_RED}, { 1} }, { { 0}, { -2} }, }; SR_ s_9[] = { { { REQ_TOKEN}, { 9} }, { { 41}, { 10} }, // ')' { { 266}, { 11} }, // info { { 267}, { 12} }, // openPar { { 257}, { 13} }, // TXT { { 269}, { 14} }, // verbblock { { 40}, { 15} }, // '(' { { 270}, { 16} }, // verbNest { { 258}, { 17} }, // VERB { { 0}, { 0} }, }; SR_ s_10[] = { { { DEF_RED}, { 1} }, { { 0}, { -6} }, }; SR_ s_11[] = { { { DEF_RED}, { 1} }, { { 0}, { -8} }, }; SR_ s_12[] = { { { DEF_RED}, { 2} }, { { 265}, { 18} }, // content { { 0}, { -9} }, }; SR_ s_13[] = { { { DEF_RED}, { 1} }, { { 0}, { -11} }, }; SR_ s_14[] = { { { DEF_RED}, { 1} }, { { 0}, { -12} }, }; SR_ s_15[] = { { { DEF_RED}, { 1} }, { { 0}, { -13} }, }; SR_ s_16[] = { { { DEF_RED}, { 2} }, { { 265}, { 19} }, // content { { 0}, { -9} }, }; SR_ s_17[] = { { { DEF_RED}, { 1} }, { { 0}, { -16} }, }; SR_ s_18[] = { { { REQ_TOKEN}, { 10} }, { { 268}, { 20} }, // closePar { { 266}, { 11} }, // info { { 41}, { 21} }, // ')' { { 267}, { 12} }, // openPar { { 257}, { 13} }, // TXT { { 269}, { 14} }, // verbblock { { 40}, { 15} }, // '(' { { 270}, { 16} }, // verbNest { { 258}, { 17} }, // VERB { { 0}, { 0} }, }; SR_ s_19[] = { { { REQ_TOKEN}, { 9} }, { { 41}, { 22} }, // ')' { { 266}, { 11} }, // info { { 267}, { 12} }, // openPar { { 257}, { 13} }, // TXT { { 269}, { 14} }, // verbblock { { 40}, { 15} }, // '(' { { 270}, { 16} }, // verbNest { { 258}, { 17} }, // VERB { { 0}, { 0} }, }; SR_ s_20[] = { { { DEF_RED}, { 1} }, { { 0}, { -10} }, }; SR_ s_21[] = { { { DEF_RED}, { 1} }, { { 0}, { -14} }, }; SR_ s_22[] = { { { DEF_RED}, { 1} }, { { 0}, { -15} }, }; // State array: SR_ *s_state[] = { s_0, s_1, s_2, s_3, s_4, s_5, s_6, s_7, s_8, s_9, s_10, s_11, s_12, s_13, s_14, s_15, s_16, s_17, s_18, s_19, s_20, s_21, s_22, }; } // anonymous namespace ends // If the parsing function call (i.e., parse()' needs arguments, then provide // an overloaded function. The code below doesn't rely on parameters, so no // arguments are required. Furthermore, parse uses a function try block to // allow us to do ACCEPT and ABORT from anywhere, even from within members // called by actions, simply throwing the appropriate exceptions. // base/base1 ParserBase::ParserBase() : d_token(Reserved_::UNDETERMINED_), // $insert baseclasscode d_requiredTokens_(0) { } // base/clearin void ParserBase::clearin_() { d_nErrors_ = 0; d_stackIdx = -1; d_stateStack.clear(); d_token = Reserved_::UNDETERMINED_; d_next = TokenPair{ Reserved_::UNDETERMINED_, STYPE_{} }; d_recovery = false; d_acceptedTokens_ = d_requiredTokens_; d_val_ = STYPE_{}; push_(0); } // base/debugfunctions void ParserBase::setDebug(bool mode) { d_actionCases_ = false; d_debug_ = mode; } void ParserBase::setDebug(DebugMode_ mode) { d_actionCases_ = mode & ACTIONCASES; d_debug_ = mode & ON; } // base/lex void ParserBase::lex_(int token) { d_token = token; if (d_token <= 0) d_token = Reserved_::EOF_; d_terminalToken = true; } // base/lookup int ParserBase::lookup_() const { // if the final transition is negative, then we should reduce by the rule // given by its positive value. SR_ const *sr = s_state[d_state]; SR_ const *last = sr + sr->d_lastIdx; for ( ; ++sr != last; ) // visit all but the last SR entries { if (sr->d_token == d_token) return sr->d_action; } if (sr == last) // reached the last element { if (sr->d_action < 0) // default reduction { return sr->d_action; } // No default reduction, so token not found, so error. throw UNEXPECTED_TOKEN_; } // not at the last element: inspect the nature of the action // (< 0: reduce, 0: ACCEPT, > 0: shift) int action = sr->d_action; return action; } // base/pop void ParserBase::pop_(size_t count) { if (d_stackIdx < static_cast(count)) { ABORT(); } d_stackIdx -= count; d_state = d_stateStack[d_stackIdx].first; d_vsp = &d_stateStack[d_stackIdx]; } // base/poptoken void ParserBase::popToken_() { d_token = d_next.first; d_val_ = std::move(d_next.second); d_next.first = Reserved_::UNDETERMINED_; } // base/push void ParserBase::push_(size_t state) { size_t currentSize = d_stateStack.size(); if (stackSize_() == currentSize) { size_t newSize = currentSize + STACK_EXPANSION_; d_stateStack.resize(newSize); } ++d_stackIdx; d_stateStack[d_stackIdx] = StatePair{ d_state = state, std::move(d_val_) }; d_vsp = &d_stateStack[d_stackIdx]; if (d_stackIdx == 0) { } else { } } // base/pushtoken void ParserBase::pushToken_(int token) { d_next = TokenPair{ d_token, std::move(d_val_) }; d_token = token; } // base/redotoken void ParserBase::redoToken_() { if (d_token != Reserved_::UNDETERMINED_) pushToken_(d_token); } // base/reduce void ParserBase::reduce_(int rule) { PI_ const &pi = s_productionInfo[rule]; d_token = pi.d_nonTerm; pop_(pi.d_size); d_terminalToken = false; } // base/shift void ParserBase::shift_(int action) { push_(action); popToken_(); // token processed if (d_recovery and d_terminalToken) { d_recovery = false; d_acceptedTokens_ = 0; } } // base/startrecovery void ParserBase::startRecovery_() { int lastToken = d_token; // give the unexpected token a // chance to be processed // again. pushToken_(Reserved_::errTok_); // specify errTok_ as next token push_(lookup_()); // push the error state d_token = lastToken; // reactivate the unexpected // token (we're now in an // ERROR state). d_recovery = true; } // base/top inline size_t ParserBase::top_() const { return d_stateStack[d_stackIdx].first; } // derived/errorrecovery void Parser::errorRecovery_() { // When an error has occurred, pop elements off the stack until the top // state has an error-item. If none is found, the default recovery // mode (which is to abort) is activated. // // If EOF is encountered without being appropriate for the current state, // then the error recovery will fall back to the default recovery mode. // (i.e., parsing terminates) if (d_acceptedTokens_ >= d_requiredTokens_)// only generate an error- { // message if enough tokens ++d_nErrors_; // were accepted. Otherwise error(); // simply skip input } // get the error state while (not (s_state[top_()][0].d_type & ERR_ITEM)) { pop_(); } // In the error state, looking up a token allows us to proceed. // Continuation may be require multiple reductions, but eventually a // terminal-token shift is used. See nextCycle_ for details. startRecovery_(); } // derived/executeaction void Parser::executeAction_(int production) try { if (token_() != Reserved_::UNDETERMINED_) pushToken_(token_()); // save an already available token switch (production) { // $insert actioncases case 1: #line 13 "grammar" { d_out << '\n'; } break; case 2: #line 20 "grammar" { d_val_ = vs_(-1); } break; case 3: #line 22 "grammar" { d_val_ = vs_(0); } break; case 4: #line 26 "grammar" { blankOut(); } break; case 5: #line 31 "grammar" { d_val_ = vs_(0); } break; case 6: #line 35 "grammar" { d_blanks.clear(); d_out << ")\n"; d_verbContext = END; d_scanner.verbEnds(); } break; case 7: #line 45 "grammar" { d_verbContext = BEGIN; d_out << d_blanks << "verb("; d_blanks.clear(); } break; case 8: #line 54 "grammar" { d_val_ = vs_(-1); } break; case 10: #line 60 "grammar" { d_val_ = vs_(-2); } break; case 11: #line 62 "grammar" { blankOut(); } break; case 12: #line 67 "grammar" { d_val_ = vs_(0); } break; case 13: #line 71 "grammar" { blankOut(); } break; case 14: #line 78 "grammar" { blankOut(); } break; case 15: #line 85 "grammar" { blankOut(); } break; case 16: #line 92 "grammar" { blankOut(); } break; } } catch (std::exception const &exc) { exceptionHandler(exc); } // derived/nextcycle void Parser::nextCycle_() try { if (s_state[state_()]->d_type & REQ_TOKEN) nextToken_(); // obtain next token int action = lookup_(); // lookup d_token in d_state if (action > 0) // SHIFT: push a new state { shift_(action); return; } if (action < 0) // REDUCE: execute and pop. { if (recovery_()) redoToken_(); else executeAction_(-action); // next token is the rule's LHS reduce_(-action); return; } if (recovery_()) ABORT(); else ACCEPT(); } catch (ErrorRecovery_) { if (not recovery_()) errorRecovery_(); else { if (token_() == Reserved_::EOF_) ABORT(); popToken_(); // skip the failing token } } // derived/nexttoken void Parser::nextToken_() { // If d_token is Reserved_::UNDETERMINED_ then if savedToken_() is // Reserved_::UNDETERMINED_ another token is obtained from lex(). Then // savedToken_() is assigned to d_token. // no need for a token: got one already if (token_() != Reserved_::UNDETERMINED_) { return; } if (savedToken_() != Reserved_::UNDETERMINED_) { popToken_(); // consume pending token } else { ++d_acceptedTokens_; // accept another token (see // errorRecover()) lex_(lex()); print_(); } print(); } // derived/print void Parser::print_() { // $insert print } // derived/parse int Parser::parse() try { // The parsing algorithm: // Initially, state 0 is pushed on the stack, and all relevant variables // are initialized by Base::clearin_. // // Then, in an eternal loop: // // 1. If a state is a REQ_TOKEN type, then the next token is obtained // from nextToken(). This may very well be the currently available // token. When retrieving a terminal token d_terminal is set to true. // // 2. lookup() is called, d_token is looked up in the current state's // SR_ array. // // 4. Depending on the result of the lookup() function the next state is // shifted on the parser's stack, a reduction by some rule is applied, // or the parsing function returns ACCEPT(). When a reduction is // called for, any action that may have been defined for that // reduction is executed. // // 5. An error occurs if d_token is not found, and the state has no // default reduction. clearin_(); // initialize, push(0) while (true) { // $insert prompt nextCycle_(); } } catch (Return_ retValue) { return retValue or d_nErrors_; } // derived/tail c++-annotations-13.02.01/src/verb/parser/outblanks.cc0000664000175000017500000000021314735537670021176 0ustar frankfrank#include "parser.ih" void Parser::outBlanks() { if (d_blanks.empty()) return; d_out << d_blanks; d_blanks.clear(); } c++-annotations-13.02.01/src/verb/parser/out.cc0000664000175000017500000000012114735537670020001 0ustar frankfrank#include "parser.ih" void Parser::out() { d_out << d_scanner.matched(); } c++-annotations-13.02.01/src/verb/parser/parser.ih0000664000175000017500000000137714735537670020517 0ustar frankfrank// Generated by Bisonc++ V6.03.00 on Fri, 08 Nov 2019 10:01:15 +0530 // Include this file in the sources of the class Parser. // $insert class.h #include "parser.h" #include inline void Parser::error() { std::cerr << "Syntax error\n"; } inline void Parser::print() { } inline void Parser::exceptionHandler(std::exception const &exc) { throw; // re-implement to handle exceptions thrown by actions } // Add here includes that are only required for the compilation // of Parser's sources. // UN-comment the next using-declaration if you want to use // int Parser's sources symbols from the namespace std without // specifying std:: using namespace std; using namespace FBB; c++-annotations-13.02.01/src/verb/parser/blankout.cc0000664000175000017500000000011614735537670021015 0ustar frankfrank#include "parser.ih" void Parser::blankOut() { outBlanks(); out(); } c++-annotations-13.02.01/src/verb/parser/grammar0000664000175000017500000000222514735537670020243 0ustar frankfrank//%default-actions quiet %filenames parser %scanner ../scanner/scanner.h //%baseclass-preinclude x.h or %token TXT VERB WS %% startrule: inputtext { d_out << '\n'; } ; inputtext: inputtext input | input ; input: TXT { blankOut(); } | verb ; verb: verbTok content ')' // outer block { d_blanks.clear(); d_out << ")\n"; d_verbContext = END; d_scanner.verbEnds(); } ; verbTok: VERB { d_verbContext = BEGIN; // starts an outer verb block d_out << d_blanks << "verb("; d_blanks.clear(); } ; content: content info | // empty ; info: openPar content closePar | TXT { blankOut(); } | verbblock ; openPar: '(' { blankOut(); } ; closePar: ')' { blankOut(); } ; verbblock: verbNest content ')' { blankOut(); } ; verbNest: // not completely OK: nested verb( and VERB // verb(\ [))] are treated identically { blankOut(); } ; c++-annotations-13.02.01/src/verb/parser/parserbase.h0000664000175000017500000000752614735537670021203 0ustar frankfrank// Generated by Bisonc++ V6.03.00 on Sat, 09 Nov 2019 12:08:40 +0530 // hdr/includes #ifndef ParserBase_h_included #define ParserBase_h_included #include #include #include // hdr/baseclass namespace // anonymous { struct PI_; } class ParserBase { public: enum DebugMode_ { OFF = 0, ON = 1 << 0, ACTIONCASES = 1 << 1 }; // $insert tokens // Symbolic tokens: enum Tokens_ { TXT = 257, VERB, WS, }; // $insert STYPE typedef int STYPE_; private: // state semval typedef std::pair StatePair; // token semval typedef std::pair TokenPair; int d_stackIdx = -1; std::vector d_stateStack; StatePair *d_vsp = 0; // points to the topmost value stack size_t d_state = 0; TokenPair d_next; int d_token; bool d_terminalToken = false; bool d_recovery = false; protected: enum Return_ { PARSE_ACCEPT_ = 0, // values used as parse()'s return values PARSE_ABORT_ = 1 }; enum ErrorRecovery_ { UNEXPECTED_TOKEN_, }; bool d_actionCases_ = false; // set by options/directives bool d_debug_ = true; size_t d_requiredTokens_; size_t d_nErrors_; // initialized by clearin() size_t d_acceptedTokens_; STYPE_ d_val_; ParserBase(); void ABORT() const; void ACCEPT() const; void ERROR() const; STYPE_ &vs_(int idx); // value stack element idx int lookup_() const; int savedToken_() const; int token_() const; size_t stackSize_() const; size_t state_() const; size_t top_() const; void clearin_(); void errorVerbose_(); void lex_(int token); void popToken_(); void pop_(size_t count = 1); void pushToken_(int token); void push_(size_t nextState); void redoToken_(); bool recovery_() const; void reduce_(int rule); void shift_(int state); void startRecovery_(); public: void setDebug(bool mode); void setDebug(DebugMode_ mode); }; // hdr/abort inline void ParserBase::ABORT() const { throw PARSE_ABORT_; } // hdr/accept inline void ParserBase::ACCEPT() const { throw PARSE_ACCEPT_; } // hdr/error inline void ParserBase::ERROR() const { throw UNEXPECTED_TOKEN_; } // hdr/savedtoken inline int ParserBase::savedToken_() const { return d_next.first; } // hdr/opbitand inline ParserBase::DebugMode_ operator&(ParserBase::DebugMode_ lhs, ParserBase::DebugMode_ rhs) { return static_cast( static_cast(lhs) & rhs); } // hdr/opbitor inline ParserBase::DebugMode_ operator|(ParserBase::DebugMode_ lhs, ParserBase::DebugMode_ rhs) { return static_cast(static_cast(lhs) | rhs); }; // hdr/recovery inline bool ParserBase::recovery_() const { return d_recovery; } // hdr/stacksize inline size_t ParserBase::stackSize_() const { return d_stackIdx + 1; } // hdr/state inline size_t ParserBase::state_() const { return d_state; } // hdr/token inline int ParserBase::token_() const { return d_token; } // hdr/vs inline ParserBase::STYPE_ &ParserBase::vs_(int idx) { return (d_vsp + idx)->second; } // hdr/tail // For convenience, when including ParserBase.h its symbols are available as // symbols in the class Parser, too. #define Parser ParserBase #endif c++-annotations-13.02.01/src/verb/files/0000775000175000017500000000000014735537670016477 5ustar frankfrankc++-annotations-13.02.01/src/verb/files/files.h0000664000175000017500000000112614735537670017752 0ustar frankfrank#ifndef INCLUDED_FILES_ #define INCLUDED_FILES_ #include #include class Files { std::vector d_fname; size_t d_idx = 0; public: Files(); explicit operator bool() const; std::string const &next(); private: void fillArgs(); // add arguments to d_fname void read(std::string const &fname); // or fnames from file }; inline Files::operator bool() const { return d_idx < d_fname.size(); } inline std::string const &Files::next() { return d_fname[d_idx++]; } #endif c++-annotations-13.02.01/src/verb/files/read.cc0000664000175000017500000000070214735537670017720 0ustar frankfrank//#define XERR #include "files.ih" void Files::read(string const &fname) { ifstream in{ Exception::factory(fname) }; string line; while (getline(in, line)) { size_t pos = line.find_first_not_of(" \t"); if (pos == string::npos or line[pos] == '#') // empty or comment? continue; // then skip this line d_fname.push_back(String::trim(line)); } } c++-annotations-13.02.01/src/verb/files/fillargs.cc0000664000175000017500000000031214735537670020605 0ustar frankfrank//#define XERR #include "files.ih" void Files::fillArgs() { Arg const &arg = Arg::instance(); for (size_t idx = 0, end = arg.nArgs(); idx != end; ++idx) d_fname.push_back(arg[idx]); } c++-annotations-13.02.01/src/verb/files/files1.cc0000664000175000017500000000061414735537670020172 0ustar frankfrank//#define XERR #include "files.ih" Files::Files() { string arg0{ Arg::instance()[0] }; size_t pos = arg0.find(':'); // ':' in 1st arg? if (pos == string::npos) // no: just a list of names fillArgs(); // add them to d_fname else read(arg0.substr(pos + 1)); // or read the names fm file } c++-annotations-13.02.01/src/verb/files/files.ih0000664000175000017500000000026614735537670020127 0ustar frankfrank#include "files.h" #include "../xerr.ih" #include #include #include #include using namespace std; using namespace FBB; c++-annotations-13.02.01/src/verb/compactor/0000775000175000017500000000000014735537670017364 5ustar frankfrankc++-annotations-13.02.01/src/verb/compactor/run.cc0000664000175000017500000000071514735537670020502 0ustar frankfrank//#define XERR #include "compactor.ih" void Compactor::run() { bool replace = Arg::instance().option('r'); Files files; while (files) { string fname{ files.next() }; cout << "processing " << fname << '\n'; Parser parser(fname); if (parser.parse() != 0) throw Exception{} << "Error(s) while processing " << fname; if (replace) filesystem::rename(fname + ".vb", fname); } } c++-annotations-13.02.01/src/verb/compactor/compactor1.cc0000664000175000017500000000010714735537670021741 0ustar frankfrank//#define XERR #include "compactor.ih" Compactor::Compactor() //: { } c++-annotations-13.02.01/src/verb/compactor/compactor.ih0000664000175000017500000000040614735537670021675 0ustar frankfrank#include "compactor.h" #include "../xerr.ih" #include #include #include #include #include #include "../parser/parser.h" #include "../files/files.h" using namespace std; using namespace FBB; c++-annotations-13.02.01/src/verb/compactor/compactor.h0000664000175000017500000000024114735537670021521 0ustar frankfrank#ifndef INCLUDED_COMPACTOR_ #define INCLUDED_COMPACTOR_ class Compactor { public: Compactor(); void run(); private: }; #endif c++-annotations-13.02.01/src/verb/scanner/0000775000175000017500000000000014735537670017026 5ustar frankfrankc++-annotations-13.02.01/src/verb/scanner/lex.cc0000664000175000017500000003511114735537670020126 0ustar frankfrank// Generated by Flexc++ V2.07.06 on Sat, 09 Nov 2019 12:08:40 +0530 #include #include #include #include // $insert class_ih #include "scanner.ih" // s_ranges_: use (unsigned) characters as index to obtain // that character's range-number. // The range for EOF is defined in a constant in the // class header file size_t const ScannerBase::s_ranges_[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 2, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 5, 5, 5, 5, 5, 5, 5, 6, 7, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11, 11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,13,14,14,14,14,15,16,17, 17,18,19,19,19,19,19,19,19,19,19,19,19,19,20,21,21,21,22,23,23,23,23,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24, 24,24,24,24,24,24, }; // $insert startcondinfo // s_dfa_ contains the rows of *all* DFAs ordered by start state. The // enum class StartCondition_is defined in the baseclass header. // StartCondition_::INITIAL is always 0. Each entry defines the row to // transit to if the column's character range was sensed. Row numbers are // relative to the used DFA, and d_dfaBase_ is set to the first row of // the subset to use. The row's final two values are respectively the // rule that may be matched at this state, and the rule's FINAL flag. If // the final value equals FINAL (= 1) then, if there's no continuation, // the rule is matched. If the BOL flag (8) is also set (so FINAL + BOL (= // 9) is set) then the rule only matches when d_atBOL is also true. int const ScannerBase::s_dfa_[][28] = { // INITIAL { 1, 2, 2, 1, 2, 1, 3, 3, 1, 4, 1, 4, 1, 1, 1, 4, 4, 4, 4, 4, 4, 4, 5, 4, 1,-1, -1, -1}, // 0 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 6, -1}, // 1 {-1, 2, 2,-1, 2,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 4, -1}, // 2 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 5, -1}, // 3 {-1,-1,-1,-1,-1,-1,-1,-1,-1, 4,-1, 4,-1,-1,-1, 4, 4, 4, 4, 4, 4, 4, 4, 4,-1,-1, 3, -1}, // 4 {-1,-1,-1,-1,-1,-1,-1,-1,-1, 4,-1, 4,-1,-1,-1, 4, 4, 4, 6, 4, 4, 4, 4, 4,-1,-1, 3, -1}, // 5 {-1,-1,-1,-1,-1,-1,-1,-1,-1, 4,-1, 4,-1,-1,-1, 4, 4, 4, 4, 4, 7, 4, 4, 4,-1,-1, 3, -1}, // 6 {-1,-1,-1,-1,-1,-1,-1,-1,-1, 4,-1, 4,-1,-1,-1, 4, 8, 4, 4, 4, 4, 4, 4, 4,-1,-1, 3, -1}, // 7 {-1,-1,-1,-1,-1,-1, 9,-1,-1, 4,-1, 4,-1,-1,-1, 4, 4, 4, 4, 4, 4, 4, 4, 4,-1,-1, 0, -1}, // 8 {-1,10,11,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,12,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, -1, -1}, // 9 {-1,10,11,-1,10,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, -1, -1}, // 10 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 1, -1}, // 11 {-1,-1,13,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, -1, -1}, // 12 {-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1,-1, -1,-1,-1,-1,-1,-1, 2, -1}, // 13 }; int const (*ScannerBase::s_dfaBase_[])[28] = { s_dfa_ + 0, }; size_t ScannerBase::s_istreamNr = 0; // $insert inputImplementation ScannerBase::Input::Input() : d_in(0), d_lineNr(1) {} ScannerBase::Input::Input(std::istream *iStream, size_t lineNr) : d_in(iStream), d_lineNr(lineNr) {} size_t ScannerBase::Input::get() { switch (size_t ch = next()) // get the next input char { case '\n': ++d_lineNr; [[fallthrough]]; default: return ch; } } size_t ScannerBase::Input::next() { size_t ch; if (d_deque.empty()) // deque empty: next char fm d_in { if (d_in == 0) return AT_EOF; ch = d_in->get(); return *d_in ? ch : static_cast(AT_EOF); } ch = d_deque.front(); d_deque.pop_front(); return ch; } void ScannerBase::Input::reRead(size_t ch) { if (ch < 0x100) { if (ch == '\n') --d_lineNr; d_deque.push_front(ch); } } void ScannerBase::Input::reRead(std::string const &str, size_t fm) { for (size_t idx = str.size(); idx-- > fm; ) reRead(str[idx]); } ScannerBase::ScannerBase(std::istream &in, std::ostream &out) : d_filename("-"), d_out(new std::ostream(out.rdbuf())), // $insert interactiveInit d_in(0), d_input(new std::istream(in.rdbuf())), d_dfaBase_(s_dfa_) {} void ScannerBase::switchStream_(std::istream &in, size_t lineNr) { d_input.close(); d_input = Input(new std::istream(in.rdbuf()), lineNr); } ScannerBase::ScannerBase(std::string const &infilename, std::string const &outfilename) : d_filename(infilename), d_out(outfilename == "-" ? new std::ostream(std::cout.rdbuf()) : outfilename == "" ? new std::ostream(std::cerr.rdbuf()) : new std::ofstream(outfilename)), d_input(new std::ifstream(infilename)), d_dfaBase_(s_dfa_) {} void ScannerBase::switchStreams(std::istream &in, std::ostream &out) { switchStream_(in, 1); switchOstream(out); } void ScannerBase::switchOstream(std::ostream &out) { *d_out << std::flush; d_out.reset(new std::ostream(out.rdbuf())); } // $insert debugFunctions void ScannerBase::setDebug(bool onOff) {} bool ScannerBase::debug() const { return false; } void ScannerBase::redo(size_t nChars) { size_t from = nChars >= length() ? 0 : length() - nChars; d_input.reRead(d_matched, from); d_matched.resize(from); } void ScannerBase::switchOstream(std::string const &outfilename) { *d_out << std::flush; d_out.reset( outfilename == "-" ? new std::ostream(std::cout.rdbuf()) : outfilename == "" ? new std::ostream(std::cerr.rdbuf()) : new std::ofstream(outfilename)); } void ScannerBase::switchIstream(std::string const &infilename) { d_input.close(); d_filename = infilename; d_input = Input(new std::ifstream(infilename)); d_atBOL = true; } void ScannerBase::switchStreams(std::string const &infilename, std::string const &outfilename) { switchOstream(outfilename); switchIstream(infilename); } void ScannerBase::pushStream(std::istream &istr) { std::istream *streamPtr = new std::istream(istr.rdbuf()); p_pushStream("(istream)", streamPtr); } void ScannerBase::pushStream(std::string const &name) { std::istream *streamPtr = new std::ifstream(name); if (!*streamPtr) { delete streamPtr; throw std::runtime_error("Cannot read " + name); } p_pushStream(name, streamPtr); } void ScannerBase::p_pushStream(std::string const &name, std::istream *streamPtr) { if (d_streamStack.size() == s_maxSizeofStreamStack_) { delete streamPtr; throw std::length_error("Max stream stack size exceeded"); } d_streamStack.push_back(StreamStruct{d_filename, d_input}); d_filename = name; d_input = Input(streamPtr); d_atBOL = true; } bool ScannerBase::popStream() { d_input.close(); if (d_streamStack.empty()) return false; StreamStruct &top = d_streamStack.back(); d_input = top.pushedInput; d_filename = top.pushedName; d_streamStack.pop_back(); return true; } // See the manual's section `Run-time operations' section for an explanation // of this member. ScannerBase::ActionType_ ScannerBase::actionType_(size_t range) { d_nextState = d_dfaBase_[d_state][range]; if (d_nextState != -1) // transition is possible return ActionType_::CONTINUE; if (knownFinalState()) // FINAL state reached return ActionType_::MATCH; if (d_matched.size()) return ActionType_::ECHO_FIRST; // no match, echo the 1st char return range != s_rangeOfEOF_ ? ActionType_::ECHO_CH : ActionType_::RETURN; } void ScannerBase::accept(size_t nChars) // old name: less { if (nChars < d_matched.size()) { d_input.reRead(d_matched, nChars); d_matched.resize(nChars); } } void ScannerBase::setMatchedSize(size_t length) { d_input.reRead(d_matched, length); // reread the tail section d_matched.resize(length); // return what's left } // At this point a rule has been matched. The next character is not part of // the matched rule and is sent back to the input. The final match length // is determined, the index of the matched rule is determined, and then // d_atBOL is updated. Finally the rule's index is returned. // The numbers behind the finalPtr assignments are explained in the // manual's `Run-time operations' section. size_t ScannerBase::matched_(size_t ch) { d_input.reRead(ch); FinalData *finalPtr; if (not d_atBOL) // not at BOL finalPtr = &d_final.std; // then use the std rule (3, 4) // at BOL else if (not available(d_final.std.rule)) // only a BOL rule avail. finalPtr = &d_final.bol; // use the BOL rule (6) else if (not available(d_final.bol.rule)) // only a std rule is avail. finalPtr = &d_final.std; // use the std rule (7) else if ( // Both are available (8) d_final.bol.length != // check lengths of matched texts d_final.std.length // unequal lengths, use the rule ) // having the longer match length finalPtr = d_final.bol.length > d_final.std.length ? &d_final.bol : &d_final.std; else // lengths are equal: use 1st rule finalPtr = d_final.bol.rule < d_final.std.rule ? &d_final.bol : &d_final.std; setMatchedSize(finalPtr->length); d_atBOL = d_matched.back() == '\n'; return finalPtr->rule; } size_t ScannerBase::getRange_(int ch) // using int to prevent casts { return ch == AT_EOF ? as(s_rangeOfEOF_) : s_ranges_[ch]; } // At this point d_nextState contains the next state and continuation is // possible. The just read char. is appended to d_match void ScannerBase::continue_(int ch) { d_state = d_nextState; if (ch != AT_EOF) d_matched += ch; } void ScannerBase::echoCh_(size_t ch) { *d_out << as(ch); d_atBOL = ch == '\n'; } // At this point there is no continuation. The last character is // pushed back into the input stream as well as all but the first char. in // the buffer. The first char. in the buffer is echoed to stderr. // If there isn't any 1st char yet then the current char doesn't fit any // rules and that char is then echoed void ScannerBase::echoFirst_(size_t ch) { d_input.reRead(ch); d_input.reRead(d_matched, 1); echoCh_(d_matched[0]); } // Update the rules associated with the current state, do this separately // for BOL and std rules. // If a rule was set, update the rule index and the current d_matched // length. void ScannerBase::updateFinals_() { size_t len = d_matched.size(); int const *rf = d_dfaBase_[d_state] + s_finIdx_; if (rf[0] != -1) // update to the latest std rule { d_final.std = FinalData { as(rf[0]), len }; } if (rf[1] != -1) // update to the latest bol rule { d_final.bol = FinalData { as(rf[1]), len }; } } void ScannerBase::reset_() { d_final = Final{ FinalData{s_unavailable, 0}, FinalData {s_unavailable, 0} }; d_state = 0; d_return = true; if (!d_more) d_matched.clear(); d_more = false; } int Scanner::executeAction_(size_t ruleIdx) try { switch (ruleIdx) { // $insert actions case 0: { #line 9 "lexer" return Parser::TXT; } break; case 1: case 2: { #line 12 "lexer" { d_verb = true; return Parser::VERB; } } break; case 3: { #line 17 "lexer" return Parser::TXT; } break; case 4: { #line 19 "lexer" return Parser::WS; } break; case 5: { #line 21 "lexer" return d_verb ? matched().front() : Parser::TXT; } break; case 6: { #line 23 "lexer" return Parser::TXT; } break; } noReturn_(); return 0; } catch (Leave_ value) { return static_cast(value); } int Scanner::lex_() { reset_(); preCode(); while (true) { size_t ch = get_(); // fetch next char size_t range = getRange_(ch); // determine the range updateFinals_(); // update the state's Final info switch (actionType_(range)) // determine the action { case ActionType_::CONTINUE: continue_(ch); continue; case ActionType_::MATCH: { d_token_ = executeAction_(matched_(ch)); if (return_()) { print(); postCode(PostEnum_::RETURN); return d_token_; } break; } case ActionType_::ECHO_FIRST: echoFirst_(ch); break; case ActionType_::ECHO_CH: echoCh_(ch); break; case ActionType_::RETURN: if (!popStream()) { postCode(PostEnum_::END); return 0; } postCode(PostEnum_::POP); continue; } // switch postCode(PostEnum_::WIP); reset_(); preCode(); } // while } void ScannerBase::print_() const { } c++-annotations-13.02.01/src/verb/scanner/scanner.ih0000664000175000017500000000037714735537670021010 0ustar frankfrank// Declare here // what's only used in the Scanner class // and let Scanner's sources include "scanner.ih" #include "scanner.h" #include "../parser/parserbase.h" // end of scanner.ih c++-annotations-13.02.01/src/verb/scanner/scanner.h0000664000175000017500000000316214735537670020632 0ustar frankfrank// Generated by Flexc++ V2.07.06 on Thu, 07 Nov 2019 22:48:49 +0530 #ifndef Scanner_H_INCLUDED_ #define Scanner_H_INCLUDED_ // $insert baseclass_h #include "scannerbase.h" // $insert classHead class Scanner: public ScannerBase { bool d_verb = false; public: explicit Scanner(std::istream &in = std::cin, std::ostream &out = std::cout); Scanner(std::string const &infile, std::string const &outfile); // $insert lexFunctionDecl int lex(); void verbEnds(); private: int lex_(); int executeAction_(size_t ruleNr); void print(); void preCode(); // re-implement this function for code that must // be exec'ed before the patternmatching starts void postCode(PostEnum_ type); // re-implement this function for code that must // be exec'ed after the rules's actions. }; inline void Scanner::verbEnds() { d_verb = false; } // $insert scannerConstructors inline Scanner::Scanner(std::istream &in, std::ostream &out) : ScannerBase(in, out) {} inline Scanner::Scanner(std::string const &infile, std::string const &outfile) : ScannerBase(infile, outfile) {} // $insert inlineLexFunction inline int Scanner::lex() { return lex_(); } inline void Scanner::preCode() { // optionally replace by your own code } inline void Scanner::postCode([[maybe_unused]] PostEnum_ type) { // optionally replace by your own code } inline void Scanner::print() { print_(); } #endif // Scanner_H_INCLUDED_ c++-annotations-13.02.01/src/verb/scanner/lexer0000664000175000017500000000101314735537670020063 0ustar frankfrank%filenames scanner %class-name "Scanner" //%interactive //%debug %% verb return Parser::TXT; "verb("[ \t]*\n | "verb(\\"\n { d_verb = true; return Parser::VERB; } [[:alnum:]]+ return Parser::TXT; [ \t\n]+ return Parser::WS; //d_verb ? Parser::WS : Parser::TXT; [()] return d_verb ? matched().front() : Parser::TXT; . return Parser::TXT; c++-annotations-13.02.01/src/verb/scanner/scannerbase.h0000664000175000017500000002726214735537670021474 0ustar frankfrank// Generated by Flexc++ V2.07.06 on Sat, 09 Nov 2019 12:08:40 +0530 #ifndef ScannerBASE_H_INCLUDED #define ScannerBASE_H_INCLUDED #include #include #include #include #include #include class ScannerBase { // idx: rule, value: tail length (NO_INCREMENTS if no tail) typedef std::vector VectorInt; static size_t const s_unavailable = std::numeric_limits::max(); enum { AT_EOF = -1 }; protected: enum Leave_ {}; enum class ActionType_ { CONTINUE, // transition succeeded, go on ECHO_CH, // echo ch itself (d_matched empty) ECHO_FIRST, // echo d_matched[0], push back the rest MATCH, // matched a rule RETURN, // no further continuation, lex returns 0. }; enum class PostEnum_ { END, // postCode called when lex_() ends POP, // postCode called after switching files RETURN, // postCode called when lex_() returns WIP // postCode called when a non-returning rule // was matched }; public: // $insert startcondenum enum class StartCondition_{ INITIAL, }; private: struct FinalData { size_t rule; size_t length; }; struct Final { FinalData std; FinalData bol; }; // class Input encapsulates all input operations. // Its member get() returns the next input character // $insert inputInterface class Input { std::deque d_deque; // pending input chars std::istream *d_in; // ptr for easy streamswitching size_t d_lineNr; // line count public: Input(); // iStream: dynamically allocated Input(std::istream *iStream, size_t lineNr = 1); size_t get(); // the next range void reRead(size_t ch); // push back 'ch' (if < 0x100) // push back str from idx 'fmIdx' void reRead(std::string const &str, size_t fmIdx); size_t lineNr() const { return d_lineNr; } size_t nPending() const { return d_deque.size(); } void setPending(size_t size) { d_deque.erase(d_deque.begin(), d_deque.end() - size); } void close() // force closing the stream { delete d_in; d_in = 0; // switchStreams also closes } private: size_t next(); // obtain the next character }; protected: struct StreamStruct { std::string pushedName; Input pushedInput; }; private: std::vector d_streamStack; std::string d_filename; // name of the currently processed static size_t s_istreamNr; // file. With istreams it receives // the name "", where // # is the sequence number of the // istream (starting at 1) int d_startCondition = 0; int d_lopSC = 0; size_t d_state = 0; int d_nextState; std::shared_ptr d_out; bool d_atBOL = true; // the matched text starts at BOL Final d_final; // only used interactively: std::istream *d_in; // points to the input stream std::shared_ptr d_line; // holds line fm d_in Input d_input; std::string d_matched; // matched characters std::string d_lopMatched; // matched lop-rule characters std::string::iterator d_lopIter; std::string::iterator d_lopTail; std::string::iterator d_lopEnd; size_t d_lopPending; // # pending input chars at lop1_ bool d_return; // return after a rule's action bool d_more = false; // set to true by more() size_t (ScannerBase::*d_get)() = &ScannerBase::getInput; protected: std::istream *d_in_; int d_token_; // returned by lex_ int const (*d_dfaBase_)[28]; static int const s_dfa_[][28]; static int const (*s_dfaBase_[])[28]; enum: bool { s_interactive_ = false }; enum: size_t { s_rangeOfEOF_ = 25, s_finIdx_ = 26, s_nRules_ = 7, s_maxSizeofStreamStack_ = 10 }; static size_t const s_ranges_[]; static size_t const s_rf_[][2]; public: ScannerBase(ScannerBase const &other) = delete; ScannerBase &operator=(ScannerBase const &rhs) = delete; bool debug() const; std::string const &filename() const; std::string const &matched() const; size_t length() const; size_t lineNr() const; void setDebug(bool onOff); void switchOstream(std::ostream &out); void switchOstream(std::string const &outfilename); void switchStreams(std::istream &in, std::ostream &out = std::cout); void switchIstream(std::string const &infilename); void switchStreams(std::string const &infilename, std::string const &outfilename); // $insert interactiveDecl protected: ScannerBase(std::istream &in, std::ostream &out); ScannerBase(std::string const &infilename, std::string const &outfilename); ~ScannerBase(); bool popStream(); std::ostream &out(); void echo() const; void leave(int retValue) const; // `accept(n)' returns all but the first `n' characters of the current // token back to the input stream, where they will be rescanned when the // scanner looks for the next match. // So, it matches n of the characters in the input buffer, and so it accepts // n characters, rescanning the rest. void accept(size_t nChars = 0); // former: less void redo(size_t nChars = 0); // rescan the last nChar // characters, reducing // length() by nChars void more(); void push(size_t ch); // push char to Input void push(std::string const &txt); // same: chars std::vector const &streamStack() const; void pushStream(std::istream &curStream); void pushStream(std::string const &curName); void setFilename(std::string const &name); void setMatched(std::string const &text); static std::string istreamName_(); // members used by lex_(): they end in _ and should not be used // otherwise. ActionType_ actionType_(size_t range); // next action bool return_(); // 'return' from codeblock size_t matched_(size_t ch); // handles a matched rule size_t getRange_(int ch); // convert char to range size_t get_(); // next character size_t state_() const; // current state void continue_(int ch); // handles a transition void echoCh_(size_t ch); // echoes ch, sets d_atBOL void echoFirst_(size_t ch); // handles unknown input void updateFinals_(); // update a state's Final info void noReturn_(); // d_return to false void print_() const; // optionally print token void pushFront_(size_t ch); // return char to Input void reset_(); // prepare for new cycle // next input stream: void switchStream_(std::istream &in, size_t lineNr); void lopf_(size_t tail); // matched fixed size tail void lop1_(int lopSC); // matched ab for a/b void lop2_(); // matches the LOP's b tail void lop3_(); // catch-all while matching b void lop4_(); // matches the LOP's a head // $insert startconddecl StartCondition_ startCondition() const; // current start condition void begin(StartCondition_ startCondition); private: static StartCondition_ constexpr SC(int sc); static int constexpr SC(StartCondition_ sc); size_t getInput(); size_t getLOP(); void p_pushStream(std::string const &name, std::istream *streamPtr); void setMatchedSize(size_t length); bool knownFinalState(); template static ReturnType constexpr as(ArgType value); static bool constexpr available(size_t value); }; inline ScannerBase::~ScannerBase() { d_input.close(); } template inline ReturnType constexpr ScannerBase::as(ArgType value) { return static_cast(value); } // $insert startcondimpl inline ScannerBase::StartCondition_ constexpr ScannerBase::SC(int sc) { return as(sc); } inline int constexpr ScannerBase::SC(StartCondition_ sc) { return as(sc); } inline ScannerBase::StartCondition_ ScannerBase::startCondition() const { return SC(d_startCondition); } inline void ScannerBase::begin(StartCondition_ startCondition) { // d_state is reset to 0 by reset_() d_dfaBase_ = s_dfaBase_[d_startCondition = SC(startCondition)]; } inline bool ScannerBase::knownFinalState() { return (d_atBOL && available(d_final.bol.rule)) || available(d_final.std.rule); } inline bool constexpr ScannerBase::available(size_t value) { return value != std::numeric_limits::max(); } inline std::ostream &ScannerBase::out() { return *d_out; } inline void ScannerBase::push(size_t ch) { d_input.reRead(ch); } inline void ScannerBase::push(std::string const &str) { d_input.reRead(str, 0); } inline void ScannerBase::setFilename(std::string const &name) { d_filename = name; } inline void ScannerBase::setMatched(std::string const &text) { d_matched = text; } inline std::string const &ScannerBase::matched() const { return d_matched; } inline std::string const &ScannerBase::filename() const { return d_filename; } inline void ScannerBase::echo() const { *d_out << d_matched; } inline size_t ScannerBase::length() const { return d_matched.size(); } inline void ScannerBase::leave(int retValue) const { throw as(retValue); } inline size_t ScannerBase::lineNr() const { return d_input.lineNr(); } inline void ScannerBase::more() { d_more = true; } inline size_t ScannerBase::state_() const { return d_state; } inline size_t ScannerBase::get_() { return (this->*d_get)(); } inline size_t ScannerBase::getInput() { return d_input.get(); } inline bool ScannerBase::return_() { return d_return; } inline void ScannerBase::noReturn_() { d_return = false; } #endif // ScannerBASE_H_INCLUDED c++-annotations-13.02.01/src/verb/VERSION0000664000175000017500000000014714735537670016447 0ustar frankfrank#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)"; #define VERSION "0.01.0" #define YEARS "2019" c++-annotations-13.02.01/src/verb/xerr.ih0000664000175000017500000000131314735537670016675 0ustar frankfrank// define X to activate the xerr/xerr2 macros: // xerr(insertion) // inserts the '<<' concatenated elements into std::cerr // preceded by the name of the source file, and ended by '\n' // xerr2(insertion, code) // performs the insertion if X is defined, and (unconditionally) // executes the statement(s) in `code'. `code' must be valid // C(++) code. // #ifdef XERR #include #define xerr(insertion) std::cerr << __FILE__": " << insertion << '\n' #define xerr2(insertion, b) \ { std::cerr << __FILE__": " << insertion << '\n'; b; } #else #define xerr(insertion) #define xerr2(insertion, b) b #endif c++-annotations-13.02.01/src/verb/icmconf0000664000175000017500000000206314735537670016737 0ustar frankfrank#define CLS //#define LIBRARY "modules" #define MAIN "main.cc" #define SOURCES "*.cc" #define OBJ_EXT ".o" #define TMP_DIR "tmp" //#define USE_ALL "a" #define USE_ECHO ON #define USE_VERSION #define CXX "g++" #define CXXFLAGS "-Wall -O2" \ " -fdiagnostics-color=never " #define IH ".ih" #define MULTICOMP "jobs -q" #define REFRESH #define LDFLAGS "-s" #define ADD_LIBRARIES "bobcat" #define ADD_LIBRARY_PATHS "" #define PARSER_DIR "parser" #define PARSGEN "bisonc++" #define PARSFLAGS "-V" #define PARSSPEC "grammar" #define PARSFILES "rules/*" #define PARSOUT "parse.cc" #define SCANNER_DIR "scanner" #define SCANGEN "flexc++" #define SCANFLAGS "" #define SCANSPEC "lexer" //#define SCANFILES "" #define SCANOUT "lex.cc" #define DEFCOM "program" c++-annotations-13.02.01/src/verb/main.cc0000664000175000017500000000122314735537670016626 0ustar frankfrank//#define XERR #include "main.ih" namespace { Arg::LongOption longOpts[] = { Arg::LongOption{"help", 'h'}, Arg::LongOption{"replace", 'r'}, Arg::LongOption{"version", 'v'}, }; auto longEnd = longOpts + size(longOpts); } int main(int argc, char **argv) try { Arg const &arg = Arg::initialize("hrv", longOpts, longEnd, argc, argv); arg.versionHelp(usage, Icmbuild::version, 1); Compactor compactor; compactor.run(); } catch (int value) { return Arg::instance().option("hv") ? 0 : value; } catch (exception const &exc) { cout << exc.what() << '\n'; return 1; } catch (...) { return 1; } c++-annotations-13.02.01/src/verb/version.cc0000664000175000017500000000056314735537670017375 0ustar frankfrank// version.cc #include "main.ih" #include "icmconf" #ifdef USE_VERSION #include "VERSION" #endif #ifndef AUTHOR #define AUTHOR "" #endif #ifndef VERSION #define VERSION "0.00.00" #endif #ifndef YEARS #define YEARS "2012" #endif namespace Icmbuild { char version[] = VERSION; char years[] = YEARS; char author[] = AUTHOR; } c++-annotations-13.02.01/src/verb/main.ih0000664000175000017500000000050314735537670016641 0ustar frankfrank#include #include #include #include #include "xerr.ih" #include "compactor/compactor.h" namespace Icmbuild { extern char version[]; extern char years[]; extern char author[]; }; void usage(std::string const &progname); using namespace std; using namespace FBB; c++-annotations-13.02.01/src/verb/CLASSES0000664000175000017500000000002014735537670016405 0ustar frankfrankcompactor files c++-annotations-13.02.01/src/verbnrs.cc0000664000175000017500000000325414735537670016433 0ustar frankfrank#include #include #include #include using namespace std; // first argument: file to process, 2nd argument (optional): indentation (by // default 1, which is also the minimum indentation that is used.) int main(int argc, char **argv) { string line; bool empty = true; ifstream in(argv[1]); while (getline(in, line)) // find the first non-empty line { if (line.find_first_not_of(" \t") != string::npos) // non-empty line { empty = false; // avoid doubly checking `line' break; } } if (empty) // nothing but emptyness... return 0; size_t indent = 0; if (argc > 2) indent = stoul(argv[2]); size_t lineNr = 0; size_t nEmpty = 0; // counts empty lines cout << "\n" "verb(" << setw(indent) << ' ' << setw(2) << ++lineNr << ' ' << line; // show the 1st line while (getline(in, line)) // read the rest of the file { if (line.find_first_not_of(" \t") == string::npos) // empty line { ++nEmpty; // count it continue; // proceed with the next line } if (lineNr != 0) cout << '\n'; for (size_t nr = 0; nr != nEmpty; ++nr) // 'for': # iterations known cout << setw(indent) << ' ' << setw(2) << ++lineNr << '\n'; nEmpty = 0; // reset the counter cout << setw(indent) << ' ' << setw(2) << ++lineNr << ' ' << line; // show the line } cout << ")\n"; } c++-annotations-13.02.01/src/trim/0000775000175000017500000000000014735537670015412 5ustar frankfrankc++-annotations-13.02.01/src/trim/trim.cc0000664000175000017500000000573014735537670016701 0ustar frankfrank#include #include #include #include #include #include #include #include #include "../../VERSION" using namespace std; bool silent; struct StringLine: public std::string {}; istream &operator>>(istream &in, StringLine &line) { return getline(in, line); } class Trimmer { ostream &d_out; public: Trimmer(ostream &out) : d_out(out) {} void operator()(string const &str) const { // find last non ws size_t idx = str.find_last_not_of(" \t"); if (idx == string::npos) // no non-ws char: print empty line d_out << '\n'; else if (idx + 1 == str.length()) // no trailing ws d_out << str << '\n'; else // \ requires 1 space d_out << str.substr(0, idx + 1) << '\n'; } }; void trim(char const *name = 0) { ifstream in; istream *ip; vector vs; if (!name) ip = &cin; else { if (!silent) cout << "trimming `" << name << "'\n"; in.open(name); if (!in) { cout << "no such file `" << name << "': skipped.\n"; return; } ip = ∈ } copy(istream_iterator(*ip), istream_iterator(), back_inserter(vs)); vector::reverse_iterator it = find_if(vs.rbegin(), vs.rend(), [&](string const &str) { return str.find_first_not_of(" \t") != string::npos; } ); ofstream out; ostream *op; if (!name) op = &cout; else { in.close(); out.open(name); op = &out; } for_each(vs.begin(), vector::iterator(&*(it - 1)), Trimmer{ *op }); } char const info[] = R"( [-q] [file(s)] Where: -q: quiet (optional), suppress informative messages file(s): zero or more files to process: trailing blanks at the end of lines are removed. When no files are specified, the file to process is read from the redirected standard input stream. )"; char const header[] = R"( by Frank B. Brokken (f.b.brokken@rug.nl) Trailing blanks trimmer V )" VERSION R"( Copyright (c) GPL )" YEARS R"(. NO WAARANTY. Usage: )"; int main(int argc, char **argv) { if (isatty(STDIN_FILENO) and argc == 1) { string base = basename(argv[0]); cout << base << header << base << info << '\n'; return 0; } if (argc == 1) trim(); else { if (argc > 1) silent = string("-q") == argv[1]; for (size_t idx = 1 + silent; idx != size_t(argc); ++idx) trim(argv[idx]); } } c++-annotations-13.02.01/src/rmindexlines/0000775000175000017500000000000014735537670017140 5ustar frankfrankc++-annotations-13.02.01/src/rmindexlines/rmindexlines.cc0000664000175000017500000000110114735537670022141 0ustar frankfrank#include #include using namespace std; int main() { string line1; string line2; getline(cin, line1); // initialization: pick up line 1 // which is never a \n while (getline(cin, line2)) { cout << line1; if (line2.find(" #include #include #include using namespace std; namespace fs = filesystem; //using namespace FBB; namespace { void latexMod(string const &filename) // called from tmp/docs/latex { fs::copy_file("../../../celeb/celeb30.eps", "celeb30.eps", fs::copy_options::skip_existing); ifstream latex{ filename }; // available .latex file ofstream mod{ filename + ".mod" }; // modified .latex file string line; while (true) { getline(latex, line); // find the \maketitle line if (line.find("ISBN") != string::npos) // stop at the ISBN line break; mod << line << '\n'; } ifstream table{ "../../../celeb/celeb30.latex" }; table.ignore(1000, '\n'); // skip the 1st (comment) line mod << table.rdbuf() << latex.rdbuf(); mod.close(); fs::rename(filename + ".mod", filename); } void htmlMod(string const &filename) // called from tmp/docs/html { fs::copy_file("../../../celeb/celeb30.gif", "celeb30.gif", fs::copy_options::skip_existing); ifstream html{ filename }; // available .html file ofstream mod{ filename + ".mod" }; // modified .html file string line; do { getline(html, line); // find the line mod << line << '\n'; } while (line.find("") == string::npos); // stop after ifstream table{ "../../../celeb/celeb30.html" }; table.ignore(1000, '\n'); // skip the 1st (comment) line mod << table.rdbuf() << html.rdbuf(); mod.close(); fs::rename(filename + ".mod", filename); } } int main(int argc, char **argv) { string arg{ argv[1] }; // arg[1] ends in html or latex called from tmp/docs/latex if (arg.find(".latex") != string::npos) latexMod(arg); else htmlMod(arg); } c++-annotations-13.02.01/src/keywordsort.cc0000664000175000017500000000446614735537670017354 0ustar frankfrank// use -lbobcat to link #include #include #include #include #include #include #include #include #include using namespace std; using namespace FBB; /* "alignas " "alignof and compl explicit new requires typedef and_eq concept extern not " "bool delete if private switch void break do inline protected template " "volatile " "case double int public this wchar_t catch dynamic_cast long register throw " "decltype friend or static_cast using bitor default goto or_eq struct " "virtual " "nullptr sizeof union axiom continue for operator static unsigned bitand " "short typeid asm const false not_eq signed typename auto const_cast float " "try xor_eq constexpr import export " "while char else mutable reinterpret_cast true xor class enum namespace " "char16_t char32_t noexcept static_assert thread_local " "return" ; */ // http://en.cppreference.com/w/cpp/keyword string keywords = R"( alignas alignof and and_eq asm atomic_cancel atomic_commit atomic_noexcept auto bitand bitor bool break case catch char char16_t char32_t class compl concept const constexpr const_cast continue co_await co_return co_yield decltype default delete do double dynamic_cast else enum explicit export extern false float for friend goto if import inline int long module mutable namespace new noexcept not not_eq nullptr operator or or_eq private protected public register reinterpret_cast requires return short signed sizeof static static_assert static_cast struct switch synchronized template this thread_local throw true try typedef typeid typename union unsigned using virtual void volatile wchar_t while xor xor_eq )"; struct Support: public TableSupport { void vline(size_t col) const { if (col > 0) out() << ' '; } }; int main() { set keyword; istringstream in(keywords); copy(istream_iterator(in), istream_iterator(), inserter(keyword, keyword.begin())); Support support; support << 0; for (size_t col = 0; col != 6; ++col) support << 1; Table table(support, 6, Table::COLUMNWISE); table.fill(keyword.begin(), keyword.end()); for(size_t col = 0; col != 6; ++col) table << Align(col, std::left); cout << table << '\n'; } c++-annotations-13.02.01/src/tabs/0000775000175000017500000000000014735537670015370 5ustar frankfrankc++-annotations-13.02.01/src/tabs/normalfile.cc0000664000175000017500000000040714735537670020030 0ustar frankfrank#include "main.ih" bool normalFile(char const *fileName) { struct stat fileInfo; if (lstat(fileName, &fileInfo)) { cout << "Can't stat `" << fileName << "': skipping\n"; return false; } return S_ISREG(fileInfo.st_mode); } c++-annotations-13.02.01/src/tabs/data.cc0000664000175000017500000000016014735537670016605 0ustar frankfrank#include "main.ih" bool g_entab = false; bool g_quiet = false; size_t g_minSpaces = 4; size_t g_tabWidth = 8; c++-annotations-13.02.01/src/tabs/arguments.cc0000664000175000017500000000140014735537670017677 0ustar frankfrank#include "main.ih" bool arguments(int argc, char **argv) { if (argc == 1) { string progname(argv[0]); size_t pos = progname.find_last_of('/'); if (pos != string::npos) progname.erase(0, pos + 1); usage(progname); return false; } while (true) { switch (getopt(argc, argv, "c:des:q")) { case 'e': g_entab = true; break; case 's': g_minSpaces = stoul(optarg); break; case 'c': g_tabWidth = stoul(optarg); break; case 'q': g_quiet = true; break; default: return true; } } } c++-annotations-13.02.01/src/tabs/usage.cc0000664000175000017500000000212614735537670017004 0ustar frankfrank// usage.cc #include "main.ih" void usage(std::string const &progname) { cout << '\n' << progname << " by " << Icmbuild::author << "\n" << progname << " V" << Icmbuild::version << " " << Icmbuild::years << "\n" "Copyright (c) GPL " << Icmbuild::years << ". All rights reserved.\n" "\n" "Usage: %s [-d | -e | -snnn | -cnnn]* file(s)\n" "Where:\n" " -c - entab at / detab to multiples of nnn columns " "(default: 8)\n" " -d - tabs in file(s) are removed (detab)\n" " (default action)\n" " -e - spaces in file(s) are changed into tabs (entab)\n" " -q - quiet: less output than otherwise\n" " -s - entab/detab a minimum number of nnn spaces " "(default: 4)\n" " file(s) - file(s) to entab/detab (are overwritten)\n" " use - to filter stdin to stdout\n" " non-regular files (e.g. symbolic links) are " "skipped.\n" "\n"; } c++-annotations-13.02.01/src/tabs/tabber/0000775000175000017500000000000014735537670016627 5ustar frankfrankc++-annotations-13.02.01/src/tabs/tabber/incColumn.cc0000664000175000017500000000013414735537670021063 0ustar frankfrank#include "tabber.ih" bool Tabber::tabColumn() { return ++d_column % g_tabWidth == 0; } c++-annotations-13.02.01/src/tabs/tabber/space.cc0000664000175000017500000000102514735537670020227 0ustar frankfrank#include "tabber.ih" void Tabber::space() { ++d_nSpaces; if (d_column % g_tabWidth != 0) // not at a tab-position return; if (d_nSpaces < g_minSpaces) // to few spaces to write a tab { d_out << setw(d_nSpaces) << ' '; // write blanks up to the tab-pos d_nSpaces = 0; } else // enough spaces to write a tab { d_nSpaces -= g_minSpaces; // remove #spaces converted to \t d_out.put('\t'); } } c++-annotations-13.02.01/src/tabs/tabber/tabber1.cc0000664000175000017500000000013314735537670020453 0ustar frankfrank#include "tabber.ih" Tabber::Tabber() : d_in(cin.rdbuf()), d_out(cout.rdbuf()) {} c++-annotations-13.02.01/src/tabs/tabber/run.cc0000664000175000017500000000017414735537670017744 0ustar frankfrank#include "tabber.ih" void Tabber::run() { d_column = 0; if (g_entab) entab(); else detab(); } c++-annotations-13.02.01/src/tabs/tabber/run2.cc0000664000175000017500000000031714735537670020025 0ustar frankfrank#include "tabber.ih" void Tabber::run(char const *inName, char const *outName) { ifstream in(inName); ofstream out(outName); d_in.rdbuf(in.rdbuf()); d_out.rdbuf(out.rdbuf()); run(); } c++-annotations-13.02.01/src/tabs/tabber/detab.cc0000664000175000017500000000154414735537670020221 0ustar frankfrank#include "tabber.ih" // d_column is the # of characters so far in the actual field of g_tabWidth // characters. void Tabber::detab() { char ch; while (d_in.get(ch)) { switch (ch) { case '\n': d_column = 0; // no characters in the current field, // since after this we're on the next line break; case '\t': d_out << setw(g_tabWidth - d_column) << ' '; d_column = 0; // no chars in the current field, as we // just filled it up by blanks continue; // process the next character default: d_column = (d_column + 1) % g_tabWidth; break; } d_out.put(ch); // write ordinary char. } } c++-annotations-13.02.01/src/tabs/tabber/tabber.ih0000664000175000017500000000017714735537670020415 0ustar frankfrank#include "tabber.h" #include #include #include #include "../globals.h" using namespace std; c++-annotations-13.02.01/src/tabs/tabber/entab.cc0000664000175000017500000000152614735537670020233 0ustar frankfrank#include "tabber.ih" void Tabber::entab() { char ch; while (d_in.get(ch)) { switch (ch) { case ' ': ++d_nSpaces; // got a space if (tabColumn()) // we're at a tab column { if (d_nSpaces < g_minSpaces) outSpaces(); else { d_nSpaces = 0; d_out.put('\t'); } } break; case '\n': case '\t': outSpaces(); d_out.put(ch); d_column = 0; break; default: outSpaces(); d_out.put(ch); ++d_column; break; } } } c++-annotations-13.02.01/src/tabs/tabber/tab.cc0000664000175000017500000000005514735537670017704 0ustar frankfrank#include "tabber.ih" void Tabber::tab() { } c++-annotations-13.02.01/src/tabs/tabber/outspaces.cc0000664000175000017500000000020714735537670021143 0ustar frankfrank#include "tabber.ih" void Tabber::outSpaces() { if (d_nSpaces != 0) d_out << setw(d_nSpaces) << ' '; d_nSpaces = 0; } c++-annotations-13.02.01/src/tabs/tabber/tabber.h0000664000175000017500000000075414735537670020245 0ustar frankfrank#ifndef INCLUDED_TABBER_ #define INCLUDED_TABBER_ #include #include class Tabber { std::istream d_in; std::ostream d_out; size_t d_nSpaces = 0; size_t d_column = 0; public: Tabber(); void run(); void run(char const *inName, char const *outName); private: void detab(); void entab(); bool tabColumn(); void outSpaces(); void space(); void tab(); }; #endif c++-annotations-13.02.01/src/tabs/VERSION0000664000175000017500000000015314735537670016437 0ustar frankfrank#define AUTHOR "Frank B. Brokken (f.b.brokken@rug.nl)" #define VERSION "2.00.00" #define YEARS "1999-2014" c++-annotations-13.02.01/src/tabs/icmconf0000664000175000017500000000161414735537670016733 0ustar frankfrank#define ADD_LIBRARIES "" #define ADD_LIBRARY_PATHS "" //#define CLS #define CXX "g++" #define CXXFLAGS " --std=c++0x -Wall -g -O2" //#define CFLAGS " -Wall -g -O2" #define LDFLAGS "" //#define LIBRARY "modules" #define MAIN "main.cc" #define OBJ_EXT ".o" #define PARSER_DIR "" //#define PARSFILES "" #define PARSFLAGS "" #define PARSGEN "" #define PARSOUT "" #define PARSSPEC "" //#define REFRESH #define SCANNER_DIR "" //#define SCANFILES "" #define SCANFLAGS "" #define SCANGEN "" #define SCANOUT "" #define SCANSPEC "" #define SHAREDREQ "" #define SOURCES "*.cc" #define TMP_DIR "tmp" #define USE_ECHO ON #define USE_VERSION #define DEFCOM "program" c++-annotations-13.02.01/src/tabs/main.cc0000664000175000017500000000046414735537670016627 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) try { if (not arguments(argc, argv)) return 0; argv += optind; argc -= optind; Tabber tabber; if (argv[0][0] == '-') tabber.run(); if (not process(argv, tabber)) return 1; } catch (...) { return 1; } c++-annotations-13.02.01/src/tabs/version.cc0000664000175000017500000000056314735537670017370 0ustar frankfrank// version.cc #include "main.ih" #include "icmconf" #ifdef USE_VERSION #include "VERSION" #endif #ifndef AUTHOR #define AUTHOR "" #endif #ifndef VERSION #define VERSION "0.00.00" #endif #ifndef YEARS #define YEARS "2012" #endif namespace Icmbuild { char version[] = VERSION; char years[] = YEARS; char author[] = AUTHOR; } c++-annotations-13.02.01/src/tabs/process.cc0000664000175000017500000000101514735537670017352 0ustar frankfrank#include "main.ih" bool process(char **argv, Tabber &tabber) { char tempfile[] = "tab.tmp"; for (; *argv; ++argv) { if (not normalFile(*argv)) continue; if (!g_quiet) cout << "processing `" << *argv << "'\n"; unlink(tempfile); if (rename(*argv, tempfile)) { cout << "can't rename `" << *argv << "'\n"; return false; } tabber.run(tempfile, *argv); } unlink(tempfile); return true; } c++-annotations-13.02.01/src/tabs/main.ih0000664000175000017500000000071514735537670016641 0ustar frankfrank#include #include #include #include #include #include #include "globals.h" #include "tabber/tabber.h" namespace Icmbuild { extern char version[]; extern char years[]; extern char author[]; }; bool arguments(int argc, char **argv); void usage(std::string const &progname); bool normalFile(char const *fileName); bool process(char **argv, Tabber &tabber); using namespace std; c++-annotations-13.02.01/src/tabs/globals.h0000664000175000017500000000026514735537670017167 0ustar frankfrank#ifndef INCLUDED_GLOBALS_H_ #define INCLUDED_GLOBALS_H_ #include extern size_t g_minSpaces; extern size_t g_tabWidth; extern bool g_entab; extern bool g_quiet; #endif c++-annotations-13.02.01/src/tabs/CLASSES0000664000175000017500000000000714735537670016405 0ustar frankfranktabber c++-annotations-13.02.01/src/paren/0000775000175000017500000000000014735537670015544 5ustar frankfrankc++-annotations-13.02.01/src/paren/paren.cc0000664000175000017500000000516214735537670017164 0ustar frankfrank// paren.cc #include #include #include #include #include #include using namespace std; using namespace FBB; bool hdr = false; bool verbose; string version("2.00"); string years("1999-2006"); void header(char const *fn) { if (hdr) return; hdr = true; if (verbose) cout << "PROCESSING " << fn << endl; } void usage(string const &prog) { cout << "\n" << prog << " by Frank B. Brokken (f.b.brokken@rug.nl)\n" "Copyright " << years << " (c) GPL, V " << version << ".\n" "\n" "Usage: " << prog << " [-v] file(s)\n" "Where:\n" " -h: print this help-info\n" " -q: quiet: less output than otherwise\n" " -v: show the version\n" " file(s): file(s) to check for unbalanced parentheses.\n" " (A simple algorithm is used, in which all \n" " characters are treated equal).\n" "\n"; } int main(int argc, char **argv) try { Arg &arg = Arg::initialize("hqv", argc, argv); arg.versionHelp(usage, version.c_str(), 1); verbose = !arg.option('q'); bool ok = true; for (size_t idx = arg.nArgs(); idx--; ) { ifstream in(arg[idx]); if (!in) { cout << "Can't read " << arg[idx] << endl; ok = false; continue; } hdr = false; stack linenr; unsigned line = 0; string text; while (getline(in, text)) { ++line; for (char ch: text) { switch (ch) { case '(': linenr.push(line); break; case ')': if (linenr.empty()) { header(arg[idx]); cout << "\tExtra closepar in line " << line << endl; ok = false; break; } linenr.pop(); break; } } } while (!linenr.empty()) { header(arg[idx]); cout << "\tUnbalanced openpar in line " << linenr.top() << endl; linenr.pop(); ok = false; } } return ok ? 0 : 1; } catch(exception const &e) { cout << e.what() << endl; return 1; } catch(...) { return 1; } c++-annotations-13.02.01/VERSION0000664000175000017500000000006714771457005014714 0ustar frankfrank#define VERSION "13.02.01" #define YEARS "1994-2025" c++-annotations-13.02.01/yo/0000755000175000017500000000000014771457207014272 5ustar frankfrankc++-annotations-13.02.01/yo/static.yo0000664000175000017500000000127514735537670016144 0ustar frankfrankincludefile(static/intro) lsect(StaticData)(Static data) includefile(static/data) subsect(Private static data) includefile(static/private) subsect(Public static data) includefile(static/public) subsect(Initializing static const data) includefile(static/const) lsubsect(GENCONST)(Generalized constant expressions (constexpr)) includefile(static/genconst) lsubsubsect(CONSTEXPR)(Constant expression data) includefile(static/constexprdata) sect(Static member functions) includefile(static/function) lsubsect(CALLINGCONVENTION)(Calling conventions) includefile(static/calling) c++-annotations-13.02.01/yo/wip.yo0000664000175000017500000000111114735537670015441 0ustar frankfrankincludefile(preamble) mailto(Frank B. Brokken: MYEMAIL) report() () () IFDEF(latex)(latexcommand( \cleardoublepage \pagestyle{headings} \pagenumbering{arabic}))() lsect(UNIONS)(Unrestricted Unions) includefile(containers/unrestricted) subsect(Implementing the destructor) includefile(containers/uniondestructor) subsect(Embedding an unrestricted union in a surrounding class) includefile(containers/embedding) subsect(Swapping unrestricted unions) includefile(containers/unionswap) subsect(Assignment) includefile(containers/assignment) c++-annotations-13.02.01/yo/namespaces/0000775000175000017500000000000014735537670016416 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/examples/0000775000175000017500000000000014771010713020214 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/examples/koenig1.cc0000664000175000017500000000067514771010720022066 0ustar frankfrank #include namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "fun called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // Koenig lookup: no namespace // for fun() specified } /* generated output: fun called for 0 */ c++-annotations-13.02.01/yo/namespaces/examples/koenig3.cc0000664000175000017500000000145314771010720022063 0ustar frankfrank #include namespace ES { enum Value // defines ES::Value { FIRST }; } namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x, ES::Value y) { std::cout << "FBB::fun() called\n"; } } namespace ES { void fun(FBB::Value x, Value y) { std::cout << "ES::fun() called\n"; } } int main() { // fun(FBB::FIRST, ES::FIRST); ambiguity: resolved by // explicitly mentioning // the namespace ES::fun(FBB::FIRST, ES::FIRST); } /* generated output: ES::fun() called */ c++-annotations-13.02.01/yo/namespaces/examples/nesting.cc0000664000175000017500000000156214771010720022174 0ustar frankfranknamespace CppAnnotations { int value; namespace Virtual { void *pointer; } } // // 0 //using namespace CppAnnotations; // 1 //using namespace CppAnnotations::Virtual; // 2 //using namespace CppAnnotations; // 3 //using namespace Virtual; //using CppAnnotations::value; // 4 //using CppAnnotations::Virtual::pointer; //using namespace CppAnnotations::Virtual; // 5 //using CppAnnotations::value; int main() { // CppAnnotations::Virtual::pointer = 0; // 0 // CppAnnotations::value = 0; // value = 0; // 1 // Virtual::pointer = 0; // CppAnnotations::value = 0; // 2 // pointer = 0; // value = 0; // 3, 4, 5 // pointer = 0; } c++-annotations-13.02.01/yo/namespaces/examples/compound.cc0000664000175000017500000000044614771010720022351 0ustar frankfrank#include #include struct Namespace { // using namespace std; cannot be used here std::string d_str; std::string text() const; }; int main() { using namespace std; // but here is OK string text; Namespace ns; cout << ns.text(); } c++-annotations-13.02.01/yo/namespaces/examples/koenig2.cc0000664000175000017500000000113314771010720022055 0ustar frankfrank #include namespace FBB { enum Value // defines FBB::Value { FIRST }; void fun(Value x) { std::cout << "FBB::fun() called for " << x << '\n'; } } namespace ES { void fun(FBB::Value x) { std::cout << "ES::fun() called for " << x << '\n'; } } int main() { fun(FBB::FIRST); // No ambiguity: argument determines // the namespace } /* generated output: FBB::fun() called for 0 */ c++-annotations-13.02.01/yo/namespaces/examples/koenig4.cc0000664000175000017500000000043114771010720022057 0ustar frankfrank namespace FBB { struct Value {}; void fun(int x); void gun(Value x); } namespace ES { void fun(int x) { fun(x); } void gun(FBB::Value x) { gun(x); } } c++-annotations-13.02.01/yo/namespaces/filesystem/0000775000175000017500000000000014745404622020571 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/filesystem/examples/0000775000175000017500000000000014771010713022400 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/filesystem/examples/fileclock.cc0000664000175000017500000001125514771010720024644 0ustar frankfrank#include #include #include using namespace std; using namespace filesystem; using namespace chrono; // 318315729 // 1403456322 -1085140593 // -1'085'344'473 class FC { struct In { tm d_tm; char const *d_fmt; In(tm const &tmData, char const *fmt); ostream &insert(ostream &out) const; }; friend ostream &operator<<(ostream &out, In const &in); using time_t2tm = tm (*)(const time_t *); using TPfileClock = time_point; using TPsystemClock = time_point; static TPsystemClock const s_sPoint; static int const s_offset; public: enum TimeType { LT, GMT }; // system time point corresponding to file_clock static TPsystemClock sysTimePoint(TPfileClock const &fp); // tm corresponding to file_clock for local time static tm tmLocal(TPfileClock const &ftp); // tm corresponding to file_clock for gmtime static tm tmGMT(TPfileClock const &ftp); static In put_time(TPfileClock const &fp, char const *fmt = "%c", TimeType type = LT); private: static tm to_tm(tm *(*funPtr)(const time_t *), TPfileClock const &fp); }; // static data FC::TPsystemClock const FC::s_sPoint = system_clock::now(); // 'now' expressed for file_clock int const FC::s_offset = FC::s_sPoint.time_since_epoch().count() - file_clock::now().time_since_epoch().count(); FC::In::In(tm const &tmData, char const *fmt) : d_tm(tmData), d_fmt(fmt) {} ostream &FC::In::insert(ostream &out) const { return out << std::put_time(&d_tm, d_fmt); }; ostream &operator<<(ostream &out, FC::In const &in) { return in.insert(out); } FC::In FC::put_time(TPfileClock const &fp, char const *fmt, TimeType type) { return In{type == LT ? tmLocal(fp) : tmGMT(fp), fmt }; } // cout << fc(fPoint) << '\n'; FC::TPsystemClock FC::sysTimePoint(TPfileClock const &fp) { int fnow = fp.time_since_epoch().count(); fnow += s_offset; // time according to the system clock return s_sPoint + nanoseconds(fnow); } tm FC::tmLocal(TPfileClock const &fp) { return to_tm(gmtime, fp); } tm FC::tmGMT(TPfileClock const &fp) { return to_tm(localtime, fp); } tm FC::to_tm(tm *(*funPtr)(const time_t *), TPfileClock const &fp) { time_t secs = system_clock::to_time_t( sysTimePoint(fp) + nanoseconds{ s_offset } ); return *(*funPtr)(&secs); } time_point conv1(time_point const &point) { auto systemNow = system_clock::now().time_since_epoch(); auto fileNow = file_clock::now().time_since_epoch(); return time_point{ nanoseconds(point.time_since_epoch() + systemNow - fileNow) }; } int main() { // 'now' expressed for system_clock time_point sPoint = system_clock::now(); int snow = sPoint.time_since_epoch().count(); cout << "system now in seconds since the epoch: " << snow << '\n'; // current local time time_t secs = system_clock::to_time_t(sPoint); cout << put_time(localtime(&secs), "%c") << '\n'; // 'now' expressed for file_clock time_point fPoint = file_clock::now(); int fnow = fPoint.time_since_epoch().count(); cout << "file clock now in seconds since the (fc) epoch: " << fnow << '\n'; int offset = snow - fnow; // difference between system- and fileclock cout << snow << ' ' << fnow << ' ' << offset << '\n'; time_point epoch; secs = system_clock::to_time_t(epoch); cout << "begin of system epoch: secs = " << secs << ", time: " << put_time(gmtime(&secs), "%c") << '\n'; time_point epochFC{ nanoseconds(-100'000'000'000) }; secs = system_clock::to_time_t(epochFC); cout << "begin of _file_clock epoch: seconds: " << secs << ", time: " << put_time(gmtime(&secs), "%c") << '\n'; // to go from filesystem_clock to system_clock add offset (expressed in // nanoseconds) to the int-count obtained from the filesystem_clock's // time_point. sPoint += nanoseconds{ offset }; secs = system_clock::to_time_t(sPoint); cout << put_time(localtime(&secs), "%c") << '\n'; tm tmData{ FC::tmLocal(fPoint) }; cout << put_time(&tmData, "%c") << '\n'; cout << FC::put_time(fPoint) << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/spaceinfo.cc0000664000175000017500000000102614771010720024653 0ustar frankfrank#include #include using namespace std; using namespace filesystem; //demo int main() { path tmp{ "/tmp" }; auto pod = space(tmp); cout << "The filesystem containing /tmp has a capacity of " << pod.capacity << " bytes,\n" "i.e., " << pod.capacity / (1024 * 1024) << " MB.\n" "# free bytes: " << pod.free << "\n" "# available: " << pod.available << "\n" "free + available: " << pod.free + pod.available << '\n'; } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/filesystemerror.cc0000664000175000017500000000122714771010720026145 0ustar frankfrank#include #include using namespace std; using namespace filesystem; //fse int main() try { try { throw filesystem_error{ "exception encountered", "p1", "p2", make_error_code(errc::address_in_use) }; } catch (filesystem_error const &fse) { cerr << "what: " << fse.what() << "\n" "path1: " << fse.path1() << "\n" "path2: " << fse.path2() << "\n" "code: " << fse.code() << '\n'; throw; } } catch (exception const &ec) { cerr << "\n" "plain exception's what: " << ec.what() << "\n\n"; } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/tosys.cc0000664000175000017500000000116114771010720024065 0ustar frankfrank#include #include #include using namespace std; using namespace chrono; using namespace filesystem; int main() { //system_clock::to_sys(system_clock::now()); // not for system_clock // steady_clock::to_sys(steady_clock::now()); // not for steady_clock // high_resolution_clock::to_sys( // not for high_res._clock // high_resolution_clock::now()); file_clock::to_sys(file_clock::now()); //file_clock::to_time_t(file_clock::now()); // not in file_clock // steady_clock::to_time_t(steady_clock::now());// not in steady_clock } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/lastwritetime2.cc0000664000175000017500000000064214771010720025666 0ustar frankfrank#include #include #include using namespace std; using namespace filesystem; using namespace chrono; //demo int main() { time_t seconds = system_clock::to_time_t( file_clock::to_sys(last_write_time("lastwritetime.cc")) ); cout << "lastwritetime.cc's last (UTC) write time: " << put_time(gmtime(&seconds), "%c") << '\n'; } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/directoryentry.cc0000664000175000017500000000053514771010720025776 0ustar frankfrank//de #include #include using namespace std; using namespace filesystem; int main(int argc, char **argv) // provide 2 arguments { directory_entry de{ argv[1] }; cout << de.path() << '\n'; de.replace_filename(argv[2]); cout << de.path() << '\n'; de.assign(argv[2]); cout << de.path() << '\n'; } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/tosys/0000775000175000017500000000000014771010713023561 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/filesystem/examples/tosys/crono.MS0000664000175000017500000105556014735537670025176 0ustar frankfrank// chrono standard header #pragma once #ifndef _CHRONO_ #define _CHRONO_ #include #if _STL_COMPILER_PREPROCESSOR #include #include #include #include #include #include #if _HAS_CXX20 #include <__msvc_tzdb.hpp> #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef __cpp_lib_concepts #include #endif // defined(__cpp_lib_concepts) #ifdef __cpp_lib_format #include #include #endif // defined(__cpp_lib_format) #endif // _HAS_CXX20 #pragma pack(push, _CRT_PACKING) #pragma warning(push, _STL_WARNING_LEVEL) #pragma warning(disable : _STL_DISABLED_WARNINGS) _STL_DISABLE_CLANG_WARNINGS #pragma push_macro("new") #undef new _STD_BEGIN namespace chrono { template struct treat_as_floating_point : is_floating_point<_Rep> {}; // tests for floating-point type template _INLINE_VAR constexpr bool treat_as_floating_point_v = treat_as_floating_point<_Rep>::value; template struct duration_values { // gets arithmetic properties of a type _NODISCARD static constexpr _Rep zero() noexcept { // get zero value return _Rep(0); } _NODISCARD static constexpr _Rep(min)() noexcept { // get smallest value return numeric_limits<_Rep>::lowest(); } _NODISCARD static constexpr _Rep(max)() noexcept { // get largest value return (numeric_limits<_Rep>::max) (); } }; #if _HAS_CXX20 template inline constexpr bool _Is_clock_v = false; template inline constexpr bool _Is_clock_v<_Clock, void_t> = true; // TRANSITION, GH-602 template struct is_clock : bool_constant<_Is_clock_v<_Clock>> {}; template inline constexpr bool is_clock_v = _Is_clock_v<_Clock>; #endif // _HAS_CXX20 template > class duration; template _INLINE_VAR constexpr bool _Is_duration_v = _Is_specialization_v<_Ty, duration>; template , int> = 0> constexpr _To duration_cast(const duration<_Rep, _Period>&) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v); // strengthened template class duration { // represents a time duration public: using rep = _Rep; using period = typename _Period::type; static_assert(!_Is_duration_v<_Rep>, "duration can't have duration as first template argument"); static_assert(_Is_ratio_v<_Period>, "period not an instance of std::ratio"); static_assert(0 < _Period::num, "period negative or zero"); constexpr duration() = default; template && (treat_as_floating_point_v<_Rep> || !treat_as_floating_point_v<_Rep2>), int> = 0> constexpr explicit duration(const _Rep2& _Val) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v<_Rep2>) // strengthened : _MyRep(static_cast<_Rep>(_Val)) {} template || (_Ratio_divide_sfinae<_Period2, _Period>::den == 1 && !treat_as_floating_point_v<_Rep2>), int> = 0> constexpr duration(const duration<_Rep2, _Period2>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v<_Rep2>) // strengthened : _MyRep(_CHRONO duration_cast(_Dur).count()) {} _NODISCARD constexpr _Rep count() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return _MyRep; } _NODISCARD constexpr common_type_t operator+() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return common_type_t(*this); } _NODISCARD constexpr common_type_t operator-() const noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return common_type_t(-_MyRep); } _CONSTEXPR17 duration& operator++() noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { ++_MyRep; return *this; } _CONSTEXPR17 duration operator++(int) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return duration(_MyRep++); } _CONSTEXPR17 duration& operator--() noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { --_MyRep; return *this; } _CONSTEXPR17 duration operator--(int) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { return duration(_MyRep--); } _CONSTEXPR17 duration& operator+=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep += _Right._MyRep; return *this; } _CONSTEXPR17 duration& operator-=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep -= _Right._MyRep; return *this; } _CONSTEXPR17 duration& operator*=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep *= _Right; return *this; } _CONSTEXPR17 duration& operator/=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep /= _Right; return *this; } _CONSTEXPR17 duration& operator%=(const _Rep& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep %= _Right; return *this; } _CONSTEXPR17 duration& operator%=(const duration& _Right) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { _MyRep %= _Right.count(); return *this; } _NODISCARD static constexpr duration zero() noexcept { // get zero value return duration(duration_values<_Rep>::zero()); } _NODISCARD static constexpr duration(min)() noexcept { // get minimum value return duration((duration_values<_Rep>::min) ()); } _NODISCARD static constexpr duration(max)() noexcept { // get maximum value return duration((duration_values<_Rep>::max) ()); } private: _Rep _MyRep; // the stored rep }; template class time_point { // represents a point in time public: using clock = _Clock; using duration = _Duration; using rep = typename _Duration::rep; using period = typename _Duration::period; static_assert(_Is_duration_v<_Duration>, "N4885 [time.point.general]/1 mandates Duration to be a specialization of chrono::duration."); constexpr time_point() = default; constexpr explicit time_point(const _Duration& _Other) noexcept(is_arithmetic_v) // strengthened : _MyDur(_Other) {} template , int> = 0> constexpr time_point(const time_point<_Clock, _Duration2>& _Tp) noexcept( is_arithmetic_v&& is_arithmetic_v) // strengthened : _MyDur(_Tp.time_since_epoch()) {} _NODISCARD constexpr _Duration time_since_epoch() const noexcept(is_arithmetic_v) /* strengthened */ { return _MyDur; } #if _HAS_CXX20 constexpr time_point& operator++() noexcept(is_arithmetic_v) /* strengthened */ { ++_MyDur; return *this; } constexpr time_point operator++(int) noexcept(is_arithmetic_v) /* strengthened */ { return time_point{_MyDur++}; } constexpr time_point& operator--() noexcept(is_arithmetic_v) /* strengthened */ { --_MyDur; return *this; } constexpr time_point operator--(int) noexcept(is_arithmetic_v) /* strengthened */ { return time_point{_MyDur--}; } #endif // _HAS_CXX20 _CONSTEXPR17 time_point& operator+=(const _Duration& _Dur) noexcept(is_arithmetic_v) /* strengthened */ { _MyDur += _Dur; return *this; } _CONSTEXPR17 time_point& operator-=(const _Duration& _Dur) noexcept(is_arithmetic_v) /* strengthened */ { _MyDur -= _Dur; return *this; } _NODISCARD static constexpr time_point(min)() noexcept { return time_point((_Duration::min) ()); } _NODISCARD static constexpr time_point(max)() noexcept { return time_point((_Duration::max) ()); } private: _Duration _MyDur{duration::zero()}; // duration since the epoch }; } // namespace chrono template _INLINE_VAR constexpr bool _Is_trivially_swappable_v> = _Is_trivially_swappable_v<_Rep>; template _INLINE_VAR constexpr bool _Is_trivially_swappable_v> = _Is_trivially_swappable_v<_Duration>; template struct _Lcm : integral_constant::value) * _Bx> {}; // compute LCM of _Ax and _Bx template struct common_type<_CHRONO duration<_Rep1, _Period1>, _CHRONO duration<_Rep2, _Period2>> { // common type of two durations using type = _CHRONO duration, ratio<_Gcd<_Period1::num, _Period2::num>::value, _Lcm<_Period1::den, _Period2::den>::value>>; }; template struct common_type<_CHRONO time_point<_Clock, _Duration1>, _CHRONO time_point<_Clock, _Duration2>> { // common type of two time points using type = _CHRONO time_point<_Clock, common_type_t<_Duration1, _Duration2>>; }; namespace chrono { template _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator+(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CD = common_type_t, duration<_Rep2, _Period2>>; return _CD(_CD(_Left).count() + _CD(_Right).count()); } template _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator-(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CD = common_type_t, duration<_Rep2, _Period2>>; return _CD(_CD(_Left).count() - _CD(_Right).count()); } template >, int> = 0> _NODISCARD constexpr duration, _Period1> operator*( const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) noexcept(is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CR = common_type_t<_Rep1, _Rep2>; using _CD = duration<_CR, _Period1>; return _CD(_CD(_Left).count() * _Right); } template >, int> = 0> _NODISCARD constexpr duration, _Period2> operator*(const _Rep1& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return _Right * _Left; } template > struct _Duration_div_mod1 { // return type for duration / rep and duration % rep using type = duration<_CR, _Period1>; }; template struct _Duration_div_mod1<_CR, _Period1, _Rep2, false> {}; // no return type template > struct _Duration_div_mod {}; // no return type template struct _Duration_div_mod<_CR, _Period1, _Rep2, false> : _Duration_div_mod1<_CR, _Period1, _Rep2> { // return type for duration / rep and duration % rep }; template _NODISCARD constexpr typename _Duration_div_mod, _Period1, _Rep2>::type operator/( const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) noexcept(is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CR = common_type_t<_Rep1, _Rep2>; using _CD = duration<_CR, _Period1>; return _CD(_CD(_Left).count() / _Right); } template _NODISCARD constexpr common_type_t<_Rep1, _Rep2> operator/(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CD = common_type_t, duration<_Rep2, _Period2>>; return _CD(_Left).count() / _CD(_Right).count(); } template _NODISCARD constexpr typename _Duration_div_mod, _Period1, _Rep2>::type operator%( const duration<_Rep1, _Period1>& _Left, const _Rep2& _Right) noexcept(is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CR = common_type_t<_Rep1, _Rep2>; using _CD = duration<_CR, _Period1>; return _CD(_CD(_Left).count() % _Right); } template _NODISCARD constexpr common_type_t, duration<_Rep2, _Period2>> operator%(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CD = common_type_t, duration<_Rep2, _Period2>>; return _CD(_CD(_Left).count() % _CD(_Right).count()); } template _NODISCARD constexpr bool operator==(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CT = common_type_t, duration<_Rep2, _Period2>>; return _CT(_Left).count() == _CT(_Right).count(); } #if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return !(_Left == _Right); } #endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { using _CT = common_type_t, duration<_Rep2, _Period2>>; return _CT(_Left).count() < _CT(_Right).count(); } template _NODISCARD constexpr bool operator<=(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return !(_Right < _Left); } template _NODISCARD constexpr bool operator>(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return _Right < _Left; } template _NODISCARD constexpr bool operator>=(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { return !(_Left < _Right); } #ifdef __cpp_lib_concepts // clang-format off template requires three_way_comparable, duration<_Rep2, _Period2>>::rep> _NODISCARD constexpr auto operator<=>(const duration<_Rep1, _Period1>& _Left, const duration<_Rep2, _Period2>& _Right) noexcept( is_arithmetic_v<_Rep1>&& is_arithmetic_v<_Rep2>) /* strengthened */ { // clang-format on using _CT = common_type_t, duration<_Rep2, _Period2>>; return _CT(_Left).count() <=> _CT(_Right).count(); } #endif // defined(__cpp_lib_concepts) template , int> _Enabled> _NODISCARD constexpr _To duration_cast(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; truncate using _CF = ratio_divide<_Period, typename _To::period>; using _ToRep = typename _To::rep; using _CR = common_type_t<_ToRep, _Rep, intmax_t>; constexpr bool _Num_is_one = _CF::num == 1; constexpr bool _Den_is_one = _CF::den == 1; if (_Den_is_one) { if (_Num_is_one) { return static_cast<_To>(static_cast<_ToRep>(_Dur.count())); } else { return static_cast<_To>( static_cast<_ToRep>(static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num))); } } else { if (_Num_is_one) { return static_cast<_To>( static_cast<_ToRep>(static_cast<_CR>(_Dur.count()) / static_cast<_CR>(_CF::den))); } else { return static_cast<_To>(static_cast<_ToRep>( static_cast<_CR>(_Dur.count()) * static_cast<_CR>(_CF::num) / static_cast<_CR>(_CF::den))); } } } template , int> = 0> _NODISCARD constexpr _To floor(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards negative infinity // i.e. the greatest integral result such that the result <= _Dur const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted > _Dur) { return _To{_Casted.count() - static_cast(1)}; } return _Casted; } template , int> = 0> _NODISCARD constexpr _To ceil(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration; round towards positive infinity // i.e. the least integral result such that _Dur <= the result const _To _Casted{_CHRONO duration_cast<_To>(_Dur)}; if (_Casted < _Dur) { return _To{_Casted.count() + static_cast(1)}; } return _Casted; } template constexpr bool _Is_even(_Rep _Val) noexcept(is_arithmetic_v<_Rep>) /* strengthened */ { // Tests whether _Val is even return _Val % 2 == 0; } template && !treat_as_floating_point_v, int> = 0> _NODISCARD constexpr _To round(const duration<_Rep, _Period>& _Dur) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { // convert duration to another duration, round to nearest, ties to even const _To _Floored{_CHRONO floor<_To>(_Dur)}; const _To _Ceiled{_Floored + _To{1}}; const auto _Floor_adjustment = _Dur - _Floored; const auto _Ceil_adjustment = _Ceiled - _Dur; if (_Floor_adjustment < _Ceil_adjustment || (_Floor_adjustment == _Ceil_adjustment && _Is_even(_Floored.count()))) { return _Floored; } return _Ceiled; } template ::is_signed, int> = 0> _NODISCARD constexpr duration<_Rep, _Period> abs(const duration<_Rep, _Period> _Dur) noexcept( is_arithmetic_v<_Rep>) /* strengthened */ { // create a duration with count() the absolute value of _Dur.count() return _Dur < duration<_Rep, _Period>::zero() ? duration<_Rep, _Period>::zero() - _Dur : _Dur; } using nanoseconds = duration; using microseconds = duration; using milliseconds = duration; using seconds = duration; using minutes = duration>; using hours = duration>; #if _HAS_CXX20 using days = duration, hours::period>>; using weeks = duration, days::period>>; using years = duration, days::period>>; using months = duration>>; #endif // _HAS_CXX20 template _NODISCARD constexpr time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>> operator+(const time_point<_Clock, _Duration>& _Left, const duration<_Rep, _Period>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v<_Rep>) /* strengthened */ { using _RT = time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>>; return _RT(_Left.time_since_epoch() + _Right); } template _NODISCARD constexpr time_point<_Clock, common_type_t, _Duration>> operator+(const duration<_Rep, _Period>& _Left, const time_point<_Clock, _Duration>& _Right) noexcept( is_arithmetic_v<_Rep>&& is_arithmetic_v) /* strengthened */ { return _Right + _Left; } template _NODISCARD constexpr time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>> operator-(const time_point<_Clock, _Duration>& _Left, const duration<_Rep, _Period>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v<_Rep>) /* strengthened */ { using _RT = time_point<_Clock, common_type_t<_Duration, duration<_Rep, _Period>>>; return _RT(_Left.time_since_epoch() - _Right); } template _NODISCARD constexpr common_type_t<_Duration1, _Duration2> operator-(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return _Left.time_since_epoch() - _Right.time_since_epoch(); } template _NODISCARD constexpr bool operator==(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return _Left.time_since_epoch() == _Right.time_since_epoch(); } #if !_HAS_CXX20 template _NODISCARD constexpr bool operator!=(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return !(_Left == _Right); } #endif // !_HAS_CXX20 template _NODISCARD constexpr bool operator<(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return _Left.time_since_epoch() < _Right.time_since_epoch(); } template _NODISCARD constexpr bool operator<=(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return !(_Right < _Left); } template _NODISCARD constexpr bool operator>(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return _Right < _Left; } template _NODISCARD constexpr bool operator>=(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return !(_Left < _Right); } #ifdef __cpp_lib_concepts template _Duration2> _NODISCARD constexpr auto operator<=>(const time_point<_Clock, _Duration1>& _Left, const time_point<_Clock, _Duration2>& _Right) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { return _Left.time_since_epoch() <=> _Right.time_since_epoch(); } #endif // defined(__cpp_lib_concepts) template , int> = 0> _NODISCARD constexpr time_point<_Clock, _To> time_point_cast(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; truncate return time_point<_Clock, _To>(_CHRONO duration_cast<_To>(_Time.time_since_epoch())); } template , int> = 0> _NODISCARD constexpr time_point<_Clock, _To> floor(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards negative infinity return time_point<_Clock, _To>(_CHRONO floor<_To>(_Time.time_since_epoch())); } template , int> = 0> _NODISCARD constexpr time_point<_Clock, _To> ceil(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round towards positive infinity return time_point<_Clock, _To>(_CHRONO ceil<_To>(_Time.time_since_epoch())); } template && !treat_as_floating_point_v, int> = 0> _NODISCARD constexpr time_point<_Clock, _To> round(const time_point<_Clock, _Duration>& _Time) noexcept( is_arithmetic_v&& is_arithmetic_v) /* strengthened */ { // change the duration type of a time_point; round to nearest, ties to even return time_point<_Clock, _To>(_CHRONO round<_To>(_Time.time_since_epoch())); } struct system_clock { // wraps GetSystemTimePreciseAsFileTime/GetSystemTimeAsFileTime using rep = long long; using period = ratio<1, 10'000'000>; // 100 nanoseconds using duration = _CHRONO duration; using time_point = _CHRONO time_point; static constexpr bool is_steady = false; _NODISCARD static time_point now() noexcept { // get current time return time_point(duration(_Xtime_get_ticks())); } _NODISCARD static __time64_t to_time_t(const time_point& _Time) noexcept { // convert to __time64_t return duration_cast(_Time.time_since_epoch()).count(); } _NODISCARD static time_point from_time_t(__time64_t _Tm) noexcept { // convert from __time64_t return time_point{seconds{_Tm}}; } }; #if _HAS_CXX20 template using sys_time = time_point; using sys_seconds = sys_time; using sys_days = sys_time; #endif // _HAS_CXX20 struct steady_clock { // wraps QueryPerformanceCounter using rep = long long; using period = nano; using duration = nanoseconds; using time_point = _CHRONO time_point; static constexpr bool is_steady = true; _NODISCARD static time_point now() noexcept { // get current time const long long _Freq = _Query_perf_frequency(); // doesn't change after system boot const long long _Ctr = _Query_perf_counter(); static_assert(period::num == 1, "This assumes period::num == 1."); // Instead of just having "(_Ctr * period::den) / _Freq", // the algorithm below prevents overflow when _Ctr is sufficiently large. // It assumes that _Freq * period::den does not overflow, which is currently true for nano period. // It is not realistic for _Ctr to accumulate to large values from zero with this assumption, // but the initial value of _Ctr could be large. const long long _Whole = (_Ctr / _Freq) * period::den; const long long _Part = (_Ctr % _Freq) * period::den / _Freq; return time_point(duration(_Whole + _Part)); } }; using high_resolution_clock = steady_clock; #if _HAS_CXX20 // [time.duration.io] #define _IF_PERIOD_RETURN_SUFFIX_ELSE(_TYPE, _SUFFIX) \ if constexpr (is_same_v<_Period, _TYPE>) { \ if constexpr (is_same_v<_CharT, char>) { \ return _SUFFIX; \ } else { \ return L##_SUFFIX; \ } \ } else template _NODISCARD constexpr const _CharT* _Get_literal_unit_suffix() { _IF_PERIOD_RETURN_SUFFIX_ELSE(atto, "as") _IF_PERIOD_RETURN_SUFFIX_ELSE(femto, "fs") _IF_PERIOD_RETURN_SUFFIX_ELSE(pico, "ps") _IF_PERIOD_RETURN_SUFFIX_ELSE(nano, "ns") _IF_PERIOD_RETURN_SUFFIX_ELSE(micro, "us") _IF_PERIOD_RETURN_SUFFIX_ELSE(milli, "ms") _IF_PERIOD_RETURN_SUFFIX_ELSE(centi, "cs") _IF_PERIOD_RETURN_SUFFIX_ELSE(deci, "ds") _IF_PERIOD_RETURN_SUFFIX_ELSE(seconds::period, "s") _IF_PERIOD_RETURN_SUFFIX_ELSE(deca, "das") _IF_PERIOD_RETURN_SUFFIX_ELSE(hecto, "hs") _IF_PERIOD_RETURN_SUFFIX_ELSE(kilo, "ks") _IF_PERIOD_RETURN_SUFFIX_ELSE(mega, "Ms") _IF_PERIOD_RETURN_SUFFIX_ELSE(giga, "Gs") _IF_PERIOD_RETURN_SUFFIX_ELSE(tera, "Ts") _IF_PERIOD_RETURN_SUFFIX_ELSE(peta, "Ps") _IF_PERIOD_RETURN_SUFFIX_ELSE(exa, "Es") _IF_PERIOD_RETURN_SUFFIX_ELSE(minutes::period, "min") _IF_PERIOD_RETURN_SUFFIX_ELSE(hours::period, "h") _IF_PERIOD_RETURN_SUFFIX_ELSE(ratio<86400>, "d") { return nullptr; } } #undef _IF_PERIOD_RETURN_SUFFIX_ELSE template _NODISCARD _CharT* _Get_general_unit_suffix(_CharT* _Rnext, const intmax_t _Num, const intmax_t _Den) { // Returns the head pointer of the string, built in reverse. _STL_INTERNAL_CHECK(_Num > 0 && _Den > 0); *--_Rnext = '\0'; *--_Rnext = 's'; *--_Rnext = ']'; if (_Den != 1) { _Rnext = _UIntegral_to_buff(_Rnext, static_cast(_Den)); *--_Rnext = '/'; } _Rnext = _UIntegral_to_buff(_Rnext, static_cast(_Num)); *--_Rnext = '['; return _Rnext; } template void _Write_unit_suffix(basic_ostream<_CharT, _Traits>& _Os) { constexpr auto _Suffix = _Get_literal_unit_suffix<_CharT, _Period>(); if constexpr (_Suffix == nullptr) { _CharT _Buffer[2 * (numeric_limits::digits10 + 1) + 5] = {}; // 2 numbers + "[/]s\0" const _CharT* const _Begin = _Get_general_unit_suffix<_CharT>(_STD end(_Buffer), _Period::num, _Period::den); _Os << _Begin; } else { _Os << _Suffix; } } template basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Dur) { basic_ostringstream<_CharT, _Traits> _Sstr; _Sstr.flags(_Os.flags()); _Sstr.imbue(_Os.getloc()); _Sstr.precision(_Os.precision()); _Sstr << _Dur.count(); _Write_unit_suffix<_Period>(_Sstr); return _Os << _Sstr.str(); } struct local_t {}; template using local_time = time_point; using local_seconds = local_time; using local_days = local_time; struct last_spec { explicit last_spec() = default; }; inline constexpr last_spec last{}; class day { public: day() = default; constexpr explicit day(unsigned int _Val) noexcept : _Day{static_cast(_Val)} {} constexpr day& operator++() noexcept { ++_Day; return *this; } constexpr day operator++(int) noexcept { return day{_Day++}; } constexpr day& operator--() noexcept { --_Day; return *this; } constexpr day operator--(int) noexcept { return day{_Day--}; } constexpr day& operator+=(const days& _Days) noexcept { _Day += static_cast(_Days.count()); return *this; } constexpr day& operator-=(const days& _Days) noexcept { _Day -= static_cast(_Days.count()); return *this; } _NODISCARD constexpr explicit operator unsigned int() const noexcept { return _Day; } _NODISCARD constexpr bool ok() const noexcept { return _Day >= 1 && _Day <= 31; } private: unsigned char _Day; }; _NODISCARD constexpr bool operator==(const day& _Left, const day& _Right) noexcept { return static_cast(_Left) == static_cast(_Right); } _NODISCARD constexpr strong_ordering operator<=>(const day& _Left, const day& _Right) noexcept { return static_cast(_Left) <=> static_cast(_Right); } _NODISCARD constexpr day operator+(const day& _Left, const days& _Right) noexcept { return day{static_cast(_Left) + _Right.count()}; } _NODISCARD constexpr day operator+(const days& _Left, const day& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr day operator-(const day& _Left, const days& _Right) noexcept { return day{static_cast(_Left) - _Right.count()}; } _NODISCARD constexpr days operator-(const day& _Left, const day& _Right) noexcept { return days{ static_cast(static_cast(_Left)) - static_cast(static_cast(_Right))}; } class month { public: month() = default; constexpr explicit month(unsigned int _Val) noexcept : _Month{static_cast(_Val)} {} constexpr month& operator++() noexcept { *this += months{1}; return *this; } constexpr month operator++(int) noexcept { month _Temp{*this}; ++*this; return _Temp; } constexpr month& operator--() noexcept { *this -= months{1}; return *this; } constexpr month operator--(int) noexcept { month _Temp{*this}; --*this; return _Temp; } constexpr month& operator+=(const months& _Months) noexcept; constexpr month& operator-=(const months& _Months) noexcept; _NODISCARD constexpr explicit operator unsigned int() const noexcept { return _Month; } _NODISCARD constexpr bool ok() const noexcept { return _Month >= 1 && _Month <= 12; } private: unsigned char _Month; }; _NODISCARD constexpr bool operator==(const month& _Left, const month& _Right) noexcept { return static_cast(_Left) == static_cast(_Right); } _NODISCARD constexpr strong_ordering operator<=>(const month& _Left, const month& _Right) noexcept { return static_cast(_Left) <=> static_cast(_Right); } _NODISCARD constexpr month operator+(const month& _Left, const months& _Right) noexcept { const auto _Mo = static_cast(static_cast(_Left)) + (_Right.count() - 1); const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; return month{static_cast(_Mo - _Div * 12 + 1)}; } _NODISCARD constexpr month operator+(const months& _Left, const month& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr month operator-(const month& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr months operator-(const month& _Left, const month& _Right) noexcept { const auto _Mo = static_cast(_Left) - static_cast(_Right); return months{_Mo <= 11 ? _Mo : _Mo + 12}; } constexpr month& month::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } constexpr month& month::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } class year { public: year() = default; constexpr explicit year(int _Val) noexcept : _Year{static_cast(_Val)} {} constexpr year& operator++() noexcept { ++_Year; return *this; } constexpr year operator++(int) noexcept { return year{_Year++}; } constexpr year& operator--() noexcept { --_Year; return *this; } constexpr year operator--(int) noexcept { return year{_Year--}; } constexpr year& operator+=(const years& _Years) noexcept { #ifdef __EDG__ // TRANSITION, VSO-1271098 _Year = static_cast(_Year + _Years.count()); #else // ^^^ workaround / no workaround vvv _Year += static_cast(_Years.count()); #endif // ^^^ no workaround ^^^ return *this; } constexpr year& operator-=(const years& _Years) noexcept { #ifdef __EDG__ // TRANSITION, VSO-1271098 _Year = static_cast(_Year - _Years.count()); #else // ^^^ workaround / no workaround vvv _Year -= static_cast(_Years.count()); #endif // ^^^ no workaround ^^^ return *this; } _NODISCARD constexpr year operator+() const noexcept { return *this; } _NODISCARD constexpr year operator-() const noexcept { return year{-_Year}; } _NODISCARD constexpr bool is_leap() const noexcept { return _Year % 4 == 0 && (_Year % 100 != 0 || _Year % 400 == 0); } _NODISCARD constexpr explicit operator int() const noexcept { return _Year; } _NODISCARD constexpr bool ok() const noexcept { return _Year_min <= _Year && _Year <= _Year_max; } _NODISCARD static constexpr year(min)() noexcept { return year{_Year_min}; } _NODISCARD static constexpr year(max)() noexcept { return year{_Year_max}; } private: short _Year; static constexpr int _Year_min = -32767; static constexpr int _Year_max = 32767; }; _NODISCARD constexpr bool operator==(const year& _Left, const year& _Right) noexcept { return static_cast(_Left) == static_cast(_Right); } _NODISCARD constexpr strong_ordering operator<=>(const year& _Left, const year& _Right) noexcept { return static_cast(_Left) <=> static_cast(_Right); } _NODISCARD constexpr year operator+(const year& _Left, const years& _Right) noexcept { return year{static_cast(_Left) + _Right.count()}; } _NODISCARD constexpr year operator+(const years& _Left, const year& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year operator-(const year& _Left, const years& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr years operator-(const year& _Left, const year& _Right) noexcept { return years{static_cast(_Left) - static_cast(_Right)}; } class weekday_indexed; class weekday_last; class weekday { public: weekday() = default; constexpr explicit weekday(unsigned int _Val) noexcept : _Weekday{static_cast(_Val == 7 ? 0 : _Val)} {} constexpr weekday(const sys_days& _Sys_day) noexcept : _Weekday{static_cast(_Weekday_from_days(_Sys_day.time_since_epoch().count()))} {} constexpr explicit weekday(const local_days& _Local_day) noexcept : _Weekday{static_cast(_Weekday_from_days(_Local_day.time_since_epoch().count()))} {} constexpr weekday& operator++() noexcept { return *this += days{1}; } constexpr weekday operator++(int) noexcept { weekday _Temp{*this}; ++*this; return _Temp; } constexpr weekday& operator--() noexcept { return *this -= days{1}; } constexpr weekday operator--(int) noexcept { weekday _Temp{*this}; --*this; return _Temp; } constexpr weekday& operator+=(const days& _Days) noexcept; constexpr weekday& operator-=(const days& _Days) noexcept; _NODISCARD constexpr unsigned int c_encoding() const noexcept { return _Weekday; } _NODISCARD constexpr unsigned int iso_encoding() const noexcept { return _Weekday == 0u ? 7u : _Weekday; } _NODISCARD constexpr bool ok() const noexcept { return _Weekday <= 6; } _NODISCARD constexpr weekday_indexed operator[](unsigned int _Index) const noexcept; _NODISCARD constexpr weekday_last operator[](last_spec) const noexcept; private: unsigned char _Weekday; // courtesy of Howard Hinnant // https://howardhinnant.github.io/date_algorithms.html#weekday_from_days _NODISCARD static constexpr unsigned int _Weekday_from_days(int _Tp) noexcept { return static_cast(_Tp >= -4 ? (_Tp + 4) % 7 : (_Tp + 5) % 7 + 6); } }; _NODISCARD constexpr bool operator==(const weekday& _Left, const weekday& _Right) noexcept { return _Left.c_encoding() == _Right.c_encoding(); } _NODISCARD constexpr weekday operator+(const weekday& _Left, const days& _Right) noexcept { const auto _Wd = static_cast(_Left.c_encoding()) + _Right.count(); const auto _Div = (_Wd >= 0 ? _Wd : _Wd - 6) / 7; return weekday{static_cast(_Wd - _Div * 7)}; } _NODISCARD constexpr weekday operator+(const days& _Left, const weekday& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr weekday operator-(const weekday& _Left, const days& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr days operator-(const weekday& _Left, const weekday& _Right) noexcept { const auto _Wd = _Left.c_encoding() - _Right.c_encoding(); const auto _Wk = _Wd <= 6 ? _Wd : _Wd + 7; return days{_Wk}; } constexpr weekday& weekday::operator+=(const days& _Days) noexcept { *this = *this + _Days; return *this; } constexpr weekday& weekday::operator-=(const days& _Days) noexcept { *this = *this - _Days; return *this; } class weekday_indexed { public: weekday_indexed() = default; constexpr weekday_indexed(const weekday& _Wd, unsigned int _Idx) noexcept : _Weekday{_Wd}, _Index{static_cast(_Idx)} {} _NODISCARD constexpr weekday weekday() const noexcept { return _Weekday; } _NODISCARD constexpr unsigned int index() const noexcept { return _Index; } _NODISCARD constexpr bool ok() const noexcept { return _Weekday.ok() && _Index >= 1 && _Index <= 5; } private: _CHRONO weekday _Weekday; unsigned char _Index; }; _NODISCARD constexpr bool operator==(const weekday_indexed& _Left, const weekday_indexed& _Right) noexcept { return _Left.weekday() == _Right.weekday() && _Left.index() == _Right.index(); } class weekday_last { public: constexpr explicit weekday_last(const weekday& _Wd) noexcept : _Weekday{_Wd} {} _NODISCARD constexpr weekday weekday() const noexcept { return _Weekday; } _NODISCARD constexpr bool ok() const noexcept { return _Weekday.ok(); } private: _CHRONO weekday _Weekday; }; _NODISCARD constexpr bool operator==(const weekday_last& _Left, const weekday_last& _Right) noexcept { return _Left.weekday() == _Right.weekday(); } _NODISCARD constexpr weekday_indexed weekday::operator[](unsigned int _Index) const noexcept { return {*this, _Index}; } _NODISCARD constexpr weekday_last weekday::operator[](last_spec) const noexcept { return weekday_last{*this}; } class month_day { public: month_day() = default; constexpr month_day(const month& _Month_, const day& _Day_) noexcept : _Month{_Month_}, _Day{_Day_} {} _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr day day() const noexcept { return _Day; } _NODISCARD constexpr bool ok() const noexcept { if (!_Month.ok() || !_Day.ok()) { return false; } const auto _Da = static_cast(_Day); const auto _Mo = static_cast(_Month); if (_Mo == 2) { return _Da <= 29; } if (_Mo == 4 || _Mo == 6 || _Mo == 9 || _Mo == 11) { return _Da <= 30; } return true; } private: _CHRONO month _Month; _CHRONO day _Day; }; _NODISCARD constexpr bool operator==(const month_day& _Left, const month_day& _Right) noexcept { return _Left.month() == _Right.month() && _Left.day() == _Right.day(); } _NODISCARD constexpr strong_ordering operator<=>(const month_day& _Left, const month_day& _Right) noexcept { const auto _Comp = _Left.month() <=> _Right.month(); if (_Comp != 0) { return _Comp; } return _Left.day() <=> _Right.day(); } class month_day_last { public: constexpr explicit month_day_last(const month& _Month_) noexcept : _Month{_Month_} {} _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr bool ok() const noexcept { return _Month.ok(); } private: _CHRONO month _Month; }; _NODISCARD constexpr bool operator==(const month_day_last& _Left, const month_day_last& _Right) noexcept { return _Left.month() == _Right.month(); } _NODISCARD constexpr strong_ordering operator<=>( const month_day_last& _Left, const month_day_last& _Right) noexcept { return _Left.month() <=> _Right.month(); } class month_weekday { public: constexpr month_weekday(const month& _Month_, const weekday_indexed& _Wdi) noexcept : _Month{_Month_}, _Weekday_index{_Wdi} {} _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { return _Weekday_index; } _NODISCARD constexpr bool ok() const noexcept { return _Month.ok() && _Weekday_index.ok(); } private: _CHRONO month _Month; _CHRONO weekday_indexed _Weekday_index; }; _NODISCARD constexpr bool operator==(const month_weekday& _Left, const month_weekday& _Right) noexcept { return _Left.month() == _Right.month() && _Left.weekday_indexed() == _Right.weekday_indexed(); } class month_weekday_last { public: constexpr month_weekday_last(const month& _Month_, const weekday_last& _Wdl) noexcept : _Month{_Month_}, _Weekday_last{_Wdl} {} _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr weekday_last weekday_last() const noexcept { return _Weekday_last; } _NODISCARD constexpr bool ok() const noexcept { return _Month.ok() && _Weekday_last.ok(); } private: _CHRONO month _Month; _CHRONO weekday_last _Weekday_last; }; _NODISCARD constexpr bool operator==(const month_weekday_last& _Left, const month_weekday_last& _Right) noexcept { return _Left.month() == _Right.month() && _Left.weekday_last() == _Right.weekday_last(); } class year_month { public: year_month() = default; constexpr year_month(const year& _Year_, const month& _Month_) noexcept : _Year{_Year_}, _Month{_Month_} {} _NODISCARD constexpr year year() const noexcept { return _Year; } _NODISCARD constexpr month month() const noexcept { return _Month; } template constexpr year_month& operator+=(const months& _Months) noexcept; template constexpr year_month& operator-=(const months& _Months) noexcept; constexpr year_month& operator+=(const years& _Years) noexcept; constexpr year_month& operator-=(const years& _Years) noexcept; _NODISCARD constexpr bool ok() const noexcept { return _Year.ok() && _Month.ok(); } private: _CHRONO year _Year; _CHRONO month _Month; }; _NODISCARD constexpr bool operator==(const year_month& _Left, const year_month& _Right) noexcept { return _Left.year() == _Right.year() && _Left.month() == _Right.month(); } _NODISCARD constexpr strong_ordering operator<=>(const year_month& _Left, const year_month& _Right) noexcept { const auto _Comp = _Left.year() <=> _Right.year(); if (_Comp != 0) { return _Comp; } return _Left.month() <=> _Right.month(); } template _NODISCARD constexpr year_month operator+(const year_month& _Left, const months& _Right) noexcept { const auto _Mo = static_cast(static_cast(_Left.month())) + (_Right.count() - 1); const auto _Div = (_Mo >= 0 ? _Mo : _Mo - 11) / 12; return year_month{_Left.year() + years{_Div}, month{static_cast(_Mo - _Div * 12 + 1)}}; } template _NODISCARD constexpr year_month operator+(const months& _Left, const year_month& _Right) noexcept { return _Right + _Left; } template _NODISCARD constexpr year_month operator-(const year_month& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr months operator-(const year_month& _Left, const year_month& _Right) noexcept { return _Left.year() - _Right.year() + months{static_cast(static_cast(_Left.month())) - static_cast(static_cast(_Right.month()))}; } _NODISCARD constexpr year_month operator+(const year_month& _Left, const years& _Right) noexcept { return {year{_Left.year() + _Right}, _Left.month()}; } _NODISCARD constexpr year_month operator+(const years& _Left, const year_month& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year_month operator-(const year_month& _Left, const years& _Right) noexcept { return _Left + -_Right; } template constexpr year_month& year_month::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } template constexpr year_month& year_month::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } constexpr year_month& year_month::operator+=(const years& _Years) noexcept { *this = *this + _Years; return *this; } constexpr year_month& year_month::operator-=(const years& _Years) noexcept { *this = *this - _Years; return *this; } // To prevent UB by going out of bounds, four extra days with an invalid day are added. inline constexpr day _Last_day_table[] = {day{31}, day{28}, day{31}, day{30}, day{31}, day{30}, day{31}, day{31}, day{30}, day{31}, day{30}, day{31}, day{255}, day{255}, day{255}, day{255}}; _NODISCARD constexpr day _Last_day(const year& _Year, const month& _Month) { if (_Month == month{2} && _Year.is_leap()) { return day{29}; } return _Last_day_table[(static_cast(_Month) - 1) & 0xF]; } class year_month_day_last; class year_month_day { public: year_month_day() = default; constexpr year_month_day(const year& _Year_, const month& _Month_, const day& _Day_) noexcept : _Year{_Year_}, _Month{_Month_}, _Day{_Day_} {} constexpr year_month_day(const year_month_day_last& _Ymdl) noexcept; constexpr year_month_day(const sys_days& _Sys_days) noexcept : year_month_day{_Civil_from_days(_Sys_days.time_since_epoch().count())} {} constexpr explicit year_month_day(const local_days& _Local_days) noexcept : year_month_day{_Civil_from_days(_Local_days.time_since_epoch().count())} {} template constexpr year_month_day& operator+=(const months& _Months) noexcept; template constexpr year_month_day& operator-=(const months& _Months) noexcept; constexpr year_month_day& operator+=(const years& _Years) noexcept; constexpr year_month_day& operator-=(const years& _Years) noexcept; _NODISCARD constexpr year year() const noexcept { return _Year; } _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr day day() const noexcept { return _Day; } _NODISCARD constexpr operator sys_days() const noexcept { return sys_days{_Days_from_civil()}; } _NODISCARD constexpr explicit operator local_days() const noexcept { return local_days{static_cast(*this).time_since_epoch()}; } _NODISCARD constexpr bool ok() const noexcept { if (!_Year.ok() || !_Month.ok()) { return false; } return _Day >= _CHRONO day{1} && _Day <= _Last_day(_Year, _Month); } _NODISCARD constexpr int _Calculate_weekday() const noexcept { const int _Day_int = static_cast(static_cast(_Day)); const int _Month_int = static_cast(static_cast(_Month)); const int _Era_year = static_cast(_Year) - (_Month_int <= 2); const int _Era = (_Era_year >= 0 ? _Era_year : _Era_year - 399) / 400; const int _Yoe = _Era_year - _Era * 400; const int _Yday_era = ((979 * (_Month_int + (_Month_int > 2 ? -3 : 9)) + 19) >> 5) + _Day_int - 1; const int _Doe = ((1461 * _Yoe) >> 2) - _Yoe / 100 + _Yday_era; return (_Doe + 3) % 7; // the era began on a Wednesday } private: _CHRONO year _Year; _CHRONO month _Month; _CHRONO day _Day; // _Civil_from_days and _Days_from_civil perform conversions between the dates in the (proleptic) Gregorian // calendar and the continuous count of days since 1970-01-01. // To simplify the handling of leap days (February 29th), the algorithm below uses a modified calendar // internally, in which each year begins on March 1st, while January and February belong to the previous year. // We denote the modified year and month number as _Yp and _Mp. We also define modified centuries that begin on // each modified year whose _Yp is a multiple of 100. // _Mp | Month | Day of Year // --- | --------- | ----------- // 0 | March | [ 0, 30] // 1 | April | [ 31, 60] // 2 | May | [ 61, 91] // 3 | June | [ 92, 121] // 4 | July | [122, 152] // 5 | August | [153, 183] // 6 | September | [184, 213] // 7 | October | [214, 244] // 8 | November | [245, 274] // 9 | December | [275, 305] // 10 | January | [306, 336] // 11 | February | [337, 365] on leap years, [337, 364] on regular years // _Yp | First Day | Last Day (inclusive) | Leap Year? // --- | ----------- | -------------------- | ---------- // -4 | -0004-03-01 | -0003-02-28 | No // -3 | -0003-03-01 | -0002-02-28 | No // -2 | -0002-03-01 | -0001-02-28 | No // -1 | -0001-03-01 | 0000-02-29 | Yes // 0 | 0000-03-01 | 0001-02-28 | No // 1 | 0001-03-01 | 0002-02-28 | No // 2 | 0002-03-01 | 0003-02-28 | No // 3 | 0003-03-01 | 0004-02-29 | Yes // _Century | First Day | Last Day (inclusive) | Long Century? // -------- | ----------- | -------------------- | ------------- // -4 | -0400-03-01 | -0300-02-28 | No // -3 | -0300-03-01 | -0200-02-28 | No // -2 | -0200-03-01 | -0100-02-28 | No // -1 | -0100-03-01 | 0000-02-29 | Yes // 0 | 0000-03-01 | 0100-02-28 | No // 1 | 0100-03-01 | 0200-02-28 | No // 2 | 0200-03-01 | 0300-02-28 | No // 3 | 0300-03-01 | 0400-02-29 | Yes // The structure of the modified calendar: // 1 ) It has a period of 4 centuries. // 2 ) Each calendar period (146097 days) contains 3 regular centuries followed by a long century (36525 days). // 3 ) Each regular century (36524 days) contains 24 regular 4-year spans followed by a short 4-year span. // 3') Each long century (36525 days) contains 25 regular 4-year spans. // 4 ) Each regular 4-year span (1461 days) contains 3 regular years followed by a leap year. // 4') Each short 4-year span (1460 days) contains 4 regular years. // Formula 1: Compute _Day_of_year of the first day of month _Mp // // _Day_of_year = (979 * _Mp + 19) >> 5 // // A more well-known formula is 30 * _Mp + floor((3 * _Mp + 2) / 5) or floor((153 * _Mp + 2) / 5), which is used // in Howard Hinnant's paper. // // The formula above returns the same result for all _Mp in [0, 11]. // Note that 979 / 2^5 = 30.59375 ~= 30.6 = 153 / 5. // Formula 1': Compute _Mp from _Day_of_year // // _Mp = (535 * _Day_of_year + 333) >> 14 // // Howard Hinnant's paper uses floor((5 * _Day_of_year + 2) / 153), the inverse of floor((153 * _Mp + 2) / 5) or // ceil((153 * _Mp - 2) / 5). // // The formula above returns the same result for all _Day_of_year in [0, 365]. // Note that 2^14 / 535 = 30.624... ~= 30.6 = 153 / 5. // Formula 2: Compute _Zx of the first day of year _Yp, where _Zx is the continuous count of days since // 0000-03-01. // // _Zx = ((1461 * _Yp) >> 2) - _Century + (_Century >> 2) // // Start with multiplying by the number of days in regular years (365), add one day for the leap year in each // 4-year span, subtract one day for the short 4-year span in each century, and finally add one day for the long // century in each calendar period. This gives us 365 * _Yp + floor(_Yp / 4) - _Century + floor(_Century / 4). // Formula 2-1: Compute _Day_of_century of the first day of year _Year_of_century // // _Day_of_century = (1461 * _Year_of_century) >> 2 // // Start with multiplying by the number of days in regular years (365), add one day for the leap year in each // 4-year span. This gives us 365 * _Year_of_century + floor(_Year_of_century / 4) // == floor(1461 * _Year_of_century / 4). // Formula 2-1': Compute _Year_of_century from _Day_of_century // // _Year_of_century = (91867 * (_Day_of_century + 1)) >> 25 // // The inverse of floor(1461 * _Year_of_century / 4) or ceil((1461 * _Year_of_century - 3) / 4) is // floor((4 * _Day_of_century + 3) / 1461). // // The formula above returns the same result for all _Day_of_century in [0, 36524]. // Note that 2^25 / 91867 = 365.2501... ~= 365.25 = 1461 / 4. // Formula 2-2: Compute _Zx of the first day of century _Century, where _Zx is the continuous count of days // since 0000-03-01. // // _Zx = (146097 * _Century) >> 2 // // Start with multiplying by the number of days in regular centuries (36524), add one day for the long century // in each calendar period. This gives us 36524 * _Century + floor(_Century / 4) = floor(146097 * _Century / 4). // Formula 2-2': Compute _Century from _Zx, where _Zx is the continuous count of days since 0000-03-01. // // _Century = floor((4 * _Zx + 3) / 146097) // // This is the inverse of floor(146097 * _Year_of_century / 4) or ceil((146097 * _Year_of_century - 3) / 4) // courtesy of Howard Hinnant // https://howardhinnant.github.io/date_algorithms.html#civil_from_days _NODISCARD static constexpr year_month_day _Civil_from_days(int _Tp) noexcept { static_assert(numeric_limits::digits >= 32); static_assert(numeric_limits::digits >= 26); const int _Zx = _Tp + 719468; // Shift epoch to 0000-03-01 // Formula 2-2' const int _Century = (_Zx >= 0 ? 4 * _Zx + 3 : 4 * _Zx - 146093) / 146097; // Formula 2-2 const unsigned int _Day_of_century = static_cast(_Zx - ((146097 * _Century) >> 2)); // [0, 36524] // Formula 2-1' const unsigned int _Year_of_century = (91867 * (_Day_of_century + 1)) >> 25; // [0, 99] const int _Yp = static_cast(_Year_of_century) + _Century * 100; // Where March is the first month // Formula 2-1 const unsigned int _Day_of_year = _Day_of_century - ((1461 * _Year_of_century) >> 2); // [0, 365] // Formula 1' const unsigned int _Mp = (535 * _Day_of_year + 333) >> 14; // [0, 11] // Formula 1 const unsigned int _Day = _Day_of_year - ((979 * _Mp + 19) >> 5) + 1; // [1, 31] const unsigned int _Month = _Mp + (_Mp < 10 ? 3 : static_cast(-9)); // [1, 12] return year_month_day{_CHRONO year{_Yp + (_Month <= 2)}, _CHRONO month{_Month}, _CHRONO day{_Day}}; } // courtesy of Howard Hinnant // https://howardhinnant.github.io/date_algorithms.html#days_from_civil _NODISCARD constexpr days _Days_from_civil() const noexcept { static_assert(numeric_limits::digits >= 18); static_assert(numeric_limits::digits >= 26); const unsigned int _Mo = static_cast(_Month); // [1, 12] const int _Yp = static_cast(_Year) - (_Mo <= 2); const int _Century = (_Yp >= 0 ? _Yp : _Yp - 99) / 100; const unsigned int _Mp = _Mo + (_Mo > 2 ? static_cast(-3) : 9); // [0, 11] // Formula 1 const int _Day_of_year = static_cast(((979 * _Mp + 19) >> 5) + static_cast(_Day)) - 1; // Formula 2 return days{((1461 * _Yp) >> 2) - _Century + (_Century >> 2) + _Day_of_year - 719468}; } }; _NODISCARD constexpr bool operator==(const year_month_day& _Left, const year_month_day& _Right) noexcept { return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.day() == _Right.day(); } _NODISCARD constexpr strong_ordering operator<=>( const year_month_day& _Left, const year_month_day& _Right) noexcept { auto _Comp = _Left.year() <=> _Right.year(); if (_Comp != 0) { return _Comp; } _Comp = _Left.month() <=> _Right.month(); if (_Comp != 0) { return _Comp; } return _Left.day() <=> _Right.day(); } template _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const months& _Right) noexcept { const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; return {_Ym.year(), _Ym.month(), _Left.day()}; } template _NODISCARD constexpr year_month_day operator+(const months& _Left, const year_month_day& _Right) noexcept { return _Right + _Left; } template _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr year_month_day operator+(const year_month_day& _Left, const years& _Right) noexcept { return {_Left.year() + _Right, _Left.month(), _Left.day()}; } _NODISCARD constexpr year_month_day operator+(const years& _Left, const year_month_day& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year_month_day operator-(const year_month_day& _Left, const years& _Right) noexcept { return _Left + -_Right; } template constexpr year_month_day& year_month_day::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } template constexpr year_month_day& year_month_day::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } constexpr year_month_day& year_month_day::operator+=(const years& _Years) noexcept { *this = *this + _Years; return *this; } constexpr year_month_day& year_month_day::operator-=(const years& _Years) noexcept { *this = *this - _Years; return *this; } class year_month_day_last { public: constexpr year_month_day_last(const year& _Year_, const month_day_last& _Mdl) noexcept : _Year{_Year_}, _Month_day_last{_Mdl} {} template constexpr year_month_day_last& operator+=(const months& _Months) noexcept; template constexpr year_month_day_last& operator-=(const months& _Months) noexcept; constexpr year_month_day_last& operator+=(const years& _Years) noexcept; constexpr year_month_day_last& operator-=(const years& _Years) noexcept; _NODISCARD constexpr year year() const noexcept { return _Year; } _NODISCARD constexpr month month() const noexcept { return _Month_day_last.month(); } _NODISCARD constexpr month_day_last month_day_last() const noexcept { return _Month_day_last; } _NODISCARD constexpr day day() const noexcept { return _Last_day(year(), month()); } _NODISCARD constexpr operator sys_days() const noexcept { return sys_days{year_month_day{year(), month(), day()}}; } _NODISCARD constexpr explicit operator local_days() const noexcept { return local_days{static_cast(*this).time_since_epoch()}; } _NODISCARD constexpr bool ok() const noexcept { return _Year.ok() && _Month_day_last.ok(); } private: _CHRONO year _Year; _CHRONO month_day_last _Month_day_last; }; _NODISCARD constexpr bool operator==(const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { return _Left.year() == _Right.year() && _Left.month_day_last() == _Right.month_day_last(); } _NODISCARD constexpr strong_ordering operator<=>( const year_month_day_last& _Left, const year_month_day_last& _Right) noexcept { const auto _Comp = _Left.year() <=> _Right.year(); if (_Comp != 0) { return _Comp; } return _Left.month_day_last() <=> _Right.month_day_last(); } template _NODISCARD constexpr year_month_day_last operator+( const year_month_day_last& _Left, const months& _Right) noexcept { const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; return {_Ym.year(), month_day_last{_Ym.month()}}; } template _NODISCARD constexpr year_month_day_last operator+( const months& _Left, const year_month_day_last& _Right) noexcept { return _Right + _Left; } template _NODISCARD constexpr year_month_day_last operator-( const year_month_day_last& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr year_month_day_last operator+(const year_month_day_last& _Left, const years& _Right) noexcept { return {_Left.year() + _Right, _Left.month_day_last()}; } _NODISCARD constexpr year_month_day_last operator+(const years& _Left, const year_month_day_last& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year_month_day_last operator-(const year_month_day_last& _Left, const years& _Right) noexcept { return _Left + -_Right; } template constexpr year_month_day_last& year_month_day_last::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } template constexpr year_month_day_last& year_month_day_last::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } constexpr year_month_day_last& year_month_day_last::operator+=(const years& _Years) noexcept { *this = *this + _Years; return *this; } constexpr year_month_day_last& year_month_day_last::operator-=(const years& _Years) noexcept { *this = *this - _Years; return *this; } constexpr year_month_day::year_month_day(const year_month_day_last& _Ymdl) noexcept : _Year{_Ymdl.year()}, _Month{_Ymdl.month()}, _Day{_Ymdl.day()} {} class year_month_weekday { public: year_month_weekday() = default; constexpr year_month_weekday(const year& _Year_, const month& _Month_, const weekday_indexed& _Wdi) noexcept : _Year{_Year_}, _Month{_Month_}, _Weekday_index{_Wdi} {} constexpr year_month_weekday(const sys_days& _Sys_days) noexcept : year_month_weekday{_Ymwd_from_days(_Sys_days.time_since_epoch())} {} constexpr explicit year_month_weekday(const local_days& _Local_days) noexcept : year_month_weekday{_Ymwd_from_days(_Local_days.time_since_epoch())} {} template constexpr year_month_weekday& operator+=(const months& _Months) noexcept; template constexpr year_month_weekday& operator-=(const months& _Months) noexcept; constexpr year_month_weekday& operator+=(const years& _Years) noexcept; constexpr year_month_weekday& operator-=(const years& _Years) noexcept; _NODISCARD constexpr year year() const noexcept { return _Year; } _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr weekday weekday() const noexcept { return _Weekday_index.weekday(); } _NODISCARD constexpr unsigned int index() const noexcept { return _Weekday_index.index(); } _NODISCARD constexpr weekday_indexed weekday_indexed() const noexcept { return _Weekday_index; } _NODISCARD constexpr operator sys_days() const noexcept { const sys_days _First = year_month_day{_Year, _Month, day{1}}; const days _Diff = weekday() - _CHRONO weekday{_First}; const days _Days = _Diff + days{(static_cast(index()) - 1) * 7}; return _First + _Days; } _NODISCARD constexpr explicit operator local_days() const noexcept { return local_days{static_cast(*this).time_since_epoch()}; } _NODISCARD constexpr bool ok() const noexcept { if (!_Year.ok() || !_Month.ok() || !_Weekday_index.ok()) { return false; } if (_Weekday_index.index() <= 4) { return true; } // As index() == 5 is not always valid // Determine the date of the first weekday and check if + days{28} is <= last day of the month const sys_days _First_of_month = year_month_day{_Year, _Month, day{1}}; const days _First_weekday = weekday() - _CHRONO weekday{_First_of_month} + days{1}; const days _Last = _First_weekday + days{28}; return static_cast(_Last.count()) <= static_cast(_Last_day(_Year, _Month)); } private: _CHRONO year _Year; _CHRONO month _Month; _CHRONO weekday_indexed _Weekday_index; _NODISCARD static constexpr year_month_weekday _Ymwd_from_days(days _Dp) noexcept { const _CHRONO year_month_day _Ymd = sys_days{_Dp}; const _CHRONO weekday _Wd = sys_days{_Dp}; const auto _Idx = ((static_cast(_Ymd.day()) - 1) / 7) + 1; return {_Ymd.year(), _Ymd.month(), _Wd[_Idx]}; } }; _NODISCARD constexpr bool operator==(const year_month_weekday& _Left, const year_month_weekday& _Right) noexcept { return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.weekday_indexed() == _Right.weekday_indexed(); } template _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const months& _Right) noexcept { const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; return {_Ym.year(), _Ym.month(), _Left.weekday_indexed()}; } template _NODISCARD constexpr year_month_weekday operator+(const months& _Left, const year_month_weekday& _Right) noexcept { return _Right + _Left; } template _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr year_month_weekday operator+(const year_month_weekday& _Left, const years& _Right) noexcept { return year_month_weekday{_Left.year() + _Right, _Left.month(), _Left.weekday_indexed()}; } _NODISCARD constexpr year_month_weekday operator+(const years& _Left, const year_month_weekday& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year_month_weekday operator-(const year_month_weekday& _Left, const years& _Right) noexcept { return _Left + -_Right; } template constexpr year_month_weekday& year_month_weekday::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } template constexpr year_month_weekday& year_month_weekday::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } constexpr year_month_weekday& year_month_weekday::operator+=(const years& _Years) noexcept { *this = *this + _Years; return *this; } constexpr year_month_weekday& year_month_weekday::operator-=(const years& _Years) noexcept { *this = *this - _Years; return *this; } class year_month_weekday_last { public: constexpr year_month_weekday_last(const year& _Year_, const month& _Month_, const weekday_last& _Wdl) noexcept : _Year{_Year_}, _Month{_Month_}, _Weekday_last{_Wdl} {} template constexpr year_month_weekday_last& operator+=(const months& _Months) noexcept; template constexpr year_month_weekday_last& operator-=(const months& _Months) noexcept; constexpr year_month_weekday_last& operator+=(const years& _Years) noexcept; constexpr year_month_weekday_last& operator-=(const years& _Years) noexcept; _NODISCARD constexpr year year() const noexcept { return _Year; } _NODISCARD constexpr month month() const noexcept { return _Month; } _NODISCARD constexpr weekday weekday() const noexcept { return _Weekday_last.weekday(); } _NODISCARD constexpr weekday_last weekday_last() const noexcept { return _Weekday_last; } _NODISCARD constexpr operator sys_days() const noexcept { const sys_days _Last = year_month_day_last{_Year, month_day_last{_Month}}; const auto _Diff = _CHRONO weekday{_Last} - weekday(); return _Last - _Diff; } _NODISCARD constexpr explicit operator local_days() const noexcept { return local_days{static_cast(*this).time_since_epoch()}; } _NODISCARD constexpr bool ok() const noexcept { return _Year.ok() && _Month.ok() && _Weekday_last.ok(); } private: _CHRONO year _Year; _CHRONO month _Month; _CHRONO weekday_last _Weekday_last; }; _NODISCARD constexpr bool operator==( const year_month_weekday_last& _Left, const year_month_weekday_last& _Right) noexcept { return _Left.year() == _Right.year() && _Left.month() == _Right.month() && _Left.weekday_last() == _Right.weekday_last(); } template _NODISCARD constexpr year_month_weekday_last operator+( const year_month_weekday_last& _Left, const months& _Right) noexcept { const auto _Ym = year_month{_Left.year(), _Left.month()} + _Right; return {_Ym.year(), _Ym.month(), _Left.weekday_last()}; } template _NODISCARD constexpr year_month_weekday_last operator+( const months& _Left, const year_month_weekday_last& _Right) noexcept { return _Right + _Left; } template _NODISCARD constexpr year_month_weekday_last operator-( const year_month_weekday_last& _Left, const months& _Right) noexcept { return _Left + -_Right; } _NODISCARD constexpr year_month_weekday_last operator+( const year_month_weekday_last& _Left, const years& _Right) noexcept { return {_Left.year() + _Right, _Left.month(), _Left.weekday_last()}; } _NODISCARD constexpr year_month_weekday_last operator+( const years& _Left, const year_month_weekday_last& _Right) noexcept { return _Right + _Left; } _NODISCARD constexpr year_month_weekday_last operator-( const year_month_weekday_last& _Left, const years& _Right) noexcept { return _Left + -_Right; } template constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const months& _Months) noexcept { *this = *this + _Months; return *this; } template constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const months& _Months) noexcept { *this = *this - _Months; return *this; } constexpr year_month_weekday_last& year_month_weekday_last::operator+=(const years& _Years) noexcept { *this = *this + _Years; return *this; } constexpr year_month_weekday_last& year_month_weekday_last::operator-=(const years& _Years) noexcept { *this = *this - _Years; return *this; } // Civil calendar conventional syntax operators _NODISCARD constexpr year_month operator/(const year& _Year, const month& _Month) noexcept { return {_Year, _Month}; } _NODISCARD constexpr year_month operator/(const year& _Year, int _Month) noexcept { return _Year / month{static_cast(_Month)}; } _NODISCARD constexpr month_day operator/(const month& _Month, const day& _Day) noexcept { return {_Month, _Day}; } _NODISCARD constexpr month_day operator/(const month& _Month, int _Day) noexcept { return _Month / day{static_cast(_Day)}; } _NODISCARD constexpr month_day operator/(int _Month, const day& _Day) noexcept { return month{static_cast(_Month)} / _Day; } _NODISCARD constexpr month_day operator/(const day& _Day, const month& _Month) noexcept { return _Month / _Day; } _NODISCARD constexpr month_day operator/(const day& _Day, int _Month) noexcept { return month{static_cast(_Month)} / _Day; } _NODISCARD constexpr month_day_last operator/(const month& _Month, last_spec) noexcept { return month_day_last{_Month}; } _NODISCARD constexpr month_day_last operator/(int _Month, last_spec) noexcept { return month{static_cast(_Month)} / last; } _NODISCARD constexpr month_day_last operator/(last_spec, const month& _Month) noexcept { return _Month / last; } _NODISCARD constexpr month_day_last operator/(last_spec, int _Month) noexcept { return month{static_cast(_Month)} / last; } _NODISCARD constexpr month_weekday operator/(const month& _Month, const weekday_indexed& _Wdi) noexcept { return {_Month, _Wdi}; } _NODISCARD constexpr month_weekday operator/(int _Month, const weekday_indexed& _Wdi) noexcept { return month{static_cast(_Month)} / _Wdi; } _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, const month& _Month) noexcept { return _Month / _Wdi; } _NODISCARD constexpr month_weekday operator/(const weekday_indexed& _Wdi, int _Month) noexcept { return month{static_cast(_Month)} / _Wdi; } _NODISCARD constexpr month_weekday_last operator/(const month& _Month, const weekday_last& _Wdl) noexcept { return {_Month, _Wdl}; } _NODISCARD constexpr month_weekday_last operator/(int _Month, const weekday_last& _Wdl) noexcept { return month{static_cast(_Month)} / _Wdl; } _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, const month& _Month) noexcept { return _Month / _Wdl; } _NODISCARD constexpr month_weekday_last operator/(const weekday_last& _Wdl, int _Month) noexcept { return month{static_cast(_Month)} / _Wdl; } _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, const day& _Day) noexcept { return {_Ym.year(), _Ym.month(), _Day}; } _NODISCARD constexpr year_month_day operator/(const year_month& _Ym, int _Day) noexcept { return _Ym / day{static_cast(_Day)}; } _NODISCARD constexpr year_month_day operator/(const year& _Year, const month_day& _Md) noexcept { return _Year / _Md.month() / _Md.day(); } _NODISCARD constexpr year_month_day operator/(int _Year, const month_day& _Md) noexcept { return year{_Year} / _Md.month() / _Md.day(); } _NODISCARD constexpr year_month_day operator/(const month_day& _Md, const year& _Year) noexcept { return _Year / _Md.month() / _Md.day(); } _NODISCARD constexpr year_month_day operator/(const month_day& _Md, int _Year) noexcept { return year{_Year} / _Md.month() / _Md.day(); } _NODISCARD constexpr year_month_day_last operator/(const year_month& _Ym, last_spec) noexcept { return {_Ym.year(), month_day_last{_Ym.month()}}; } _NODISCARD constexpr year_month_day_last operator/(const year& _Year, const month_day_last& _Mdl) noexcept { return {_Year, _Mdl}; } _NODISCARD constexpr year_month_day_last operator/(int _Year, const month_day_last& _Mdl) noexcept { return year{_Year} / _Mdl; } _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, const year& _Year) noexcept { return _Year / _Mdl; } _NODISCARD constexpr year_month_day_last operator/(const month_day_last& _Mdl, int _Year) noexcept { return year{_Year} / _Mdl; } _NODISCARD constexpr year_month_weekday operator/(const year_month& _Ym, const weekday_indexed& _Wdi) noexcept { return year_month_weekday{_Ym.year(), _Ym.month(), _Wdi}; } _NODISCARD constexpr year_month_weekday operator/(const year& _Year, const month_weekday& _Mwd) noexcept { return year_month_weekday{_Year, _Mwd.month(), _Mwd.weekday_indexed()}; } _NODISCARD constexpr year_month_weekday operator/(int _Year, const month_weekday& _Mwd) noexcept { return year{_Year} / _Mwd; } _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, const year& _Year) noexcept { return _Year / _Mwd; } _NODISCARD constexpr year_month_weekday operator/(const month_weekday& _Mwd, int _Year) noexcept { return year{_Year} / _Mwd; } _NODISCARD constexpr year_month_weekday_last operator/(const year_month& _Ym, const weekday_last& _Wdl) noexcept { return {_Ym.year(), _Ym.month(), _Wdl}; } _NODISCARD constexpr year_month_weekday_last operator/( const year& _Year, const month_weekday_last& _Mwdl) noexcept { return {_Year, _Mwdl.month(), _Mwdl.weekday_last()}; } _NODISCARD constexpr year_month_weekday_last operator/(int _Year, const month_weekday_last& _Mwdl) noexcept { return year{_Year} / _Mwdl; } _NODISCARD constexpr year_month_weekday_last operator/( const month_weekday_last& _Mwdl, const year& _Year) noexcept { return _Year / _Mwdl; } _NODISCARD constexpr year_month_weekday_last operator/(const month_weekday_last& _Mwdl, int _Year) noexcept { return year{_Year} / _Mwdl; } // Calendrical constants inline constexpr weekday Sunday{0}; inline constexpr weekday Monday{1}; inline constexpr weekday Tuesday{2}; inline constexpr weekday Wednesday{3}; inline constexpr weekday Thursday{4}; inline constexpr weekday Friday{5}; inline constexpr weekday Saturday{6}; inline constexpr month January{1}; inline constexpr month February{2}; inline constexpr month March{3}; inline constexpr month April{4}; inline constexpr month May{5}; inline constexpr month June{6}; inline constexpr month July{7}; inline constexpr month August{8}; inline constexpr month September{9}; inline constexpr month October{10}; inline constexpr month November{11}; inline constexpr month December{12}; _NODISCARD constexpr intmax_t _Pow10(const unsigned int _Exp) { intmax_t _Result = 1; for (unsigned int _Ix = 0; _Ix < _Exp; ++_Ix) { _Result *= 10; } return _Result; } template class hh_mm_ss { public: static_assert(_Is_duration_v<_Duration>, "N4885 [time.hms.overview]/2 mandates Duration to be a specialization of chrono::duration."); static constexpr unsigned int fractional_width = [] { auto _Num = _Duration::period::num; constexpr auto _Den = _Duration::period::den; // Returns the number of fractional digits of _Num / _Den in the range [0, 18]. // If it can't be represented, 6 is returned. // Example: _Fractional_width(1, 8) would return 3 for 0.125. _STL_ASSERT(_Num > 0 && _Den > 0, "Numerator and denominator can't be less than 1."); unsigned int _Result = 0; for (; _Num % _Den != 0 && _Result < 19; _Num = _Num % _Den * 10, ++_Result) { } return _Result == 19 ? 6 : _Result; }(); using precision = duration, ratio<1, _Pow10(fractional_width)>>; constexpr hh_mm_ss() noexcept : hh_mm_ss{_Duration::zero()} {} // clang-format off constexpr explicit hh_mm_ss(_Duration _Dur) : _Is_neg{_Dur < _Duration::zero()}, _Hours{_CHRONO duration_cast<_CHRONO hours>(_CHRONO abs(_Dur))}, _Mins{_CHRONO duration_cast<_CHRONO minutes>(_CHRONO abs(_Dur) - hours())}, _Secs{_CHRONO duration_cast<_CHRONO seconds>(_CHRONO abs(_Dur) - hours() - minutes())} { // clang-format on if constexpr (treat_as_floating_point_v) { _Sub_secs = _CHRONO abs(_Dur) - hours() - minutes() - seconds(); } else { _Sub_secs = _CHRONO duration_cast(_CHRONO abs(_Dur) - hours() - minutes() - seconds()); } } _NODISCARD constexpr bool is_negative() const noexcept { return _Is_neg; } _NODISCARD constexpr hours hours() const noexcept { return _Hours; } _NODISCARD constexpr minutes minutes() const noexcept { return _Mins; } _NODISCARD constexpr seconds seconds() const noexcept { return _Secs; } _NODISCARD constexpr precision subseconds() const noexcept { return _Sub_secs; } _NODISCARD constexpr explicit operator precision() const noexcept { return to_duration(); } _NODISCARD constexpr precision to_duration() const noexcept { const auto _Dur = _Hours + _Mins + _Secs + _Sub_secs; return _Is_neg ? -_Dur : _Dur; } private: bool _Is_neg; _CHRONO hours _Hours; _CHRONO minutes _Mins; _CHRONO seconds _Secs; precision _Sub_secs; }; _NODISCARD constexpr bool is_am(const hours& _Hours) noexcept { return _Hours >= hours{0} && _Hours <= hours{11}; } _NODISCARD constexpr bool is_pm(const hours& _Hours) noexcept { return _Hours >= hours{12} && _Hours <= hours{23}; } _NODISCARD constexpr hours make12(const hours& _Hours) noexcept { const auto _H_count{_Hours.count()}; auto _Ret{_H_count == 0 ? 12 : _H_count}; if (_Ret > 12) { _Ret -= 12; } return hours{_Ret}; } _NODISCARD constexpr hours make24(const hours& _Hours, bool _Is_pm) noexcept { const auto _H_count{_Hours.count()}; auto _Ret{_H_count == 12 ? 0 : _H_count}; if (_Is_pm) { _Ret += 12; } return hours{_Ret}; } // [time.zone.info] struct sys_info { sys_seconds begin; sys_seconds end; seconds offset; minutes save; string abbrev; }; struct local_info { static constexpr int unique = 0; static constexpr int nonexistent = 1; static constexpr int ambiguous = 2; int result; sys_info first; sys_info second; }; class nonexistent_local_time : public runtime_error { public: template nonexistent_local_time(const local_time<_Duration>& _Tp, const local_info& _Info) : runtime_error(_Make_string(_Tp, _Info)) {} private: #ifdef __cpp_lib_format template _NODISCARD static string _Make_string(const local_time<_Duration>& _Tp, const local_info& _Info); #else // ^^^ no workaround / workaround vvv template _NODISCARD static string _Make_string(const local_time<_Duration>&, const local_info&) { return "nonexistent_local_time"; } #endif // ^^^ workaround ^^^ }; class ambiguous_local_time : public runtime_error { public: template ambiguous_local_time(const local_time<_Duration>& _Tp, const local_info& _Info) : runtime_error(_Make_string(_Tp, _Info)) {} private: #ifdef __cpp_lib_format template _NODISCARD static string _Make_string(const local_time<_Duration>& _Tp, const local_info& _Info); #else // ^^^ no workaround / workaround vvv template _NODISCARD static string _Make_string(const local_time<_Duration>&, const local_info&) { return "ambiguous_local_time"; } #endif // ^^^ workaround ^^^ }; // [time.zone.timezone] enum class choose { earliest, latest }; class time_zone { public: explicit time_zone(string_view _Name_) : _Name(_Name_) {} time_zone(time_zone&&) = default; time_zone& operator=(time_zone&&) = default; _NODISCARD string_view name() const noexcept { return _Name; } template _NODISCARD sys_info get_info(const sys_time<_Duration>& _Sys) const { return _Get_info(_Sys.time_since_epoch()); } template _NODISCARD local_info get_info(const local_time<_Duration>& _Local) const { local_info _Info{}; const auto _Time_since_ep = _Local.time_since_epoch(); _Info.first = _Get_info(_Time_since_ep); const sys_seconds _Local_sys{_CHRONO duration_cast(_Time_since_ep)}; const auto _Curr_sys = _Local_sys - _Info.first.offset; if (_Info.first.begin != _Min_seconds && _Curr_sys < _Info.first.begin + days{1}) { // get previous transition information _Info.second = get_info(_Info.first.begin - seconds{1}); const auto _Transition = _Info.first.begin; const auto _Prev_sys = _Local_sys - _Info.second.offset; if (_Curr_sys >= _Transition) { if (_Prev_sys < _Transition) { _Info.result = local_info::ambiguous; _STD swap(_Info.first, _Info.second); } else { _Info.result = local_info::unique; _Info.second = {}; } } else { if (_Prev_sys >= _Transition) { _Info.result = local_info::nonexistent; _STD swap(_Info.first, _Info.second); } else { _Info.result = local_info::unique; _Info.first = _STD move(_Info.second); _Info.second = {}; } } } else if (_Info.first.end != _Max_seconds && _Curr_sys > _Info.first.end - days{1}) { // get next transition information _Info.second = get_info(_Info.first.end + seconds{1}); const auto _Transition = _Info.first.end; const auto _Next_sys = _Local_sys - _Info.second.offset; if (_Curr_sys < _Transition) { if (_Next_sys >= _Transition) { _Info.result = local_info::ambiguous; } else { _Info.result = local_info::unique; _Info.second = {}; } } else { if (_Next_sys < _Transition) { _Info.result = local_info::nonexistent; } else { _Info.result = local_info::unique; _Info.first = _STD move(_Info.second); _Info.second = {}; } } } else { // local time is contained inside of first transition boundaries by at least 1 day _Info.result = local_info::unique; _Info.second = {}; } return _Info; } template _NODISCARD sys_time> to_sys(const local_time<_Duration>& _Local) const { const auto _Info = get_info(_Local); if (_Info.result == local_info::nonexistent) { _THROW(nonexistent_local_time(_Local, _Info)); } else if (_Info.result == local_info::ambiguous) { _THROW(ambiguous_local_time(_Local, _Info)); } return sys_time>{_Local.time_since_epoch() - _Info.first.offset}; } template _NODISCARD sys_time> to_sys( const local_time<_Duration>& _Local, const choose _Choose) const { const auto _Info = get_info(_Local); if (_Info.result == local_info::nonexistent) { return _Info.first.end; } const auto _Offset = (_Info.result == local_info::unique || _Choose == choose::earliest) ? _Info.first.offset : _Info.second.offset; return sys_time>{_Local.time_since_epoch() - _Offset}; } template _NODISCARD local_time> to_local(const sys_time<_Duration>& _Sys) const { const auto _Info = get_info(_Sys); return local_time>{_Sys.time_since_epoch() + _Info.offset}; } static constexpr sys_seconds _Min_seconds{sys_days{(year::min) () / January / 1}}; static constexpr sys_seconds _Max_seconds{sys_seconds{sys_days{(year::max) () / December / 32}} - seconds{1}}; private: template _NODISCARD sys_info _Get_info(const _Duration& _Dur) const { using _Internal_duration = duration<__std_tzdb_epoch_milli, milli>; const auto _Internal_dur = _CHRONO duration_cast<_Internal_duration>(_Dur); const unique_ptr<__std_tzdb_sys_info, _Tzdb_deleter<__std_tzdb_sys_info>> _Info{ __std_tzdb_get_sys_info(_Name.c_str(), _Name.length(), _Internal_dur.count())}; if (_Info == nullptr) { _Xbad_alloc(); } else if (_Info->_Err == __std_tzdb_error::_Win_error) { _XGetLastError(); } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { _Xruntime_error("Internal error loading IANA database information"); } constexpr auto _Min_internal = _CHRONO duration_cast<_Internal_duration>(_Min_seconds.time_since_epoch()).count(); constexpr auto _Max_internal = _CHRONO duration_cast<_Internal_duration>(_Max_seconds.time_since_epoch()).count(); const auto _Begin = _Info->_Begin <= _Min_internal ? _Min_seconds : sys_seconds{_CHRONO duration_cast(_Internal_duration{_Info->_Begin})}; const auto _End = _Info->_End >= _Max_internal ? _Max_seconds : sys_seconds{_CHRONO duration_cast(_Internal_duration{_Info->_End})}; return {.begin = _Begin, .end = _End, .offset = _CHRONO duration_cast(_Internal_duration{_Info->_Offset}), .save = _CHRONO duration_cast(_Internal_duration{_Info->_Save}), .abbrev = _Info->_Abbrev}; } string _Name; }; _NODISCARD inline bool operator==(const time_zone& _Left, const time_zone& _Right) noexcept { return _Left.name() == _Right.name(); } #ifdef __cpp_lib_concepts _NODISCARD inline strong_ordering operator<=>(const time_zone& _Left, const time_zone& _Right) noexcept { return _Left.name() <=> _Right.name(); } #endif // __cpp_lib_concepts // [time.zone.leap] class leap_second { public: leap_second(const leap_second&) = default; leap_second& operator=(const leap_second&) = default; constexpr leap_second( const sys_seconds& _Date_, const bool _Is_positive_, const seconds& _Prev_elapsed) noexcept : _Date{_Date_}, _Is_positive{_Is_positive_} { _Elapsed_offset = _Prev_elapsed + value(); } _NODISCARD constexpr sys_seconds date() const noexcept { return _Date; } _NODISCARD constexpr seconds value() const noexcept { return _Is_positive ? seconds{1} : seconds{-1}; } _NODISCARD constexpr bool _Positive() const noexcept { return _Is_positive; } _NODISCARD constexpr seconds _Elapsed() const noexcept { return _Elapsed_offset; } private: sys_seconds _Date; bool _Is_positive; seconds _Elapsed_offset; }; _NODISCARD constexpr bool operator==(const leap_second& _Left, const leap_second& _Right) noexcept { return _Left.date() == _Right.date(); } template _NODISCARD constexpr bool operator==(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { return _Left.date() == _Right; } template _NODISCARD constexpr bool operator<(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { return _Left.date() < _Right; } template _NODISCARD constexpr bool operator<(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { return _Left < _Right.date(); } template _NODISCARD constexpr bool operator>(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { return _Right < _Left.date(); } template _NODISCARD constexpr bool operator>(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { return _Right.date() < _Left; } template _NODISCARD constexpr bool operator<=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { return !(_Right < _Left.date()); } template _NODISCARD constexpr bool operator<=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { return !(_Right.date() < _Left); } template _NODISCARD constexpr bool operator>=(const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { return !(_Left.date() < _Right); } template _NODISCARD constexpr bool operator>=(const sys_time<_Duration>& _Left, const leap_second& _Right) noexcept { return !(_Left < _Right.date()); } #ifdef __cpp_lib_concepts // clang-format off template requires three_way_comparable_with> _NODISCARD constexpr auto operator<=>( const leap_second& _Left, const sys_time<_Duration>& _Right) noexcept { // clang-format on return _Left.date() <=> _Right; } _NODISCARD constexpr strong_ordering operator<=>(const leap_second& _Left, const leap_second& _Right) noexcept { return _Left.date() <=> _Right.date(); } #endif // __cpp_lib_concepts // [time.zone.link] class time_zone_link { public: explicit time_zone_link(string_view _Name_, string_view _Target_) : _Name(_Name_), _Target(_Target_) {} time_zone_link(time_zone_link&&) = default; time_zone_link& operator=(time_zone_link&&) = default; _NODISCARD string_view name() const noexcept { return _Name; } _NODISCARD string_view target() const noexcept { return _Target; } private: string _Name; string _Target; }; _NODISCARD inline bool operator==(const time_zone_link& _Left, const time_zone_link& _Right) noexcept { return _Left.name() == _Right.name(); } #ifdef __cpp_lib_concepts _NODISCARD inline strong_ordering operator<=>(const time_zone_link& _Left, const time_zone_link& _Right) noexcept { return _Left.name() <=> _Right.name(); } #endif // __cpp_lib_concepts // [time.zone.db] _NODISCARD inline string _Tzdb_generate_current_zone() { unique_ptr<__std_tzdb_current_zone_info, _Tzdb_deleter<__std_tzdb_current_zone_info>> _Info{ __std_tzdb_get_current_zone()}; if (_Info == nullptr) { _Xbad_alloc(); } else if (_Info->_Err == __std_tzdb_error::_Win_error) { _XGetLastError(); } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { _Xruntime_error("Internal error loading IANA database information"); } return {_Info->_Tz_name}; } template _NODISCARD const _Ty* _Locate_zone_impl(const vector<_Ty>& _Vec, string_view _Name) { const auto _Result = _STD find_if(_Vec.begin(), _Vec.end(), [&](auto& _Tz) { return _Tz.name() == _Name; }); return _Result == _Vec.end() ? nullptr : &*_Result; } struct tzdb { string version; vector zones; vector links; vector leap_seconds; bool _All_ls_positive; _NODISCARD const time_zone* locate_zone(string_view _Tz_name) const { auto _Tz = _Locate_zone_impl(zones, _Tz_name); if (_Tz != nullptr) { return _Tz; } const auto _Link = _Locate_zone_impl(links, _Tz_name); if (_Link != nullptr) { _Tz = _Locate_zone_impl(zones, _Link->target()); if (_Tz != nullptr) { return _Tz; } } _Xruntime_error("unable to locate time_zone with given name"); } _NODISCARD const time_zone* current_zone() const { return locate_zone(_Tzdb_generate_current_zone()); } }; _NODISCARD inline tuple _Tzdb_generate_time_zones() { unique_ptr<__std_tzdb_time_zones_info, _Tzdb_deleter<__std_tzdb_time_zones_info>> _Info{ __std_tzdb_get_time_zones()}; if (_Info == nullptr) { _Xbad_alloc(); } else if (_Info->_Err == __std_tzdb_error::_Win_error) { _XGetLastError(); } else if (_Info->_Err == __std_tzdb_error::_Icu_error) { _Xruntime_error("Internal error loading IANA database information"); } decltype(tzdb::zones) _Time_zones; decltype(tzdb::links) _Time_zone_links; for (size_t _Idx = 0; _Idx < _Info->_Num_time_zones; ++_Idx) { const string_view _Name{_Info->_Names[_Idx]}; if (_Info->_Links[_Idx] == nullptr) { _Time_zones.emplace_back(_Name); } else { const string_view _Target{_Info->_Links[_Idx]}; _Time_zone_links.emplace_back(_Name, _Target); } } return {_Info->_Version, _STD move(_Time_zones), _STD move(_Time_zone_links)}; } _NODISCARD inline pair _Tzdb_generate_leap_seconds(const size_t _Current_size) { // Returns empty vector if no new leap seconds are found. static constexpr leap_second _Known_leap_seconds[]{ {sys_seconds{seconds{78796800}}, true, seconds{0}}, {sys_seconds{seconds{94694400}}, true, seconds{1}}, {sys_seconds{seconds{126230400}}, true, seconds{2}}, {sys_seconds{seconds{157766400}}, true, seconds{3}}, {sys_seconds{seconds{189302400}}, true, seconds{4}}, {sys_seconds{seconds{220924800}}, true, seconds{5}}, {sys_seconds{seconds{252460800}}, true, seconds{6}}, {sys_seconds{seconds{283996800}}, true, seconds{7}}, {sys_seconds{seconds{315532800}}, true, seconds{8}}, {sys_seconds{seconds{362793600}}, true, seconds{9}}, {sys_seconds{seconds{394329600}}, true, seconds{10}}, {sys_seconds{seconds{425865600}}, true, seconds{11}}, {sys_seconds{seconds{489024000}}, true, seconds{12}}, {sys_seconds{seconds{567993600}}, true, seconds{13}}, {sys_seconds{seconds{631152000}}, true, seconds{14}}, {sys_seconds{seconds{662688000}}, true, seconds{15}}, {sys_seconds{seconds{709948800}}, true, seconds{16}}, {sys_seconds{seconds{741484800}}, true, seconds{17}}, {sys_seconds{seconds{773020800}}, true, seconds{18}}, {sys_seconds{seconds{820454400}}, true, seconds{19}}, {sys_seconds{seconds{867715200}}, true, seconds{20}}, {sys_seconds{seconds{915148800}}, true, seconds{21}}, {sys_seconds{seconds{1136073600}}, true, seconds{22}}, {sys_seconds{seconds{1230768000}}, true, seconds{23}}, {sys_seconds{seconds{1341100800}}, true, seconds{24}}, {sys_seconds{seconds{1435708800}}, true, seconds{25}}, {sys_seconds{seconds{1483228800}}, true, seconds{26}}, }; // __std_tzdb_get_leap_seconds gets leap second (LS) data from the registry, but only if it contains more // LSs than we already know about. The registry only contains LSs after 2018, so we need to tell it how many of // *those* we already know about. The *total* number of LSs known at this point is a combination of what the // caller knows (_Current_size, 0 on first call) and the _Known_leap_seconds entries. constexpr size_t _Pre_2018_count = 27; const size_t _Known_post_2018_ls_size = (_STD max) (_Current_size, _STD size(_Known_leap_seconds)) - _Pre_2018_count; size_t _Reg_post_2018_ls_size; // number of post-2018 LSs found in the registry unique_ptr<__std_tzdb_leap_info[], _Tzdb_deleter<__std_tzdb_leap_info[]>> _Reg_ls_data{ __std_tzdb_get_leap_seconds(_Known_post_2018_ls_size, &_Reg_post_2018_ls_size)}; if (_Reg_post_2018_ls_size > _Known_post_2018_ls_size && !_Reg_ls_data) { _Xbad_alloc(); // registry has new data, but failed to allocate storage } else if (_Reg_post_2018_ls_size == 0 && _Reg_ls_data) { _XGetLastError(); // allocated storage for registry data, but failed to read } const size_t _New_size = _Pre_2018_count + _Reg_post_2018_ls_size; // total size with registry data decltype(tzdb::leap_seconds) _Leap_sec_info; bool _All_ls_positive = true; if (_New_size > _Current_size) { _Leap_sec_info.reserve(_New_size); _Leap_sec_info.assign(_STD cbegin(_Known_leap_seconds), _STD cend(_Known_leap_seconds)); for (size_t _Idx = 0; _Idx < _Reg_post_2018_ls_size; ++_Idx) { // Leap seconds occur at _Ls._Hour:59:59. We store the next second after, so we need to add an entire // hour. const auto& _Ls = _Reg_ls_data[_Idx]; const auto _Date = static_cast(year_month_day{year{_Ls._Year}, month{_Ls._Month}, day{_Ls._Day}}) + hours{_Ls._Hour + 1}; _Leap_sec_info.emplace_back(_Date, !_Ls._Negative, _Leap_sec_info.back()._Elapsed()); _All_ls_positive = _All_ls_positive && !_Ls._Negative; } } return {_STD move(_Leap_sec_info), _All_ls_positive}; } _NODISCARD inline string _Tzdb_update_version(const string_view _Version, const size_t _Num_leap_seconds) { string _Icu_version{_Version.substr(0, _Version.find_last_of('.'))}; return _STD move(_Icu_version) + "." + _STD to_string(_Num_leap_seconds); } class tzdb_list { private: using _ListType = forward_list>; public: using const_iterator = _ListType::const_iterator; tzdb_list(const tzdb_list&) = delete; tzdb_list& operator=(const tzdb_list&) = delete; tzdb_list() { auto [_Icu_version, _Zones, _Links] = _Tzdb_generate_time_zones(); auto [_Leap_sec, _All_ls_positive] = _Tzdb_generate_leap_seconds(0); auto _Version = _Icu_version + "." + _STD to_string(_Leap_sec.size()); _Tzdb_list.emplace_front(tzdb{ _STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } _NODISCARD const tzdb& front() const noexcept { _Shared_lock _Lk(_Tzdb_mutex); return _Tzdb_list.front(); } const_iterator erase_after(const_iterator _Where) noexcept /* strengthened */ { _Unique_lock _Lk(_Tzdb_mutex); return _Tzdb_list.erase_after(_Where); } _NODISCARD const_iterator begin() const noexcept { _Shared_lock _Lk(_Tzdb_mutex); return _Tzdb_list.begin(); } _NODISCARD const_iterator end() const noexcept { return _Tzdb_list.end(); // no lock necessary for forward_list::end() } _NODISCARD const_iterator cbegin() const noexcept { _Shared_lock _Lk(_Tzdb_mutex); return _Tzdb_list.cbegin(); } _NODISCARD const_iterator cend() const noexcept { return _Tzdb_list.cend(); // no lock necessary for forward_list::cend() } template void _Emplace_front(_ArgsTy&&... _Args) { _Unique_lock _Lk(_Tzdb_mutex); _Tzdb_list.emplace_front(_STD forward<_ArgsTy>(_Args)...); } const tzdb& _Reload() { _Unique_lock _Lk(_Tzdb_mutex); auto [_Leap_sec, _All_ls_positive] = _Tzdb_generate_leap_seconds(_Tzdb_list.front().leap_seconds.size()); if (!_Leap_sec.empty()) { const auto& _Tzdb = _Tzdb_list.front(); vector _Zones; _STD transform(_Tzdb.zones.begin(), _Tzdb.zones.end(), _STD back_inserter(_Zones), [](const auto& _Tz) { return time_zone{_Tz.name()}; }); vector _Links; _STD transform( _Tzdb.links.begin(), _Tzdb.links.end(), _STD back_inserter(_Links), [](const auto& _Link) { return time_zone_link{_Link.name(), _Link.target()}; }); auto _Version = _Tzdb_update_version(_Tzdb.version, _Leap_sec.size()); _Tzdb_list.emplace_front(tzdb{ _STD move(_Version), _STD move(_Zones), _STD move(_Links), _STD move(_Leap_sec), _All_ls_positive}); } return _Tzdb_list.front(); } private: _ListType _Tzdb_list; mutable _Smtx_t _Tzdb_mutex = {}; struct _NODISCARD _Shared_lock { explicit _Shared_lock(_Smtx_t& _Mtx_) : _Mtx{&_Mtx_} { _Smtx_lock_shared(_Mtx); } _Shared_lock(const _Shared_lock&) = delete; _Shared_lock& operator=(const _Shared_lock&) = delete; ~_Shared_lock() { _Smtx_unlock_shared(_Mtx); } _Smtx_t* _Mtx; }; struct _NODISCARD _Unique_lock { explicit _Unique_lock(_Smtx_t& _Mtx_) : _Mtx{&_Mtx_} { _Smtx_lock_exclusive(_Mtx); } _Unique_lock(const _Unique_lock&) = delete; _Unique_lock& operator=(const _Unique_lock&) = delete; ~_Unique_lock() { _Smtx_unlock_exclusive(_Mtx); } _Smtx_t* _Mtx; }; }; inline atomic _Global_tzdb_list; _NODISCARD inline tzdb_list& get_tzdb_list() { auto* _Tzdb_ptr = _Global_tzdb_list.load(); if (_Tzdb_ptr != nullptr) { return *_Tzdb_ptr; } auto _My_tzdb = static_cast(__std_calloc_crt(1, sizeof(tzdb_list))); if (_My_tzdb == nullptr) { _Xruntime_error("bad allocation"); // not bad_alloc, see N4878 [time.zone.db.access]/4 } _TRY_BEGIN _STD construct_at(_My_tzdb); _CATCH(const runtime_error&) __std_free_crt(_My_tzdb); _RERAISE; _CATCH(const exception& _Except) #if _HAS_EXCEPTIONS __std_free_crt(_My_tzdb); _Xruntime_error(_Except.what()); #endif // _HAS_EXCEPTIONS _CATCH_END if (_Global_tzdb_list.compare_exchange_strong(_Tzdb_ptr, _My_tzdb)) { _Tzdb_ptr = _My_tzdb; } else { _STD destroy_at(_My_tzdb); __std_free_crt(_My_tzdb); } return *_Tzdb_ptr; } _NODISCARD inline const tzdb& get_tzdb() { return _CHRONO get_tzdb_list().front(); } _NODISCARD inline const time_zone* locate_zone(string_view _Tz_name) { return _CHRONO get_tzdb().locate_zone(_Tz_name); } _NODISCARD inline const time_zone* current_zone() { return _CHRONO get_tzdb().current_zone(); } inline const tzdb& reload_tzdb() { _TRY_BEGIN return _CHRONO get_tzdb_list()._Reload(); _CATCH(const runtime_error&) _RERAISE; _CATCH(const exception& _Except) #if _HAS_EXCEPTIONS _Xruntime_error(_Except.what()); #endif // _HAS_EXCEPTIONS _CATCH_END } _NODISCARD inline string remote_version() { const auto& _Tzdb = _CHRONO get_tzdb(); const auto& _Version = _Tzdb.version; const auto [_Leap_sec, _Ignored] = _Tzdb_generate_leap_seconds(_Tzdb.leap_seconds.size()); return _Leap_sec.empty() ? _Version : _Tzdb_update_version(_Version, _Leap_sec.size()); } // [time.zone.zonedtraits] template struct zoned_traits {}; template <> struct zoned_traits { _NODISCARD static const time_zone* default_zone() { return _CHRONO get_tzdb().locate_zone("UTC"); } _NODISCARD static const time_zone* locate_zone(string_view _Name) { return _CHRONO get_tzdb().locate_zone(_Name); } }; // [time.zone.zonedtime] template class zoned_time { private: static_assert(_Is_duration_v<_Duration>, "N4885 [time.zone.zonedtime.overview]/2 mandates Duration to be a specialization of chrono::duration."); using _Traits = zoned_traits<_TimeZonePtr>; public: using duration = common_type_t<_Duration, seconds>; template > zoned_time() : _Zone{_Traits::default_zone()} {} zoned_time(const zoned_time&) = default; zoned_time& operator=(const zoned_time&) = default; template > zoned_time(const sys_time<_Duration>& _Sys) : _Zone{_Traits::default_zone()}, _Tp{_Sys} {} explicit zoned_time(_TimeZonePtr _Tz) noexcept /* strengthened */ : _Zone{_STD move(_Tz)} {} // clang-format off template , int> = 0> // clang-format on explicit zoned_time(string_view _Name) : _Zone{_Traits::locate_zone(_Name)} {} template , sys_time<_Duration>>, int> = 0> zoned_time(const zoned_time<_Duration2, _TimeZonePtr>& _Zt) noexcept /* strengthened */ : _Zone{_Zt.get_time_zone()}, _Tp{_Zt.get_sys_time()} {} zoned_time(_TimeZonePtr _Tz, const sys_time<_Duration>& _Sys) : _Zone{_STD move(_Tz)}, _Tp{_Sys} {} // clang-format off template &>, int> = 0> // clang-format on zoned_time(string_view _Name, type_identity_t&> _Sys) : zoned_time{_Traits::locate_zone(_Name), _Sys} {} template ()->to_sys(local_time<_Duration>{})), sys_time>, int> = 0> zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local) : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local)} {} // clang-format off template &>, int> = 0> // clang-format on zoned_time(string_view _Name, type_identity_t>& _Local) : zoned_time{_Traits::locate_zone(_Name), _Local} {} template ()->to_sys(local_time<_Duration>{}, choose::earliest)), sys_time>, int> = 0> zoned_time(_TimeZonePtr _Tz, const local_time<_Duration>& _Local, choose _Choose) : _Zone{_STD move(_Tz)}, _Tp{_Zone->to_sys(_Local, _Choose)} {} // clang-format off template &, choose>, int> = 0> // clang-format on zoned_time(string_view _Name, type_identity_t&> _Local, choose _Choose) : zoned_time{_Traits::locate_zone(_Name), _Local, _Choose} {} template , sys_time<_Duration>>, int> = 0> zoned_time(_TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) noexcept /* strengthened */ : _Zone{_STD move(_Tz)}, _Tp{_Zt.get_sys_time()} {} template , sys_time<_Duration>>, int> = 0> zoned_time( _TimeZonePtr _Tz, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose) noexcept /* strengthened */ : zoned_time{_Tz, _Zt} {} // clang-format off template &>, int> = 0> // clang-format on zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt) : zoned_time{_Traits::locate_zone(_Name), _Zt} {} // clang-format off template &, choose>, int> = 0> // clang-format on zoned_time(string_view _Name, const zoned_time<_Duration2, _TimeZonePtr2>& _Zt, choose _Choose) : zoned_time{_Traits::locate_zone(_Name), _Zt, _Choose} {} zoned_time& operator=(const sys_time<_Duration>& _Sys) noexcept /* strengthened */ { _Tp = _Sys; return *this; } zoned_time& operator=(const local_time<_Duration>& _Local) { _Tp = _Zone->to_sys(_Local); return *this; } operator sys_time() const noexcept /* strengthened */ { return get_sys_time(); } explicit operator local_time() const { return get_local_time(); } _NODISCARD _TimeZonePtr get_time_zone() const noexcept /* strengthened */ { return _Zone; } _NODISCARD local_time get_local_time() const { return _Zone->to_local(_Tp); } _NODISCARD sys_time get_sys_time() const noexcept /* strengthened */ { return _Tp; } _NODISCARD sys_info get_info() const { return _Zone->get_info(_Tp); } private: _TimeZonePtr _Zone; sys_time _Tp{}; }; zoned_time()->zoned_time; template zoned_time(sys_time<_Duration>) -> zoned_time>; template using _Time_zone_representation = conditional_t, const time_zone*, remove_cvref_t<_TimeZonePtrOrName>>; template zoned_time(_TimeZonePtrOrName&&) -> zoned_time>; template zoned_time(_TimeZonePtrOrName&&, sys_time<_Duration>) -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>; template zoned_time(_TimeZonePtrOrName&&, local_time<_Duration>, choose = choose::earliest) -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>; template zoned_time(_TimeZonePtrOrName&&, zoned_time<_Duration, _TimeZonePtr2>, choose = choose::earliest) -> zoned_time, _Time_zone_representation<_TimeZonePtrOrName>>; using zoned_seconds = zoned_time; template _NODISCARD bool operator==( const zoned_time<_Duration1, _TimeZonePtr>& _Left, const zoned_time<_Duration2, _TimeZonePtr>& _Right) { return _Left.get_time_zone() == _Right.get_time_zone() && _Left.get_sys_time() == _Right.get_sys_time(); } // [time.clock.utc] class utc_clock; template using utc_time = time_point; using utc_seconds = utc_time; struct leap_second_info { bool is_leap_second; seconds elapsed; }; template _NODISCARD leap_second_info get_leap_second_info(const utc_time<_Duration>& _Time) { const utc_seconds _Time_floor = _CHRONO floor(_Time); const auto& _Tzdb = _CHRONO get_tzdb(); const auto& _Ls_vector = _Tzdb.leap_seconds; // Find first leap second after _Time. vector::const_iterator _It; if (_Tzdb._All_ls_positive) { // Where "target_ls" is the next leap second at or after _Time, _It either points to: // (1) The 2nd leap second after _Time if _Time_floor is in the range [target_ls - _Elapsed() - 1, // target_ls), or // (2) The leap second just after _Time otherwise. // Note that we can always use prev(_It) to determine whether _Time is *during* a leap second insertion, // since that falls under case (2) above. However, when we fall under case (1), we need to execute an // additional decrement to get the correct elapsed offset. For example, if leap seconds are inserted at // seconds {100, 200, 300, 400}, we have: // // UTC sys *_It // 99 99 100 // 100 X 200 // 101 100 200 // 102 101 200 // ... // 199 198 200 // 200 199 300^ // 201 X 300 // 202 200 300 // ... // 299 297 300 // 300 298 400^ // 301 299 400^ // 302 X 400 // 303 300 400 // // ^_It points to 2nd leap second _It = _STD upper_bound(_Ls_vector.begin(), _Ls_vector.end(), sys_seconds{_Time_floor.time_since_epoch()}); } else { seconds _Prev_elapsed{0}; for (_It = _Ls_vector.begin(); _It != _Ls_vector.end(); ++_It) { // UTC time when leap second insertion begins. In all cases, _It->date() + _It->_Elapsed() is the *end* // of the insertion. For a negative leap that's also the beginning, but for a positive one, insertion // begins 1 second earlier. const utc_seconds _This_ls_begin{ _It->date().time_since_epoch() + (_It->_Positive() ? _Prev_elapsed : _It->_Elapsed())}; if (_This_ls_begin > _Time_floor) { break; } _Prev_elapsed = _It->_Elapsed(); } } if (_It == _Ls_vector.begin()) { return {false, seconds{0}}; } else { // Convert to the last leap second before or equal to _Time. const auto& _Last_leap = *--_It; const utc_seconds _Utc_leap_second{_Last_leap.date().time_since_epoch() + _It->_Elapsed() - seconds{1}}; #ifdef __cpp_lib_concepts const auto _Leap_cmp = _Utc_leap_second <=> _Time_floor; #else // ^^^ __cpp_lib_concepts / TRANSITION, GH-395 workaround vvv const auto _Leap_cmp = _Utc_leap_second > _Time_floor ? strong_ordering::greater : _Utc_leap_second == _Time_floor ? strong_ordering::equal : strong_ordering::less; #endif // ^^^ workaround if (_Tzdb._All_ls_positive && _STD is_gt(_Leap_cmp)) { // Case (1) --_It; } return {_Last_leap._Positive() && _STD is_eq(_Leap_cmp), _It->_Elapsed()}; } } class utc_clock { public: using rep = system_clock::rep; using period = system_clock::period; using duration = _CHRONO duration; using time_point = _CHRONO time_point; static constexpr bool is_steady = system_clock::is_steady; _NODISCARD static time_point now() { return from_sys(system_clock::now()); } template _NODISCARD static sys_time> to_sys(const utc_time<_Duration>& _Utc_time) { using _CommonType = common_type_t<_Duration, seconds>; const auto _Lsi{_CHRONO get_leap_second_info(_Utc_time)}; _CommonType _Ticks; if (_Lsi.is_leap_second) { const auto _Leap_sec_minus_one = _CHRONO floor(_Utc_time.time_since_epoch()) - _Lsi.elapsed; if constexpr (is_integral_v) { constexpr auto _Delta{seconds{1} - _CommonType{1}}; _Ticks = _Leap_sec_minus_one + _Delta; } else { const auto _Leap_sec_begin = _CHRONO ceil<_CommonType>(_Leap_sec_minus_one + seconds{1}); _Ticks = _CommonType{_STD nextafter(_Leap_sec_begin.count(), typename _CommonType::rep{0})}; } } else { _Ticks = _Utc_time.time_since_epoch() - _Lsi.elapsed; } return sys_time<_CommonType>{_Ticks}; } template _NODISCARD static utc_time> from_sys(const sys_time<_Duration>& _Sys_time) { const auto& _Tzdb = _CHRONO get_tzdb(); const auto& _Ls_vector = _Tzdb.leap_seconds; auto _It = _STD upper_bound(_Ls_vector.begin(), _Ls_vector.end(), _CHRONO floor(_Sys_time)); const auto _Offset = _It == _Ls_vector.begin() ? seconds{0} : (--_It)->_Elapsed(); return utc_time>{_Sys_time.time_since_epoch() + _Offset}; } }; // [time.clock.tai] class tai_clock; template using tai_time = time_point; using tai_seconds = tai_time; class tai_clock { public: using rep = system_clock::rep; using period = system_clock::period; using duration = _CHRONO duration; using time_point = _CHRONO time_point; static constexpr bool is_steady = system_clock::is_steady; static constexpr seconds _Tai_epoch_adjust{378691210}; _NODISCARD static time_point now() { return from_utc(utc_clock::now()); } template _NODISCARD static utc_time> to_utc( const tai_time<_Duration>& _Time) noexcept { return utc_time>{_Time.time_since_epoch()} - _Tai_epoch_adjust; } template _NODISCARD static tai_time> from_utc( const utc_time<_Duration>& _Time) noexcept { return tai_time>{_Time.time_since_epoch()} + _Tai_epoch_adjust; } }; // [time.clock.gps] class gps_clock; template using gps_time = time_point; using gps_seconds = gps_time; class gps_clock { public: using rep = system_clock::rep; using period = system_clock::period; using duration = _CHRONO duration; using time_point = _CHRONO time_point; static constexpr bool is_steady = system_clock::is_steady; static constexpr seconds _Gps_epoch_adjust{-315964809}; _NODISCARD static time_point now() { return from_utc(utc_clock::now()); } template _NODISCARD static utc_time> to_utc( const gps_time<_Duration>& _Time) noexcept { return utc_time>{_Time.time_since_epoch()} - _Gps_epoch_adjust; } template _NODISCARD static gps_time> from_utc( const utc_time<_Duration>& _Time) noexcept { return gps_time>{_Time.time_since_epoch()} + _Gps_epoch_adjust; } }; #endif // ^^^ _HAS_CXX20 } // namespace chrono // [time.clock.file] #if _HAS_CXX20 namespace filesystem { struct _File_time_clock; } // namespace filesystem namespace chrono { using file_clock = filesystem::_File_time_clock; template using file_time = time_point; } // namespace chrono #endif // ^^^ _HAS_CXX20 #if _HAS_CXX17 namespace filesystem { inline constexpr long long __std_fs_file_time_epoch_adjustment = 0x19DB1DED53E8000LL; // TRANSITION, ABI struct _File_time_clock { // Implementation of trivial-clock using rep = long long; using period = chrono::system_clock::period; using duration = chrono::duration; using time_point = chrono::time_point<_File_time_clock>; static constexpr bool is_steady = false; _NODISCARD static time_point now() noexcept { // get current time; undo epoch adjustment return time_point(duration(_Xtime_get_ticks() + __std_fs_file_time_epoch_adjustment)); // TRANSITION, ABI } #if _HAS_CXX20 // Assumes that FILETIME counts leap seconds only after the first 27 (i.e., after 1 January 2017), even though // systems can opt out of this behavior. static constexpr chrono::seconds _Skipped_filetime_leap_seconds{27}; static constexpr chrono::sys_days _Cutoff{ chrono::year_month_day{chrono::year{2017}, chrono::January, chrono::day{1}}}; template _NODISCARD static chrono::utc_time> to_utc( const chrono::file_time<_Duration>& _File_time) { using namespace chrono; using _CommonType = common_type_t<_Duration, seconds>; const auto _Ticks = _File_time.time_since_epoch() - _CHRONO duration_cast(duration{__std_fs_file_time_epoch_adjustment}); if (_Ticks < _Cutoff.time_since_epoch()) { return utc_clock::from_sys(sys_time<_CommonType>{_Ticks}); } else { return utc_time<_CommonType>{_Ticks + _Skipped_filetime_leap_seconds}; } } template _NODISCARD static chrono::file_time> from_utc( const chrono::utc_time<_Duration>& _Utc_time) { using namespace chrono; file_time> _File_time{ _CHRONO duration_cast(duration{__std_fs_file_time_epoch_adjustment})}; if (_Utc_time < utc_seconds{_Cutoff.time_since_epoch()} + _Skipped_filetime_leap_seconds) { _File_time += utc_clock::to_sys(_Utc_time).time_since_epoch(); } else { _File_time += _Utc_time.time_since_epoch() - _Skipped_filetime_leap_seconds; } return _File_time; } #endif // ^^^ _HAS_CXX20 }; } // namespace filesystem #endif // ^^^ _HAS_CXX17 namespace chrono { #if _HAS_CXX20 // [time.clock.conv] template struct clock_time_conversion {}; // [time.clock.cast.id] template struct clock_time_conversion<_Clock, _Clock> { template _NODISCARD time_point<_Clock, _Duration> operator()(const time_point<_Clock, _Duration>& _Time) const noexcept(is_arithmetic_v) /* strengthened */ { return _Time; } }; template <> struct clock_time_conversion { template _NODISCARD sys_time<_Duration> operator()(const sys_time<_Duration>& _Time) const noexcept(is_arithmetic_v) /* strengthened */ { return _Time; } }; template <> struct clock_time_conversion { template _NODISCARD utc_time<_Duration> operator()(const utc_time<_Duration>& _Time) const noexcept(is_arithmetic_v) /* strengthened */ { return _Time; } }; // [time.clock.cast.sys.utc] template <> struct clock_time_conversion { template _NODISCARD utc_time> operator()(const sys_time<_Duration>& _Sys_time) const { return utc_clock::from_sys(_Sys_time); } }; template <> struct clock_time_conversion { template _NODISCARD sys_time> operator()(const utc_time<_Duration>& _Utc_time) const { return utc_clock::to_sys(_Utc_time); } }; // [time.clock.cast.sys] template inline constexpr bool _Is_time_point_for_clock = false; template inline constexpr bool _Is_time_point_for_clock, _Clock> = true; template struct clock_time_conversion { template &>()))>> _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const noexcept(noexcept(_SourceClock::to_sys(_Time))) /* strengthened */ { static_assert(_Is_time_point_for_clock, "N4885 [time.clock.cast.sys]/2: Mandates: SourceClock::to_sys(t) returns a sys_time"); return _SourceClock::to_sys(_Time); } }; template struct clock_time_conversion<_DestClock, system_clock> { template &>()))>> _NODISCARD auto operator()(const sys_time<_Duration>& _Time) const noexcept(noexcept(_DestClock::from_sys(_Time))) /* strengthened */ { static_assert(_Is_time_point_for_clock, "N4885 [time.clock.cast.sys]/5: Mandates: DestClock::from_sys(t) returns a " "time_point"); return _DestClock::from_sys(_Time); } }; // [time.clock.cast.utc] template struct clock_time_conversion { template &>()))>> _NODISCARD auto operator()(const time_point<_SourceClock, _Duration>& _Time) const noexcept(noexcept(_SourceClock::to_utc(_Time))) /* strengthened */ { static_assert(_Is_time_point_for_clock, "N4885 [time.clock.cast.utc]/2: Mandates: SourceClock::to_utc(t) returns a utc_time"); return _SourceClock::to_utc(_Time); } }; template struct clock_time_conversion<_DestClock, utc_clock> { template &>()))>> _NODISCARD auto operator()(const utc_time<_Duration>& _Time) const noexcept(noexcept(_DestClock::from_utc(_Time))) /* strengthened */ { static_assert(_Is_time_point_for_clock, "N4885 [time.clock.cast.utc]/5: Mandates: DestClock::from_utc(t) returns a " "time_point"); return _DestClock::from_utc(_Time); } }; // [time.clock.cast.fn] enum class _Clock_cast_strategy { _Direct, _Via_sys, _Via_utc, _Via_utc_from_sys, _Via_sys_from_utc, _Two_step_ambiguous, _Three_step_ambiguous, _None, }; template inline constexpr bool _Has_two_step_conversion = false; template inline constexpr bool _Has_two_step_conversion<_Conv1, _Conv2, _Tp, void_t())))>> = true; template inline constexpr bool _Has_three_step_conversion = false; template inline constexpr bool _Has_three_step_conversion<_Conv1, _Conv2, _Conv3, _Tp, void_t()))))>> = true; template _NODISCARD _CONSTEVAL _Clock_cast_strategy _Choose_clock_cast() noexcept { using _Tp = const time_point<_SourceClock, _Duration>&; if constexpr (is_invocable_v, _Tp>) { return _Clock_cast_strategy::_Direct; } else { constexpr bool _Has_sys = _Has_two_step_conversion< // clock_time_conversion<_DestClock, system_clock>, // clock_time_conversion, _Tp>; constexpr bool _Has_utc = _Has_two_step_conversion< // clock_time_conversion<_DestClock, utc_clock>, // clock_time_conversion, _Tp>; if constexpr (_Has_sys && _Has_utc) { return _Clock_cast_strategy::_Two_step_ambiguous; } else if constexpr (_Has_sys) { return _Clock_cast_strategy::_Via_sys; } else if constexpr (_Has_utc) { return _Clock_cast_strategy::_Via_utc; } else { constexpr bool _Has_utc_from_sys = _Has_three_step_conversion< // clock_time_conversion<_DestClock, utc_clock>, // clock_time_conversion, // clock_time_conversion, _Tp>; constexpr bool _Has_sys_from_utc = _Has_three_step_conversion< // clock_time_conversion<_DestClock, system_clock>, // clock_time_conversion, // clock_time_conversion, _Tp>; if constexpr (_Has_utc_from_sys && _Has_sys_from_utc) { return _Clock_cast_strategy::_Three_step_ambiguous; } else if constexpr (_Has_utc_from_sys) { return _Clock_cast_strategy::_Via_utc_from_sys; } else if constexpr (_Has_sys_from_utc) { return _Clock_cast_strategy::_Via_sys_from_utc; } else { return _Clock_cast_strategy::_None; } } } } template inline constexpr auto _Clock_cast_choice = _Choose_clock_cast<_DestClock, _SourceClock, _Duration>(); template != _Clock_cast_strategy::_None, int> = 0> _NODISCARD auto clock_cast(const time_point<_SourceClock, _Duration>& _Time) { constexpr auto _Strat = _Clock_cast_choice<_DestClock, _SourceClock, _Duration>; if constexpr (_Strat == _Clock_cast_strategy::_Direct) { return clock_time_conversion<_DestClock, _SourceClock>{}(_Time); } else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys) { return clock_time_conversion<_DestClock, system_clock>{}( clock_time_conversion{}(_Time)); } else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc) { return clock_time_conversion<_DestClock, utc_clock>{}( clock_time_conversion{}(_Time)); } else if constexpr (_Strat == _Clock_cast_strategy::_Via_utc_from_sys) { return clock_time_conversion<_DestClock, utc_clock>{}( // clock_time_conversion{}( clock_time_conversion{}(_Time))); } else if constexpr (_Strat == _Clock_cast_strategy::_Via_sys_from_utc) { return clock_time_conversion<_DestClock, system_clock>{}( // clock_time_conversion{}( clock_time_conversion{}(_Time))); } else if constexpr (_Strat == _Clock_cast_strategy::_Two_step_ambiguous) { static_assert(_Always_false<_Duration>, "A two-step clock time conversion is required to be unique, " "either through utc_clock or system_clock, but not both (N4878 [time.clock.cast.fn]/2)."); } else if constexpr (_Strat == _Clock_cast_strategy::_Three_step_ambiguous) { static_assert(_Always_false<_Duration>, "A three-step clock time conversion is required to be unique, " "either utc-to-system or system-to-utc, but not both (N4878 [time.clock.cast.fn]/2)."); } else { static_assert(_Always_false<_Duration>, "should be unreachable"); } } // [time.parse] struct _Time_parse_fields { using _SubsecondType = duration; // These are the primary fields, used to set the chrono type being parsed. optional _Subsecond; optional _Second; optional _Minute; optional _Hour_24; optional _Weekday; // 0-based, starts Sunday optional _Day; // 1-based optional _Month; // 1-based optional _Day_of_year; // 1-based optional _Two_dig_year; optional _Century; optional _Utc_offset; // in minutes optional _Tz_name; // These are the secondary fields, used to store parsed data. They must be converted to primary fields and // checked for consistency. optional _Hour_12; optional _Ampm; optional _Iso_year; optional _Two_dig_iso_year; optional _Iso_week; // 1-based optional _Week_u; // week number, W01 begins on first Sunday optional _Week_w; // week number, W01 begins on first Monday enum _FieldFlags : unsigned int { _F_sec = 0x01, _F_min = 0x02, _F_hr = 0x04, _F_day = 0x08, _F_wkday = 0x10, _F_mon = 0x20, _F_doy = 0x40, _F_year = 0x80, }; _NODISCARD unsigned int _Used_fields() const { unsigned int _Ret{0}; if (_Second || _Subsecond) { _Ret |= _F_sec; } if (_Minute) { _Ret |= _F_min; } if (_Hour_24) { _Ret |= _F_hr; } if (_Day) { _Ret |= _F_day; } if (_Weekday) { _Ret |= _F_wkday; } if (_Month) { _Ret |= _F_mon; } if (_Day_of_year) { _Ret |= _F_doy; } if (_Two_dig_year && _Century) { _Ret |= _F_year; } return _Ret; } _NODISCARD static bool _Test_bits( const unsigned int _Bits, const unsigned int _Must_set, const unsigned int _Optional = 0) { return (_Bits & ~_Optional) == _Must_set; } template static constexpr _Ty _Invalid_time_field{numeric_limits<_Ty>::lowest()}; static void _Initialize_time_point(tm& _Tp) { _Tp.tm_sec = _Invalid_time_field; _Tp.tm_min = _Invalid_time_field; _Tp.tm_hour = _Invalid_time_field; _Tp.tm_wday = _Invalid_time_field; _Tp.tm_mday = _Invalid_time_field; _Tp.tm_mon = _Invalid_time_field; _Tp.tm_yday = _Invalid_time_field; _Tp.tm_year = _Invalid_time_field; } template _NODISCARD static bool _Update(optional<_Ty>& _Val, const _Ty& _New) { // Update a field. Ignores invalid values. If _Val already has a value, returns true or false according to // whether the new value matches the current one or not, so that inconsistencies can be detected. if constexpr (!is_same_v<_Ty, string>) { if (_New == _Invalid_time_field<_Ty>) { return true; } } if (!_Val.has_value()) { _Val = _New; return true; } else { return _STD exchange(_Val, _New) == _New; } } _NODISCARD static pair _Decompose_year(const int _Year) { int _Two_d_year = _Year % 100; if (_Two_d_year < 0) { _Two_d_year += 100; } return {_Year - _Two_d_year, _Two_d_year}; } _NODISCARD bool _Update_if_valid(const tm& _Tp, const bool _Full_year) { bool _No_err{true}; if (_Tp.tm_hour != _Invalid_time_field) { _No_err = _No_err && _Update(_Hour_24, _Tp.tm_hour); _No_err = _No_err && _Update(_Ampm, _Hour_24 >= 12 ? 1 : 0); _No_err = _No_err && _Update(_Hour_12, _CHRONO make12(hours{*_Hour_24}).count()); } _No_err = _No_err && _Update(_Minute, _Tp.tm_min); _No_err = _No_err && _Update(_Second, _Tp.tm_sec); _No_err = _No_err && _Update(_Day, _Tp.tm_mday); _No_err = _No_err && _Update(_Weekday, _Tp.tm_wday); if (_Tp.tm_mon != _Invalid_time_field) { _No_err = _No_err && _Update(_Month, _Tp.tm_mon + 1); } if (_Tp.tm_yday != _Invalid_time_field) { _No_err = _No_err && _Update(_Day_of_year, _Tp.tm_yday + 1); } if (_Tp.tm_year != _Invalid_time_field) { // Sometimes we expect only the last two digits. const auto _Year_parts = _Decompose_year(_Tp.tm_year + 1900); _No_err = _No_err && _Update(_Two_dig_year, _Year_parts.second); if (_Full_year) { _No_err = _No_err && _Update(_Century, _Year_parts.first); } } return _No_err; } _NODISCARD bool _Yday_to_month_day(const int _Yday, const int _Year) { // A day-of-year that's February 28 or earlier, by itself, is a valid month_day. Any later day is // ambiguous without a year. if (_Out_of_range(_Day_of_year, 1, _Two_dig_year || _Iso_year ? _Days_in_year(_Year) : 59)) { return false; } if (_Day_of_year <= 31) { return _Update(_Day, _Yday) && _Update(_Month, 1); } const int _Feb_end{_Is_leap(_Year) ? 60 : 59}; if (_Day_of_year <= _Feb_end) { return _Update(_Day, _Yday - 31) && _Update(_Month, 2); } // Shift day-of-year so that 1 == March 1. This is the same as year_month_day::_Civil_from_days, except // _Day_of_year --> _Shifted_yday-1 and _Mp --> _Month - 3. const int _Shifted_yday{*_Day_of_year - _Feb_end}; return _Update(_Month, (535 * _Shifted_yday + 48950) >> 14) && _Update(_Day, _Shifted_yday - ((979 * *_Month - 2918) >> 5)); } static constexpr int _Era_begin_wday{3}; // Wednesday _NODISCARD static constexpr int _Jan1_weekday(int _Year) { --_Year; const int _Era = (_Year >= 0 ? _Year : _Year - 399) / 400; const int _Yoe = _Year - _Era * 400; // Jan. 1 is always day 306 of the shifted [Mar, ..., Dec, Jan, Feb] year. const int _Doe = ((1461 * _Yoe) >> 2) - _Yoe / 100 + 306; return (_Doe + _Era_begin_wday) % 7; } _NODISCARD static constexpr int _Iso8601_weeks(int _Year) { const int _P_y = (_Year + _Year / 4 - _Year / 100 + _Year / 400) % 7; --_Year; const int _P_ym1 = (_Year + _Year / 4 - _Year / 100 + _Year / 400) % 7; return 52 + (_P_y == 4 || _P_ym1 == 3); } _NODISCARD static constexpr int _Iso8601_week(const int _Day_of_year, const int _Weekday, const int _Year) { // Jan. 4 is always week 1; rollover to next week always happens on Monday. const auto _Week{(_Day_of_year + 9 - _Prev_weekday(_Weekday, 1)) / 7}; if (_Week < 1) { return _Iso8601_weeks(_Year - 1); } else if (_Week > _Iso8601_weeks(_Year)) { return 1; } else { return _Week; } } _NODISCARD static constexpr bool _Is_leap(const int _Year) { return _Year % 4 == 0 && (_Year % 100 != 0 || _Year % 400 == 0); } _NODISCARD static constexpr int _Days_in_year(const int _Year) { return _Is_leap(_Year) ? 366 : 365; } _NODISCARD static constexpr int _Next_weekday(const int _Wday, const int _Shift) { // 0 <= _Shift <= 6 int _Result = _Wday + _Shift; if (_Result >= 7) { _Result -= 7; } return _Result; } _NODISCARD static constexpr int _Prev_weekday(const int _Wday, const int _Shift) { // 0 <= _Shift <= 6 return (_Wday >= _Shift ? 0 : 7) + (_Wday - _Shift); } _NODISCARD bool _Calculate_ymd_from_week_date(const int _Starting_wday, const int _Week, const int _Year) { // (a) Calculate day-of-year of first _Starting_wday in January. // (b) Shift *_Weekday so that it's relative to _Starting_wday. // (c) Offset to desired week. const int _Jan1_wday = _Jan1_weekday(_Year); const int _Yday = 1 + _Prev_weekday(_Starting_wday, _Jan1_wday) // (a) + _Prev_weekday(*_Weekday, _Starting_wday) // (b) + 7 * (_Week - 1); // (c) return _Update(_Day_of_year, _Yday) && !_Out_of_range(_Day_of_year, 1, _Days_in_year(_Year)) && _Yday_to_month_day(*_Day_of_year, _Year); } _NODISCARD bool _Calculate_ymd() { bool _No_err = true; // Flags to indicate if a field should be checked for consistency with other data. Set to false when the // field is used to calculate the date, as it's necessarily self-consistent in that case (barring a bug). bool _Check_u = true; bool _Check_w = true; bool _Check_iso = true; bool _Check_wday = true; if (_Day_of_year && _Out_of_range(_Day_of_year, 1, 366)) { return false; } bool _Have_year = false; int _Year{0}; if (_Two_dig_year) { _Year = *_Century + *_Two_dig_year; _Have_year = true; if (_Day_of_year) { _No_err = _No_err && _Yday_to_month_day(*_Day_of_year, _Year); } else if (_Week_u || _Week_w) { _Check_wday = false; if (_Week_u) { _Check_u = false; _No_err = _No_err && _Calculate_ymd_from_week_date(0 /*Sunday*/, *_Week_u, _Year); } if (_Week_w) { _Check_w = false; _No_err = _No_err && _Calculate_ymd_from_week_date(1 /*Monday*/, *_Week_w, _Year); } } } if (_Iso_year) { // ISO weeks begin on Monday. W01 always contains January 4. There is no W00, so the beginning of // January can be in W52 or W53 of the previous year. Likewise, the end of December can occur at the // beginning of W01 of the following year, depending on where in the week Jan. 4 falls. _Check_wday = false; _Check_iso = false; _Year = *_Iso_year; _Have_year = true; // Shift weekdays to Monday-based. Jan. 4 is the anchor of week 1, so calculate where the parsed weekday // is relative to that point. const int _Jan4_wday = _Next_weekday(_Jan1_weekday(_Year), 3 - 1); const int _Offset_from_jan4 = _Prev_weekday(*_Weekday, 1) - _Jan4_wday; int _Trial_yday = 4 + 7 * (*_Iso_week - 1) + _Offset_from_jan4; const int _Ref_num_days = _Trial_yday < 1 ? _Days_in_year(_Year - 1) : _Days_in_year(_Year); if (_Trial_yday < 1) { _Trial_yday += _Ref_num_days; --_Year; } else if (_Trial_yday > _Ref_num_days) { _Trial_yday -= _Ref_num_days; ++_Year; } const auto _Year_parts = _Decompose_year(_Year); _No_err = _No_err && _Update(_Day_of_year, _Trial_yday) && _Yday_to_month_day(*_Day_of_year, _Year) && _Update(_Century, _Year_parts.first) && _Update(_Two_dig_year, _Year_parts.second); } // Must have YMD by this point, either parsed directly or calculated above. if (!_Have_year || !_Month || !_Day || !_No_err) { return false; } // consistency checks if (_Check_wday && _Weekday) { const auto _Era_year = _Year - (*_Month <= 2); const int _Era = (_Era_year >= 0 ? _Era_year : _Era_year - 399) / 400; const int _Yoe = _Era_year - _Era * 400; const int _Yday_era = ((979 * (*_Month + (*_Month > 2 ? -3 : 9)) + 19) >> 5) + *_Day - 1; const int _Doe = ((1461 * _Yoe) >> 2) - _Yoe / 100 + _Yday_era; _No_err = _No_err && _Update(_Weekday, (_Doe + _Era_begin_wday) % 7); } if (_Check_u && _Week_u) { _No_err = _No_err && _Update(_Week_u, (*_Day_of_year + 6 - *_Weekday) / 7); } if (_Check_w && _Week_w) { _No_err = _No_err && _Update(_Week_w, (*_Day_of_year + 6 - _Prev_weekday(*_Weekday, 1)) / 7); } if (_Check_iso && _Iso_week) { _No_err = _No_err && _Update(_Iso_week, _Iso8601_week(*_Day_of_year, *_Weekday, _Year)); } return _No_err; } _NODISCARD bool _Calculate_hour24() { if (_Hour_12) { return _Update( _Hour_24, _CHRONO make24(hours{*_Hour_12}, static_cast(_Ampm.value_or(0))).count()); } else { return true; } } _NODISCARD bool _Calculate_year_fields() { bool _No_err = true; // The order of these updates is significant. Updating the ISO date second allows // formats with %g and %y, but not %C, to get the century implicitly from %y. if (_Two_dig_year && !_Century) { _No_err = _No_err && _Update(_Century, _Two_dig_year >= 69 ? 1900 : 2000); } // %C is only combined with %g if %G is missing, to avoid an unnecessary parse failure when the ISO and // Gregorian years are in different centuries. if (_Two_dig_iso_year && _Century && !_Iso_year) { _No_err = _No_err && _Update(_Iso_year, *_Century + *_Two_dig_iso_year); } return _No_err; } _NODISCARD static bool _Out_of_range(const optional& _Field, const int _Min, const int _Max) { return _Field && (_Field < _Min || _Max < _Field); } _NODISCARD bool _Is_complete() const { // Check for data that is incomplete, ambiguous, or obviously out-of-range. The exception is 12-hour time // without am/pm. Most strptime implementations will assume am in this case, so we'll do that too. Don't // check for consistency yet, because the data might not even be representable by the type being parsed, // and calendar computations are relatively expensive. // Most time-of-day fields are deferred until we know if we're parsing a time_point. if (_Out_of_range(_Hour_12, 1, 12) // || _Out_of_range(_Weekday, 0, 6) // || _Out_of_range(_Day, 1, 31) // || _Out_of_range(_Month, 1, 12)) { return false; } if (_Iso_year || _Two_dig_iso_year || _Iso_week) { // Need to have %G or %C+%g. The century can be parsed explicitly, or derived implicitly from %y. const bool _Has_complete_year{_Iso_year || ((_Century || _Two_dig_year) && _Two_dig_iso_year)}; if (!_Has_complete_year || !_Iso_week || !_Weekday || _Out_of_range(_Iso_week, 1, 53)) { return false; } } if (_Week_u || _Week_w) { // Need a weekday and year to be complete. if (!_Weekday || !_Two_dig_year) { return false; } if (_Out_of_range(_Week_u, 0, 53) || _Out_of_range(_Week_w, 0, 53)) { return false; } } return true; } template _NODISCARD static constexpr bool _Can_represent() { using _Rep1 = typename _Duration1::rep; using _Period1 = typename _Duration1::period; using _Period2 = typename _Duration2::period; // Returns whether _Duration1 can represent _Duration2{1}. Assumes 1 <= _Period2 <= // 86,400, i.e., we're interested in time periods between seconds and days. if constexpr (is_integral_v<_Rep1>) { // Must have _Period1 <= _Period2 and numeric_limits<_Rep1>::max() >= _Period2 / _Period1. For example, // std::days can't represent std::seconds, and duration::max() is ~9.2 seconds. constexpr auto _Max_tick = static_cast((numeric_limits>::max) ()); // clang-format off return ratio_less_equal_v<_Period1, _Period2> && ratio_greater_equal_v, ratio_divide, _Period1>>; // clang-format on } else if (is_floating_point_v<_Rep1>) { // With the smallest possible _Period1, ratio<1,INTMAX_MAX>, one day has a tick count of // 86,400*INTMAX_MAX ~= 7.97e23. This is representable by float and double, so they can always represent // at least one day. On the other hand, one second with the largest possible _Period1 needs a tick count // of 1/(INTMAX_MAX) ~= 1.08e-19, which is also representable in both float and double. So, both // floating point types can represent durations between one second and one day, regardless of _Period1. return true; } else { // TRANSITION: user-defined arithmetic-like types return true; } } enum class _Parse_tp_or_duration { _Time_point, _Duration }; template <_Parse_tp_or_duration _Parse_type, class _DurationType> _NODISCARD bool _Apply_duration_fields(_DurationType& _Result) { constexpr bool _Can_rep_sec = _Can_represent<_DurationType, seconds>(); constexpr bool _Can_rep_min = _Can_represent<_DurationType, minutes>(); constexpr bool _Can_rep_hr = _Can_represent<_DurationType, hours>(); constexpr bool _Can_rep_day = _Can_represent<_DurationType, days>(); constexpr bool _For_time_point = _Parse_type == _Parse_tp_or_duration::_Time_point; const auto _Required{(_For_time_point ? _F_day | _F_mon | _F_year : 0)}; const auto _Optional{(_For_time_point ? _F_wkday : 0) | (_Can_rep_sec ? _F_sec : 0) | (_Can_rep_min ? _F_min : 0) | (_Can_rep_hr ? _F_hr : 0) | (_Can_rep_day ? _F_doy : 0)}; const auto _Used{_Used_fields()}; const auto _Time_out_of_range{ _For_time_point && (_Out_of_range(_Second, 0, 60) || _Out_of_range(_Minute, 0, 59) || _Out_of_range(_Hour_24, 0, 23))}; if (_Time_out_of_range || !_Test_bits(_Used, _Required, _Optional)) { return false; } _Result = _DurationType::zero(); if constexpr (_Can_rep_sec) { if (_Used & _F_sec) { if (_Subsecond) { using _CastedType = duration; const _SubsecondType _Sub{*_Subsecond}; if (treat_as_floating_point_v<_DurationType> // || _CHRONO duration_cast<_CastedType>(_Sub) == _Sub) { _Result += _CHRONO duration_cast<_DurationType>(_Sub); } else { return false; } } if (_Second) { _Result += _CHRONO duration_cast<_DurationType>(seconds{*_Second}); } } } if constexpr (_Can_rep_min) { if (_Used & _F_min) { _Result += _CHRONO duration_cast<_DurationType>(minutes{*_Minute}); } if (_Utc_offset) { _Result -= _CHRONO duration_cast<_DurationType>(minutes{*_Utc_offset}); } } if constexpr (_Can_rep_hr) { if (_Used & _F_hr) { _Result += _CHRONO duration_cast<_DurationType>(hours{*_Hour_24}); } } if constexpr (_Can_rep_day) { if (_For_time_point) { const year_month_day _Ymd{year{*_Century + *_Two_dig_year}, month{static_cast(*_Month)}, day{static_cast(*_Day)}}; _Result += _CHRONO duration_cast<_DurationType>(static_cast(_Ymd).time_since_epoch()); } else if (_Used & _F_doy) { _Result += _CHRONO duration_cast<_DurationType>(days{*_Day_of_year}); } } return true; } template _NODISCARD bool _Make_duration(duration<_Rep, _Period>& _Duration_result) { const bool _Consistent = _Calculate_hour24(); if (_Consistent) { _Duration_result = duration<_Rep, _Period>::zero(); // TRANSITION: LWG-3536 & GH-1740 return _Apply_duration_fields<_Parse_tp_or_duration::_Duration>(_Duration_result); } return false; } enum class _LeapSecondRep : unsigned int { _None, // tai_clock, gps_clock; oblivious to leap seconds _Negative, // system_clock, observes negative, but not positive, leap seconds _All, // utc_clock _File_time // _Negative before 1 January 2017, _All afterwards. }; template _NODISCARD bool _Make_time_point(_DurationType& _Dur, _LeapSecondRep _Leap) { const bool _Consistent{_Calculate_hour24() && _Calculate_year_fields() && _Calculate_ymd()}; if (!_Consistent || !_Apply_duration_fields<_Parse_tp_or_duration::_Time_point>(_Dur)) { return false; } const _LeapSecondRep _Original_leap{_Leap}; if (_Leap == _LeapSecondRep::_File_time) { const int _Year{*_Century + *_Two_dig_year}; _Leap = _Year <= 2016 ? _LeapSecondRep::_Negative : _LeapSecondRep::_All; } if (_Second > (_Leap == _LeapSecondRep::_All ? 60 : 59)) { return false; } // A distinction has to be made here between clocks that tick monotonically, even around a positive leap // second (everything except system_clock) and ones that have a special representation for leap seconds // (utc_clock and, for negative leap seconds, system_clock). gps_clock and tai_clock, in particular, always // monotonically count 86,400 seconds/day. The correct tick count, therefore, can be determined without // knowing whether any leap seconds have occurred, and there aren't any invalid times due to negative leap // second deletions. // // system_clock also has 86,400 seconds/day, but observes negative leap seconds by skipping them in its tick // count. So leap second data is needed to check for a valid time, but not to calculate the tick count. if (_Leap != _LeapSecondRep::_None) { if (_Hour_24 == 23 && _Minute == 59 && _Second >= 59) { // It's possible that the parsed time doesn't exist because (a) _Seconds == 60 and there *isn't* a // leap second insertion or (b) _Seconds == 59 and there *is* a leap second subtraction. // Check for quick exit. const auto& _Tzdb{_CHRONO get_tzdb()}; if (_Leap == _LeapSecondRep::_Negative && _Tzdb._All_ls_positive) { return true; } const bool _Possible_insertion{_Second == 60}; const sys_seconds _Target_sys_time{ _CHRONO floor(_Dur) + (_Possible_insertion ? seconds{0} : seconds{1})}; const auto& _Ls_vector{_Tzdb.leap_seconds}; const auto _It{_STD lower_bound(_Ls_vector.begin(), _Ls_vector.end(), _Target_sys_time)}; const bool _Match_leap{_It != _Ls_vector.end() && *_It == _Target_sys_time}; // Condition for a good parse: (_Seconds == 59 && !_Match_leap) || (_Match_leap && // _It->_Is_positive()). Below is the inverse of this. if (!(_Match_leap ? _It->_Positive() : !_Possible_insertion)) { return false; } } if (_Leap == _LeapSecondRep::_All) { constexpr bool _Can_rep_sec = _Can_represent<_DurationType, seconds>(); if constexpr (_Can_rep_sec) { _Dur = utc_clock::from_sys(sys_time<_DurationType>{_Dur}).time_since_epoch(); // If we parsed a positive leap second, then _Dur, interpreted as a system time, refers to the // second *after* insertion. Need to back up one second in this case. if (_Second == 60) { _Dur -= _CHRONO duration_cast<_DurationType>(seconds{1}); } if (_Original_leap == _LeapSecondRep::_File_time) { _Dur -= _CHRONO duration_cast<_DurationType>( filesystem::_File_time_clock::_Skipped_filetime_leap_seconds); } } else { // Error if _Dur can't represent the above adjustment. return false; } } } return true; } _NODISCARD bool _Make_day(day& _Day_result) { if (_Used_fields() == _F_day) { _Day_result = day{static_cast(*_Day)}; return true; } else { return false; } } _NODISCARD bool _Make_weekday(weekday& _Weekday_result) { if (_Used_fields() == _F_wkday) { _Weekday_result = weekday{static_cast(*_Weekday)}; return true; } else { return false; } } _NODISCARD bool _Make_month(month& _Month_result) { if (_Used_fields() == _F_mon) { _Month_result = month{static_cast(*_Month)}; return true; } else { return false; } } _NODISCARD bool _Make_month_day(month_day& _Month_day_result) { if (_Day_of_year && !_Yday_to_month_day(*_Day_of_year, 0)) { return false; } constexpr auto _Required = _F_mon | _F_day; constexpr auto _Optional = _F_doy; if (_Test_bits(_Used_fields(), _Required, _Optional)) { _Month_day_result = month_day{month{static_cast(*_Month)}, day{static_cast(*_Day)}}; return true; } else { return false; } } _NODISCARD bool _Make_year(year& _Year_result) { if (_Calculate_year_fields() && _Used_fields() == _F_year) { _Year_result = year{*_Century + *_Two_dig_year}; return true; } else { return false; } } _NODISCARD bool _Make_year_month(year_month& _Year_month_result) { if (_Calculate_year_fields() && _Used_fields() == (_F_mon | _F_year)) { _Year_month_result = year_month{year{*_Century + *_Two_dig_year}, month{static_cast(*_Month)}}; return true; } else { return false; } } _NODISCARD bool _Make_year_month_day( year_month_day& _Year_month_day_result, const bool _For_time_point = false) { const bool _Consistent = _Calculate_year_fields() && _Calculate_ymd(); constexpr auto _Required = _F_day | _F_mon | _F_year; auto _Optional = _F_wkday | _F_doy; if (_For_time_point) { // These fields aren't used here, but they might be used later if converting to a time_point. _Optional |= _F_sec | _F_min | _F_hr; } if (_Consistent && _Test_bits(_Used_fields(), _Required, _Optional)) { _Year_month_day_result = year_month_day{year{*_Century + *_Two_dig_year}, month{static_cast(*_Month)}, day{static_cast(*_Day)}}; return true; } else { return false; } } template _NODISCARD _InIt _Parse_time_field(_InIt _First, ios_base& _Iosbase, ios_base::iostate& _State, const char _Flag, const char _Modifier, const unsigned int _Width, const unsigned int _Subsecond_precision) { using _CharT = typename _InIt::value_type; const auto& _Ctype_fac = _STD use_facet>(_Iosbase.getloc()); const auto& _Time_fac = _STD use_facet>(_Iosbase.getloc()); constexpr _InIt _Last{}; int _Val{0}; switch (_Flag) { case 'a': case 'A': { tm _Tp; _Tp.tm_wday = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'a'); if (!_Update(_Weekday, _Tp.tm_wday)) { _State |= ios_base::failbit; } break; } case 'b': case 'B': case 'h': { tm _Tp; _Tp.tm_mon = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'b'); if (_Tp.tm_mon == _Invalid_time_field || !_Update(_Month, ++_Tp.tm_mon)) { _State |= ios_base::failbit; } break; } case 'C': if (_Modifier != 'E') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); _Val *= 100; } else { tm _Tp; _Tp.tm_year = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'C', 'E'); _Val = _Tp.tm_year; if (_Tp.tm_year != _Invalid_time_field) { _Val += 1900; } } if (!_Update(_Century, _Val)) { _State |= ios_base::failbit; } break; case 'd': case 'e': if (_Modifier != 'O') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Tp.tm_mday = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'd', 'O'); _Val = _Tp.tm_mday; } if (!_Update(_Day, _Val)) { _State |= ios_base::failbit; } break; case 'D': _First = _Parse_time_field_restricted(_First, _Iosbase, _State, "%m/%d/%y"); break; case 'F': { // If modified with a width N, the width is applied to only %Y. _State |= _Get_int(_First, _Width == 0 ? 4u : _Width, _Val, _Ctype_fac); const auto _Year_parts = _Decompose_year(_Val); if (_Update(_Century, _Year_parts.first) && _Update(_Two_dig_year, _Year_parts.second)) { _First = _Parse_time_field_restricted(_First, _Iosbase, _State, "-%m-%d"); } else { _State |= ios_base::failbit; } break; } case 'g': _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); if (!_Update(_Two_dig_iso_year, _Val)) { _State |= ios_base::failbit; } break; case 'G': { _State |= _Get_int(_First, _Width == 0 ? 4u : _Width, _Val, _Ctype_fac); const auto _Year_parts = _Decompose_year(_Val); if (!_Update(_Iso_year, _Val) || !_Update(_Two_dig_iso_year, _Year_parts.second)) { _State |= ios_base::failbit; } break; } case 'H': if (_Modifier != 'O') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Tp.tm_hour = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'H', 'O'); _Val = _Tp.tm_hour; } if (!_Update(_Hour_24, _Val) || (_Val < 24 && (!_Update(_Ampm, _Val >= 12 ? 1 : 0) || !_Update(_Hour_12, _CHRONO make12(hours{_Val}).count())))) { _State |= ios_base::failbit; } break; case 'I': if (_Modifier != 'O') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Tp.tm_hour = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'I', 'O'); _Val = (_Tp.tm_hour == 0) ? 12 : _Tp.tm_hour; } if (!_Update(_Hour_12, _Val)) { _State |= ios_base::failbit; } break; case 'j': _State |= _Get_int(_First, _Width == 0 ? 3u : _Width, _Val, _Ctype_fac); if (!_Update(_Day_of_year, _Val)) { _State |= ios_base::failbit; } break; case 'M': if (_Modifier != 'O') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Tp.tm_min = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'M', 'O'); _Val = _Tp.tm_min; } if (!_Update(_Minute, _Val)) { _State |= ios_base::failbit; } break; case 'm': if (_Modifier != 'O') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Initialize_time_point(_Tp); _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'm', 'O'); _Val = _Tp.tm_mon; if (_Tp.tm_mon != _Invalid_time_field) { ++_Val; } } if (!_Update(_Month, _Val)) { _State |= ios_base::failbit; } break; case 'p': { tm _Tp; _Tp.tm_hour = 0; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'p'); if (!_Update(_Ampm, _Tp.tm_hour == 0 ? 0 : 1)) { _State |= ios_base::failbit; } break; } case 'c': case 'r': case 'x': case 'X': { tm _Tp; _Initialize_time_point(_Tp); const bool _Full_year = (_Flag == 'c'); // 'x' reads two-digit year, 'r' and 'X' read times _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, _Flag, _Modifier); if (!_Update_if_valid(_Tp, _Full_year)) { _State |= ios_base::failbit; } break; } case 'R': _First = _Parse_time_field_restricted(_First, _Iosbase, _State, "%H:%M"); break; case 'T': _First = _Parse_time_field_restricted(_First, _Iosbase, _State, "%H:%M:%S", _Subsecond_precision); break; case 'S': if (_Subsecond_precision == 0) { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); if (!_Update(_Second, _Val)) { _State |= ios_base::failbit; } } else { const auto& _Numpunct_fac = _STD use_facet>(_Iosbase.getloc()); _State |= _Get_fixed(_First, _Width == 0 ? 3 + _Subsecond_precision : _Width, _Ctype_fac, _Numpunct_fac); } break; case 'u': case 'w': if (_Flag == 'w' && _Modifier == 'O') { tm _Tp; _Tp.tm_wday = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'w', 'O'); _Val = _Tp.tm_wday; } else { _State |= _Get_int(_First, _Width == 0 ? 1u : _Width, _Val, _Ctype_fac); if (_Flag == 'u') { // ISO weekday: [1,7], 7 == Sunday if (_Val == 7) { _Val = 0; } else if (_Val == 0) { _Val = 7; // out of range } } } if (!_Update(_Weekday, _Val)) { _State |= ios_base::failbit; } break; case 'U': case 'V': case 'W': { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); auto& _Field{(_Flag == 'U') ? _Week_u : (_Flag == 'W' ? _Week_w : _Iso_week)}; if (!_Update(_Field, _Val)) { _State |= ios_base::failbit; } break; } case 'y': if (_Modifier == '\0') { _State |= _Get_int(_First, _Width == 0 ? 2u : _Width, _Val, _Ctype_fac); } else { tm _Tp; _Tp.tm_year = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'y', _Modifier); if (_Modifier == 'E') { _Val = _Tp.tm_year + 1900; // offset from %EC base year } else { const auto _Year_parts = _Decompose_year(_Tp.tm_year); _Val = _Year_parts.second; } } if (!_Update(_Two_dig_year, _Val)) { _State |= ios_base::failbit; } break; case 'Y': { if (_Modifier == 'E') { tm _Tp; _Tp.tm_year = _Invalid_time_field; _First = _Time_fac.get(_First, _Last, _Iosbase, _State, &_Tp, 'Y', 'E'); _Val = _Tp.tm_year + 1900; } else { _State |= _Get_int(_First, _Width == 0 ? 4u : _Width, _Val, _Ctype_fac); } const auto _Year_parts = _Decompose_year(_Val); if (!_Update(_Century, _Year_parts.first) || !_Update(_Two_dig_year, _Year_parts.second)) { _State |= ios_base::failbit; } break; } case 'z': _State |= _Get_tz_offset(_First, _Ctype_fac, _Modifier == 'E' || _Modifier == 'O', _Val); if (!_Update(_Utc_offset, _Val)) { _State |= ios_base::failbit; } break; case 'Z': { string _Name; _State |= _Get_tz_name(_First, _Ctype_fac, _Name); if (!_Update(_Tz_name, _Name)) { _State |= ios_base::failbit; } break; } default: // Invalid flag _State |= ios_base::failbit; break; } return _First; } template _NODISCARD _InIt _Parse_time_field_restricted(_InIt _First, ios_base& _Iosbase, ios_base::iostate& _State, const char* _Fmt, const unsigned int _Subsecond_precision = 0) { using _Ctype = ctype; // Parses a restricted format string. It generally doesn't handle anything parsed outside of // _Parse_time_field: // (a) any whitespace (' ', %n, %t) // (b) %% literal (other literals are parsed, however) // (c) E or O modifiers // (d) width parameter // It also assumes a valid format string, specifically that '%' is always followed by a flag. const _Ctype& _Ctype_fac{_STD use_facet<_Ctype>(_Iosbase.getloc())}; constexpr _InIt _Last{}; while (*_Fmt != '\0' && _First != _Last && _State == ios_base::goodbit) { if (*_Fmt == '%') { _First = _Parse_time_field(_First, _Iosbase, _State, *++_Fmt, '\0', 0, _Subsecond_precision); } else if (_Ctype_fac.narrow(*_First++) != *_Fmt) { _State |= ios_base::failbit; } ++_Fmt; } return _First; } template _NODISCARD ios_base::iostate _Get_fixed(_InIt& _First, unsigned int _Width, const ctype& _Ctype_fac, const numpunct& _Numpunct_fac) { constexpr _InIt _Last{}; while (_First != _Last && _Ctype_fac.is(ctype_base::space, *_First) && _Width > 0) { ++_First; --_Width; } int _Second_ = 0; int64_t _Subsecond_ = 0; int64_t _Multiplier = _SubsecondType::period::den; bool _Found_point = false; bool _Found_digit = false; while (_First != _Last && _Width > 0 && _Multiplier >= 10) { const auto _Ch = *_First; if (_Ch == _Numpunct_fac.decimal_point() && !_Found_point) { _Found_point = true; } else if (_Ctype_fac.is(ctype_base::digit, _Ch)) { _Found_digit = true; const auto _Digit = _Ctype_fac.narrow(_Ch) - '0'; if (_Found_point) { _Multiplier /= 10; _Subsecond_ += _Digit * _Multiplier; } else { if (_Second_ > ((numeric_limits::max) () - _Digit) / 10) { return ios_base::failbit; } _Second_ = _Second_ * 10 + _Digit; } } else { break; } ++_First; --_Width; } ios_base::iostate _State = ios_base::goodbit; if (_First == _Last) { _State |= ios_base::eofbit; } if (!(_Found_digit && _Update(_Second, _Second_) && _Update(_Subsecond, _Subsecond_))) { _State |= ios_base::failbit; } return _State; } template _NODISCARD ios_base::iostate _Get_int( _InIt& _First, unsigned int _Width, int& _Val, const ctype& _Ctype_fac) { constexpr _InIt _Last{}; while (_First != _Last && _Ctype_fac.is(ctype_base::space, *_First) && _Width > 0) { ++_First; --_Width; } char _Ac[_MAX_INT_DIG]; char* _Ptr = _Ac; if (_First != _Last && _Width > 0) { const char _Ch = _Ctype_fac.narrow(*_First); if (_Ch == '+' || _Ch == '-') { // copy sign *_Ptr++ = _Ch; ++_First; --_Width; } } bool _Has_leading_zero = false; while (_First != _Last && _Width > 0 && _Ctype_fac.narrow(*_First) == '0') { // strip leading zeros ++_First; --_Width; _Has_leading_zero = true; } if (_Has_leading_zero) { *_Ptr++ = '0'; } char _Ch; while (_First != _Last && _Width > 0 && '0' <= (_Ch = _Ctype_fac.narrow(*_First)) && _Ch <= '9') { // copy digits *_Ptr = _Ch; if (_Ptr < _STD cend(_Ac)) { ++_Ptr; // drop trailing digits if already too large } ++_First; --_Width; } *_Ptr = '\0'; int _Errno = 0; char* _Ep; const long _Ans = _CSTD _Stolx(_Ac, &_Ep, 10, &_Errno); ios_base::iostate _State = ios_base::goodbit; if (_First == _Last) { _State |= ios_base::eofbit; } if (_Ep == _Ac || _Errno != 0) { _State |= ios_base::failbit; // bad conversion } else { _Val = _Ans; // store valid result } return _State; } template _NODISCARD ios_base::iostate _Get_tz_offset( _InIt& _First, const ctype& _Ctype_fac, const bool _Is_modified, int& _Offset) { constexpr _InIt _Last{}; if (_First == _Last) { return ios_base::eofbit; } bool _Negative = false; switch (_Ctype_fac.narrow(*_First)) { case '-': _Negative = true; [[fallthrough]]; case '+': ++_First; break; } // For a regular offset hh[mm], simply read four digits, with the option of an EOF or non-digit after // reading two. The modified form h[h][:mm] is similar, except for the following points: // (a) an EOF or non-digit is allowable after reading *one* digit, not two. // (b) after reading one digit, another optional digit keeps us in the same state, except for decrementing // the number of optional digits allowed. In this state, reading a ':' allows parsing to continue. int _Tz_hours = 0; int _Tz_minutes = 0; int _Optional_digits = 1; for (int _Count = 0; _Count < 4; ++_Count) { const bool _Allow_match_fail{_Count == (_Is_modified ? 1 : 2)}; if (_First == _Last) { if (_Allow_match_fail) { break; } else { return ios_base::eofbit | ios_base::failbit; } } const char _Ch = _Ctype_fac.narrow(*_First++); const bool _Is_digit = ('0' <= _Ch && _Ch <= '9'); if (_Is_modified && _Count == 1) { if (_Ch == ':') { continue; } else if (_Is_digit && _Optional_digits > 0) { _Tz_hours = 10 * _Tz_hours + (_Ch - '0'); --_Optional_digits; --_Count; } else { if (_Allow_match_fail) { break; } else { return ios_base::failbit; } } } else if (_Is_digit) { auto& _Part = _Count < 2 ? _Tz_hours : _Tz_minutes; _Part = 10 * _Part + (_Ch - '0'); } else { if (_Allow_match_fail) { break; } else { return ios_base::failbit; } } } _Offset = 60 * _Tz_hours + _Tz_minutes; if (_Negative) { _Offset = -_Offset; } return ios_base::goodbit; } template _NODISCARD ios_base::iostate _Get_tz_name( _InIt& _First, const ctype& _Ctype_fac, string& _Tz_name) { constexpr _InIt _Last{}; _Tz_name.clear(); while (_First != _Last) { const char _Ch{_Ctype_fac.narrow(*_First)}; if (_STD isalnum(static_cast(_Ch)) || _Ch == '_' || _Ch == '/' || _Ch == '-' || _Ch == '+') { _Tz_name.push_back(_Ch); ++_First; } else { break; } } return _First == _Last ? ios_base::eofbit : ios_base::goodbit; } template > _Time_parse_fields(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _FmtFirst, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr, unsigned int _Subsecond_precision = 0) { using _Myis = basic_istream<_CharT, _Traits>; const auto& _Ctype_fac = _STD use_facet>(_Istr.getloc()); ios_base::iostate _State = ios_base::goodbit; const _CharT* const _FmtLast = _FmtFirst + _Traits::length(_FmtFirst); const typename _Myis::sentry _Ok{_Istr, true}; istreambuf_iterator _First{_Istr}; constexpr decltype(_First) _Last{}; if (_Ok) { _TRY_IO_BEGIN for (; _FmtFirst != _FmtLast && _State == ios_base::goodbit; ++_FmtFirst) { if (_First == _Last) { // EOF is not an error if the remaining flags can match zero characters. for (; _FmtFirst != _FmtLast; ++_FmtFirst) { char _Flag{}; if (_Ctype_fac.is(ctype_base::space, *_FmtFirst)) { _Flag = ' '; } else { if (_Ctype_fac.narrow(*_FmtFirst) == '%' && ++_FmtFirst != _FmtLast) { _Flag = _Ctype_fac.narrow(*_FmtFirst); } } if (_Flag != ' ' && _Flag != 't') { _State |= ios_base::failbit | ios_base::eofbit; break; } } break; } else if (_Ctype_fac.narrow(*_FmtFirst) != '%') { // match literal element if (_Ctype_fac.is(ctype_base::space, *_FmtFirst)) { while (_First != _Last && _Ctype_fac.is(ctype_base::space, *_First)) { ++_First; } } else if (*_First == *_FmtFirst) { ++_First; } else { _State |= ios_base::failbit; // bad literal match } } else if (++_FmtFirst == _FmtLast) { // not enough for a valid flag _State |= ios_base::failbit; } else { // get flag after % char _Flag = _Ctype_fac.narrow(*_FmtFirst); char _Modifier = '\0'; unsigned int _Width = 0; if (_Flag == 'E' || _Flag == 'O') { if (++_FmtFirst == _FmtLast) { _State |= ios_base::failbit; break; } _Modifier = _STD exchange(_Flag, _Ctype_fac.narrow(*_FmtFirst)); } else if ('0' <= _Flag && _Flag <= '9') { _Width = static_cast(_Flag - '0'); while (++_FmtFirst != _FmtLast && _Ctype_fac.is(ctype_base::digit, *_FmtFirst)) { const auto _Digit = static_cast(_Ctype_fac.narrow(*_FmtFirst) - '0'); if (_Width > ((numeric_limits::max) () - _Digit) / 10) { _State |= ios_base::failbit; break; } _Width = 10 * _Width + _Digit; } if (_FmtFirst == _FmtLast) { _State |= ios_base::failbit; break; } _Flag = _Ctype_fac.narrow(*_FmtFirst); } switch (_Flag) { case 'n': // exactly one space if (!_Ctype_fac.is(ctype_base::space, *_First++)) { _State |= ios_base::failbit; } break; case 't': // zero or one space if (_Ctype_fac.is(ctype_base::space, *_First)) { ++_First; } break; case '%': if (_Ctype_fac.narrow(*_First++) != '%') { _State |= ios_base::failbit; } break; default: _First = _Parse_time_field(_First, _Istr, _State, _Flag, _Modifier, _Width, _Subsecond_precision); // convert a single field break; } } } _CATCH_IO_(_Myis, _Istr) } if (!_Is_complete()) { _State |= ios_base::failbit; } if (!(_State & ios_base::failbit)) { if (_Offset != nullptr && _Utc_offset) { *_Offset = minutes{*_Utc_offset}; } if (_Abbrev != nullptr && _Tz_name) { if constexpr (is_same_v) { *_Abbrev = _STD move(*_Tz_name); } else { _Abbrev->clear(); for (const char& _Ch : *_Tz_name) { _Abbrev->push_back(_Ctype_fac.widen(_Ch)); } } } } _Istr.setstate(_State); } }; template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, duration<_Rep, _Period>& _Duration, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, hh_mm_ss>::fractional_width}; if (_Istr && !_Time._Make_duration(_Duration)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, weekday& _Wd, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_weekday(_Wd)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, day& _Day, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_day(_Day)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, month& _Month, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_month(_Month)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, month_day& _Md, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_month_day(_Md)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, year& _Year, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_year(_Year)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, year_month& _Ym, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_year_month(_Ym)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, year_month_day& _Ymd, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset}; if (_Istr && !_Time._Make_year_month_day(_Ymd)) { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, utc_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_All)) { _Tp = utc_time<_Duration>{_Dur}; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, sys_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_Negative)) { _Tp = sys_time<_Duration>{_Dur}; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, tai_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_None)) { _Tp = tai_time<_Duration>{_Dur + _CHRONO duration_cast<_Duration>(days{4383})}; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, gps_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, chrono::minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_None)) { _Tp = gps_time<_Duration>{_Dur - _CHRONO duration_cast<_Duration>(days{3657})}; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, file_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, chrono::minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_File_time)) { constexpr auto _File_clock_adj{_CHRONO duration_cast<_Duration>( filesystem::_File_time_clock::duration{filesystem::__std_fs_file_time_epoch_adjustment})}; _Tp = file_time<_Duration>{_Dur} + _File_clock_adj; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template > basic_istream<_CharT, _Traits>& from_stream(basic_istream<_CharT, _Traits>& _Istr, const _CharT* _Fmt, local_time<_Duration>& _Tp, basic_string<_CharT, _Traits, _Alloc>* _Abbrev = nullptr, minutes* _Offset = nullptr) { constexpr auto _Subsecond_precision{hh_mm_ss<_Duration>::fractional_width}; _Time_parse_fields _Time{_Istr, _Fmt, _Abbrev, _Offset, _Subsecond_precision}; // *_Offset is not subtracted from local_time, see N4885 [time.clock.local]/4. _Time._Utc_offset.reset(); _Duration _Dur; if (_Istr && _Time._Make_time_point(_Dur, _Time_parse_fields::_LeapSecondRep::_None)) { _Tp = local_time<_Duration>{_Dur}; } else { _Istr.setstate(ios_base::failbit); } return _Istr; } template struct _Time_parse_iomanip { _Time_parse_iomanip(const basic_string<_CharT, _Traits, _Alloc>& _Fmt_, _Parsable& _Tp_, basic_string<_CharT, _Traits, _Alloc>* _Abbrev_ = nullptr, minutes* _Offset_ = nullptr) : _Fmt{_Fmt_}, _Tp{_Tp_}, _Abbrev{_Abbrev_}, _Offset{_Offset_} {} const basic_string<_CharT, _Traits, _Alloc>& _Fmt; _Parsable& _Tp; basic_string<_CharT, _Traits, _Alloc>* _Abbrev; minutes* _Offset; }; template &>(), _STD declval(), _STD declval<_Parsable&>()))>> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp) { return _Time_parse_iomanip{_Fmt, _Tp}; } template &>(), _STD declval(), _STD declval<_Parsable&>(), _STD declval*>()))>> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev) { return _Time_parse_iomanip{_Fmt, _Tp, _STD addressof(_Abbrev)}; } template &>(), _STD declval(), _STD declval<_Parsable&>(), _STD declval*>(), _STD declval()))>> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, minutes& _Offset) { return _Time_parse_iomanip{_Fmt, _Tp, static_cast*>(nullptr), &_Offset}; } template &>(), _STD declval(), _STD declval<_Parsable&>(), _STD declval*>(), _STD declval()))>> _NODISCARD auto parse(const basic_string<_CharT, _Traits, _Alloc>& _Fmt, _Parsable& _Tp, basic_string<_CharT, _Traits, _Alloc>& _Abbrev, minutes& _Offset) { return _Time_parse_iomanip{_Fmt, _Tp, _STD addressof(_Abbrev), &_Offset}; } template basic_istream<_CharT, _Traits>& operator>>( basic_istream<_CharT, _Traits>& _Is, const _Time_parse_iomanip<_CharT, _Traits, _Alloc, _Parsable>& _Tpi) { return _CHRONO from_stream(_Is, _Tpi._Fmt.c_str(), _Tpi._Tp, _Tpi._Abbrev, _Tpi._Offset); } #endif // _HAS_CXX20 } // namespace chrono #ifdef __cpp_lib_format // [time.format] template _NODISCARD constexpr const _CharT* _Choose_literal(const char* const _Str, const wchar_t* const _WStr) noexcept { if constexpr (is_same_v<_CharT, char>) { return _Str; } else { return _WStr; } } #define _STATICALLY_WIDEN(_CharT, _Literal) (_Choose_literal<_CharT>(_Literal, L##_Literal)) // clang-format off template concept _Chrono_parse_spec_callbacks = _Parse_align_callbacks<_Ty, _CharT> && _Parse_width_callbacks<_Ty, _CharT> && _Parse_precision_callbacks<_Ty, _CharT> && _Width_adapter_callbacks<_Ty, _CharT> && _Precision_adapter_callbacks<_Ty, _CharT> && requires(_Ty _At, basic_string_view<_CharT> _Sv, _Fmt_align _Aln) { { _At._On_conversion_spec(char{}, _CharT{}) } -> same_as; { _At._On_lit_char(_CharT{}) } -> same_as; }; // clang-format on // clang-format off template concept _Has_ok = requires(_Ty _At) { { _At.ok() } -> same_as; }; // clang-format on // A chrono spec is either a type (with an optional modifier), OR a literal character, never both. template struct _Chrono_spec { _CharT _Lit_char = _CharT{'\0'}; // any character other than '{', '}', or '%' char _Modifier = '\0'; // either 'E' or 'O' char _Type = '\0'; }; template struct _Chrono_format_specs { int _Width = 0; int _Precision = -1; int _Dynamic_width_index = -1; int _Dynamic_precision_index = -1; _Fmt_align _Alignment = _Fmt_align::_None; uint8_t _Fill_length = 1; // At most one codepoint (so one char32_t or four utf-8 char8_t) _CharT _Fill[4 / sizeof(_CharT)] = {_CharT{' '}}; // recursive definition in grammar, so could have any number of these vector<_Chrono_spec<_CharT>> _Chrono_specs_list; }; // Model of _Chrono_parse_spec_callbacks that fills a _Chrono_format_specs with the parsed data template class _Chrono_specs_setter { public: constexpr explicit _Chrono_specs_setter(_Chrono_format_specs<_CharT>& _Specs_, _ParseContext& _Parse_ctx_) : _Specs(_Specs_), _Parse_ctx(_Parse_ctx_) {} // same as _Specs_setter constexpr void _On_align(_Fmt_align _Aln) { _Specs._Alignment = _Aln; } // same as _Specs_setter constexpr void _On_fill(basic_string_view<_CharT> _Sv) { if (_Sv.size() > _STD size(_Specs._Fill)) { _THROW(format_error("Invalid fill (too long).")); } const auto _Pos = _STD _Copy_unchecked(_Sv._Unchecked_begin(), _Sv._Unchecked_end(), _Specs._Fill); _STD fill(_Pos, _STD end(_Specs._Fill), _CharT{}); _Specs._Fill_length = static_cast(_Sv.size()); } constexpr void _On_width(int _Width) { _Specs._Width = _Width; } constexpr void _On_precision(int _Prec) { _Specs._Precision = _Prec; } constexpr void _On_dynamic_width(const size_t _Arg_id) { _Parse_ctx.check_arg_id(_Arg_id); _Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Arg_id); } constexpr void _On_dynamic_width(_Auto_id_tag) { _Specs._Dynamic_width_index = _Verify_dynamic_arg_index_in_range(_Parse_ctx.next_arg_id()); } constexpr void _On_dynamic_precision(const size_t _Arg_id) { _Parse_ctx.check_arg_id(_Arg_id); _Specs._Dynamic_precision_index = _Verify_dynamic_arg_index_in_range(_Arg_id); } constexpr void _On_dynamic_precision(_Auto_id_tag) { _Specs._Dynamic_precision_index = _Verify_dynamic_arg_index_in_range(_Parse_ctx.next_arg_id()); } constexpr void _On_conversion_spec(char _Modifier, _CharT _Type) { // NOTE: same performance note from _Basic_format_specs also applies here if (_Modifier != '\0' && _Modifier != 'E' && _Modifier != 'O') { _THROW(format_error("Invalid modifier specification.")); } if (_Type < 0 || _Type > (numeric_limits::max) ()) { _THROW(format_error("Invalid type specification.")); } _Chrono_spec<_CharT> _Conv_spec{._Modifier = _Modifier, ._Type = static_cast(_Type)}; _Specs._Chrono_specs_list.push_back(_Conv_spec); } constexpr void _On_lit_char(_CharT _Lit_ch) { _Chrono_spec<_CharT> _Lit_char_spec{._Lit_char = _Lit_ch}; _Specs._Chrono_specs_list.push_back(_Lit_char_spec); } private: _Chrono_format_specs<_CharT>& _Specs; _ParseContext& _Parse_ctx; _NODISCARD static constexpr int _Verify_dynamic_arg_index_in_range(const size_t _Idx) { if (_Idx > static_cast((numeric_limits::max) ())) { _THROW(format_error("Dynamic width or precision index too large.")); } return static_cast(_Idx); } }; // assumes that the required '%' at the beginning of a conversion-spec has already been consumed template _Callbacks_type> _NODISCARD constexpr const _CharT* _Parse_conversion_specs( const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) { if (_Begin == _End || *_Begin == '}') { _THROW(format_error("Invalid format string.")); } char _Mod = '\0'; _CharT _Ch = *_Begin; if (_Ch == 'E' || _Ch == 'O') { // includes modifier _Mod = static_cast(_Ch); ++_Begin; if (_Begin == _End || *_Begin == '}') { _THROW(format_error("Invalid format string - missing type after modifier.")); } } _CharT _Type = *_Begin; _Callbacks._On_conversion_spec(_Mod, _Type); return ++_Begin; } template _Callbacks_type> _NODISCARD constexpr const _CharT* _Parse_chrono_format_specs( const _CharT* _Begin, const _CharT* _End, _Callbacks_type&& _Callbacks) { if (_Begin == _End || *_Begin == '}') { return _Begin; } _Begin = _Parse_align(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } _Begin = _Parse_width(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } if (*_Begin == '.') { _Begin = _Parse_precision(_Begin, _End, _Callbacks); if (_Begin == _End) { return _Begin; } } if (*_Begin != '}' && *_Begin != '%') { _THROW(format_error("Invalid format string - chrono-specs must begin with conversion-spec")); } // chrono-spec while (_Begin != _End && *_Begin != '}') { if (*_Begin == '%') { // conversion-spec if (++_Begin == _End) { _THROW(format_error("Invalid format string - missing type after %")); } switch (*_Begin) { case 'n': _Callbacks._On_lit_char('\n'); ++_Begin; break; case 't': _Callbacks._On_lit_char('\t'); ++_Begin; break; case '%': _Callbacks._On_lit_char('%'); ++_Begin; break; default: // some other type _Begin = _Parse_conversion_specs(_Begin, _End, _Callbacks); break; } } else { // literal-char _Callbacks._On_lit_char(*_Begin); ++_Begin; } } return _Begin; } namespace chrono { template struct _Local_time_format_t { local_time<_Duration> _Time; const string* _Abbrev = nullptr; const seconds* _Offset_sec = nullptr; }; template _NODISCARD _Local_time_format_t<_Duration> local_time_format(const local_time<_Duration> _Time, const string* const _Abbrev = nullptr, const seconds* const _Offset_sec = nullptr) { return {_Time, _Abbrev, _Offset_sec}; } // Replacement for %S, as put_time does not honor writing fractional seconds. template void _Write_seconds(basic_ostream<_CharT, _Traits>&, const _Ty&) { _STL_INTERNAL_CHECK(false); } template void _Write_fractional_seconds( basic_ostream<_CharT, _Traits>& _Os, const seconds& _Seconds, const _Precision& _Subseconds) { _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:02}"), _Seconds.count()); if constexpr (_Fractional_width > 0) { _Os << _STD use_facet>(_Os.getloc()).decimal_point(); if constexpr (treat_as_floating_point_v) { _Os << _STD format( _STATICALLY_WIDEN(_CharT, "{:0{}.0f}"), _STD floor(_Subseconds.count()), _Fractional_width); } else { _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:0{}}"), _Subseconds.count(), _Fractional_width); } } } template void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const hh_mm_ss<_Duration>& _Val) { _Write_fractional_seconds::fractional_width>(_Os, _Val.seconds(), _Val.subseconds()); } template void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const time_point<_Clock, _Duration>& _Val) { if constexpr (is_same_v<_Clock, utc_clock>) { const auto _Lsi = _CHRONO get_leap_second_info(_Val); const auto _Dp = _CHRONO floor(_Val - _Lsi.elapsed) + _Lsi.elapsed - seconds{_Lsi.is_leap_second ? 1 : 0}; const hh_mm_ss _Hms{_Val - _Dp}; constexpr auto _Fractional_width = decltype(_Hms)::fractional_width; if (_Lsi.is_leap_second) { _Write_fractional_seconds<_Fractional_width>(_Os, _Hms.seconds() + seconds{60}, _Hms.subseconds()); } else { _Write_fractional_seconds<_Fractional_width>(_Os, _Hms.seconds(), _Hms.subseconds()); } } else { const auto _Dp = _CHRONO floor(_Val); _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); } } template void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const _Local_time_format_t<_Duration>& _Val) { _Write_seconds(_Os, _Val._Time); } template void _Write_seconds(basic_ostream<_CharT, _Traits>& _Os, const duration<_Rep, _Period>& _Val) { const auto _Dp = _CHRONO duration_cast(_Val); _Write_seconds(_Os, hh_mm_ss{_Val - _Dp}); } template _NODISCARD tm _Fill_tm(const _Ty& _Val) { unsigned int _Day = 0; unsigned int _Month = 0; int _Year = 0; int _Yearday = 0; int _Weekday = 0; int _Hours = 0; int _Minutes = 0; int _Seconds = 0; if constexpr (_Is_specialization_v<_Ty, duration>) { const auto _Dp = _CHRONO duration_cast(_Val); return _Fill_tm(hh_mm_ss{_Val - _Dp}); } else if constexpr (_Is_specialization_v<_Ty, _Local_time_format_t>) { return _Fill_tm(_Val._Time); } else if constexpr (is_same_v<_Ty, day>) { _Day = static_cast(_Val); } else if constexpr (is_same_v<_Ty, month>) { _Month = static_cast(_Val); } else if constexpr (is_same_v<_Ty, year>) { _Year = static_cast(_Val); } else if constexpr (is_same_v<_Ty, weekday>) { _Weekday = static_cast(_Val.c_encoding()); } else if constexpr (_Is_any_of_v<_Ty, weekday_indexed, weekday_last>) { _Weekday = static_cast(_Val.weekday().c_encoding()); } else if constexpr (is_same_v<_Ty, month_day>) { _Day = static_cast(_Val.day()); _Month = static_cast(_Val.month()); if (_Val.month() == January) { _Yearday = static_cast(_Day) - 1; } else if (_Val.month() == February) { _Yearday = 31 + static_cast(_Day) - 1; } } else if constexpr (is_same_v<_Ty, month_day_last>) { _Month = static_cast(_Val.month()); _Day = static_cast(_Last_day_table[(_Month - 1) & 0xF]); if (_Val.month() == January) { _Yearday = 30; } } else if constexpr (is_same_v<_Ty, month_weekday>) { _Month = static_cast(_Val.month()); _Weekday = static_cast(_Val.weekday_indexed().weekday().c_encoding()); } else if constexpr (is_same_v<_Ty, month_weekday_last>) { _Month = static_cast(_Val.month()); _Weekday = static_cast(_Val.weekday_last().weekday().c_encoding()); } else if constexpr (is_same_v<_Ty, year_month>) { _Month = static_cast(_Val.month()); _Year = static_cast(_Val.year()); } else if constexpr (_Is_any_of_v<_Ty, year_month_day, year_month_day_last>) { _Day = static_cast(_Val.day()); _Month = static_cast(_Val.month()); _Year = static_cast(_Val.year()); if (_Val.ok()) { const year_month_day& _Ymd = _Val; _Weekday = _Ymd._Calculate_weekday(); _Yearday = (static_cast(_Val) - static_cast(_Val.year() / January / 1)).count(); } } else if constexpr (_Is_any_of_v<_Ty, year_month_weekday, year_month_weekday_last>) { auto _Tm = _Fill_tm(year_month_day{_Val}); _Tm.tm_wday = static_cast(_Val.weekday().c_encoding()); return _Tm; } else if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { _Hours = _Val.hours().count(); _Minutes = _Val.minutes().count(); _Seconds = static_cast(_Val.seconds().count()); } else if constexpr (_Is_any_of_v<_Ty, sys_info, local_info>) { return {}; // none of the valid conversion specifiers need tm fields } else if constexpr (_Is_specialization_v<_Ty, time_point>) { const auto _Dp = _CHRONO floor(_Val); const year_month_day _Ymd{_Dp}; const hh_mm_ss _Time{_Val - _Dp}; const auto _Hms = _Fill_tm(_Time); auto _Tm = _Fill_tm(_Ymd); _Tm.tm_sec = _Hms.tm_sec; _Tm.tm_min = _Hms.tm_min; _Tm.tm_hour = _Hms.tm_hour; return _Tm; } tm _Time; _Time.tm_sec = _Seconds; _Time.tm_min = _Minutes; _Time.tm_hour = _Hours; _Time.tm_mday = static_cast(_Day); _Time.tm_mon = static_cast(_Month) - 1; _Time.tm_year = _Year - 1900; _Time.tm_yday = _Yearday; _Time.tm_wday = _Weekday; return _Time; } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const day& _Val) { return _Os << (_Val.ok() ? _STD format(_STATICALLY_WIDEN(_CharT, "{:%d}"), _Val) : _STD format(_STATICALLY_WIDEN(_CharT, "{:%d} is not a valid day"), _Val)); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const month& _Val) { return _Os << (_Val.ok() ? _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{:%b}"), _Val) : _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{} is not a valid month"), static_cast(_Val))); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const year& _Val) { return _Os << (_Val.ok() ? _STD format(_STATICALLY_WIDEN(_CharT, "{:%Y}"), _Val) : _STD format(_STATICALLY_WIDEN(_CharT, "{:%Y} is not a valid year"), _Val)); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const weekday& _Val) { return _Os << (_Val.ok() ? _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{:%a}"), _Val) : _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{} is not a valid weekday"), _Val.c_encoding())); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const weekday_indexed& _Val) { const auto _Idx = _Val.index(); return _Os << (_Idx >= 1 && _Idx <= 5 ? _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}[{}]"), _Val.weekday(), _Idx) : _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}[{} is not a valid index]"), _Val.weekday(), _Idx)); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const weekday_last& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}[last]"), _Val.weekday()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const month_day& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}"), _Val.month(), _Val.day()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const month_day_last& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/last"), _Val.month()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const month_weekday& _Val) { return _Os << _STD format( _Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}"), _Val.month(), _Val.weekday_indexed()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const month_weekday_last& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}"), _Val.month(), _Val.weekday_last()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const year_month& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}"), _Val.year(), _Val.month()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const year_month_day& _Val) { return _Os << (_Val.ok() ? _STD format(_STATICALLY_WIDEN(_CharT, "{:%F}"), _Val) : _STD format(_STATICALLY_WIDEN(_CharT, "{:%F} is not a valid date"), _Val)); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const year_month_day_last& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}"), _Val.year(), _Val.month_day_last()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const year_month_weekday& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}/{}"), _Val.year(), _Val.month(), _Val.weekday_indexed()); } template basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& _Os, const year_month_weekday_last& _Val) { return _Os << _STD format( _Os.getloc(), _STATICALLY_WIDEN(_CharT, "{}/{}/{}"), _Val.year(), _Val.month(), _Val.weekday_last()); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const hh_mm_ss<_Duration>& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{:%T}"), _Val); } #pragma warning(push) #pragma warning(disable : 4365) // 'argument': conversion from 'char' to 'const wchar_t', signed/unsigned mismatch template _NODISCARD decltype(auto) _Widen_string(const string& _Str) { if constexpr (is_same_v<_CharT, char>) { return _Str; } else { return wstring{_Str.begin(), _Str.end()}; // TRANSITION, should probably use ctype::widen } } #pragma warning(pop) template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const sys_info& _Val) { return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "begin: {}, end: {}, offset: {}, save: {}, abbrev: {}"), // _Val.begin, _Val.end, _Val.offset, _Val.save, _Widen_string<_CharT>(_Val.abbrev)); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const local_info& _Val) { switch (_Val.result) { case local_info::unique: return _Os << _STD format(_Os.getloc(), // _STATICALLY_WIDEN(_CharT, "result: unique, first: ({})"), // _Val.first); case local_info::nonexistent: return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "result: nonexistent, first: ({}), second: ({})"), // _Val.first, _Val.second); case local_info::ambiguous: return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "result: ambiguous, first: ({}), second: ({})"), // _Val.first, _Val.second); default: return _Os << _STD format(_Os.getloc(), // _STATICALLY_WIDEN(_CharT, "result: {}, first: ({}), second: ({})"), // _Val.result, _Val.first, _Val.second); } } template // clang-format off requires (!treat_as_floating_point_v && _Duration{1} < days{1}) basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const sys_time<_Duration>& _Val) { // clang-format on const auto _Dp = _CHRONO floor(_Val); return _Os << _STD format( _Os.getloc(), _STATICALLY_WIDEN(_CharT, "{} {}"), year_month_day{_Dp}, hh_mm_ss{_Val - _Dp}); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const sys_days& _Val) { return _Os << year_month_day{_Val}; } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const utc_time<_Duration>& _Val) { return _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:%F %T}"), _Val); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const tai_time<_Duration>& _Val) { return _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:%F %T}"), _Val); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const gps_time<_Duration>& _Val) { return _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:%F %T}"), _Val); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const file_time<_Duration>& _Val) { return _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:%F %T}"), _Val); } template basic_ostream<_CharT, _Traits>& operator<<(basic_ostream<_CharT, _Traits>& _Os, const local_time<_Duration>& _Val) { return _Os << sys_time<_Duration>{_Val.time_since_epoch()}; } template basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& _Os, const _Local_time_format_t<_Duration>& _Val) { // Doesn't appear in the Standard, but allowed by N4885 [global.functions]/2. // Implements N4885 [time.zone.zonedtime.nonmembers]/2 for zoned_time. return _Os << _STD format(_Os.getloc(), _STATICALLY_WIDEN(_CharT, "{:%F %T %Z}"), _Val); } template basic_ostream<_CharT, _Traits>& operator<<( basic_ostream<_CharT, _Traits>& _Os, const zoned_time<_Duration, _TimeZonePtr>& _Val) { const auto _Info = _Val.get_info(); return _Os << _Local_time_format_t<_Duration>{_Val.get_local_time(), &_Info.abbrev}; } template struct _Chrono_formatter { _Chrono_formatter() = default; explicit _Chrono_formatter(const basic_string_view<_CharT> _Time_zone_abbreviation_) : _Time_zone_abbreviation{_Time_zone_abbreviation_} {} template _NODISCARD auto _Parse(basic_format_parse_context<_CharT>& _Parse_ctx) { _Chrono_specs_setter<_CharT, basic_format_parse_context<_CharT>> _Callback{_Specs, _Parse_ctx}; const auto _It = _Parse_chrono_format_specs(_Parse_ctx._Unchecked_begin(), _Parse_ctx._Unchecked_end(), _Callback); const auto _Res_iter = _Parse_ctx.begin() + (_It - _Parse_ctx._Unchecked_begin()); if (_It != _Parse_ctx._Unchecked_end() && *_It != '}') { _THROW(format_error("Missing '}' in format string.")); } if constexpr (_Is_specialization_v<_Ty, duration>) { if constexpr (!treat_as_floating_point_v) { if (_Specs._Precision != -1) { _THROW(format_error("Precision specification invalid for chrono::duration type with " "integral representation type, see N4885 [time.format]/1.")); } } } else { if (_Specs._Precision != -1) { _THROW(format_error("Precision specification invalid for non-chrono::duration type, " "see N4885 [time.format]/1.")); } } for (const auto& _Spec : _Specs._Chrono_specs_list) { if (_Spec._Type != '\0' && !_Is_valid_type<_Ty>(_Spec._Type)) { _THROW(format_error("Invalid type.")); } _Check_modifier(_Spec._Type, _Spec._Modifier); } return _Res_iter; } static void _Check_modifier(const char _Type, const char _Modifier) { if (_Modifier == '\0') { return; } enum _Allowed_bit : uint8_t { _E_mod = 1, _O_mod = 2, _EO_mod = _E_mod | _O_mod }; struct _Table_entry { char _Type; _Allowed_bit _Allowed; }; static constexpr _Table_entry _Table[] = { {'c', _E_mod}, {'C', _E_mod}, {'d', _O_mod}, {'e', _O_mod}, {'H', _O_mod}, {'I', _O_mod}, {'m', _O_mod}, {'M', _O_mod}, {'S', _O_mod}, {'u', _O_mod}, {'U', _O_mod}, {'V', _O_mod}, {'w', _O_mod}, {'W', _O_mod}, {'x', _E_mod}, {'X', _E_mod}, {'y', _EO_mod}, {'Y', _E_mod}, {'z', _EO_mod}, }; const _Allowed_bit _Mod = _Modifier == 'E' ? _E_mod : _O_mod; if (auto _It = _RANGES find(_Table, _Type, &_Table_entry::_Type); _It != _STD end(_Table)) { if (_It->_Allowed & _Mod) { return; } } _THROW(format_error("Incompatible modifier for type")); } template _NODISCARD static constexpr bool _Is_valid_type(const char _Type) noexcept { if constexpr (_Is_specialization_v<_Ty, duration>) { return _Type == 'j' || _Type == 'q' || _Type == 'Q' || _Is_valid_type>(_Type); } else if constexpr (is_same_v<_Ty, day>) { return _Type == 'd' || _Type == 'e'; } else if constexpr (is_same_v<_Ty, month>) { return _Type == 'b' || _Type == 'B' || _Type == 'h' || _Type == 'm'; } else if constexpr (is_same_v<_Ty, year>) { return _Type == 'Y' || _Type == 'y' || _Type == 'C'; } else if constexpr (_Is_any_of_v<_Ty, weekday, weekday_indexed, weekday_last>) { return _Type == 'a' || _Type == 'A' || _Type == 'u' || _Type == 'w'; } else if constexpr (_Is_any_of_v<_Ty, month_day, month_day_last>) { return _Type == 'j' || _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (_Is_any_of_v<_Ty, month_weekday, month_weekday_last>) { return _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (is_same_v<_Ty, year_month>) { return _Type == 'g' || _Type == 'G' || _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (_Is_any_of_v<_Ty, year_month_day, year_month_day_last, year_month_weekday, year_month_weekday_last>) { return _Type == 'D' || _Type == 'F' || _Type == 'g' || _Type == 'G' || _Type == 'j' || _Type == 'U' || _Type == 'V' || _Type == 'W' || _Is_valid_type(_Type) || _Is_valid_type(_Type) || _Is_valid_type(_Type) || _Is_valid_type(_Type); } else if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { return _Type == 'H' || _Type == 'I' || _Type == 'M' || _Type == 'S' || _Type == 'r' || _Type == 'R' || _Type == 'T' || _Type == 'p'; } else if constexpr (_Is_any_of_v<_Ty, sys_info, local_info>) { return _Type == 'z' || _Type == 'Z'; } else if constexpr (_Is_specialization_v<_Ty, time_point>) { if constexpr (!is_same_v) { if (_Type == 'z' || _Type == 'Z') { return true; } } return _Type == 'c' || _Type == 'x' || _Type == 'X' || _Is_valid_type(_Type) || _Is_valid_type>(_Type); } else if constexpr (_Is_specialization_v<_Ty, _Local_time_format_t>) { return _Type == 'z' || _Type == 'Z' || _Is_valid_type(_Type); } else { static_assert(_Always_false<_Ty>, "should be unreachable"); } } template _NODISCARD auto _Write(_FormatContext& _FormatCtx, const _Ty& _Val, const tm& _Time) { basic_ostringstream<_CharT> _Stream; if (_Specs._Chrono_specs_list.empty()) { _Stream << _Val; // N4885 [time.format]/6 } else { _Stream.imbue(_FormatCtx.locale()); if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { if (_Val.is_negative()) { _Stream << _CharT{'-'}; } } else if constexpr (_Is_specialization_v<_Ty, duration>) { if (_Val < _Ty::zero()) { _Stream << _CharT{'-'}; } } for (const auto& _Spec : _Specs._Chrono_specs_list) { if (_Spec._Lit_char != _CharT{'\0'}) { _Stream << _Spec._Lit_char; continue; } // We need to manually do certain writes, either because the specification is different from // put_time or custom logic is needed. if (_Custom_write(_Stream, _Spec, _Time, _Val)) { continue; } _Validate_specifiers(_Spec, _Val); _CharT _Fmt_str[4]; _Stream << _STD put_time<_CharT>(&_Time, _Fmt_string(_Spec, _Fmt_str)); } } int _Estimated_width = -1; (void) _Measure_string_prefix(_Stream.view(), _Estimated_width); return _Write_aligned(_STD move(_FormatCtx.out()), _Estimated_width, _Specs, _Fmt_align::_Left, [&](auto _Out) { return _Fmt_write(_STD move(_Out), _Stream.view()); }); } // This echoes the functionality of put_time, but is able to handle invalid dates (when !ok()) since the // Standard mandates that invalid dates still be formatted properly. For example, put_time isn't able to handle // a tm_mday of 40, but format("{:%d}", day{40}) should return "40" and operator<< for day prints // "40 is not a valid day". template bool _Custom_write( basic_ostream<_CharT>& _Os, const _Chrono_spec<_CharT>& _Spec, const tm& _Time, const _Ty& _Val) { if constexpr (is_same_v<_Ty, local_info>) { if (_Val.result != local_info::unique) { _THROW(format_error("Cannot print non-unique local_info")); } } const auto _Year = _Time.tm_year + 1900; const auto _Month = _Time.tm_mon + 1; const bool _Has_modifier = _Spec._Modifier != '\0'; switch (_Spec._Type) { case 'd': // Print days as a decimal, even if invalid. case 'e': // Most months have a proper last day, but February depends on the year. if constexpr (is_same_v<_Ty, month_day_last>) { if (_Val.month() == February) { _THROW(format_error("Cannot print the last day of February without a year")); } if (!_Val.ok()) { return false; } } if (_Has_modifier) { return false; } if (_Time.tm_mday < 10) { _Os << (_Spec._Type == 'd' ? _CharT{'0'} : _CharT{' '}); } _Os << _Time.tm_mday; return true; case 'g': case 'G': if constexpr (is_same_v<_Ty, year_month>) { if (_Val.month() == January || _Val.month() == December) { _THROW(format_error( "The ISO week-based year for a year_month of January or December is ambiguous.")); } if (!_Val.ok()) { _THROW(format_error("The ISO week-based year for an out-of-bounds year_month is ambiguous.")); } const char _Gregorian_type = _Spec._Type == 'g' ? 'y' : 'Y'; _CharT _Fmt_str[4]; _Os << _STD put_time(&_Time, _Fmt_string({._Type = _Gregorian_type}, _Fmt_str)); return true; } return false; case 'r': // put_time uses _Strftime in order to bypass reference-counting that locale uses. This function // takes the locale information by pointer, but the pointer (from _Gettnames) returns a copy. // _Strftime delegates to other functions but eventually (for the C locale) has the %r specifier // rewritten. It checks for the locale by comparing pointers, which do not compare equal as we have // a copy of the pointer instead of the original. Therefore, we replace %r for the C locale // ourselves. if (_Os.getloc() == locale::classic()) { _Os << _STD put_time(&_Time, _STATICALLY_WIDEN(_CharT, "%I:%M:%S %p")); return true; } return false; case 'j': if constexpr (_Is_specialization_v<_Ty, duration>) { _Os << _STD abs(_CHRONO duration_cast(_Val).count()); return true; } return false; case 'q': if constexpr (_Is_specialization_v<_Ty, duration>) { _Write_unit_suffix(_Os); } return true; case 'Q': if constexpr (_Is_specialization_v<_Ty, duration>) { _Os << _STD abs(_Val.count()); } return true; case 'm': // Print months as a decimal, even if invalid. if (_Has_modifier) { return false; } if (_Month < 10) { _Os << _CharT{'0'}; } _Os << _Month; return true; case 'Y': // Print years as a decimal, even if invalid. if (_Has_modifier) { return false; } if (_Year < 0) { _Os << _CharT{'-'}; } _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:04}"), _STD abs(_Year)); return true; case 'y': // Print the two-digit year as a decimal, even if invalid. if (_Has_modifier) { return false; } _Os << _STD format( _STATICALLY_WIDEN(_CharT, "{:02}"), _Time_parse_fields::_Decompose_year(_Year).second); return true; case 'C': // Print the century as a decimal, even if invalid. if (_Has_modifier) { return false; } if (_Year < 0) { _Os << _CharT{'-'}; } _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{:02}"), _STD abs(_Time_parse_fields::_Decompose_year(_Year).first) / 100); return true; case 'F': // Print YMD even if invalid. _Custom_write(_Os, {._Type = 'Y'}, _Time, _Val); _Os << _CharT{'-'}; _Custom_write(_Os, {._Type = 'm'}, _Time, _Val); _Os << _CharT{'-'}; _Custom_write(_Os, {._Type = 'd'}, _Time, _Val); return true; case 'D': // Print YMD even if invalid. _Custom_write(_Os, {._Type = 'm'}, _Time, _Val); _Os << _CharT{'/'}; _Custom_write(_Os, {._Type = 'd'}, _Time, _Val); _Os << _CharT{'/'}; _Custom_write(_Os, {._Type = 'y'}, _Time, _Val); return true; case 'T': // Alias for %H:%M:%S but we need to rewrite %S to display fractions of a second. _Validate_specifiers({._Type = 'H'}, _Val); _Os << _STD put_time(&_Time, _STATICALLY_WIDEN(_CharT, "%H:%M:")); [[fallthrough]]; case 'S': if (_Has_modifier) { return false; } _Write_seconds(_Os, _Val); return true; case 'Z': if constexpr (is_same_v<_Ty, sys_info>) { _Os << _Widen_string<_CharT>(_Val.abbrev); } else if constexpr (is_same_v<_Ty, local_info>) { _Os << _Widen_string<_CharT>(_Val.first.abbrev); } else if constexpr (_Is_specialization_v<_Ty, _Local_time_format_t>) { if (_Val._Abbrev == nullptr) { _THROW(format_error("Cannot print local-time-format-t with null abbrev.")); } _Os << _Widen_string<_CharT>(*_Val._Abbrev); } else { _Os << _Time_zone_abbreviation; } return true; case 'z': { hh_mm_ss _Offset; if constexpr (is_same_v<_Ty, sys_info>) { _Offset = hh_mm_ss{_Val.offset}; } else if constexpr (is_same_v<_Ty, local_info>) { _Offset = hh_mm_ss{_Val.first.offset}; } else if constexpr (_Is_specialization_v<_Ty, _Local_time_format_t>) { if (_Val._Offset_sec == nullptr) { _THROW(format_error("Cannot print local-time-format-t with null offset_sec.")); } _Offset = hh_mm_ss{*_Val._Offset_sec}; } else { _Offset = hh_mm_ss{}; } const auto _Sign = _Offset.is_negative() ? _CharT{'-'} : _CharT{'+'}; const auto _Separator = _Has_modifier ? _STATICALLY_WIDEN(_CharT, ":") : _STATICALLY_WIDEN(_CharT, ""); _Os << _STD format(_STATICALLY_WIDEN(_CharT, "{}{:02}{}{:02}"), _Sign, _Offset.hours().count(), _Separator, _Offset.minutes().count()); return true; } default: return false; } } template static void _Validate_specifiers(const _Chrono_spec<_CharT>& _Spec, const _Ty& _Val) { // clang-format off if constexpr (_Is_specialization_v<_Ty, duration> || is_same_v<_Ty, sys_info> || _Is_specialization_v<_Ty, time_point> || _Is_specialization_v<_Ty, _Local_time_format_t>) { return; } // clang-format on if constexpr (_Is_specialization_v<_Ty, hh_mm_ss>) { if (_Spec._Type == 'H' && _Val.hours() >= hours{24}) { _THROW(format_error("Cannot localize hh_mm_ss with an absolute value of 24 hours or more.")); } return; } constexpr bool _Is_ymd = _Is_any_of_v<_Ty, year_month_day, year_month_day_last, year_month_weekday, year_month_weekday_last>; const auto _Validate = [&] { switch (_Spec._Type) { case 'a': case 'A': case 'u': case 'w': if constexpr (_Is_any_of_v<_Ty, weekday, weekday_last>) { return _Val.ok(); } else if constexpr (_Is_any_of_v<_Ty, weekday_indexed, year_month_weekday, year_month_weekday_last>) { return _Val.weekday().ok(); } else if constexpr (is_same_v<_Ty, month_weekday>) { return _Val.weekday_indexed().weekday().ok(); } else if constexpr (is_same_v<_Ty, month_weekday_last>) { return _Val.weekday_last().ok(); } else if constexpr (_Is_any_of_v<_Ty, year_month_day, year_month_day_last>) { return _Val.ok(); } break; case 'b': case 'B': case 'h': case 'm': if constexpr (is_same_v<_Ty, month>) { return _Val.ok(); } else if constexpr (_Is_any_of_v<_Ty, month_day, month_day_last, month_weekday, month_weekday_last, year_month> || _Is_ymd) { return _Val.month().ok(); } break; case 'C': case 'y': case 'Y': if constexpr (is_same_v<_Ty, year>) { return _Val.ok(); } else if constexpr (_Is_any_of_v<_Ty, year_month> || _Is_ymd) { return _Val.year().ok(); } break; case 'd': case 'e': if constexpr (_Is_any_of_v<_Ty, day, month_day_last>) { return _Val.ok(); } else if constexpr (is_same_v<_Ty, month_day>) { return _Val.day().ok(); } else if constexpr (_Is_ymd) { const year_month_day& _Ymd{_Val}; return _Ymd.day().ok(); } break; case 'D': case 'F': if constexpr (_Has_ok<_Ty>) { return _Val.ok(); } break; case 'j': if constexpr (is_same_v<_Ty, month_day>) { if (_Val.month() > February) { _THROW(format_error("The day of year for a month_day past February is ambiguous.")); } return true; } else if constexpr (is_same_v<_Ty, month_day_last>) { if (_Val.month() >= February) { _THROW( format_error("The day of year for a month_day_last other than January is ambiguous")); } return true; } else if constexpr (_Is_ymd) { return _Val.ok(); } break; case 'g': case 'G': case 'U': case 'V': case 'W': if constexpr (_Is_ymd) { return _Val.ok(); } break; default: if constexpr (_Has_ok<_Ty>) { return _Val.ok(); } return true; } _STL_INTERNAL_CHECK(false); return false; }; if (!_Validate()) { _THROW(format_error("Cannot localize out-of-bounds time point.")); } } _NODISCARD static const _CharT* _Fmt_string(const _Chrono_spec<_CharT>& _Spec, _CharT (&_Fmt_str)[4]) { size_t _Next_idx = 0; _Fmt_str[_Next_idx++] = _CharT{'%'}; if (_Spec._Modifier != '\0') { _Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Modifier); } _Fmt_str[_Next_idx++] = static_cast<_CharT>(_Spec._Type); _Fmt_str[_Next_idx] = _CharT{'\0'}; return _Fmt_str; } _Chrono_format_specs<_CharT> _Specs{}; basic_string_view<_CharT> _Time_zone_abbreviation{}; }; } // namespace chrono template struct _Fill_tm_formatter { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_Ty>(_Parse_ctx); } template auto format(const _Ty& _Val, _FormatContext& _FormatCtx) { return _Impl._Write(_FormatCtx, _Val, _Fill_tm(_Val)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl; }; template struct formatter<_CHRONO duration<_Rep, _Period>, _CharT> : _Fill_tm_formatter<_CHRONO duration<_Rep, _Period>, _CharT> {}; template struct formatter<_CHRONO day, _CharT> // : _Fill_tm_formatter<_CHRONO day, _CharT> {}; template struct formatter<_CHRONO month, _CharT> // : _Fill_tm_formatter<_CHRONO month, _CharT> {}; template struct formatter<_CHRONO year, _CharT> // : _Fill_tm_formatter<_CHRONO year, _CharT> {}; template struct formatter<_CHRONO weekday, _CharT> // : _Fill_tm_formatter<_CHRONO weekday, _CharT> {}; template struct formatter<_CHRONO weekday_indexed, _CharT> // : _Fill_tm_formatter<_CHRONO weekday_indexed, _CharT> {}; template struct formatter<_CHRONO weekday_last, _CharT> // : _Fill_tm_formatter<_CHRONO weekday_last, _CharT> {}; template struct formatter<_CHRONO month_day, _CharT> // : _Fill_tm_formatter<_CHRONO month_day, _CharT> {}; template struct formatter<_CHRONO month_day_last, _CharT> // : _Fill_tm_formatter<_CHRONO month_day_last, _CharT> {}; template struct formatter<_CHRONO month_weekday, _CharT> // : _Fill_tm_formatter<_CHRONO month_weekday, _CharT> {}; template struct formatter<_CHRONO month_weekday_last, _CharT> // : _Fill_tm_formatter<_CHRONO month_weekday_last, _CharT> {}; template struct formatter<_CHRONO year_month, _CharT> // : _Fill_tm_formatter<_CHRONO year_month, _CharT> {}; template struct formatter<_CHRONO year_month_day, _CharT> // : _Fill_tm_formatter<_CHRONO year_month_day, _CharT> {}; template struct formatter<_CHRONO year_month_day_last, _CharT> // : _Fill_tm_formatter<_CHRONO year_month_day_last, _CharT> {}; template struct formatter<_CHRONO year_month_weekday, _CharT> // : _Fill_tm_formatter<_CHRONO year_month_weekday, _CharT> {}; template struct formatter<_CHRONO year_month_weekday_last, _CharT> : _Fill_tm_formatter<_CHRONO year_month_weekday_last, _CharT> {}; template struct formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT> : _Fill_tm_formatter<_CHRONO hh_mm_ss<_CHRONO duration<_Rep, _Period>>, _CharT> {}; template struct formatter<_CHRONO sys_info, _CharT> // : _Fill_tm_formatter<_CHRONO sys_info, _CharT> {}; template struct formatter<_CHRONO local_info, _CharT> // : _Fill_tm_formatter<_CHRONO local_info, _CharT> {}; template struct formatter<_CHRONO sys_time<_Duration>, _CharT> { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_CHRONO sys_time<_Duration>>(_Parse_ctx); } template auto format(const _CHRONO sys_time<_Duration>& _Val, _FormatContext& _FormatCtx) { return _Impl._Write(_FormatCtx, _Val, _Fill_tm(_Val)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")}; }; template struct formatter<_CHRONO utc_time<_Duration>, _CharT> { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_CHRONO utc_time<_Duration>>(_Parse_ctx); } template auto format(const _CHRONO utc_time<_Duration>& _Val, _FormatContext& _FormatCtx) { const auto _Sys = _CHRONO utc_clock::to_sys(_Val); return _Impl._Write(_FormatCtx, _Val, _Fill_tm(_Sys)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")}; }; template struct formatter<_CHRONO tai_time<_Duration>, _CharT> { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_CHRONO tai_time<_Duration>>(_Parse_ctx); } template auto format(const _CHRONO tai_time<_Duration>& _Val, _FormatContext& _FormatCtx) { using namespace chrono; using _Common = common_type_t<_Duration, days>; // slightly optimize by performing conversion at compile time constexpr _Common _Offset{sys_days{year{1970} / January / 1} - sys_days{year{1958} / January / 1}}; const auto _Sys = sys_time<_Duration>{_Val.time_since_epoch()} - _Offset; return _Impl._Write(_FormatCtx, _Val, _Fill_tm(_Sys)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "TAI")}; }; template struct formatter<_CHRONO gps_time<_Duration>, _CharT> { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_CHRONO gps_time<_Duration>>(_Parse_ctx); } template auto format(const _CHRONO gps_time<_Duration>& _Val, _FormatContext& _FormatCtx) { using namespace chrono; using _Common = common_type_t<_Duration, days>; // slightly optimize by performing conversion at compile time constexpr _Common _Offset{sys_days{year{1980} / January / Sunday[1]} - sys_days{year{1970} / January / 1}}; const auto _Sys = sys_time<_Duration>{_Val.time_since_epoch()} + _Offset; return _Impl._Write(_FormatCtx, _Val, _Fill_tm(_Sys)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "GPS")}; }; template struct formatter<_CHRONO file_time<_Duration>, _CharT> { auto parse(basic_format_parse_context<_CharT>& _Parse_ctx) { return _Impl.template _Parse<_CHRONO file_time<_Duration>>(_Parse_ctx); } template auto format(const _CHRONO file_time<_Duration>& _Val, _FormatContext& _FormatCtx) { const auto _Utc = _CHRONO file_clock::to_utc(_Val); const auto _Sys = _CHRONO utc_clock::to_sys(_Utc); return _Impl._Write(_FormatCtx, _Utc, _Fill_tm(_Sys)); } private: _CHRONO _Chrono_formatter<_CharT> _Impl{_STATICALLY_WIDEN(_CharT, "UTC")}; }; template struct formatter<_CHRONO local_time<_Duration>, _CharT> // : _Fill_tm_formatter<_CHRONO local_time<_Duration>, _CharT> {}; template struct formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> : _Fill_tm_formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> {}; template struct formatter<_CHRONO zoned_time<_Duration, _TimeZonePtr>, _CharT> : formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT> { template auto format(const _CHRONO zoned_time<_Duration, _TimeZonePtr>& _Val, _FormatContext& _FormatCtx) { using _Mybase = formatter<_CHRONO _Local_time_format_t<_Duration>, _CharT>; const auto _Info = _Val.get_info(); return _Mybase::format({_Val.get_local_time(), &_Info.abbrev, &_Info.offset}, _FormatCtx); } }; namespace chrono { template _NODISCARD string nonexistent_local_time::_Make_string(const local_time<_Duration>& _Tp, const local_info& _Info) { ostringstream _Os; _Os << _Tp << " is in a gap between\n" << local_seconds{_Info.first.end.time_since_epoch()} + _Info.first.offset << ' ' << _Info.first.abbrev << " and\n" << local_seconds{_Info.second.begin.time_since_epoch()} + _Info.second.offset << ' ' << _Info.second.abbrev << " which are both equivalent to\n" << _Info.first.end << " UTC"; return _STD move(_Os).str(); } template _NODISCARD string ambiguous_local_time::_Make_string(const local_time<_Duration>& _Tp, const local_info& _Info) { ostringstream _Os; _Os << _Tp << " is ambiguous. It could be\n" << _Tp << ' ' << _Info.first.abbrev << " == " << _Tp - _Info.first.offset << " UTC or\n" << _Tp << ' ' << _Info.second.abbrev << " == " << _Tp - _Info.second.offset << " UTC"; return _STD move(_Os).str(); } } // namespace chrono #endif // __cpp_lib_format template _NODISCARD bool _To_xtime_10_day_clamped(_CSTD xtime& _Xt, const _CHRONO duration<_Rep, _Period>& _Rel_time) noexcept( is_arithmetic_v<_Rep>) { // Convert duration to xtime, maximum 10 days from now, returns whether clamping occurred. // If clamped, timeouts will be transformed into spurious non-timeout wakes, due to ABI restrictions where // the other side of the DLL boundary overflows int32_t milliseconds. // Every function calling this one is TRANSITION, ABI constexpr _CHRONO nanoseconds _Ten_days{_CHRONO hours{24} * 10}; constexpr _CHRONO duration _Ten_days_d{_Ten_days}; _CHRONO nanoseconds _Tx0 = _CHRONO system_clock::now().time_since_epoch(); const bool _Clamped = _Ten_days_d < _Rel_time; if (_Clamped) { _Tx0 += _Ten_days; } else { _Tx0 += _CHRONO duration_cast<_CHRONO nanoseconds>(_Rel_time); } const auto _Whole_seconds = _CHRONO duration_cast<_CHRONO seconds>(_Tx0); _Xt.sec = _Whole_seconds.count(); _Tx0 -= _Whole_seconds; _Xt.nsec = static_cast(_Tx0.count()); return _Clamped; } inline namespace literals { inline namespace chrono_literals { _NODISCARD constexpr _CHRONO hours operator"" h(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO hours(_Val); } _NODISCARD constexpr _CHRONO duration> operator"" h(long double _Val) noexcept /* strengthened */ { return _CHRONO duration>(_Val); } _NODISCARD constexpr _CHRONO minutes(operator"" min)(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO minutes(_Val); } _NODISCARD constexpr _CHRONO duration>(operator"" min)(long double _Val) noexcept /* strengthened */ { return _CHRONO duration>(_Val); } _NODISCARD constexpr _CHRONO seconds operator"" s(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO seconds(_Val); } _NODISCARD constexpr _CHRONO duration operator"" s(long double _Val) noexcept /* strengthened */ { return _CHRONO duration(_Val); } _NODISCARD constexpr _CHRONO milliseconds operator"" ms(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO milliseconds(_Val); } _NODISCARD constexpr _CHRONO duration operator"" ms(long double _Val) noexcept /* strengthened */ { return _CHRONO duration(_Val); } _NODISCARD constexpr _CHRONO microseconds operator"" us(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO microseconds(_Val); } _NODISCARD constexpr _CHRONO duration operator"" us(long double _Val) noexcept /* strengthened */ { return _CHRONO duration(_Val); } _NODISCARD constexpr _CHRONO nanoseconds operator"" ns(unsigned long long _Val) noexcept /* strengthened */ { return _CHRONO nanoseconds(_Val); } _NODISCARD constexpr _CHRONO duration operator"" ns(long double _Val) noexcept /* strengthened */ { return _CHRONO duration(_Val); } #if _HAS_CXX20 _NODISCARD constexpr _CHRONO day operator"" d(unsigned long long _Day) noexcept { return _CHRONO day{static_cast(_Day)}; } _NODISCARD constexpr _CHRONO year operator"" y(unsigned long long _Year) noexcept { return _CHRONO year{static_cast(_Year)}; } #endif // _HAS_CXX20 } // namespace chrono_literals } // namespace literals namespace chrono { using namespace literals::chrono_literals; } // namespace chrono #undef _STATICALLY_WIDEN _STD_END #pragma pop_macro("new") _STL_RESTORE_CLANG_WARNINGS #pragma warning(pop) #pragma pack(pop) #endif // _STL_COMPILER_PREPROCESSOR #endif // _CHRONO_ c++-annotations-13.02.01/yo/namespaces/filesystem/examples/tosys/demo.cc0000664000175000017500000000275114771010720025017 0ustar frankfrank#include #include #include #include using namespace std; using namespace chrono; using namespace filesystem; using namespace FBB; int main(int argc, char **argv) try { error_code ec; // comment out the 2nd clock_time_conversion template and you get the // first: time_t seconds = system_clock::to_time_t( clock_time_conversion{}( system_clock::now() ) ); auto syspoint = system_clock::now(); auto filepoint = clock_time_conversion (syspoint); // cout << syspoint.count() << '\n' << // filepoint.count() << '\n'; return 0; cout << put_time(localtime(&seconds), "%c") << '\n'; auto sysTime = file_clock::to_sys(file_clock::now()); time_t sysSecs = system_clock::to_time_t(sysTime); cout << put_time(localtime(&sysSecs), "%c") << '\n'; // seconds = system_clock::to_time_t( // clock_time_conversion{}( // file_clock::now() // ) // ); // // cout << put_time(localtime(&seconds), "%c") << '\n'; } catch (exception const &exc) { cout << exc.what() << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/tosys/clocktimeconv0000664000175000017500000000436614735537670026375 0ustar frankfrank#ifndef INCLUDED_CLOCKTIMECONV_ #define INCLUDED_CLOCKTIMECONV_ // previously included by demo.cc. Not needed anymore #include namespace std { namespace chrono { template struct clock_time_conversion {}; template struct clock_time_conversion { template [[nodiscard]] time_point operator() (time_point const & timePoint) const noexcept(is_arithmetic::value) // strengthened { std::cout << "clock_time_conversion 1\n"; return timePoint; } }; template <> struct clock_time_conversion { template [[nodiscard]] sys_time operator()( sys_time const &timePoint) const noexcept(is_arithmetic::value) // strengthened { std::cout << "clock_time_conversion 2\n"; return timePoint; } }; // No utc_clock in chrono. // ======================= // //template <> //struct clock_time_conversion { // template // [[nodiscard]] utc_time operator()(const utc_time& timePoint) const // noexcept(is_arithmetic_v) /* strengthened */ { // return timePoint; // } //}; // //// [time.clock.cast.sys.utc] // //template <> //struct clock_time_conversion { // template // [[nodiscard]] utc_time> operator()(const sys_time& _Sys_time) const { // return utc_clock::from_sys(_Sys_time); // } //}; // //template <> //struct clock_time_conversion { // template // [[nodiscard]] sys_time> operator()(const utc_time& _Utc_time) const { // return utc_clock::to_sys(_Utc_time); // } //}; } } #endif c++-annotations-13.02.01/yo/namespaces/filesystem/examples/perms.cc0000664000175000017500000000124114771010720024031 0ustar frankfrank#include #include using namespace std; using namespace filesystem; int main() { path perm{ "perms.cc" }; auto stat = status(perm); cout << oct << "permissions: " << static_cast(stat.permissions()) << '\n'; permissions(perm, perms::owner_write, perm_options::remove); stat = status(perm); cout << oct << "permissions: " << static_cast(stat.permissions()) << '\n'; permissions(perm, perms::owner_write, perm_options::add); stat = status(perm); cout << oct << "permissions: " << static_cast(stat.permissions()) << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/statusknown.cc0000664000175000017500000000302314771010720025303 0ustar frankfrank#include #include #include using namespace std; using namespace filesystem; //demo namespace { std::unordered_map statusMap = { { file_type::not_found, "an unknown file" }, { file_type::none, "not yet or erroneously evaluated " "file type" }, { file_type::regular, "a regular file" }, { file_type::directory, "a directory" }, { file_type::symlink, "a symbolic link" }, { file_type::block, "a block device" }, { file_type::character, "a character device" }, { file_type::fifo, "a named pipe" }, { file_type::socket, "a socket file" }, { file_type::unknown, "an unknown file type" } }; } int main() { cout << oct; string line; while (true) { cout << "enter the name of a file system entry: "; if (not getline(cin, line) or line.empty()) break; path entry{ line }; error_code ec; file_status stat = status(entry, ec); if (not status_known(stat)) { cout << "status of " << entry << " is unknown. " "Ec = " << ec << '\n'; continue; } cout << "status of " << entry << ": type = " << statusMap[stat.type()] << ", permissions: " << static_cast(stat.permissions()) << '\n'; } } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/recurs.cc0000664000175000017500000000072614771010720024215 0ustar frankfrank#include #include using namespace std; using namespace filesystem; //demo int main() { recursive_directory_iterator base{ "/var/log", directory_options::skip_permission_denied }; for (auto entry = base, endIt = end(base); entry != endIt; ++entry) { cout << entry.depth() << ": " << *entry << '\n'; if (entry.depth() == 1) entry.disable_recursion_pending(); } } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/path.cc0000664000175000017500000000105114771010720023636 0ustar frankfrank#include #include using namespace std; using namespace filesystem; int main() { path p{ "/abs/olu/te.cc" }; p.replace_filename("this/part"); cout << "Current path is " << current_path() << '\n' << "Absolute path for " << p << " is " << absolute(p) << '\n'; cout << absolute("tmp/filename") << '\n'; p /= "extension"; cout << p << '\n'; cout << path{}.append("entry") << '\n'; cout << p.replace_extension("out") << '\n'; cout << p.replace_extension(".out") << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/absolute.cc0000664000175000017500000000041614771010720024524 0ustar frankfrank#include #include using namespace std; using namespace filesystem; int main() { path p{ "absolute.cc" }; cout << "Current path is " << current_path() << '\n' << "Absolute path for " << p << " is " << absolute(p) << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/breadth.cc0000664000175000017500000000217414771010720024322 0ustar frankfrank#include #include #include using namespace std; using namespace filesystem; //code void breadth(path const &dir) // starting dir. { vector level{ dir }; // currently processed level while (not level.empty()) // process all its dirs. { vector next; // dirs of the next level for (auto const &dir: level) // visit all dirs at this level { cout << "At " << dir << '\n'; // at each dir: visit all entries for (auto const &entry: directory_iterator{ dir }) { if (entry.is_directory()) // store all dirs at the current next.push_back(entry); // level else // or process its non-dir entry cout << " entry: " << entry << '\n'; } } level = next; // continue at the next level, } // which eventually won't exist } //= int main() { breadth("/home/frank/tmp"); } c++-annotations-13.02.01/yo/namespaces/filesystem/examples/lastwritetime.cc0000664000175000017500000000311414771010720025601 0ustar frankfrank#include #include #include using namespace std; using namespace filesystem; using namespace chrono; // t1; // 1'573'443'680 '202'029'390 // -4'864'220'319 '797'970'245 // // t0: // 1'573'443'602 '813'273'869 // -4'864'220'397 '186'725'741 // 6'437'663'999 //demo int main() { // get `now' according to the system_clock and // the file_clock, compute their difference in // nanoseconds and seconds: auto systemNow = system_clock::now().time_since_epoch(); auto fileNow = file_clock::now().time_since_epoch(); duration diffNano = systemNow - fileNow; time_t diff = diffNano.count() / 1'000'000'000; cout << "system_clock now: " << systemNow.count() << "\n" "file_clock now: " << fileNow.count() << "\n" "difference (nano): " << diffNano.count() << "\n" "difference (secs): " << diff << '\n'; auto lwt = last_write_time("lastwritetime.cc").time_since_epoch(); time_t seconds = diff + system_clock::to_time_t( time_point{ nanoseconds(lwt) } ); cout << "lastwritetime.cc's time: " << put_time(gmtime(&seconds), "%c") << '\n'; seconds = system_clock::to_time_t(time_point{ diffNano }); cout << "file_clock's epoch time expressed using the system_clock:\n" " " << put_time(gmtime(&seconds), "%c") << "\n" "same, merely using the difference in `now' clock-seconds:\n" " " << put_time(gmtime(&diff), "%c") << '\n'; } //= c++-annotations-13.02.01/yo/namespaces/filesystem/examples/direntry.cc0000664000175000017500000000110014771010720024535 0ustar frankfrank#include #include using namespace std; using namespace filesystem; int main() { directory_entry one; one = directory_entry{ "one" }; one = one; cout << (one == directory_entry( "one" )) << '\n'; directory_iterator("/home")->status(); cout << *directory_iterator{ "/home" } << '\n'; directory_iterator dir; filesystem::begin( directory_iterator{ "/home" } ); filesystem::end( directory_iterator{ "/home" } ); for (directory_entry const &de: directory_iterator{ "/home" }) cout << de << '\n'; } c++-annotations-13.02.01/yo/namespaces/filesystem/spaceinfo.yo0000664000175000017500000000242014735537670023120 0ustar frankfrankEvery existing tt(path) lives in a file system, Sizes of file systems typically are quite large, but there is a limit to their sizes. The size of file systems, the number of bytes that is currently being used and the remaining number of bytes is made available by the function hi(space(_info))hi(available space) tt(space(path const &entry [, error_code &ec])), returning the information about the file system containing tt(entry) in a POD tt(struct space_info). If the tt(error_code) argument is provided then it is cleared if no error occurs, and set to the operating system's error code if an error has occurred. If an error occurs and the tt(error_code) argument was not provided then a tt(filesystem_error) exception is thrown, receiving tt(path) as its first argument and the operating system's error code as its tt(error_code) argument. The returned tt(space_info) has three fields: verb( uintmax_t capacity; // total size in bytes uintmax_t free; // number of free bytes on the file system uintmax_t available; // free bytes for a non-privileged process) If a field cannot be determined it is set to -1 (i.e., the max. value of the type tt(uintmax_t)). The function can be used this way: verbinsert(-s4 //demo examples/spaceinfo.cc) c++-annotations-13.02.01/yo/namespaces/filesystem/filestatus.yo0000664000175000017500000001301714735537670023340 0ustar frankfrankFile system entries (represented by tt(path) objects, cf. section ref(PATH) below), have attributes: permissions (e.g., the owner may modify an entry), and types (like files, directories, and soft-links). Those attributes are defined in the class tt(std::filesystem::file_status). bf(Types): hi(file_type) Defined in the tt((std::filesystem) enum class file_type). centertbl(ll)(\ tline()()\ tr(xcell(2)(std::filesystem::file_type))\ tr(tlc()(Type)tlc()(Meaning))\ tline()()\ rowtwo(not_found (= -1)) (the file system entry was not found+nl() (not considered an error)) rowtwo(none)(the file status has not yet been evaluated+nl() or an error occurred when evaluating the status) rowtwo(regular)(a regular file) rowtwo(directory)(a directory) rowtwo(symlink)(a symbolic link) rowtwo(block)(a block device) rowtwo(character)(a character device) rowtwo(fifo)( a named pipe) rowtwo(socket)(a socket file) rowtwo(unknown)(an unknown file type) tline()()\ ) bf(Permissions): hi(perms) Defined in the tt((std::filesystem) enum class perms). The enumeration's symbols were defined to make their meanings more descriptive than the constants defined in the tthi(sys/stat.h) header file, but their values are identical. The tt(enum class perms) supports all bitwise operators. centertbl(lrll)(\ tline()()\ tr(xcell(4)(std::filesystem::perms))\ tr(cell(Symbol+nbsp(2))cell(Value)cell(sys/stat.h)tlc()(Meaning))\ tline()()\ rowfour(tt(none))(tt(0000))(nbsp(3)tt(-)tt(-)tt(-)) (No permission bits were set) rowfour(tt(owner_read))(tt(0400))(tt(S_IRUSR)) (File owner has read permission) rowfour(tt(owner_write))(tt(0200))(tt(S_IWUSR)) (File owner has write permission) rowfour(tt(owner_exec))(tt(0100))(tt(S_IXUSR)) (File owner has execute/search+nl() permissions) rowfour(tt(owner_all))(tt(0700))(tt(S_IRWXU)) (File owner has read, write, and+nl() execute/search permissions) rowfour(tt(group_read))(tt(0040))(tt(S_IRGRP)) (The file's group has read permission) rowfour(tt(group_write))(tt(0020))(tt(S_IWGRP)) (The file's group has write permission) rowfour(tt(group_exec))(tt(0010))(tt(S_IXGRP)) (The file's group has execute/search+nl() permissions) rowfour(tt(group_all))(tt(0070))(tt(S_IRWXG)) (The file's group has read, write, and+nl() execute/search permissions) rowfour(tt(others_read))(tt(0004))(tt(S_IROTH)) (Other users have read permission) rowfour(tt(others_write))(tt(0002))(tt(S_IWOTH)) (Other users have write permission) rowfour(tt(others_exec))(tt(0001))(tt(S_IXOTH)) (Other users have execute/search+nl() permissions) rowfour(tt(others_all))(tt(0007))(tt(S_IRWXO)) (Other users have read, write, and nl() execute/search permissions) rowfour(tt(all))(tt(0777))(nbsp(3)tt(-)tt(-)tt(-)) (All users have read, write, and+nl() execute/search permissions) rowfour(tt(set_uid))(tt(04000))(tt(S_ISUID)) (Set user ID to file owner user ID on+nl() execution) rowfour(tt(set_gid))(tt(02000))(tt(S_ISGID)) (Set group ID to file's user group ID on+nl() execution) rowfour(tt(sticky_bit))(tt(01000))(tt(S_ISVTX)) (POSIX XSI specifies that when set on a+nl() directory only file owners may delete+nl() files even if the directory is writeable+nl() by others (used, e.g., with tt(/tmp))) rowfour(tt(mask))(tt(07777))(nbsp(3)tt(-)tt(-)tt(-)) (All valid permission bits.) tline()()\ ) bf(Perm_options): hi(perm_options) The tt((std::file_system) enum class perm_options) specifies the way file system entries are modified centertbl(ll)(\ tline()()\ tr(xcell(2)(std::filesystem::perm_options))\ tr(tlc()(Value)tlc()(Meaning))\ tline()()\ rowtwo(replace)(current permisions are replaced new permissions) rowtwo(remove)(the specified permissions are removed from the+nl() file system entry's current permissions) rowtwo(nofollow) (when the current file system entry refers+nl() to a symbolic link the permissions of the+nl() symbolic link itself are updated) tline()()\ ) bf(Constructors): itemization( itt(explicit file_status(file_type type = file_type::none, perms permissions = perms::unknown)) ) Copy and move constructors and assignment operators are avaialble; bf(Members): itemization( itht(permissions)(perms permissions() const) returns the permissions of the file system entry represented by the tt(file_status) object.nl() Refer to section ref(FREEFS) for the function tt(permissions) changing the permissions of a file system entry; COMMENT( itt(void permissions(perms newPerms [, perm_options opts] [, error_code &ec])) modifies the permissions of the file system entry to which the tt(file_status) object refers; END) itht(type)(file_type type() const) returns the type of the file system entry to which the tt(file_status) object refers; itt(void type(file_type type)) changes the type of the file system entry to which the tt(file_tatus) object refers. ) c++-annotations-13.02.01/yo/namespaces/filesystem/filesystemerror.yo0000664000175000017500000000120614735537670024410 0ustar frankfrankThe tt(std::filesystem) namespace offers its own exception type ti(filesystem_error) (see also chapter ref(EXCEPTIONS)). Its constructor has the following signature (the bracketed parameters are optional): verb( filesystem_error(string const &what, [path const &path1, [path const &path2,]] error_code ec);) As tt(filesystem) facilities are closely related to standard system functions, tt(errc) error code enumeration values can be used to obtain tt(error_codes) to pass to tt(filesystem_error), as illustrated by the following program: verbinsert(-s4 //fse examples/filesystemerror.cc) c++-annotations-13.02.01/yo/namespaces/filesystem/errorcode.yo0000664000175000017500000001456514745404622023141 0ustar frankfrankObjects of the class ti(std::error_code) (note: em(not) tt(std::filesystem::error_code)!) encapsulate em(error values), and associated em(error categories) (cf. section ref(SYSTEMERROR); tt(error_code) can be used after including the tthi(system_error) header, but it is also available after including the tthi(filesystem) header file). Traditionally error values are available as values assigned to the global hi(errno) tt(int errno) variable. By convention, when tt(errno's) value equals zero there's no error. This convention was adopted by tt(error_code). Error codes can be defined for many conceptually different situations. Those situations are characterized by their own em(error categories). Error categories are used to associate tt(error_code) objects with the errors that are defined by those categories. Default available error categories may use values like tt(EADDRINUSE) (or the equivalent tt(enum class errc) value tt(address_in_use)) but new types of error categories, tailored to other contexts, can also be defined. The tt(enum class errc) is defined in the tthi(bits/error_constants.h) header file. Error categories and how to define them is covered near the end of the annotations() (section ref(ERRCAT)). COMMENT(========== Two tt(error_category) members (note: they're not tt(error_code) members) are briefly introduced: itemization( itt(std::string message(int err)) returning a textual description of error tt(err) (like em(address already in use) when tt(err) equals tt(address_in_use)). itt(char const *name()) returning the name of the error category (like em(generic) for the generic category); ) Error category classes are singleton classes: only one object exists of each error category. In the context of the filesystem namespace the standard category ti(system_category) is used, and a reference to the ti(system_category) object is returned by the free function tt(std::system_category), expecting no arguments. The public interface of the class tt(error_code) declares these construtors and members: ============ END) bf(Constructors): itemization( ittq(error_code() noexcept) (the object is initialized with error em(value) 0 and the tt(system_category) error category. Value 0 is not considered an error;) ittq(error_code(int ec, error_category const &cat) noexcept) (the object is initialized from error value tt(ec) (e.g., tt(errno), set by a failing function), and a const reference to the applicable error em(category) (provided by, e.g., hi(system_category) tt(std::system_category()) or hi(generic_category) tt(std::generic_category())). Here is an example defining an tt(error_code) object: verb( error_code ec{ 5, system_category() }; ) ) ittq(error_code(ErrorCodeEnum value) noexcept) (this is a member template (cf. section ref(MEMTEMP)), using template header tt(template ). It initializes the object with the return value of tt(make_error_code(value)) (see below). In section ref(ERRCODEENUM) defining tt(ErrorCodeEnums) is covered. Note: tt(ErrorCodeEnum) as such does not exist. It is a mere placeholder for existing tt(ErrorCodeEnum) enumerations; ) ) Copy- and move-constructors are available. bf(Operators): itemization( it() Standard assignment operators and an assignment operator accepting an tt(ErrorCodeEnum) are available; ittq(operator std::errc() const noexcept) (returns the object's tt(errc) error-code value. For tt(g++) these are defined in the tt(enum class errc)hi(errc) in the file tt(/usr/include/x86_64-linux-gnu/c++/14/bits/error_constants.h);) ittq(explicit operator bool() const noexcept) (returns tt(true) if the object's error value is unequal 0 (i.e., it represents and error).) ) bf(Members): itemization( ittq(void assign(int val, error_category const &cat)) (assigns new values to the object's error value and category. E.g, tt(ec.assign(0, generic_category()));) ittq(error_category const &category() const noexcept) (returns a reference to the object's error category;) ittq(void clear() noexcept) (sets the tt(error_code's) value to 0 and its error category to tt(system_category);) ittq(error_condition default_error_condition() const noexcept) (returns the current category's default error condition initialized with the current object's error value and error category (see section ref(ERRCOND) for details about the class tt(error_condition));) ittq(string message() const) (the message that is associated with the current object's error value is returned (equivalent to tt(category().message(ec.value())));) ittq(int value() const noexcept) (returns the object's error value.) ) bf(Free functions): itemization( it() Two tt(error_code) objects can be compared for (in) equality and can be ordered (using tt(operator<)). Ordering tt(error_codes) associated with different error categories has no meaning. But when the error categories are identical then they are compared by their error code values (cf. this url(SG14 discussion summary) (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0824r1.html)); ithtq(make_error_code)(error_code make_error_code(errc value) noexcept) (returns an tt(error_code) object initialized with tt(static_cast(value)) and tt(generic_category())). This function converts an tt(enum class errc) value to an tt(error_code). Other error related enums may also be defined with which tailored tt(make_error_code) functions can be associated (cf. section ref(ERRCODEENUM);) ittq(std::ostream &operator<<(std::ostream & os, error_code const &ec)) (executes verb(return os << ec.category().name() << ':' << ec.value();) ) ) Many tt(filesystem) functions define an optional last tt(error_code &ec) parameter. Those functions have tt(noexcept) specifications. If those functions cannot complete their tasks, then tt(ec) is set to the appropriate error code, calling tt(ec.clear()) if no error was encountered. If no tt(ec) argument is provided then those functions throw a tt(filesystem_error) exception if they cannot complete their tasks. c++-annotations-13.02.01/yo/namespaces/filesystem/directoryentry.yo0000664000175000017500000000430614735537670024244 0ustar frankfrankThe file system is a recursive data structure. Its top-level entry is a directory (the root directory) containing plain directory entries (files, (soft) links, named sockets, etc.) and possibly also (sub)directory entries referring to nested directories which in turn may contiain plain- and (sub)directory entries. In the tt(std::filesystem) namespace the elements of directories are objects of the class ti(directory_entry), containing names and statuses of the entries of that directory. bf(Constructors): The class tt(directory_entry) supports all standard constructors (and assignment operators) and also a constructor expecting a tt(path): verb( directory_entry(path const &entry);) Objects of the class tt(directory_entry) can be constructed by name, and do not have to refer to existing entries in the file system. bf(Operators): itemization( itt(ostream &operator<<(ostream &, directory_entry const &)) inserts the object's tt(path) into the tt(ostream); it() the comparsion operators (tt(==, <=>)) compare their tt(std::path) data members; itht(path)(path const &path() const), hi(operator path const &()) tt(operator path const &() const) returns the current object's path name. ) bf(Members): itemization( ithtq(assign)(void assign(path const &dest)) (the current path is replaced by tt(dest) (identical to tt(directory_entry's) assignment operator);) ithtq(replace_filename)(void replace_filename(path const &dest)) (the last element of the current object's path is replaced by tt(dest). If that element is empty (e.g., when the object's path ends in a directory separator) then tt(dest) is appended to the current object's path;) ithtq(status)(filesystem::file_status status([error_code &ec])) (returns type and attributes of the directory entry referred to by the current object. If the current object refers to a symlink then the status of the entry the symlink refers to is returned. To obtain the status of the entry itself, even if it's a symlink use ti(symlink_status) (see also section ref(FSSTATUS) and ref(FSESTAT) below).) ) c++-annotations-13.02.01/yo/namespaces/filesystem/pathmembers.yo0000664000175000017500000001433614735537670023471 0ustar frankfrank bf(Operators:) itemization( itt(path &operator/=(Type const &arg)):nl() the arguments that can be passed to constructors can also be passed to this member. The tt(arg) argument is separated from the path's current content by a directory separator (unless the path is initially empty as in tt(cout << path{}.append("entry"))). See also the members tt(append) and tt(concat), below. The free operator tt(/) accepts two tt(path) (promotable) arguments, returning a tt(path) containing both paths separated by a directory separator (e.g., tt(lhs / rhs) returns the tt(path) object tt(lhs/rhs)); itt(path &operator+=(Type const &arg)):nl() similar to tt(/=), but em(no) directory separator is used when adding tt(arg) to the current tt(path); it() comparison operators: tt(path) objects can be compared using the (operators implied by the) tt(==) and tt(<=>) operators. Path objects are compared by lexicographical comparing their ascii-character content; itt(ostream &operator<<(ostream &out, path const &path)) (stream insertion) inserts tt(path's) content, surrounded by double quotes, into tt(out); itt(istream &operator>>(istream &in, path &path)) extracts tt(path's) content from tt(in). The extracted path name may optionally be surrounded by double quotes. When inserting a previously extracted tt(path) object only one set of surrounding quotes are shown. ) bf(Accessors:) Accessors return specific tt(path) components. If a path doesn't contain the requested component then an empty tt(path) is returned. itemization( itt(char const *c_str()): the path's content is returned as an NTBS; itt(path extension()) returns the dot-extension of the path's last component (including the dot); itt(path filename()) returns the last path-content of the current tt(path) object. See also the tt(stem()) accessor, below; itt(bool is_absolute()): returns tt(true) if the tt(path) object contains an absolute path specification; itt(bool is_relative()): returns tt(true) if the tt(path) object contains a relative path specification; itt(path parent_path()) returns the current path-content from which the last element has been removed. Note that if the tt(path) object contains a filename's path (like tt("/usr/bin/zip")) then tt(parent_path) removes tt(/zip) and returns tt(/usr/bin), so not tt(zip's) parent directory, but its actual directory; itt(path relative_path()): returns the path's content beyond the path's root-directory component of the tt(path) object. E.g., if the tt(path ulb{ "/usr/local/bin" }) is defined then tt(ulb.relative_path()) returns a path containing tt("usr/local/bin"); itt(path root_directory()): returns the root-directory component of the tt(path) object; itt(path root_name()): returns the root-name's component of the tt(path) object; itt(path root_path()): returns the root-path component of the tt(path) object; itt(path stem()) returns the last path-content of the current tt(path) object from which the dot-extension hash been removed; itt(string()): returns the path's content as a tt(std::string).nl() Similar accessors are available for the following string-types: tt(wstring, u8string, u16string, , u32string, generic_string, generic_wstring, generic_u8string, generic_u16string,) and tt(generic_u32string); ) Except for the family of tt(string()) and the tt(is_...) accessors, there are also tt(bool has_...) members returning tt(true) if the tt(path) contains the specified component (e.g., tt(has_extension) returns tt(true) if the tt(path) contains an extension). bf(Member functions:) itemization( itt(path &append(Type const &arg)) acts like the tt(/=) operator; itt(path::iterator begin()) returns an iterator containing the first path component; Dereferencing a tt(path::iterator) returns a tt(path) object.nl() When available root names and root directories are returned as initial components. When incrementing tt(path::iterators) the individual directories and finally filename components are returned. The directory separators themselves are not returned when dereferencing subsequent tt(path::iterators); itt(path::const_iterator begin() const) returns a iterator to the immutable first path component; Dereferencing a tt(path::const_iterator) returns a tt(path const) object; itt(void clear()): the tt(path's) content is erased; itt(int compare(Type const &other)):nl() returns the result of lexicographically comparing the current path's content with tt(other). tt(Other) can be a tt(path), a string-type or an NTBS; itt(path &concat(Type const &arg)) acts like the tt(+=) operator; itt(path::iterator end()) returns an iterator beyond the last path component; itt(path::const_iterator end() const) returns an iterator beyond the immutable last path component itt(path &remove_filename()):nl() removes the last component of the stored path not ending in tt(/). If the tt(path) doesn't contain a slash then the tt(path) object's cleared; itt(path &replace_extension(path const &replacement = path{} )):nl() replaces the extension of the last component of the stored path (including the extension's dot) with tt(replacement). The extension is removed if tt(replacement) is empty. If the tt(path) calling tt(replace_extension) has no extension then tt(replacement) is added. The replacement may optionally start with a dot. The path object's extension receives only one dot; itt(path &replace_filename(path const &replacement)):nl() replaces the last component of the stored path with tt(replacement), which itself may contain multiple path elements. If only a root-directory is stored, then it is replaced by tt(replacement). The member's behavior is undefined if the current path object is empty; ) c++-annotations-13.02.01/yo/namespaces/filesystem/getstatus.yo0000664000175000017500000000415214735537670023200 0ustar frankfrankThe tt(std::path) free functions tt(status) and tt(symlink_status) (cf. section ref(FREEFS)) return the tt(file_status) of file system entries. The following functions provide specific information about the status of file system entries: COMMENT( The tt(filesystem) functions tt(status) and tt(symlink_status) retrieve or change statuses of file system entries. These functions may be called with a final (optional) tt(error_code) argument which is assigned an appropriate error code if they cannot perform their tasks. If the argument is omitted the members throw exceptions if they cannot perform their tasks END) itemization( itht(status_known)(bool status_known(file_status const &status)) returns tt(true) if tt(status) refers to a determined status (tt(status) itself may indicate that the entity referred to by tt(status) does not exist). One way of receiving tt(false) is by passing it a default status object: tt(status_known(file_status{})); itt(bool is_WHATEVER(file_status status)), replacing tt(WHATEVER) by the requested file type, returns tt(true) if tt(status) refers to an entry of the specified type. ) These following tt(is_WHATEVER) functions are available: centertbl(ll)(\ tline()()\ tr(xcell(2)(is_WHATEVER(file_status) ))\ tr(tlc()(Function)tlc()(Meaning))\ tline()()\ rowtwo(is_block_file)('entry' is a block device) rowtwo(is_character_file)('entry' is a character device) rowtwo(is_directory)('entry' is a directory) rowtwo(is_empty) ('entry' is an empty file or directory) rowtwo(is_fifo) ('entry' is a named pipe) rowtwo(is_other) ('entry' is not a directory,nl() regular file or symlink) rowtwo(is_regular_file)('entry' is a regular file) rowtwo(is_socket) ('entry' is a named socket) rowtwo(is_symlink) ('entry' is a symbolic link) tline()()\ ) Here is a small program showing how file statuses can be obtained and displayed (cf. sections ref(PATH) and (for the em(map)) section ref(MAP)): verbinsert(-s4 //demo examples/statusknown.cc) c++-annotations-13.02.01/yo/namespaces/filesystem/freefunctions.yo0000664000175000017500000002447014735537670024034 0ustar frankfrankbf(Copy_options): hi(copy_options) Defined in the tt((std::filesystem) enum class copy_options). The enumeration supports bitwise operators. The tt(copy_options) enum values are used to fine-tune the behavior of tt(filesystem) functions copying file system elements. centertbl(lrll)(\ tline()()\ tr(xcell(4)(std::filesystem::copy_options))\ tr(tlc()(Symbol) tlc()(Value) cell() tlc()(Meaning))\ tline()()\ threecols(none)(0)(default: copy like tt(cp)) COMMENT(Files:) threecols(overwrite_existing)(2)(replace the destination file) threecols(update_existing)(4)( replace the destination file only if it is nl() older than the file being copied) COMMENT(Directories:) threecols(recursive)(8)( recursively copy subdirectories and their+nl() content) COMMENT(Symlinks:) threecols(copy_symlinks)(16)(copy symlinks as symlinks) threecols(skip_symlinks)(32)(ignore symlinks) COMMENT(copy itself) threecols(directories_only)(64)( copy the directory structure, but do not copy nl() any non-directory files) threecols(create_symlinks)(128)( create symlinks instead of copying files.nl() The source path must be an absolute path unless nl() the destination path is in the current directory) threecols(create_hard_links)(256)( instead of copying files create hard links nl() resolving to the same files as the original) tline()()\ ) bf(Functions): itemization( ithtq(absolute)(path absolute(path const &src, [, error_code &ec])) (returns tt(src) as an absolute path (i.e., starting at the filesystem's root (and maybe disk) name). It can be called as, e.g., tt(absolute("tmp/filename")), returning the (absolute) current working directory to which tt(absolute's) argument is appended as a final element, separated by a directory separator. Relative path indicators (like tt(../) and tt(./)) are kept;) ithtq(canonical)(path canonical(path const &src [, error_code &ec])) (returns tt(src's) canonical path. tt(Src) must exist. Example: verb( canonical("/usr/local/bin/../../share/man"); // returns path{ "/usr/share/man" } )) ithtq(copy)(void copy(path const &src, path const &dest [, copy_options opts [, error_code &ec]])) (tt(src) must exist. By default copies tt(src) to tt(dest) if the tt(cp) program would also succeed. Use tt(opts) to fine-tune tt(copy's) behavior.nl() If tt(src) is a directory, and tt(dest) does not exist, tt(dest) is created. Directories are recursively copied if copy options tt(recursive) or tt(none) were specified;) ithtq(copy_file)(bool copy_file(path const &src, path const &dest [, copy_options opts [, error_code &ec]])) (tt(src) must exist. Copies tt(src) to tt(dest) if the tt(cp) program would also succeed. Symbolic links are followed. The value tt(true) is returned if copying succeeded;) ithtq(copy_symlink)(void copy_symlink(path const &src, path const &dest [, error_code &ec])) (creates the symlink tt(dest) as a copy of the symlink tt(src);) ithtq(create_directories)(bool create_directories(path const &dest [, error_code &ec])) (creates each component of tt(dest), unless already existing. E.g., using argument tt("a/b/c") and tt("a") doesn't yet exist then tt("a/b/c") are all created. The value tt(true) is returned if tt(dest) was actually created. If tt(false) is returned tt(ec) contains an error-code, which is zero (tt(ec.value() == 0)) if tt(dest) already existed. See also tt(create_directory) below;) ithtq(create_directory)(bool create_directory(path const &dest [, path const &existing] [, error_code &ec])) (tt(dest's) parent directory must exist. This function creates directory tt(dest) if it does not yet exist. Nested subdirectories are not created by tt(create_directory): using argument tt("a/b/c") and neither tt("a") nor tt("a/b") exist then this function fails. The value tt(true) is returned if tt(dest) was actually created. If tt(false) is returned tt(ec) contains an error-code, which is zero (tt(ec.value() == 0)) if tt(dest) already existed. If tt(existing) is specified, then tt(dest) receives the same attributes as tt(existing);) ithtq(create_directory_symlink)(void create_directory_symlink(path const &dir, path const &link [, error_code &ec])) (like tt(create_symlink) (see below), but is used to create a symbolic link to a directory;) ithtq(create_hard_link)(void create_hard_link(path const &dest, path const &link [, error_code &ec])) (creates a hard link from tt(link) to tt(dest). tt(Dest) must exist;) ithtq(create_symlink)(void create_symlink(path const &dest, path const &link [, error_code &ec])) (creates a symbolic (soft) link from tt(link) to tt(dest); tt(dest) does em(not) have to exist;) itht(current_path)(path current_path([error_code &ec])), tt(void current_path(path const &toPath [, error_code &ec])):nl() the former function returns the current working directory (cwd), the latter changes the cwd to tt(toPath). The returned path's last character is not a slash, unless called from the root-directory; ithtq(equivalent)(bool equivalent(path const &path1, path const &path2 [, error_code &ec])) (tt(true) is returned if tt(path1) and tt(path2) refer to the same file or directory, and have identical statuses. Both paths must exist;) itht(exists)(bool exists(path const &dest [, error_code &ec])), tt(exists(file_status status)):nl() tt(true) is returned if tt(dest) exists (actually: if tt(status(dest[, ec])) (see below) returns tt(true)). Note: when iterating over directories, the iterator usually provides the entries' statuses. In those cases calling tt(exists(iterator->status())) is more efficient than calling tt(exists(*iterator)). When tt(dest) is the path to a symbolic reference then tt(exists) returns whether the link's destination exists or not (see also the functions tt(status) and tt(symlink_status) in section ref(DIRENTRY)); ithtq(file_size)(std::unintmax_t file_size(path const &dest [, error_code &ec])) (returns the size in bytes of a regular file (or symlink destination);) ithtq(hard_link_count)(std::uintmax_t hard_link_count(path const &dest [, error_code &ec])) (returns the number of hard links associated with tt(dest);) itht(last_write_time)(file_clock::time_point last_write_time(path const &dest [, error_code &ec])), tt(void last_write_time(path const &dest, file_clock::time_point newTime [, error_code &ec])):nl() the former function returns tt(dest's) last modification time; the latter function changes tt(dest's) last modification time to tt(newTime). tt(last_write_time's) return type is defined through a tt(using) alias for tt(chrono::time_point) (cf. section ref(TIMEPOINT)). The returned tt(time_point) is guaranteed to cover all file time values that may be encountered in the current file system. The function tt(file_clock::to_sys) (see below) can be used to convert tt(file_clock) time points to tt(system_clock) time_points; ithtq(permissions)(void permissions(Path const &entry, perms newPerms [, perm_options opts = perm_options::replace ] [, error_code &ec])) (Modifies the permissions of tt(entry). Each of the two last arguments is optional. E.g., when specifying an tt(error_code) as third argument then tt(opts) is implicitly specified as tt(replace);) ithtq(read_symlink)(path read_symlink(path const &src [, error_code &ec])) (tt(src) must refer to a symbolic link or an error is generated. The link's target is returned;) itht(remove)(bool remove(path const &dest [, error_code &ec])), hi(remove_all) tt(std::uintmax_t remove_all(path const &dest [, error_code &ec])):nl() tt(remove) removes the file, symlink, or empty directory tt(dest), returning tt(true) if tt(dest) could be removed; tt(remove_all) removes tt(dest) if it's a file (or symlink); and recursively removes directory tt(dest), returning the number of removed entries; ithtq(rename)(void rename(path const &src, path const &dest [, error_code &ec])) (renames tt(src) to tt(dest), as if using the standard bf(mv)(1) command (if tt(dest) exists it is overwritten);) ithtq(resize_file)(void resize_file(path const &src, std::uintmax_t size [, error_code &ec])) (tt(src's) size is changed to tt(size) as if using the standard bf(truncate)(1) command;) ithtq(space)(space_info space(path const &src [, error_code &ec])) (returns information about the file system in which tt(src) is located;) ithtq(status)(file_status status(path const &entry [, error_code &ec])) (returns tt(entry's file_status). If tt(entry) is the name of a symbolic link then the status of the link's destination is returned;) ithtq(symlink_status)(file_status symlink_status(path const &entry [, error_code &ec])) (returns tt(entry's) own tt(file_status);) ithtq(system_complete)(path system_complete(path const &src[, error_code& ec])) (returns the absolute path matching tt(src), using tt(current_path) as its base;) ithtq(temp_directory_path)(path temp_directory_path([error_code& ec])) ( returns the path to a directory that can be used for temporary files. The directory is not created, but its name is commonly available from the environment variables ti(TMPDIR), tt(TMP, TEMP), or tt(TEMPDIR). Otherwise, tt(/tmp) is returned.) ithtq(to_sys)(system_clock::time_point file_clock::to_sys(file_clock::time_point timePoint)) (here is how the time returned by tt(last_write_time) can be represented using the tt(system_clock's) epoch: verbinsert(//demo examples/lastwritetime2.cc)) ) c++-annotations-13.02.01/yo/namespaces/filesystem/directoryiterator.yo0000664000175000017500000001266514735537670024743 0ustar frankfrankThe tt(filesystem) namespace has two classes simplifying directory processing: objects of the class tt(directory_iterator) are (input) iterators iterating over the entries of directories; and objects of the class tt(recursive_directory_iterator) are (input) iterators recursively visiting all entries of directories.location bf(enum class directory_options) The tt(enum class directory_options)hi(directory_options) defines values that are used to fine-tune the behavior of tt(recursive_directory_iterator) objects, supporting bitwise operators (the values of its symbols are shown between parentheses): itemization( itt(none) (0): directory symlinks are skipped, denied permission to enter a sub-directory generates an error; itt(follow_directory_symlink) (1): symlinks to sub-directories are followed; itt(skip_permission_denied) (2): directories that cannot be entered are silently skipped. ) bf(Constructors): itemization( ittq((recursive_)directory_iterator()) (the end-iterator of the tt((recursive_)directory_iterator's) iterator-range;) ittq((recursive_)directory_iterator(path const &from [, error_code &ec])) (constructs a tt((recursive-)directory_iterator) using tt(from) as the starting directory of the iterator. All members of standard input iterators (cf. section ref(ITERATORS)) are supported;) ittq(recursive_directory_iterator(path const &from, directory_options opts [, error_code &ec])) (constructs a tt((recursive-)directory_iterator) fine-tuning its behavior to the options specified by tt(opts).) ) Copy, and move constructors are available. These iterators point to tt(directory_entry) objects referring to entries in the computer's file system. E.g., verb( cout << *directory_iterator{ "/home" } << '\n'; // shows the first entry under /home ) tt((Recursive_)directory_iterators) can be used with range-based for-loops and in standard tt(for) and tt(while) statements. COMMENT( After constructing a tt((recursive_)directory_iterator base{"/var/log"}) object it refers to the first element of its directory. Such iterators can also explicitly be defined: tt(auto &iter = begin(base), auto iter = begin(base), auto &iter = base) or tt(auto iter = base). All these tt(iter) objects refer to tt(base's) data, and incrementing them also advances tt(base) to its next element: verb( recursive_directory_iterator base{ "/var/log/" }; auto iter = base; // final two elements show identical paths, // different from the first element. cout << *iter << ' ' << *++iter << ' ' << *base << '\n';) The functions tt(begin) and tt(end) that are used in the above examples are, like tt((recursive_)directory_iterator), available in the tt(filesystem) namespace. END) bf(Additional members of recursive_directory_iterators) itemization( ithtq(depth)(int depth() const) (returns the current iteration depth. The depth of the initial directory, specified at construction-time, equals 0;) ithtq(disable_recursion_pending)(void disable_recursion_pending()) (when called before incrementing the iterator the next directory entry is not recursively visited. Once the iterator is incremented recursion is again allowed. If a recursion should end at a specific depth then once tt(depth()) returns that specific depth this member must be called each time before the iterator's increment operator is called;) ithtq(increment)(recursive_directory_iterator &increment(error_code &ec)) (acts identically to the iterator's increment operator. However, at errors tt(operator++) throws a tt(filesystem_error) exception, while tt(increment) assigns the error to tt(ec);) ithtq(options)(directory_options options() const) (returns the option(s) specified at construction-time;) ithtq(pop)(void pop()) (ends processing the current directory, and continues at the next entry in the current directory's parent;) ithtq(recursion_pending)(bool recursion_pending() const) (tt(true) is returned if recursive processing of sub-directories of the currently processed directory is allowed. If so, and the the iterator points at a sub-directory, then processing continues in that sub-directory at the iterator's next increment;) ) Here's a small program displaying all elements and all immediate sub-directories of a directory: verbinsert(-s4 //demo examples/recurs.cc) The above program handles entries as they come. Other strategies must be implemented `by hand'. E.g., a breadth-first strategy first visits all the non-directory entries and then visits the sub-directories, as illustrated in the next example by processingthe directories stored in tt(level) in turn (initially it merely contains the starting directory). `Processing a directory' means that its non-directory entries are directly processed storing the names of sub-directories in tt(next). Once all entries at tt(level) have been processed the names of the next level sub-directories are available (in tt(next)). By assigning tt(next) to tt(level) all directories at the next level are processed. When reaching the most deeply nested sub-directories its tt(next) is empty and the tt(while) statement ends: verbinsert(-s4 //code examples/breadth.cc) c++-annotations-13.02.01/yo/namespaces/filesystem/intro.yo0000664000175000017500000000342114735537670022306 0ustar frankfrankComputers commonly store information that must survive reboots in their file systems. Traditionally, to manipulate the file system the bf(C) programming language offers functions performing the required system calls. Such functions (like bf(rename)(2), tt(truncate)(2), bf(opendir)(2), and bf(realpath)(3)) are of course also available in bf(C++), but their signatures and way of use are often less attractive as they usually expect tt(char const *) parameters and may use static buffers or memory allocation based on bf(malloc)(3) and bf(free)(3). Since 2003 the hi(Boost Filesystem)url(Boost library) (http://www.boost.org/doc/libs/1_65_1/libs/filesystem/doc/index.htm) offers em(wrappers) around these functions, offering interfaces to those system calls that are more bf(C++)-like. Currently bf(C++) directly supports these functions in the tt(std::filesystem)hi(filesystem) namespace. These facilities can be used after including the tthi(filesystem) header file. The tt(filesystem) namespace is extensive: it contains more than 10 different classes, and more than 30 free functions. To refer to the identifiers defined in the tt(std::filesystem) namespace their fully qualified names (e.g., tt(std::filesystem::path)) can be used. Alternatively, after specifying `tt(using namespace std::filesystem;)' the identifiers can be used without further qualifications. Namespace specifications like `tt(namespace fs = std::filesystem;)' are also encountered, allowing specifications like tt(fs::path). Functions in the tt(filesystem) namespace may fail. When functions cannot perform their assigned tasks they may throw exceptions (cf. chapter ref(EXCEPTIONS)) or they may assign values to tt(error_code) objects that are passed as arguments to those functions (see section ref(ERRORCODE) below). c++-annotations-13.02.01/yo/namespaces/filesystem/path.yo0000664000175000017500000000343514735537670022114 0ustar frankfrankObjects of the class tt(filesysten::path)hi(path) commonly contain names of file system entries. bf(Constructors): itemization( itt(path()): the default constructor is initialized with an empty tt(path); itt(path(InputIter begin, InputIter end)):nl() the characters from tt(begin) to tt(end) define the tt(path's) name. ) Copy- and move constructors are available, also using argument types tt(std::string) and tt(char const *).nl() A tt(path) object doesn't have to refer to an existing file system entry.nl() Arguments of tt(path) constructors may contain (all optional): itemization( it() a root-name, e.g., a disk-name (like tt(E:)) or device indicator (like tt(//nfs)); it() a root-directory, if it is the first character after the (optional) root-name; it() filename characters (not containing directory separators). In addition the `single dot filename' (tt(.)) indicates the current directory and the `double dot filename' (tt(..)) indicates the current directory's parent directory; it() directory separators (by default the forward slash). Multiple consecutive separators are automatically merged into one separator. ) The constructors also define a last tt(format ftmp = auto_format) parameter, for which in practice almost never an argument has to be provided (for its details see url(cppreference) (http://en.cppreference.com/w/cpp/experimental/fs/path).) COMMENT( Many functions expect tt(path) arguments which can usually be created from NTBSs or tt(std::string) objects as tt(path) allows promotions (cf. section ref(EXPLICIT)). E.g., the filesystem function tt(absolute) expects a tt(const &path) argument. It can be called like this: tt(absolute("tmp/filename")). END) c++-annotations-13.02.01/yo/namespaces/defining.yo0000664000175000017500000000253714735537670020561 0ustar frankfrankNamespaces are defined according to the following syntax: verb( namespace identifier { // declared or defined entities // (declarative region) }) The identifier used when defining a namespace is a standard bf(C++) identifier. Within the emi(declarative region), introduced in the above code example, functions, variables, structs, classes and even (nested) namespaces can be defined or declared. Namespaces cannot be defined within a function body. However, it is possible to define a namespace using multiple em(namespace) declarations. Namespaces are `em(open)' meaning that a namespace tt(CppAnnotations) could be defined in a file tt(file1.cc) and also in a file tt(file2.cc). Entities defined in the tt(CppAnnotations) namespace of files tt(file1.cc) and tt(file2.cc) are then united in one tt(CppAnnotations) namespace region. For example: verb( // in file1.cc namespace CppAnnotations { double cos(double argInDegrees) { ... } } // in file2.cc namespace CppAnnotations { double sin(double argInDegrees) { ... } }) Both tt(sin) and tt(cos) are now defined in the same tt(CppAnnotations) namespace. Namespace entities can be defined outside of their namespaces. This topic is discussed in section ref(OUTSIDE). c++-annotations-13.02.01/yo/namespaces/placeholders.yo0000664000175000017500000000217314735537670021437 0ustar frankfrankThis section contains quite a few forward references. It merely introduces the emi(placeholders) namespace, which is nested under the tt(std) namespace; this section can be skipped without loss of continuity. Before using the namespace tt(std::placeholders) the tthi(functional) header file must be included. Further down the annotations() we will encounter em(function objects) (section ref(FUNOBJ)), which are `objects' that can be used as functions. Such function objects (also called em(functors)) are extensively used in the em(Standard Template Library) (STL, chapter ref(STL)). The STL offers a function (tt(bind), see section ref(BIND)), returning a function adapter in which a function is called which may or may not already have received its arguments. If not, then em(placeholders) for arguments must be used, for which actual arguments must be specified once the functor that is returned by tt(bind) is called. Such placeholders have predefined names: tt(_1, _2, _3,) etc. These placeholders are defined in the tt(std::placeholders) namespace. Several illustrations of the use of these placeholders are found in section ref(BIND). c++-annotations-13.02.01/yo/namespaces/declaring.yo0000664000175000017500000000070114735537670020715 0ustar frankfrank Instead of em(defining) entities in a namespace, entities may also be em(declared) in a namespace. This allows us to put all the hi(namespace declarations) declarations in a header file that can thereupon be included in sources using the entities defined in the namespace. Such a header file could contain, e.g., verb( namespace CppAnnotations { double cos(double degrees); double sin(double degrees); }) c++-annotations-13.02.01/yo/namespaces/nesting.yo0000664000175000017500000000761514735537670020447 0ustar frankfrankNamespaces can be nested. Here is an example: verb( namespace CppAnnotations { int value; namespace Virtual { void *pointer; } }) The variable tt(value) is defined in the tt(CppAnnotations) namespace. Within the tt(CppAnnotations) namespace another namespace (tt(Virtual)) is nested. Within that latter namespace the variable tt(pointer) is defined. To refer to these variable the following options are available: itemization( it() The hi(fully qualified name)em(fully qualified names) can be used. A fully qualified name of an entity is a list of all the namespaces that are encountered until reaching the definition of the entity. The namespaces and entity are glued together by the scope resolution operator: verb(int main() { CppAnnotations::value = 0; CppAnnotations::Virtual::pointer = 0; }) it() A tt(using namespace CppAnnotations) directive can be provided. Now tt(value) can be used without any prefix, but tt(pointer) must be used with the tt(Virtual::) prefix: verb(using namespace CppAnnotations; int main() { value = 0; Virtual::pointer = 0; }) it() A tt(using namespace) directive for the full namespace chain can be used. Now tt(value) needs its tt(CppAnnotations) prefix again, but tt(pointer) doesn't require a prefix anymore: verb(using namespace CppAnnotations::Virtual; int main() { CppAnnotations::value = 0; pointer = 0; }) it() When using two separate tt(using namespace) directives none of the namespace prefixes are required anymore: verb(using namespace CppAnnotations; using namespace Virtual; int main() { value = 0; pointer = 0; }) it() The same can be accomplished (i.e., no namespace prefixes) for specific variables by providing specific tt(using) declarations: verb(using CppAnnotations::value; using CppAnnotations::Virtual::pointer; int main() { value = 0; pointer = 0; }) it() A combination of tt(using namespace) directives and tt(using) declarations can also be used. E.g., a tt(using namespace) directive can be used for the tt(CppAnnotations::Virtual) namespace, and a tt(using) declaration can be used for the tt(CppAnnotations::value) variable: verb(using namespace CppAnnotations::Virtual; using CppAnnotations::value; int main() { value = 0; pointer = 0; }) ) Following a tt(using namespace) directive all entities of that namespace can be used without any further prefix. If a single tt(using namespace) directive is used to refer to a nested namespace, then all entities of that nested namespace can be used without any further prefix. However, the entities defined in the more shallow namespace(s) still need the shallow namespace's name(s). Only after providing specific tt(using namespace) directives or tt(using) declarations namespace qualifications can be omitted. When fully qualified names are preferred but a long name like verb( CppAnnotations::Virtual::pointer) is considered too long, a emi(namespace alias) may be used: verb( namespace CV = CppAnnotations::Virtual;) This defines tt(CV) as an em(alias) for the full name. The variable tt(pointer) may now be accessed using: verb( CV::pointer = 0;) A namespace alias can also be used in a tt(using namespace) directive or tt(using) declaration: verb( namespace CV = CppAnnotations::Virtual; using namespace CV;) bf(Nested namespace definitions) Starting with the C++17 standard, when nesting namespaces a nested namespace can directly be referred to using scope resolution operators. E.g., verb( namespace Outer::Middle::Inner { // entities defined/declared here are defined/declared in the Inner // namespace, which is defined in the Middle namespace, which is // defined in the Outer namespace }) c++-annotations-13.02.01/yo/namespaces/referring.yo0000664000175000017500000000407314735537670020756 0ustar frankfrankGiven a namespace and its entities, the i(scope resolution operator) can be used to refer to its entities. For example, the function tt(cos()) defined in the tt(CppAnnotations) namespace may be used as follows: verb( // assume CppAnnotations namespace is declared in the // following header file: #include int main() { cout << "The cosine of 60 degrees is: " << CppAnnotations::cos(60) << '\n'; }) This is a rather cumbersome way to refer to the tt(cos()) function in the tt(CppAnnotations) namespace, especially so if the function is frequently used. In cases like these an em(abbreviated) form can be used after specifying a emi(using declaration). Following verb( using CppAnnotations::cos; // note: no function prototype, // just the name of the entity // is required.) calling tt(cos) results in a call of the tt(cos) function defined in the tt(CppAnnotations) namespace. This implies that the standard tt(cos) function, accepting radians, is not automatically called anymore. To call that latter tt(cos) function the plain scope resolution operator should be used: verb( int main() { using CppAnnotations::cos; ... cout << cos(60) // calls CppAnnotations::cos() << ::cos(1.5) // call the standard cos() function << '\n'; }) A tt(using) declaration can have restricted scope. It can be used inside a block. The tt(using) declaration prevents the definition of entities having the same name as the one used in the tt(using) declaration. It is not possible to specify a tt(using) declaration for a variable tt(value) in some namespace, and to define (or declare) an identically named object in a block also containing a tt(using) declaration. Example: verb( int main() { using CppAnnotations::value; ... cout << value << '\n'; // uses CppAnnotations::value int value; // error: value already declared. }) c++-annotations-13.02.01/yo/namespaces/std.yo0000664000175000017500000000366714735537670017575 0ustar frankfrankThe tt(std) namespace is reserved by bf(C++). The standard defines many entities that are part of the runtime available software (e.g., tt(cout, cin, cerr)); the templates defined in the em(Standard Template Library) (cf. chapter ref(STL)); and the em(Generic Algorithms) (cf. chapter ref(GENERIC)) are defined in the tt(std) namespace. Regarding the discussion in the previous section, tt(using) declarations may be used when referring to entities in the tt(std) namespace. For example, to use the tt(std::cout) stream, the code may declare this object as follows: verb( #include using std::cout;) Often, however, the identifiers defined in the tt(std) namespace can all be accepted without much thought. Because of that, one frequently encounters a tt(using) directive, allowing the programmer to omit a namespace prefix when referring to any of the entities defined in the namespace specified with the tt(using) directive. Instead of specifying tt(using) declarations the following tt(using) directive is frequently encountered: construction like verb( #include using namespace std;) Should a tt(using) directive, rather than tt(using) declarations be used? As a i(rule of thumb) one might decide to stick to tt(using) declarations, up to the point where the list becomes impractically long, at which point a tt(using) directive could be considered. Two hi(using: restrictions) restrictions apply to tt(using) directives and declarations: itemization( it() Programmers should not declare or define anything inside the tt(namespace std). This is em(not) compiler enforced but is imposed upon user code by the standard; it() tt(Using) declarations and directives should not be imposed upon code written by third parties. In practice this means that tt(using) directives and declarations should be banned from header files and should only be used in source files (cf. section ref(NAMESPACEHDR)). ) c++-annotations-13.02.01/yo/namespaces/intro.yo0000664000175000017500000000200014735537670020112 0ustar frankfrankImagine a math teacher who wants to develop an interactive math program. For this program functions like tt(cos, sin, tan) etc. are to be used accepting arguments in degrees rather than arguments in radians. Unfortunately, the function name tt(cos) is already in use, and that function accepts radians as its arguments, rather than degrees. Problems like these are usually solved by defining another name, e.g., the function name tt(cosDegrees) is defined. bf(C++) offers an alternative solution through hi(namespace)em(namespaces). Namespaces can be considered as areas or regions in the code in which identifiers may be defined. Identifiers defined in a namespace normally won't conflict with names already defined elsewhere (i.e., outside of their namespaces). So, a function tt(cos) (expecting angles in degrees) could be defined in a namespace tt(Degrees). When calling tt(cos) from within tt(Degrees) you would call the tt(cos) function expecting degrees, rather than the standard tt(cos) function expecting radians. c++-annotations-13.02.01/yo/namespaces/koenig.yo0000664000175000017500000000756014735537670020253 0ustar frankfrankIf emi(Koenig lookup) were called the `Koenig principle', it could have been the title of a new i(Ludlum) novel. However, it is not. Instead it refers to a bf(C++) technicality. `Koenig lookup' refers to the fact that if a function is called without specifying its namespace, then the namespaces of its argument types are used to determine the function's namespace. If the namespace in which the argument types are defined contains such a function, then that function is used. This procedure is called the `Koenig lookup'. As an illustration consider the next example. The function tt(FBB::fun(FBB::Value v)) is defined in the tt(FBB) namespace. It can be called without explicitly mentioning its namespace: verbinclude(-a examples/koenig1.cc) The compiler is rather smart when handling namespaces. If tt(Value) in the tt(namespace FBB) would have been defined as tt(using Value = int) then tt(FBB::Value) would be recognized as tt(int), thus causing the Koenig lookup to fail. As another example, consider the next program. Here two namespaces are involved, each defining their own tt(fun) function. There is no ambiguity, since the argument defines the namespace and tt(FBB::fun) is called: verbinclude(-a examples/koenig2.cc) Here is an example in which there em(is) an ambiguity: tt(fun) has two arguments, one from each namespace. The ambiguity must be resolved by the programmer: verbinclude(-a examples/koenig3.cc) An interesting subtlety with namespaces is that definitions in one namespace may break the code defined in another namespace. It shows that namespaces may affect each other and that namespaces may backfire if we're not aware of their peculiarities. Consider the following example: verbinclude(-a examples/koenig4.cc) Whatever happens, the programmer'd better not use any of the functions defined in the tt(ES) namespace, since that would result in infinite recursion. However, that's not the point. The point is that the programmer won't even be given the opportunity to call tt(ES::fun) since the compilation fails. Compilation fails for tt(gun) but not for tt(fun). But why is that so? Why is tt(ES::fun) flawlessly compiling while tt(ES::gun) isn't? In tt(ES::fun) tt(fun(x)) is called. As tt(x)'s type is not defined in a namespace the Koenig lookup does not apply and tt(fun) calls itself with infinite recursion. With tt(ES::gun) the argument is defined in the tt(FBB) namespace. Consequently, the tt(FBB::gun) function is a possible candidate to be called. But tt(ES::gun) itself also is possible as tt(ES::gun)'s prototype perfectly matches the call tt(gun(x)). Now consider the situation where tt(FBB::gun) has not yet been declared. Then there is of course no ambiguity. The programmer responsible for the tt(ES) namespace is resting happily. Some time after that the programmer who's maintaining the tt(FBB) namespace decides it may be nice to add a function tt(gun(Value x)) to the tt(FBB) namespace. Now suddenly the code in the namespace tt(ES) breaks because of an addition in a completely other namespace (tt(FBB)). Namespaces clearly are not completely independent of each other and we should be aware of subtleties like the above. Later in the annotations() (chapter ref(OVERLOADING)) we'll return to this issue. em(Koenig lookup) is only used in the context of namespaces. If a function is defined outside of a namespace, defining a parameter of a type that's defined inside a namespace, and that namespace also defines a function with an identical signature, then the compiler reports an ambiguity when that function is called. Here is an example, assuming the abovementioned namespace tt(FBB) is also available: verb( void gun(FBB::Value x); int main(int argc, char **argv) { gun(FBB::Value{}); // ambiguity: FBB::gun and ::gun can both // be called. }) c++-annotations-13.02.01/yo/namespaces/chrono/0000775000175000017500000000000014735537670017706 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/chrono/examples/0000775000175000017500000000000014771010713021504 5ustar frankfrankc++-annotations-13.02.01/yo/namespaces/chrono/examples/timepoint.cc0000664000175000017500000000151714771010720024025 0ustar frankfrank#include #include #include using namespace std; using namespace chrono; using namespace filesystem; int main() { time_point tp; time_point tp2; tp2 += seconds(5); // to_time_t(tp); time_point minpoint = time_point::min(); cout << minpoint.time_since_epoch().count() << '\n'; cout << time_point::min().time_since_epoch().count() << '\n'; // time_point tp3{ tp2 }; time_point tp3{ time_point{} += seconds{ 5 } }; cout << tp3.time_since_epoch().count() << '\n'; // time_point{} + 1s }; } c++-annotations-13.02.01/yo/namespaces/chrono/examples/puttime.cc0000664000175000017500000000073014771010720023500 0ustar frankfrank#include #include using namespace std; using namespace chrono; //demo int main() { auto now = system_clock::now(); // get a time_point cout << now << '\n'; // now's UTC time // convert to a time_t time_t timeT = system_clock::to_time_t(now); tm *local = localtime(&timeT); // get a tm * cout << put_time(local, "%c") << '\n'; // show the time } //= c++-annotations-13.02.01/yo/namespaces/chrono/examples/clock.cc0000664000175000017500000000272014771010720023105 0ustar frankfrank #include #include #include using namespace std; using namespace chrono; using namespace filesystem; namespace fs = filesystem; auto local_time_point(time_point const &tp, char const *fmt) { time_t secs = system_clock::to_time_t( tp ); return put_time(localtime(&secs), fmt); } int main() { // system_clock::duration ds{ 24h }; // file_clock::duration df{ 1h }; file_clock::time_point p1 = fs::last_write_time("clock.cc"); file_clock::time_point p2 = fs::last_write_time("clock.cc"); cout << (p1 == p2) << '\n'; return 0; system_clock::from_time_t( system_clock::to_time_t( system_clock::from_time_t( 12345 ) ) ); std::time_t tm {time(0)}; std::cout << std::put_time(std::localtime(&tm), "%c") << '\n'; time_t secs = system_clock::to_time_t( system_clock::now() ); cout << put_time(std::localtime(&secs), "%c\n"); cout << local_time_point(system_clock{}.now(), "%c") << '\n'; // file_clock::to_time_t(file_clock::from_time_t(12345)); high_resolution_clock::to_time_t(high_resolution_clock::from_time_t(12345)); // steady_clock::to_time_t(steady_clock::from_time_t(12345)); // unsigned uval = system_clock::period::num; // file_clock::period rf; // system_clock::rep vs; // file_clock::rep vf; // system_clock::time_point st = system_clock{}.now(); file_clock::time_point ft; } c++-annotations-13.02.01/yo/namespaces/chrono/examples/milli.cc0000664000175000017500000000030114771010720023111 0ustar frankfrank#include #include using namespace std; int main() { //milli cout << milli::num << ',' << milli::den << '\n' << kilo::num << ',' << kilo::den << '\n'; //= } c++-annotations-13.02.01/yo/namespaces/chrono/examples/durationmembers.cc0000664000175000017500000000146014771010720025212 0ustar frankfrank#include #include using namespace std; using namespace chrono; int main() { milliseconds amount(30); amount = seconds{5}; minutes halfHour{ 30 }; hours oneHour{ 1 }; cout << (halfHour + oneHour).count() << '\n'; // displays 90 halfHour += oneHour; // halfHour.count() == 90 // oneHour += halfHour; // won't compile minutes min{ 1h }; cout << min.count() << '\n'; minutes fullHour = minutes{ 30 } + halfHour; halfHour = 2 * fullHour; halfHour = fullHour / 2; fullHour = halfHour + halfHour; halfHour /= 2; halfHour *= 2; cout << halfHour.count() << ' ' << fullHour.count() << '\n'; cout << seconds::zero().count() << '\n'; cout << minutes::min().count() << ' ' << minutes::max().count() << '\n'; } c++-annotations-13.02.01/yo/namespaces/chrono/examples/ratio.cc0000664000175000017500000000036014771010720023126 0ustar frankfrank//demo #include #include using namespace std; int main() { cout << ratio<5, 1000>::num << ',' << ratio<5, 1000>::den << '\n'; } //= // milli::num << ',' << milli::den << '\n'; c++-annotations-13.02.01/yo/namespaces/chrono/fileclock.yo0000664000175000017500000000535314735537670022220 0ustar frankfrankTime points obtained using ti(file_clock) differ from time points obtained using the system clock: time points using tt(file_clock) are based on an epoch that lies beyond the starting time point of the system clock (Jan 1, 00:00:00 1970) that is used by the system clock (Jan 1 00:00:00 2174). The two epochs can be positioned on a time scale with the present somewhere in between: verb ( <------|-----------------------|-----------------------|-------> system_clock's --------> present <-------- file_clock's epoch starts positive negative epoch starts count count) The tt(file_clock) has its own peculiarities: the static member tt(now) is available, as are some non-static members: additions and subtractions of durations and the member tt(time_since_epoch) can all be used, but the members tt(to_time_t) and tt(from_time_t) are not available. Since tt(to_time_t) is not available for tt(file_clock) how can we show the time or obtain the time's components of a tt(time_point) object? Currently, there are two ways to accomplish that: compute the correction `by hand' or use the static ti(file_clock::to_sys) function converting a hi(time_point) tt(file_clock) time point to a tt(time_point) as used by tt(system_clock, steady_clock,) and tt(high_resolution_clock). Computing the difference between the epochs we find 6'437'663'999 seconds, which we can add to the obtained time since the tt(file_clock's) epoch to obtain the time since the tt(system_clock's) epoch. If tt(timePt) holds the duration since the tt(file_clock) epoch then verb( 6'437'663'999 + system_clock::to_time_t( time_point{ nanoseconds(timePt) })) equals the number of seconds since the tt(system_clock's) epoch. The potential drawback of this procedure is that, as tt(file_clock's) name starts with underscores, the begin of its epoch might change. By using the tt(now) members of both clocks this drawback is avoided: verb( auto systemNow = system_clock::now().time_since_epoch(); auto fileNow = file_clock::now().time_since_epoch(); time_t diff = (systemNow - fileNow) / 1'000'000'000; time_t seconds = diff + system_clock::to_time_t( time_point{ nanoseconds(timePt) });) Although being able to compute the time-shifts yourself is attractive from an understanding point of view, it's maybe also a bit (too) cumbersome for daily practices. The static function tt(file_clock::to_sys) can be used to convert tt(file_clock::time_points) to tt(system_clock:::time_points). The tt(file_clock::to_sys) function is covered in section ref(FREEFS). COMMENT( see examples/lastwritetime[2].cc) c++-annotations-13.02.01/yo/namespaces/chrono/timepoint.yo0000664000175000017500000001052614735537670022273 0ustar frankfrankPoints in time are specified by objects of the class hi(time_point) tt(std::chrono::time_point). Before using the class tt(time_point) the tthi(chrono) header file must be included. Like tt(duration) the class tt(time_point) requires two template arguments: A clock type and a duration type. The standard clock types define their own tt(time_point) types using tt(nanoseconds) as their duration type (tt(time_point) by default uses tt(nanoseconds)). The following time point type definitions are therefore identical: verb( time_point time_point standard_clock::time_point ) bf(Constructors): itemization( itt(time_point()):nl() the default constructor is initialized to the beginning of the clock's emi(epoch). For tt(system_clock) it is January, 1, 1970, 00:00h, but note that tt(file_clock::time_point) has a different starting point (see the example at the end of this section); ) Copy- and move-constructors as well as copy- and move-assignment operators (cf. chapter ref(MEMORY)) are available bf(Operators): itemization( itt(time_point &operator+=(duration const &amount)) adds the amount of time represented by tt(amount) to the current tt(time_point) object; itt(time_point &operator-=(duration const &amount)) subtracts the amount of time represented by tt(amount) from the current tt(time_point) object; itt(Type operator<<(std::ostream &, time_point const &)) inserts a textual representation of the tt(time_point's) UTC time into the tt(ostream). ) The compound operators are also available as binary arithmetic operators using a tt(time_point const &) and a tt(duration const &) operand (in any order). Example: verb( system_clock::now() + seconds{ 5 };) bf(Members): itemization( itht(time_since_epoch)(duration time_since_epoch() const):nl() tt(duration) is the duration type used by the time point object for which this member is called. To convert the returned tt(duration) to a tt(size_t) value use tt(time_since_epoch().count()); itt(time_point min() const): a static member returning the time point's tt(duration::min) value. Example: verb( cout << time_point::min().time_since_epoch().count() << '\n'; // shows -9223372036854775808) itt(time_point max() const): a static member returning the time point's tt(duration::max) value. ) bf(Conversions:) All predefined clocks use nanoseconds for their duration types. Converting to different tt(duration) types is covered in the previous section (ref(DURATION)). Alternatively, the members tt(to_time_t) of the tt(system_clock) and the tt(high_resolution_clock) can be used to convert their tt(time_point) values to tt(time_t). Such tt(time_t) values are commonly used to convert time to text, e.g., using the em(manipulator) tt(put_time) (cf. section ref(IOFORMAT)). The tt(put_time) manipulator must be provided with the address of a tt(std::tm) object, which can be obtained from a tt(std::time_t) value. See figure ref(TIMEIMG) for a visual representation of the involved elements. figure(threading/time)(Time according to bf(C++))(TIMEIMG) Use the following blueprint to insert a tt(system_clock::time point) value into a tt(std::ostream) (cf. section ref(PUTTIME)): verbinsert(-s4 //demo examples/puttime.cc) To convert a tt(time_point) to another tt(std::chrono) clock's tt(time_point) the template hi(clock_cast) tt(DestClock::time_point std::chrono::clock_cast(TimePoint tp)) can be used. The argument tt(tp) is an available tt(time_point), and tt(DestClock) specifies the clock type of the returned tt(time_point). E.g., the following tt(cout) statement displays four identical times: verb( auto fNow = file_clock::now(); auto sNow = file_clock::to_sys(fnow); cout << fNow << '\n' << sNow << '\n' << clock_cast(fNow) << '\n' << clock_cast(sNow) << '\n'; ) So, where is the starting point of the tt(file_clock) clock? nl() Since tt(time_point's) default cconstructor is initialized to its clock's starting point it can be obtained this way: verb( cout << file_clock::time_point{}<< '\n'; // shows: 2174-01-01 00:00:00.000000000 ) c++-annotations-13.02.01/yo/namespaces/chrono/clock.yo0000664000175000017500000000550014735537670021352 0ustar frankfrankClocks are used to measure time. bf(C++) has several predefined emi(clock) types, defined in the tt(std::chrono) namespace. Before using the tt(chrono) clocks the tthi(chrono) header file must be included. `tt(Clock)' clock-types are used to define points in time and define the following sub-types: itemization( it() tt(Clock::duration): the clock's time granularity type (by default using tt(nanoseconds). E.g., tt(system_clock::duration oneDay{ 24h }); it() tt(Clock::period): the clock's tt(std::ratio) type. E.g., tt(system_clock::period::den); it() tt(Clock::rep): the type storing amounts of time. By default using tt(int64_t)). E.g., tt(system_clock::rep amount); it() tt(Clock::time_point): the type storing time points (covered in the next section). By default using tt(time_point) E.g., tt(system_clock::time_point start). ) All clocks have a member ti(now) returning the clock type's tt(time_point) corresponding to the current time (relative to the clock's epoch). It is a static member which can be used like this: tt(system_clock::time_point tp = system_clock::now()). Four clock types are defined in the chrono namespace: itemization( iti(system_clock) is the `wall clock', using the system's real time clock; iti(steady_clock) is a clock whose time increases in parallel with the increase of real time; iti(high_resolution_clock) is the computer's fastest clock (i.e., the clock having the shortest timer-tick interval). In practice this is the same clock as tt(system_clock). iti(file_clock): used for time specifications of file-system elements. tt(File_clock) time specifications use a different starting (epoch) time than the other clocks, but it's easy to convert tt(file_clock) times to/from other clock types. ) In addition to the member tt(now) the classes tt(system_clock) and tt(high_resolution_clock) (referred to as tt(Clock) below) provide two static members: itemization( itht(to_time_t) (std::time_t Clock::to_time_t(Clock::time_point const &tp))nl() a tt(std::time_t)hi(time_t) value (the same type as returned by bf(C)'s bf(time)(2) function) converting a tt(time_point) value to a tt(time_t) value; itht(from_time_t) (Clock::time_point Clock::from_time_t(std::time_tvseconds))nl() the opposite conversion: returning a tt(time_point) corresponding to a tt(time_t) value. ) For example: verb( system_clock::time_point now = system_clock::now(); time_t value = system_clock::to_time_t(now); system_clock::time_point now2 = system_clock::from_time_t(value); // now2 != now since time_t uses seconds, not nanoseconds ) c++-annotations-13.02.01/yo/namespaces/chrono/ratio.yo0000664000175000017500000000566614735537670021412 0ustar frankfrankTime resolutions (or em(units of time)) are essential components of time specifications. Time resolutions are defined by objects of the class hi(ratio)tt(std::ratio). Before the class tt(ratio) can be used, the tthi(ratio) header file must be included. But the frquently included tt() header file already includes the tt(ratio) header file. The class tt(ratio) has two em(template arguments). These are positive integral numbers surrounded by pointed brackets defining, respectively, the numerator and denominator of a fraction (by default the denominator equals 1). Examples: verb( ratio<1> - representing one; ratio<60> - representing 60 ratio<1, 1000> - representing 1/1000.) The class tt(ratio) defines two directly accessible static data members: tt(num)hi(ratio: num) represents its numerator, tt(den)hi(ratio: den) its denominator. A tt(ratio) definition by itself simply defines a certain amount. E.g., when executing the following program verbinsert(//demo examples/ratio.cc) 1,200 is displayed, as that's the `amount' represented by tt(ratio<5, 1000>): tt(ratio) simplifies its fraction whenever possible. Several predefined tt(ratio) types exist. They are, like tt(ratio) itself, defined in the standard namespace and can be used instead of the more cumbersome tt(ratio) or tt(ratio) specifications: tablecenter(8)(llcllcll)( rowline() row() row(cell(tt(yocto)) cell(10+sups(-24)) cellq() cell(tt(zepto)) cell(10+sups(-21)) cellq() cells(2)()) rowline() row() row(cell(tt(atto)) cell(10+sups(-18)) cell() cell(tt(femto)) cell(10+sups(-15)) cell() cell(tt(pico)) cell(10+sups(-12))) row(cell(tt(nano)) cell(10+sups(-9)) cell() cell(tt(micro)) cell(10+sups(-6)) cell() cell(tt(milli)) cell(10+sups(-3))) row(cell(tt(centi)) cell(10+sups(-2)) cell() cell(tt(deci)) cell(10+sups(-1))) rowline() row() row(cell(tt(deca)) cell(10+sups(1)) cell() cell(tt(hecto)) cell(10+sups(2)) cell() cell(tt(kilo)) cell(10+sups(3))) row(cell(tt(mega)) cell(10+sups(6)) cell() cell(tt(giga)) cell(10+sups(9)) cell() cell(tt(tera)) cell(10+sups(12))) row(cell(tt(peta)) cell(10+sups(15)) cell() cell(tt(exa)) cell(10+sups(18))) rowline() row() row(cell(tt(zetta)) cell(10+sups(21)) cell() cell(tt(yotta)) cell(10+sups(24))) rowline() ) (em(note:) the definitions of the types tt(yocto, zepto, zetta) and tt(yotta) use integral constants exceeding 64 bits. Although these constants are defined in bf(C++), they are not available on 64 bit or smaller architectures.) Time related ratios can very well be interpreted as fractions or multiple of seconds, with tt(ratio<1, 1>) representing a resolution of one second. Here is an example showing how these abbreviations can be used: verbinsert(-s4 //milli examples/milli.cc) c++-annotations-13.02.01/yo/namespaces/chrono/intro.yo0000664000175000017500000000756414735537670021426 0ustar frankfrankThe bf(C) programming language offers tools like bf(sleep)(3) and bf(select)(2) to suspend program execution for a certain amount of time. And of course the family of bf(time)(3) functions for setting and displaying time tt(Sleep) and tt(select) can be used for waiting, but as they were designed in an era when multi threading was unavailable, their usefulness is limited when used in multi threaded programs. Multi threading has become part of bf(C++) (covered in detail in chapter ref(THREADING)), and additional time-related functions are available in the tt(std::filesystem) namespace, covered below in this chapter. In multi threaded programs threads are frequently suspended, albeit usually for a very short time. E.g., when a thread wants to access a variable, but the variable is currently being updated by another thread, then the former thread should wait until the latter thread has completed the update. Updating a variable usually doesn't take much time, but if it takes an unexpectedly long time, then the former thread may want to be informed about that, so it can do something else while the latter thread is busy updating the variable. Interactions between threads like these cannot be realized with functions like tt(sleep) and tt(select). The hi(chrono)tt(std::chrono) namespace bridges the gap between the traditionally available time-related functions and the time-related requirements of multi-threading and of the tt(std::filesystem) name space. All but the specific tt(std::filesystem) related time functionality is available after including the tthi(chrono) header file. After including the tthi(filesystem) header file the facilities of the tt(std::filesystem) are available. Time can be measured in various resolutions: in Olympic Games time differences of hundreds of seconds may make the distinction between gold and silver medals, but when planning a vacation we might talk about it months before we go on vacation. Time resolutions are specified by objects of the class tt(std::ratio), which (apart from including the tt() header file) is also available after including the tt() header file. Different events usually last for different amounts of time (given a specific time resolution). Amounts of time are specified by objects of the class tt(std::chrono::duration). Events can also be characterized by their points in time: midnight, January 1, 1970 GMT is a point in time, as is 19:00, December 5, 2010. Points in time are specified by objects of the class tt(std::chrono::time_point). It's not just that resolutions, durations of events, and points in time of events may differ, but the devices (clocks) we use for specifying time also differ. In the past em(hour glasses) were used (and sometimes they're still used when boiling eggs), but on the other hand we may use atomic clocks when measurements should be very precise. Four different types of clocks are available. The commonly used clock is tt(std::chrono::system_clock), but in the context of the file system there's also a tt(std::chrono::file_clock). In the upcoming sections the details of the tt(std::chrono) namespace are covered. First we look at characteristics of time resolutions. How to handle amounts of time given their resolutions is covered next. The next section describes facilities for defining and handling time-points. The relationships between these types and the various clock-types are covered thereafter. In this chapter the specification tt(std::chrono::) is often omitted (in practice tt(using namespace std) followed by tt(using namespace chrono) is commonly used; tt([std::]chrono::) specifications are occasionally used to avoid ambiguities). Also, every now and then you'll encounter em(forward references) to later chapters, like the reference to the chapter about multi-threading. These are hard to avoid, but studying those chapters at this point can safely be postponed without loss of continuity. c++-annotations-13.02.01/yo/namespaces/chrono/duration.yo0000664000175000017500000001150714735537670022110 0ustar frankfrankAmounts of time are specified by objects of the class hi(duration)tt(std::chrono::duration). Before using the class tt(duration) the tthi(chrono) header file must be included. The class tt(duration) has two template arguments. A numeric type (tt(int64_t) is normally used) defining the type holding the duration's amount of time, and a time-resolution tt(ratio) (called its em(resolution)). Often the following predefined tt(duration) types are used: center( tbl(lll)(\ tline()()\ tr(tc(tt(predefined:))tc(nbsp())tc(tt(duration type)))\ tline()()\ tr(tc(tt(nanoseconds))tc(nbsp())tc(tt(duration)))\ tr(tc(tt(microseconds))tc(nbsp())tc(tt(duration)))\ tr(tc(tt(milliseconds))tc(nbsp())tc(tt(duration)))\ tr(tc(tt(seconds))tc(nbsp())tc(tt(duration)))\ tr(tc(tt(minutes))tc(nbsp())tc(tt(duration>)))\ tr(tc(tt(hours))tc(nbsp())tc(tt(duration>)))\ tline()()\ )) E.g., to define a duration of 30 minutes use tt(minutes halfHour{ 30 }). The suffixes tt(h, min, s, ms, us, ns) are available for integral values, creating the corresponding tt(duration) times. E.g., tt(minutes min = 1h) stores 60 minutes in tt(min). bf(Sub-types): itemization( itt(rep): the duration's numeric type (commonly tt(int64_t)); itt(period): the tt(ratio) type (like tt(kilo)). E.g., tt(minutes::period::num) equals 60. ) COMMENT(all constexpr, the constructor: explicit) bf(Constructors): itemization( itt(duration()):nl() the default constructor initializes the object to 0 units; itt(duration(Type const &value)):nl() the object is initialized to tt(value) time units (tt(Type) refers to the duration's numeric type. E.g., when defining tt(minutes halfHour{ 30 }) the argument 30 is stored inside its tt(int64_t) data member). ) Copy- and move-constructors (cf. chapter ref(MEMORY)) are available. bf(Operators): Duration types support assignment, negation (e.g., tt(halfHour = -halfHour)), addition and subtraction of duration values, and also multiplication, division and modulo computations by numeric factors. Compound assignment operators are also available. E.g., verb( minutes time = 2 * halfHour; // time: 60 minutes time += minutes{ 30 }; // time: 90 minutes ) bf(Members): itemization( itt(Type count() const) returns the value stored inside the tt(duration) object. E.g., tt(minutes{ 30 }.count()) returns 30. The following members are static members; itt(duration::zero()) returns an (immutable) duration object whose tt(count) member returns 0. E.g., tt(seconds::zero().count()) returns tt(0s); itt(duration::min()) returns an (immutable) duration object whose tt(count) member returns the lowest value of its tt(rep) type (i.e., tt(std::numeric_limits::min()) (cf. section ref(NUMLIM))); itt(duration::max()) returns an (immutable) duration object whose tt(count) member returns the maximum value of its tt(rep) type. ) bf(Conversions): The precision of left-hand side arguments of assignment operators must be greater than or equal to the precision of the right-hand side arguments (the left-hand argument may not lose precision). When using binary arithmetic operators the resulting duration type has a precision equal to the finer of the two precisions. E.g., verb( cout << (1min + 1h).count() << '\n'; // shows: 61 hours hr{ 1 }; halfHour += hr; // OK // hr += halfHours; // won't compile ) Durations can be converted by the hi(duration_cast) tt(std::chrono::duration_cast(source)) function template, where tt(destination) is the destination's tt(duration) type and tt(source) is an available tt(destination) object, but tt(duration_cast) truncates the destination value when tt(destination's) precision is less than tt(source's) precision. E.g., tt(duration_cast(seconds{ 90 })) returns tt(minutes{ 1 }). When the left-hand side argument's precision em(is) less than the right-hand side's precision some decision must be made about how to handle the loss of precision. The following function template can be used to convert a duration to a less precise type, returning a tt(double) value, which can be, e.g., truncated or rounded. verb( template double durationCast(From from) { return static_cast(from.count()) * To::period::den * From::period::num / (To::period::num * From::period::den); } ) returning a tt(double) value (1.5 when called as tt(durationCast(seconds{ 90 }))), leaving the decision how to use the returned tt(double) value to the caller. c++-annotations-13.02.01/yo/namespaces/outside.yo0000664000175000017500000000654314735537670020453 0ustar frankfrankIt is not strictly necessary to i(define members of namespaces) inside a namespace region. But before an entity is defined em(outside) of a namespace it must have been declared em(inside) its namespace. To define an entity outside of its namespace its name must be em(fully qualified) by prefixing the member by its namespaces. The definition may be provided at the global level or at intermediate levels in the case of nested namespaces. This allows us to define an entity belonging to namespace tt(A::B) within the region of namespace tt(A). Assume the type tt(int INT8[8]) is defined in the tt(CppAnnotations::Virtual) namespace. Furthermore assume that it is our intent to define a function tt(squares), inside the namespace nl() tt(CppAnnotations::Virtual) returning a pointer to tt(CppAnnotations::Virtual::INT8). Having defined the prerequisites within the tt(CppAnnotations::)tt(Virtual) namespace, our function could be defined as follows (cf. chapter ref(MEMORY) for coverage of the memory allocation operator tt(new[])): verb( namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } } }) The function tt(squares) defines an array of one tt(INT8) vector, and returns its address after initializing the vector by the squares of the first eight natural numbers. Now the function tt(squares) can be defined outside of the tt(CppAnnotations::)tt(Virtual) namespace: verb( namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares(); } } CppAnnotations::Virtual::INT8 *CppAnnotations::Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; }) In the above code fragment note the following: itemization( itt(squares) is declared inside of the tt(CppAnnotations::Virtual) namespace. itt() The definition outside of the namespace region requires us to use the fully qualified name of the function em(and) of its return type. itt() em(Inside) the body of the function tt(squares) we are within the tt(CppAnnotations::)tt(Virtual) namespace, so inside the function fully qualified names (e.g., for tt(INT8)) are not required any more. ) Finally, note that the function could also have been defined in the tt(CppAnnotations) region. In that case the tt(Virtual) namespace would have been required when defining tt(squares()) and when specifying its return type, while the internals of the function would remain the same: verb( namespace CppAnnotations { namespace Virtual { void *pointer; using INT8 = int[8]; INT8 *squares(); } Virtual::INT8 *Virtual::squares() { INT8 *ip = new INT8[1]; for (size_t idx = 0; idx != sizeof(INT8) / sizeof(int); ++idx) (*ip)[idx] = (idx + 1) * (idx + 1); return ip; } }) c++-annotations-13.02.01/yo/namespaces/closed.yo0000664000175000017500000000133614735537670020243 0ustar frankfrankNamespaces can be defined without a name. Such an hi(namespace: anonymous) anonymous namespace restricts the visibility of the defined entities to the source file defining the anonymous namespace. Entities defined in the anonymous namespace are comparable to bf(C)'s ti(static) functions and variables. In bf(C++) the tt(static) keyword can still be used, but its preferred use is in tt(class) definitions (see chapter ref(Classes)). In situations where in bf(C) static variables or functions would have been used the anonymous namespace should be used in bf(C++). The anonymous namespace is a hi(namespace: closed) closed namespace: it is not possible to add entities to the same anonymous namespace using different source files. c++-annotations-13.02.01/yo/namespaces/directive.yo0000664000175000017500000000365714735537670020760 0ustar frankfrankA generalized alternative to the tt(using) declaration is the emi(using directive): verb( using namespace CppAnnotations;) Following this directive, em(all) entities defined in the tt(CppAnnotations) namespace are used as if they were declared by tt(using) declarations. While the tt(using) directive is a quick way to hi(namespace: import all names) import all the names of a namespace (assuming the namespace has previously been declared or defined), it is at the same time a somewhat dirty way to do so, as it is less clear what entity is actually used in a particular block of code. If, e.g., tt(cos) is defined in the tt(CppAnnotations) namespace, tt(CppAnnotations::cos) is going to be used when tt(cos) is called. However, if tt(cos) is em(not) defined in the tt(CppAnnotations) namespace, the standard tt(cos) function will be used. The tt(using) directive does not document as clearly as the tt(using) declaration what entity will actually be used. Therefore use caution when applying the tt(using) directive. Namespace declarations are context sensitive: when a tt(using namespace) declaration is specified inside a compound statement then the declaration is valid until the compound statement's closing curly brace has been encountered. In the next example a string tt(first) is defined without explicit specifying tt(std::string), but once the compound statement has ended the scope of the tt(using namespace std) declaration has also ended, and so tt(std::) is required once again when defining tt(second): verb( #include int main() { { using namespace std; string first; } std::string second; }) A tt(using namespace) directive cannot be used within the declaration block of a class- or enumeration-type. E.g., the following example won't compile: verb( struct Namespace { using namespace std; // won't compile };) c++-annotations-13.02.01/yo/concrete/0000775000175000017500000000000014735537670016101 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fdunget.yo0000664000175000017500000001056114735537670020111 0ustar frankfranktt(Streambuf) classes and classes derived from ti(streambuf) should support em(at least) ungetting the last read character. Special care must be taken when em(series) of ti(unget) calls must be supported. In this section the construction of a class supporting a configurable number of tt(istream::unget) or hi(putback)tt(istream::putback) calls is discussed. Support for multiple (say `tt(n)') tt(unget) calls is implemented by reserving an initial section of the input buffer, which is gradually filled up to contain the last tt(n) characters read. The class is implemented as follows: itemization( it() Once again, the class is derived from tt(std::streambuf). It defines several data members, allowing the class to perform the bookkeeping required to maintain an unget-buffer of a configurable size: verbinclude(//CLASS examples/fdunget.h) it() The class's constructor expects a i(file descriptor), a buffer size and the number of characters that can be ungot or pushed back as its arguments. This number determines the size of a em(reserved) area, defined as the first tt(d_reserved) bytes of the class's input buffer. itemization( it() The input buffer will always be at least one byte larger than tt(d_reserved). So, a certain number of bytes may be read. Once tt(d_reserved) bytes have been read at most tt(d_reserved) bytes can be ungot. it() Next, the starting point for reading operations is configured. It is called tt(d_base), pointing to a location tt(d_reserved) bytes beyond the location represented by tt(d_buffer). This is always the location where buffer refills start. it() Now that the buffer has been constructed, we're ready to define tt(streambuf)'s buffer pointers using tt(setg). As no characters have been read yet, all pointers are set to point to tt(d_base). If tt(unget) is called at this point, no characters are available, and tt(unget) (correctly) fails. it() Eventually, the refill buffer's size is determined as the number of allocated bytes minus the size of the reserved area. ) Here is the class's constructor: verbinclude(//CONS examples/fdunget.h) it() The class's destructor simply returns the memory allocated for the buffer to the common pool: verbinclude(//DESTR examples/fdunget.h) it() Finally, tt(underflow) is overridden as follows: itemization( it() First tt(underflow) determines the number of characters that could potentially be ungot. If that number of characters are ungot, the input buffer is exhausted. So this value may be any value between 0 (the initial state) or the input buffer's size (when the reserved area has been filled up completely, and all current characters in the remaining section of the buffer have also been read); it() Next the number of bytes to move into the reserved area is computed. This number is at most tt(d_reserved), but it is set equal to the actual number of characters that can be ungot if this value is smaller; it() Now that the number of characters to move into the reserved area is known, this number of characters is moved from the input buffer's end to the area immediately before tt(d_base); it() Then the buffer is refilled. This all is standard, but notice that reading starts from tt(d_base) and not from tt(d_buffer); it() Finally, tt(streambuf)'s read buffer pointers are set up. hi(eback) tt(Eback) is set to tt(move) locations before tt(d_base), thus defining the guaranteed unget-area, ti(gptr) is set to tt(d_base), since that's the location of the first read character after a refill, and ti(egptr) is set just beyond the location of the last character read into the buffer. ) Here is tt(underflow)'s implementation: verbinclude(//UNDERFLOW examples/fdunget.h) ) bf(An example using FdUnget) The next example program illustrates the use of the class tt(FdUnget). It reads at most 10 characters from the standard input, stopping at endOfFile(). A guaranteed unget-buffer of 2 characters is defined in a buffer holding 3 characters. Just before reading a character, the program tries to unget at most 6 characters. This is, of course, not possible; but the program nicely ungets as many characters as possible, considering the actual number of characters read: verbinclude(-a examples/fdunget.cc) c++-annotations-13.02.01/yo/concrete/predicates.yo0000664000175000017500000000711514735537670020601 0ustar frankfrankMany tt(STL) algorithms require us to specify predicates. For example tt(count_if()) (ref(COUNT)), tt(find_if()) (ref(FIND)), tt(min_element()) (ref(MINEL)) or tt(search()) (ref(SEARCH)). In these cases a function object must be provided whose tt(operator()()) member is called, defining the predicate function. Conditional to its argument(s), it returns tt(true) or tt(false). Sometimes a simple emi(predicate function) already exists. For example tt(int isdigit(int)) returns if its argument is a character representing a digit, otherwise 0; tt(char *strchr(char const *, int)) returns a non-0 pointer if the set of characters provided as its first argument contains the character represented by its second argument, and returns 0 otherwise. Existing unary predicate functions may be specified with the tt(PredicateFunction1) class template, defining a unary predicate class. Its ti(argument_type) using-declaration is required by, e.g., function adapters: verbinclude(//UNARYPRED examples/predicates.h) Existing binary predicate functions may be specified with the tt(PredicateFunction2) class template, defining a binary predicate class. Its ti(first_argument_type), ti(second_argument_type) and ti(result_type) using-declarations are required by, e.g., function adapters: verbinclude(//BINPRED examples/predicates.h) Here is an example of their use, counting the number of digits appearing at the program's standard input stream: verbinclude(-a examples/predfun.cc) Alternatively, although the function operator is called when a predicate function is used, the actual member function we have available might be another function or a useful member may be available from an object of another class. In that case an object acting as em(man in the middle) might come in handy. The following class tt(PredicateObject1) performs exactly that function. It defines a class template whose parameters refer to a class and a data type. Its constructors expect a pointer or reference to an object of the template parameter's class as well as a pointer to a member function of that class implementing a predicate. By default it's the class's function object operator. Here is its definition: verbinclude(//PREDOBJ1 examples/predicates.h) The class tt(PredicateObject2) can be used to construct a emi(binary predicate) object. Here the class template has three parameters: the class type of the object passed to its constructor as well as the types of the two arguments of the binary predicate member that's called: verbinclude(//PREDOBJ2 examples/predicates.h) The object passed to these constructors is not copied by generic algorithms, in contrast to the tt(PredicateObject)s themselves, which em(are) copied. The object specified when instantiating the tt(PredicateObject)s must actually exist before the instantiation takes place. Also, the object's members do not have to be tt(const) member functions, thus allowing modifications of the passed object's data. Function adapters may be used with the tt(PredicateObject)s as well. Here is an example using tt(PredicateObject)s. The program counts the number of words containing vowels appearing at the program's standard input stream. First a support class tt(Contains) is defined. It's a simple class defining unary and binary predicate functions: verbinclude(//CONTAINS examples/predobj.cc) When the program is called without arguments its unary predicate object functionality is used, otherwise its binary predicate object functionality. Here is the program's tt(main()) function: verbinclude(//MAIN examples/predobj.cc) c++-annotations-13.02.01/yo/concrete/examples/0000775000175000017500000000000014771010711017675 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/examples/fork.h0000664000175000017500000000105414771010714021012 0ustar frankfrank//CLASS class Fork { int d_pid; public: virtual ~Fork(); void fork(); protected: int pid() const; int waitForChild(); // returns the status private: virtual void childRedirections(); virtual void parentRedirections(); virtual void childProcess() = 0; // pure virtual members virtual void parentProcess() = 0; }; //= //PID inline int Fork::pid() const { return d_pid; } //= c++-annotations-13.02.01/yo/concrete/examples/ifdnbuf.h0000664000175000017500000000424114771010714021467 0ustar frankfrank #ifndef IFDNBUF_H_ #define IFDNBUF_H_ #include #include #include //CLASS class IFdNStreambuf: public std::streambuf { protected: int d_fd = -1; size_t d_bufsize = 0; char* d_buffer = 0; public: IFdNStreambuf() = default; IFdNStreambuf(int fd, size_t bufsize = 1); ~IFdNStreambuf() override; void open(int fd, size_t bufsize = 1); private: int underflow() override; std::streamsize xsgetn(char *dest, std::streamsize n) override; }; //= //CONS inline IFdNStreambuf::IFdNStreambuf(int fd, size_t bufsize) { open(fd, bufsize); } //= // In real applications, the following members should be defined in // source files. Headers should not have external linkage. //DESTR IFdNStreambuf::~IFdNStreambuf() { if (d_bufsize) { close(d_fd); delete[] d_buffer; } } //= //OPEN void IFdNStreambuf::open(int fd, size_t bufsize) { d_fd = fd; d_bufsize = bufsize == 0 ? 1 : bufsize; delete[] d_buffer; d_buffer = new char[d_bufsize]; setg(d_buffer, d_buffer + d_bufsize, d_buffer + d_bufsize); } //= //UFLOW int IFdNStreambuf::underflow() { if (gptr() < egptr()) return *gptr(); int nread = read(d_fd, d_buffer, d_bufsize); if (nread <= 0) return EOF; setg(d_buffer, d_buffer, d_buffer + nread); return static_cast(*gptr()); } //= //XSGETN std::streamsize IFdNStreambuf::xsgetn(char *dest, std::streamsize n) { int nread = 0; while (n) { if (!in_avail()) { if (underflow() == EOF) break; } int avail = in_avail(); if (avail > n) avail = n; memcpy(dest + nread, gptr(), avail); gbump(avail); nread += avail; n -= avail; } return nread; } //= #endif c++-annotations-13.02.01/yo/concrete/examples/lines0.h0000664000175000017500000000034714771010714021247 0ustar frankfrank #include #include //LINES class Lines { std::vector d_line; public: Lines(std::istream &in); std::string &operator[](size_t idx); }; //= c++-annotations-13.02.01/yo/concrete/examples/buildslurp0000775000175000017500000000010714735537670022030 0ustar frankfrank#!/bin/bash g++ -Wall parentslurp.cc fork.cc pipe.cc waitforchild.cc c++-annotations-13.02.01/yo/concrete/examples/fdout.cc0000664000175000017500000000143714771010716021337 0ustar frankfrank #include #include #include #include "fdout.h" using namespace std; int main(int argc, char **argv) { OFdnStreambuf fds(STDOUT_FILENO, 500); ostream os(&fds); switch (argc) { case 1: for (string s; getline(cin, s); ) os << s << '\n'; os << "COPIED cin LINE BY LINE\n"; break; case 2: cin >> os.rdbuf(); // Alternatively, use: cin >> &fds; os << "COPIED cin BY EXTRACTING TO os.rdbuf()\n"; break; case 3: os << cin.rdbuf(); os << "COPIED cin BY INSERTING cin.rdbuf() into os\n"; break; } } c++-annotations-13.02.01/yo/concrete/examples/fdunget.cc0000664000175000017500000000402014771010716021641 0ustar frankfrank #include "fdunget.h" #include #include #include using namespace std; int main() { FdUnget fds(0, 3, 2); istream is(&fds); char c; for (int idx = 0; idx < 10; ++idx) { cout << "after reading " << idx << " characters:\n"; for (int ug = 0; ug <= 6; ++ug) { if (!is.unget()) { cout << "\tunget failed at attempt " << (ug + 1) << "\n" << "\trereading: '"; is.clear(); while (ug--) { is.get(c); cout << c; } cout << "'\n"; break; } } if (!is.get(c)) { cout << " reached\n"; break; } cout << "Next character: " << c << '\n'; } } /* Generated output after 'echo abcde | program': after reading 0 characters: unget failed at attempt 1 rereading: '' Next character: a after reading 1 characters: unget failed at attempt 2 rereading: 'a' Next character: b after reading 2 characters: unget failed at attempt 3 rereading: 'ab' Next character: c after reading 3 characters: unget failed at attempt 4 rereading: 'abc' Next character: d after reading 4 characters: unget failed at attempt 4 rereading: 'bcd' Next character: e after reading 5 characters: unget failed at attempt 4 rereading: 'cde' Next character: after reading 6 characters: unget failed at attempt 4 rereading: 'de ' reached */ c++-annotations-13.02.01/yo/concrete/examples/foreach.h0000664000175000017500000000205514771010714021462 0ustar frankfrank //FOREACH1 template Class &ForEach(Iterator begin, Iterator end, Class &object, void (Class::*member)(Data &)) { while (begin != end) (object.*member)(*begin++); return object; } //= //FOREACH2 template Class &ForEach(Iterator begin, Iterator end, Class &object, void (Class::*member)(Data &) const) { while (begin != end) (object.*member)(*begin++); return object; } //= //FOREACH3 template Class &ForEach(Iterator begin, Iterator end, Class &object) { while (begin != end) object(*begin++); return object; } //= //FOREACH4 template void ForEach(Iterator begin, Iterator end, Data(*function)(Data)) { for (; begin != end; ++begin) *begin = function(*begin); } //= c++-annotations-13.02.01/yo/concrete/examples/fork.ih0000664000175000017500000000017214771010714021163 0ustar frankfrank #include "fork.h" #include #include #include #include c++-annotations-13.02.01/yo/concrete/examples/predfun.cc0000664000175000017500000000206314771010716021655 0ustar frankfrank #include #include #include #include #include #include #include "predicates.h" using namespace std; int main(int argc, char **argv) { if (argc == 1) cout << "Counted " << count_if(istream_iterator(cin), istream_iterator(), PredicateFunction1(isdigit)) << " digits\n"; else cout << "Counted " << count_if(istream_iterator(cin), istream_iterator(), bind1st( PredicateFunction2(strchr), "0123456789") ) << " digits\n"; } /* Generated output after echo 1 world, there are 6 continents and 3 oceans | a.out or: echo 1 world, there are 6 continents and 3 oceans | a.out 2 Counted 3 digits */ c++-annotations-13.02.01/yo/concrete/examples/command.h0000664000175000017500000000062414771010714021471 0ustar frankfrank #include #include #include class Command { std::string d_line; std::vector d_command; public: Command(size_t n, char const **commands) { copy(commands, commands + n, back_inserter(d_command)); } int next(std::string &line); }; c++-annotations-13.02.01/yo/concrete/examples/fdout.h0000664000175000017500000000300314771010714021166 0ustar frankfrank #ifndef OFDNSTREAMBUF_H_ #define OFDNSTREAMBUF_H_ #include #include //CLASS class OFdnStreambuf: public std::streambuf { int d_fd = -1; size_t d_bufsize = 0; char *d_buffer = 0; public: OFdnStreambuf() = default; OFdnStreambuf(int fd, size_t bufsize = 1); ~OFdnStreambuf() override; void open(int fd, size_t bufsize = 1); private: int sync() override; int overflow(int c) override; }; //= //CONS inline OFdnStreambuf::OFdnStreambuf(int fd, size_t bufsize) { open(fd, bufsize); } //= //DESTR inline OFdnStreambuf::~OFdnStreambuf() { if (d_buffer) { sync(); delete[] d_buffer; } } //= //OPEN inline void OFdnStreambuf::open(int fd, size_t bufsize) { d_fd = fd; d_bufsize = bufsize == 0 ? 1 : bufsize; delete[] d_buffer; d_buffer = new char[d_bufsize]; setp(d_buffer, d_buffer + d_bufsize); } //= //SYNC inline int OFdnStreambuf::sync() { if (pptr() > pbase()) { write(d_fd, d_buffer, pptr() - pbase()); setp(d_buffer, d_buffer + d_bufsize); } return 0; } //= //OVERFLOW inline int OFdnStreambuf::overflow(int c) { sync(); if (c != EOF) { *pptr() = c; pbump(1); } return c; } //= #endif c++-annotations-13.02.01/yo/concrete/examples/lines.h0000664000175000017500000000227114771010714021165 0ustar frankfrank#include #include #include #include //LINES class Lines { std::vector d_line; public: class Proxy; Proxy operator[](size_t idx); class Proxy { friend Proxy Lines::operator[](size_t idx); std::string &d_str; Proxy(std::string &str); public: std::string &operator=(std::string const &rhs); operator std::string const &() const; }; Lines(std::istream &in); }; //= //MEMBERS inline Lines::Proxy::Proxy(std::string &str) : d_str(str) {} inline std::string &Lines::Proxy::operator=(std::string const &rhs) { return d_str = rhs; } inline Lines::Proxy::operator std::string const &() const { return d_str; } //= //INSERT inline std::ostream &operator<<(std::ostream &out, Lines::Proxy const &proxy) { return out << static_cast(proxy); } //= //OPIDX inline Lines::Proxy Lines::operator[](size_t idx) { Proxy ret(d_line[idx]); return ret; } //= c++-annotations-13.02.01/yo/concrete/examples/a2x.h0000664000175000017500000000232714771010714020547 0ustar frankfrank#ifndef INCLUDED_A2X_H_ #define INCLUDED_A2X_H_ #include #include //CLASS class A2x: public std::istringstream { public: A2x() = default; A2x(char const *txt); A2x(std::string const &str); template operator Type(); template Type to(); A2x &operator=(char const *txt); A2x &operator=(std::string const &str); A2x &operator=(A2x const &other); }; //= //CONS inline A2x::A2x(char const *txt) // initialize from text : std::istringstream(txt) {} inline A2x::A2x(std::string const &str) : std::istringstream(str.c_str()) {} //= //TO template inline Type A2x::to() { Type t; return (*this >> t) ? t : Type(); } //= //TYPE template inline A2x::operator Type() { return to(); } //= inline A2x &A2x::operator=(std::string const &str) { return operator=(str.c_str()); } //OP= inline A2x &A2x::operator=(A2x const &other) { return operator=(other.str()); } //= #endif c++-annotations-13.02.01/yo/concrete/examples/rsh.cc0000664000175000017500000000262614771010716021013 0ustar frankfrank #include #include #include #include #include using namespace std; int main() { while (true) { string cmd; cout << "rsh: " << flush; cin >> cmd; if (cmd == "exit") { cout << "terminating the shell\n"; return 0; } if (cmd != "date" && cmd != "id") { cout << "Command " << cmd << " disallowed\n"; continue; } pid_t pid = fork(); if (pid == 0) { execlp(cmd.c_str(), cmd.c_str(), 0); cerr << "Execution of " << cmd << " failed\n"; return 1; } if (pid < 0) { cerr << "Fork() failed\n"; return 1; } int status; wait(&status); if ((status = WEXITSTATUS(status))) cerr << cmd << " returned exit status " << status << '\n'; } } /* Example of generated conversation: rsh: opa Command opa disallowed rsh: date Tue Jul 17 23:19:08 CEST 2001 rsh: id uid=405(frank) gid=100(users) groups=100(users),4(adm) rsh: quit Command quit disallowed rsh: exit terminating the shell */ c++-annotations-13.02.01/yo/concrete/examples/binopclasses.cc0000664000175000017500000000612614771010716022703 0ustar frankfrank#include #include #include // The complete interface of the class template Binops: if additional // operators are overloaded Binops requires no modifications. // template class Binops { template friend std::ostream &operator<<( std::ostream &out, Binops const &rhs); template friend std::istream &operator>>(std::istream &in, Binops &rhs); void eWrap(std::istream &in); void iWrap(std::ostream &out) const; }; // Completing the overloads for operator+: all function templates, that // depend on operator+=(...) defined in Derived // template Derived &operator+=(Binops &lhs, Rhs const &rhs) { Derived tmp{ Derived{static_cast(lhs)} += rhs }; tmp.swap(static_cast(lhs)); return static_cast(lhs); } template Derived operator+(Binops &&lhs, Rhs const &rhs) { return static_cast(std::move(lhs)) += rhs; } template Derived operator+(Binops const &lhs, Rhs const &rhs) { return Derived{static_cast(lhs)} += rhs; } // Other operators may be added here, and are implemented analogously, see // the Annotations. // Implementing the insertion operator. The extraction operator is // implemented analogously, see the Annotations: // template inline void Binops::iWrap(std::ostream &out) const { static_cast(*this).insert(out); } template inline std::ostream &operator<<(std::ostream &out, Binops const &rhs) { rhs.iWrap(out); return out; } //////////////////////////////////////////////////////////////////////// // User area: the user defines a class Derived, and wants to provide // addition and insertion: the operator+=() && and insert() functions have // to be implemented and Derived derives from Binops. For insert // a friend declaration is also required. #include using namespace std; class Derived: public Binops { friend Binops; // only required for stream insertion/extraction int d_value = 0; public: Derived() = default; Derived(int value) : d_value(value) {} void swap(Derived &other); Derived &&operator+=(Derived const &rhs) &&; private: void insert(std::ostream &out) const; }; inline void Derived::insert(std::ostream &out) const { out << "Inserting a Derived object"; } Derived &&Derived::operator+=(Derived const &rhs) && { d_value += rhs.d_value; return std::move(*this); } inline void Derived::swap(Derived &rhs) { std::swap(d_value, rhs.d_value); } int main() { Derived o1{ 1 }, Derived o2{ 2 }; o1 += o2; // o1 *= o2; // adding this statement results in // a compilation error o1 = o1 + o2; o1 += o1; cout << o1 << '\n'; } c++-annotations-13.02.01/yo/concrete/examples/pipe.cc0000664000175000017500000000164514771010716021154 0ustar frankfrank #include "pipe.h" #include //CONS Pipe::Pipe() { if (pipe(d_fd)) throw "Pipe::Pipe(): pipe() failed"; } //= //REDIRECT void Pipe::redirect(int d_fd, int alternateFd) { if (dup2(d_fd, alternateFd) < 0) throw "Pipe: redirection failed"; } //= //READ int Pipe::readOnly() { close(d_fd[WRITE]); return d_fd[READ]; } void Pipe::readFrom(int fd) { readOnly(); redirect(d_fd[READ], fd); close(d_fd[READ]); } //= //WRITE int Pipe::writeOnly() { close(d_fd[READ]); return d_fd[WRITE]; } void Pipe::writtenBy(int fd) { writtenBy(&fd, 1); } void Pipe::writtenBy(int const *fd, size_t n) { writeOnly(); for (size_t idx = 0; idx < n; idx++) redirect(d_fd[WRITE], fd[idx]); close(d_fd[WRITE]); } //= c++-annotations-13.02.01/yo/concrete/examples/iterators/0000775000175000017500000000000014771010711021711 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/examples/iterators/output.cc0000664000175000017500000000025314771010716023565 0ustar frankfrank#include "input.h" #include "output.h" #include using namespace std; int main() { copy(InputIterator{ 0 }, InputIterator{ 100 }, OutputIterator{ 0 }); } c++-annotations-13.02.01/yo/concrete/examples/iterators/random.h0000664000175000017500000000367414771010714023357 0ustar frankfrank #include struct RandomIterator { using iterator_category = std::bidirectional_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: RandomIterator(int init); // standard: bool operator==(RandomIterator const &other) const; bool operator!=(RandomIterator const &other) const; int &operator*(); RandomIterator &operator++(); // required: int operator-(RandomIterator const &rhs) const; RandomIterator operator+(int step) const; RandomIterator operator-(int step) const; bool operator<(RandomIterator const &other) const; // consider: int *operator->() const; RandomIterator &operator--(); RandomIterator operator--(int); RandomIterator operator++(int); RandomIterator &operator-=(int step); RandomIterator &operator+=(int step); }; RandomIterator::RandomIterator(int init) : d_value(init) {} bool RandomIterator::operator!=(RandomIterator const &other) const { return d_value != other.d_value; } bool RandomIterator::operator==(RandomIterator const &other) const { return d_value == other.d_value; } bool RandomIterator::operator<(RandomIterator const &other) const { return d_value < other.d_value; } int RandomIterator::operator-(RandomIterator const &rhs) const { return 0; } RandomIterator RandomIterator::operator+(int step) const { return *this; } RandomIterator RandomIterator::operator-(int step) const { return *this; } RandomIterator &RandomIterator::operator--() { return *this; } RandomIterator &RandomIterator::operator++() { return *this; } int &RandomIterator::operator*() { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/iterators/forward.cc0000664000175000017500000000022114771010716023664 0ustar frankfrank#include "forward.h" #include using namespace std; int main() { adjacent_find(ForwardIterator{ 0 }, ForwardIterator{ 100 }); } c++-annotations-13.02.01/yo/concrete/examples/iterators/iterator.h0000664000175000017500000000262714771010714023725 0ustar frankfrank #include struct RandomIterator { using iterator_category = std::bidirectional_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: RandomIterator(int init); bool operator==(RandomIterator const &other) const; int operator-(RandomIterator const &rhs) const; RandomIterator operator+(int step) const; RandomIterator &operator--() int &operator*(); int *operator->() const; bool operator<(RandomIterator const &other) const; RandomIterator operator--(int); RandomIterator &operator++(); RandomIterator operator++(int); RandomIterator operator-(int step) const; RandomIterator &operator-=(int step); RandomIterator &operator+=(int step); }; RandomIterator::RandomIterator(int init) : d_value(init) {} bool RandomIterator::operator!=(RandomIterator const &other) const { return d_value != other.d_value; } int RandomIterator::operator-(RandomIterator const &rhs) const { return 0; } RandomIterator &RandomIterator::operator--() { return *this; } int &RandomIterator::operator*() { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/iterators/bidirectional.h0000664000175000017500000000245514771010714024703 0ustar frankfrank #include struct BidirectionalIterator { using iterator_category = std::bidirectional_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: BidirectionalIterator(int init); // standard: bool operator==(BidirectionalIterator const &other) const; bool operator!=(BidirectionalIterator const &other) const; int &operator*(); BidirectionalIterator &operator++(); // required: BidirectionalIterator &operator--(); // consider: int *operator->(); }; BidirectionalIterator::BidirectionalIterator(int init) : d_value(init) {} bool BidirectionalIterator::operator!=(BidirectionalIterator const &other) const { return d_value != other.d_value; } bool BidirectionalIterator::operator==(BidirectionalIterator const &other) const { return d_value == other.d_value; } BidirectionalIterator &BidirectionalIterator::operator++() { return *this; } BidirectionalIterator &BidirectionalIterator::operator--() { return *this; } int &BidirectionalIterator::operator*() { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/iterators/bidirectional.cc0000664000175000017500000000050214771010716025032 0ustar frankfrank#include "bidirectional.h" #include using namespace std; int main() { inplace_merge(BidirectionalIterator{ 0 }, BidirectionalIterator{ 100 }, BidirectionalIterator{ 200 }); next_permutation(BidirectionalIterator{ 0 }, BidirectionalIterator{ 100 }); } c++-annotations-13.02.01/yo/concrete/examples/iterators/input.cc0000664000175000017500000000021114771010716023356 0ustar frankfrank#include "input.h" #include using namespace std; int main() { accumulate(InputIterator{ 0 }, InputIterator{ 100 }, 0); } c++-annotations-13.02.01/yo/concrete/examples/iterators/input.h0000664000175000017500000000211014771010714023216 0ustar frankfrank #include struct InputIterator { using iterator_category = std::input_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: InputIterator(int init); // standard: bool operator==(InputIterator const &other) const; bool operator!=(InputIterator const &other) const; int const &operator*() const; InputIterator &operator++(); // consider: int const *operator->() const; }; InputIterator::InputIterator(int init) : d_value(init) {} bool InputIterator::operator!=(InputIterator const &other) const { return d_value != other.d_value; } bool InputIterator::operator==(InputIterator const &other) const { return d_value == other.d_value; } InputIterator &InputIterator::operator++() { return *this; } int const &InputIterator::operator*() const { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/iterators/output.h0000664000175000017500000000206314771010714023426 0ustar frankfrank #include struct OutputIterator { using iterator_category = std::output_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: OutputIterator(int init); // standard: bool operator==(OutputIterator const &other) const; bool operator!=(OutputIterator const &other) const; int &operator*(); OutputIterator &operator++(); // consider: int *operator->(); }; OutputIterator::OutputIterator(int init) : d_value(init) {} bool OutputIterator::operator!=(OutputIterator const &other) const { return d_value != other.d_value; } bool OutputIterator::operator==(OutputIterator const &other) const { return d_value == other.d_value; } OutputIterator &OutputIterator::operator++() { return *this; } int &OutputIterator::operator*() { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/iterators/random.cc0000664000175000017500000000020514771010716023502 0ustar frankfrank#include "random.h" #include using namespace std; int main() { sort(RandomIterator{ 0 }, RandomIterator{ 100 }); } c++-annotations-13.02.01/yo/concrete/examples/iterators/forward.h0000664000175000017500000000210214771010714023524 0ustar frankfrank #include struct ForwardIterator { using iterator_category = std::forward_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = int; using pointer = value_type *; using reference = value_type &; private: int d_value; public: ForwardIterator(int init); // standard: bool operator==(ForwardIterator const &other) const; bool operator!=(ForwardIterator const &other) const; int &operator*(); ForwardIterator &operator++(); // consider: int *operator->(); }; ForwardIterator::ForwardIterator(int init) : d_value(init) {} bool ForwardIterator::operator!=(ForwardIterator const &other) const { return d_value != other.d_value; } bool ForwardIterator::operator==(ForwardIterator const &other) const { return d_value == other.d_value; } ForwardIterator &ForwardIterator::operator++() { return *this; } int &ForwardIterator::operator*() { return d_value; } c++-annotations-13.02.01/yo/concrete/examples/noredir.cc0000664000175000017500000000077114771010716021660 0ustar frankfrank #include #include #include using namespace std; int main() { ofstream of("outfile"); streambuf *buf = cout.rdbuf(of.rdbuf()); cout << "To the of stream\n"; system("echo hello world"); cout << "To the of stream\n"; cout.rdbuf(buf); } /* Generated output: on the file `outfile' To the of stream To the of stream On standard output: hello world */ c++-annotations-13.02.01/yo/concrete/examples/foreachdemo.cc0000664000175000017500000000264614771010716022475 0ustar frankfrank#include #include #include #include "foreach.h" //VECTOR2 template class Vector2: public std::vector > { using iterator = typename Vector2::iterator; template friend Class &ForEach(Iterator begin, Iterator end, Class &object, void (Class::*member)(Data &)); public: void process(); private: void rows(std::vector &row); void columns(Type &str); }; template void Vector2::process() { ForEach, std::vector > (this->begin(), this->end(), *this, &Vector2::rows); } template void Vector2::rows(std::vector &row) { ForEach(row.begin(), row.end(), *this, &Vector2::columns); std::cout << '\n'; } template void Vector2::columns(Type &str) { std::cout << str << " "; } using namespace std; int main() { Vector2 c; c.push_back(vector(3, "Hello")); c.push_back(vector(2, "World")); c.process(); } /* Generated output: Hello Hello Hello World World */ //= c++-annotations-13.02.01/yo/concrete/examples/fistream/0000775000175000017500000000000014771010711021507 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/examples/fistream/fistream.ih0000664000175000017500000000020114771010714023637 0ustar frankfrank#include "fistream.h" // #include #include #include using namespace std; using namespace FBB; c++-annotations-13.02.01/yo/concrete/examples/fistream/fisin0000664000175000017500000000004514735537670022563 0ustar frankfrankba10 hello world My+name+is+%60Ed%27 c++-annotations-13.02.01/yo/concrete/examples/fistream/fistream.h0000664000175000017500000000337414771010714023504 0ustar frankfrank#ifndef INCLUDED_FISTREAM_H_ #define INCLUDED_FISTREAM_H_ #include #include #include #include #include /* fis >> field(3) >> x extracts x over max 3 positions. First, 3 chars are extracted from fis itself. They are put in a separate buffer which is then extracted. What if the extraction is not complete? Then a rest remains in the buffer, most likely resulting in a failing read, thereafter. Manipulators are provided to prevent this: field(0) returns to the non-fixed reading: the last field, even if not completely read, is then further ignored. field() reads the next field, same width as the previous field. If no field has been set before, field() has no effect. */ namespace FBB { class field; //INITIAL class Fistream: public std::istream { std::unique_ptr d_filebuf; std::streambuf *d_streambuf; std::istringstream d_iss; size_t d_width; //= public: //CONS Fistream(std::istream &stream); Fistream(char const *name, std::ios::openmode mode = std::ios::in); //= std::istream &setField(field const ¶ms); private: void setBuffer(); }; //FIELD class field { friend class Fistream; size_t d_width; bool d_newWidth; public: field(size_t width); field(); }; inline field::field(size_t width) : d_width(width), d_newWidth(true) {} inline field::field() : d_newWidth(false) {} //= } // FBB //OPEX namespace std { istream &operator>>(istream &str, FBB::field const ¶ms); } //= #endif c++-annotations-13.02.01/yo/concrete/examples/fistream/fistream.cc0000664000175000017500000000254114771010716023637 0ustar frankfrank#include "fistream.ih" //OPEX istream &std::operator>>(istream &str, field const ¶ms) { return static_cast(&str)->setField(params); } //= //CONS1 Fistream::Fistream(istream &stream) : istream(stream.rdbuf()), d_streambuf(rdbuf()), d_width(0) {} //= //CONS2 Fistream::Fistream(char const *name, ios::openmode mode) : istream(new filebuf()), d_filebuf(static_cast(rdbuf())), d_streambuf(d_filebuf.get()), d_width(0) { d_filebuf->open(name, mode); } //= //SETFIELD std::istream &Fistream::setField(field const ¶ms) { if (params.d_newWidth) // new field size requested d_width = params.d_width; // set new width if (!d_width) // no width? rdbuf(d_streambuf); // return to the old buffer else setBuffer(); // define the extraction buffer return *this; } //= //SETBUFFER void Fistream::setBuffer() { char *buffer = new char[d_width + 1]; rdbuf(d_streambuf); // use istream's buffer to buffer[read(buffer, d_width).gcount()] = 0; // read d_width chars, // terminated by a 0-byte d_iss.str(buffer); delete[] buffer; rdbuf(d_iss.rdbuf()); // switch buffers } //= c++-annotations-13.02.01/yo/concrete/examples/fistream/main.cc0000664000175000017500000000151514771010716022751 0ustar frankfrank#include #include "fistream.h" using namespace std; using namespace FBB; //MAIN int main() { Fistream fis(cin); fis >> hex; while (true) { size_t x; switch (x = fis.get()) { case '\n': cout << '\n'; break; case '+': cout << ' '; break; case '%': fis >> field(2) >> x >> field(0); // FALLING THROUGH default: cout << static_cast(x); break; case EOF: return 0; } } } /* Generated output after: echo My+name+is+%60Ed%27 | a.out My name is `Ed' */ //= c++-annotations-13.02.01/yo/concrete/examples/predicates.h0000664000175000017500000000566214771010714022205 0ustar frankfrank//UNARYPRED template class PredicateFunction1 { F_PTR d_fun; public: using argument_type = Type; PredicateFunction1(F_PTR const &ptr) : d_fun(ptr) {} bool operator()(Type const &t) const { return d_fun(t); } }; //= //BINPRED template class PredicateFunction2 { F_PTR d_fun; public: using first_argument_type = Type1; using second_argument_type = Type2; using result_type = bool; PredicateFunction2(F_PTR const &ptr) : d_fun(ptr) {} bool operator()(Type1 const &t1, Type2 const &t2) const { return d_fun(t1, t2); } }; //= //PREDOBJ1 template class PredicateObject1 { Class &d_cl; bool (Class::*d_member)(Type const &); public: using argument_type = Type; PredicateObject1(Class &cl, bool (Class::*member)(Type const &) = &Class::operator()) : d_cl(cl), d_member(member) {} PredicateObject1(Class *cl, bool (Class::*member)(Type const &) = &Class::operator()) : d_cl(*cl), d_member(member) {} bool operator()(Type const &t) const { return (d_cl.*d_member)(t); } operator Class() const { return d_cl; } }; //= //PREDOBJ2 template class PredicateObject2 { Class &d_cl; bool (Class::*d_member)(Type1 const &, Type2 const &); public: using first_argument_type = Type1; using second_argument_type = Type2; using result_type = bool; PredicateObject2(Class &cl, bool (Class::*member)(Type1 const &, Type2 const &) = &Class::operator()) : d_cl(cl), d_member(member) {} PredicateObject2(Class *cl, bool (Class::*member)(Type1 const &, Type2 const &) = &Class::operator()) : d_cl(*cl), d_member(member) {} bool operator()(Type1 const &t1, Type2 const &t2) const { return (d_cl.*d_member)(t1, t2); } operator Class() const { return d_cl; } }; //= c++-annotations-13.02.01/yo/concrete/examples/lines.cc0000664000175000017500000000101614771010716021321 0ustar frankfrank#include "lines.h" #include Lines::Lines(std::istream &in) { std::string str; while (getline(in, str)) d_line.push_back(str); } using namespace std; //MAIN int main() { ifstream in("lines.cc"); Lines lines(in); string s = lines[0]; // rvalue use lines[0] = s; // lvalue use cout << lines[0] << '\n'; // rvalue use lines[0] = "hello world"; // lvalue use cout << lines[0] << '\n'; // rvalue use } //= c++-annotations-13.02.01/yo/concrete/examples/parentslurp.cc0000664000175000017500000000117614771010716022575 0ustar frankfrank #include "parentslurp.h" #include #include //PARENT void ParentSlurp::parentProcess() { std::string line; size_t nr = 1; while (getline(std::cin, line)) std::cout << nr++ << ": " << line << '\n'; waitForChild(); } //= //MAIN int main() { ParentSlurp{}.fork(); } /* Generated Output (example only, actually obtained output may differ): 1: a.out 2: bitand.h 3: bitfunctional 4: bitnot.h 5: daemon.cc 6: fdinseek.cc 7: fdinseek.h ... */ //= c++-annotations-13.02.01/yo/concrete/examples/daemon.cc0000664000175000017500000000130514771010716021453 0ustar frankfrank #include #include #include "fork.h" class Daemon: public Fork { void parentProcess() override // the parent does nothing. {} void childProcess() override // actions by the child { sleep(3); // just a message... std::cout << "Hello from the child process\n"; throw 0; // The child process ends } }; int main() try { Daemon{}.fork(); } catch(...) {} /* Generated output: The next command prompt, then after 3 seconds: Hello from the child process */ c++-annotations-13.02.01/yo/concrete/examples/monitor/0000775000175000017500000000000014771010711021364 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/examples/monitor/monitor.h0000664000175000017500000000335514771010714023235 0ustar frankfrank #include #include #include #include "../selector.h" #include "child.h" //CLASS class Monitor { enum Commands { UNKNOWN, START, EXIT, STOP, TEXT, sizeofCommands }; using MapIntChild = std::map>; friend class Find; class Find { int d_nr; public: Find(int nr); bool operator()(MapIntChild::value_type &vt) const; }; Selector d_selector; int d_nr; MapIntChild d_child; static void (Monitor::*s_handler[])(int, std::string const &); static int s_initialize; public: enum Done {}; Monitor(); void run(); private: static void killChild(MapIntChild::value_type it); static int initialize(); Commands next(int *value, std::string *line); void processInput(); void processChild(int fd); void createNewChild(int, std::string const &); void exiting(int = 0, std::string const &msg = std::string{}); void sendChild(int value, std::string const &line); void stopChild(int value, std::string const &); void unknown(int, std::string const &); }; //= //CONS inline Monitor::Monitor() : d_nr(0) {} //= //FINDIMP inline Monitor::Find::Find(int nr) : d_nr(nr) {} inline bool Monitor::Find::operator()(MapIntChild::value_type &vt) const { return d_nr == vt.second->nr(); } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/build0000775000175000017500000000017214735537670022433 0ustar frankfrank#!/bin/sh g++ --std=c++11 *.cc ../selector.cc ../fork.cc ../forkvirtual.cc \ ../pipe.cc -lbobcat -s c++-annotations-13.02.01/yo/concrete/examples/monitor/data.compiletime0000664000175000017500000000051014735537670024544 0ustar frankfrank #include "monitor.ih" //HANDLER void (Monitor::*Monitor::s_handler[])(int, string const &) = { &Monitor::unknown, // order follows enum Command's &Monitor::createNewChild, // elements &Monitor::exiting, &Monitor::stopChild, &Monitor::sendChild, }; //= c++-annotations-13.02.01/yo/concrete/examples/monitor/run.cc0000664000175000017500000000132314771010716022503 0ustar frankfrank #include "monitor.ih" int Monitor::s_initialize = Monitor::initialize(); void Monitor::run() { d_selector.addReadFd(STDIN_FILENO); while (true) { cout << "? " << flush; try { d_selector.wait(); int fd; while ((fd = d_selector.readFd()) != -1) { if (fd == STDIN_FILENO) processInput(); else processChild(fd); } cout << "NEXT ...\n"; } catch (char const *msg) { exiting(1, msg); } } } c++-annotations-13.02.01/yo/concrete/examples/monitor/child.h0000664000175000017500000000233614771010714022627 0ustar frankfrank #include "../pipe.h" #include "../fork.h" #include "../selector.h" #include #include #include #include //CLASS class Child: public Fork { Pipe d_in; Pipe d_out; int d_parentReadFd; int d_parentWriteFd; int d_nr; public: Child(int nr); ~Child() override; int readFd() const; int writeFd() const; int pid() const; int nr() const; private: void childRedirections() override; void parentRedirections() override; void childProcess() override; void parentProcess() override; }; //= //CONS inline Child::Child(int nr) : d_nr(nr) {} //= //PIPES inline int Child::readFd() const { return d_parentReadFd; } inline int Child::writeFd() const { return d_parentWriteFd; } //= //PIDNR inline int Child::pid() const { return Fork::pid(); } inline int Child::nr() const { return d_nr; } //= inline void Child::parentProcess() {} c++-annotations-13.02.01/yo/concrete/examples/monitor/monitor.cc0000664000175000017500000000175414771010716023376 0ustar frankfrank #include "monitor.ih" //KILL void Monitor::killChild(MapIntChild::value_type it) { if (kill(it.second->pid(), SIGTERM)) cerr << "Couldn't kill process " << it.second->pid() << '\n'; // reap defunct child process int status = 0; while( waitpid( it.second->pid(), &status, WNOHANG) > -1) ; } //= //EXIT void Monitor::exiting(int value, string const &msg) { for_each(d_child.begin(), d_child.end(), killChild); if (msg.length()) cerr << msg << '\n'; throw value; } //= //INIT void (Monitor::*Monitor::s_handler[sizeofCommands])(int, string const &); int Monitor::initialize() { s_handler[UNKNOWN] = &Monitor::unknown; s_handler[START] = &Monitor::createNewChild; s_handler[EXIT] = &Monitor::exiting; s_handler[STOP] = &Monitor::stopChild; s_handler[TEXT] = &Monitor::sendChild; return 0; } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/processchild.cc0000664000175000017500000000041014771010716024355 0ustar frankfrank #include "monitor.ih" //CHILD void Monitor::processChild(int fd) { IFdStreambuf ifdbuf(fd); istream istr(&ifdbuf); string line; getline(istr, line); cout << d_child[fd]->pid() << ": " << line << '\n'; } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/monitor.ih0000664000175000017500000000037714771010714023407 0ustar frankfrank #include "monitor.h" #include #include #include #include #include #include #include "../ifdbuf.h" #include "../fdout.h" using namespace std; c++-annotations-13.02.01/yo/concrete/examples/monitor/processinput.cc0000664000175000017500000000165614771010716024446 0ustar frankfrank #include "monitor.ih" //INPUT void Monitor::processInput() { string line; int value; Commands cmd = next(&value, &line); (this->*s_handler[cmd])(value, line); } //= //NEXT Monitor::Commands Monitor::next(int *value, string *line) { if (!getline(cin, *line)) exiting(1, "Monitor::next(): reading cin failed"); if (*line == "start") return START; if (*line == "exit" || *line == "quit") { *value = 0; return EXIT; } if (line->find("stop") == 0) { istringstream istr(line->substr(4)); istr >> *value; return !istr ? UNKNOWN : STOP; } istringstream istr(line->c_str()); istr >> *value; if (istr) { getline(istr, *line); return TEXT; } return UNKNOWN; } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/sendchild.cc0000664000175000017500000000064214771010716023637 0ustar frankfrank #include "monitor.ih" //SEND void Monitor::sendChild(int nr, string const &line) { auto it = find_if(d_child.begin(), d_child.end(), Find(nr)); if (it == d_child.end()) cerr << "No child number " << nr << '\n'; else { OFdnStreambuf ofdn{ it->second->writeFd() }; ostream out(&ofdn); out << line << '\n'; } } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/main.cc0000664000175000017500000000144414771010716022627 0ustar frankfrank #include "monitor.h" //MAIN int main() try { Monitor{}.run(); } catch (int exitValue) { return exitValue; } //= /* Example of a session: # a.out ? start Child 1 started ? 1 hello world ? 3394: Child 1:1: hello world ? 1 hi there! ? 3394: Child 1:2: hi there! ? start Child 2 started ? 3394: Child 1: standing by ? 3395: Child 2: standing by ? 3394: Child 1: standing by ? 3395: Child 2: standing by ? stop 1 ? 3395: Child 2: standing by ? 2 hello world ? 3395: Child 2:1: hello world ? 1 hello world No child number 1 ? exit3395: Child 2: standing by ? # */ c++-annotations-13.02.01/yo/concrete/examples/monitor/unknown.cc0000664000175000017500000000020714771010716023376 0ustar frankfrank #include "monitor.ih" void Monitor::unknown(int, string const &line) { cout << "unknown: " << line << "\n"; } c++-annotations-13.02.01/yo/concrete/examples/monitor/stopchild.cc0000664000175000017500000000057414771010716023677 0ustar frankfrank #include "monitor.ih" //STOP void Monitor::stopChild(int nr, string const &) { auto it = find_if(d_child.begin(), d_child.end(), Find{ nr }); if (it == d_child.end()) cerr << "No child number " << nr << '\n'; else { d_selector.rmReadFd(it->second->readFd()); d_child.erase(it); } } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/child.cc0000664000175000017500000000275214771010716022771 0ustar frankfrank #include "child.h" #include #include #include using namespace std; //CHILD void Child::childRedirections() { d_in.readFrom(STDIN_FILENO); d_out.writtenBy(STDOUT_FILENO); } //= //PARENT void Child::parentRedirections() { d_parentReadFd = d_out.readOnly(); d_parentWriteFd = d_in.writeOnly(); } //= //PROCESS void Child::childProcess() { Selector selector; size_t message = 0; selector.addReadFd(STDIN_FILENO); selector.setAlarm(5); while (true) { try { if (!selector.wait()) // timeout cout << "Child " << d_nr << ": standing by\n"; else { string line; getline(cin, line); cout << "Child " << d_nr << ":" << ++message << ": " << line << '\n'; } } catch (...) { cout << "Child " << d_nr << ":" << ++message << ": " << "select() failed" << '\n'; } } exit(0); } //= //CHILDDES Child::~Child() { if (pid()) { cout << "Killing process " << pid() << "\n"; kill(pid(), SIGTERM); int status; wait(&status); } } //= c++-annotations-13.02.01/yo/concrete/examples/monitor/createnewchild.cc0000664000175000017500000000047414771010716024666 0ustar frankfrank #include "monitor.ih" //CHILD void Monitor::createNewChild(int, string const &) { Child *cp = new Child{ ++d_nr }; cp->fork(); int fd = cp->readFd(); d_selector.addReadFd(fd); d_child[fd].reset(cp); cerr << "Child " << d_nr << " started\n"; } //= c++-annotations-13.02.01/yo/concrete/examples/parentslurp.h0000664000175000017500000000134314771010714022431 0ustar frankfrank // compile with 'g++ parentslurp.cc fork.cc waitforchild.cc pipe.cc' #include "fork.h" #include "pipe.h" #include //CLASS class ParentSlurp: public Fork { Pipe d_pipe; void childRedirections() override; void parentRedirections() override; void childProcess() override; void parentProcess() override; }; //= //CHILDREDIR inline void ParentSlurp::childRedirections() { d_pipe.writtenBy(STDOUT_FILENO); } //= //PARENTREDIR inline void ParentSlurp::parentRedirections() { d_pipe.readFrom(STDIN_FILENO); } //= //CHILDPROC inline void ParentSlurp::childProcess() { execl("/bin/ls", "/bin/ls", 0); } //= c++-annotations-13.02.01/yo/concrete/examples/stringptrs/0000775000175000017500000000000014771010711022114 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/examples/stringptrs/stringptr.h0000664000175000017500000000221614771010714024325 0ustar frankfrank #ifndef INCLUDED_STRINGPTR_H_ #define INCLUDED_STRINGPTR_H_ #include #include #include "iterator.h" class StringPtr: public std::vector { public: using iterator = RandomPtrIterator < StringPtr, std::vector::iterator, std::string >; using reverse_iterator = std::reverse_iterator; iterator begin(); iterator end(); reverse_iterator rbegin(); reverse_iterator rend(); }; inline StringPtr::iterator StringPtr::begin() { return iterator(this->std::vector::begin() ); } inline StringPtr::iterator StringPtr::end() { return iterator(this->std::vector::end()); } inline StringPtr::reverse_iterator StringPtr::rbegin() { return reverse_iterator(end()); } inline StringPtr::reverse_iterator StringPtr::rend() { return reverse_iterator(begin()); } #endif c++-annotations-13.02.01/yo/concrete/examples/stringptrs/iterators.cc0000664000175000017500000000125314771010716024445 0ustar frankfrank#include #include #include "stringptr.h" using namespace std; int main(int argc, char **argv) { StringPtr sp; while (*argv) sp.push_back(new string{ *argv++ }); sort(sp.begin(), sp.end()); copy(sp.begin(), sp.end(), ostream_iterator(cout, " ")); cout << "\n======\n"; sort(sp.rbegin(), sp.rend()); copy(sp.begin(), sp.end(), ostream_iterator(cout, " ")); cout << '\n'; } /* when called as: a.out bravo mike charlie zulu quebec generated output: a.out bravo charlie mike quebec zulu ====== zulu quebec mike charlie bravo a.out */ c++-annotations-13.02.01/yo/concrete/examples/stringptrs/iterator.h0000664000175000017500000001140514771010714024122 0ustar frankfrank #ifndef INCLUDED_ITERATOR_H_ #define INCLUDED_ITERATOR_H_ //HEAD #include #include template struct RandomPtrIterator; #define PtrIterator RandomPtrIterator #define PtrIteratorValue RandomPtrIterator template bool operator==(PtrIterator const &lhs, PtrIterator const &rhs); template auto operator<=>(PtrIterator const &lhs, PtrIterator const &rhs); template int operator-(PtrIterator const &lhs, PtrIterator const &rhs); template struct RandomPtrIterator { using iterator_category = std::random_access_iterator_tag; using difference_type = std::ptrdiff_t; using value_type = Type; using pointer = value_type *; using reference = value_type &; friend PtrIterator Class::begin(); friend PtrIterator Class::end(); friend bool operator==<>(RandomPtrIterator const &lhs, RandomPtrIterator const &rhs); friend auto operator<=><>(RandomPtrIterator const &lhs, RandomPtrIterator const &rhs); friend int operator-<>(RandomPtrIterator const &lhs, RandomPtrIterator const &rhs); private: BaseIterator d_current; public: int operator-(RandomPtrIterator const &rhs) const; RandomPtrIterator operator+(int step) const; value_type &operator*() const; RandomPtrIterator &operator--(); RandomPtrIterator operator--(int); RandomPtrIterator &operator++(); RandomPtrIterator operator++(int); RandomPtrIterator operator-(int step) const; RandomPtrIterator &operator-=(int step); RandomPtrIterator &operator+=(int step); value_type *operator->() const; private: RandomPtrIterator(BaseIterator const ¤t); }; template PtrIteratorValue::RandomPtrIterator(BaseIterator const ¤t) : d_current(current) {} //= template PtrIteratorValue PtrIteratorValue::operator+(int step) const { return RandomPtrIterator(d_current + step); } //OP* template value_type &PtrIteratorValue::operator*() const { return **d_current; } //= //CMP template inline auto operator<=>(PtrIterator const &lhs, PtrIterator const &rhs) { return **lhs.d_current <=> **rhs.d_current; } //= template PtrIteratorValue &PtrIteratorValue::operator--() { --d_current; return *this; } template PtrIteratorValue PtrIteratorValue::operator--(int) { return RandomPtrIterator(d_current--); } //INC template PtrIteratorValue &PtrIteratorValue::operator++() { ++d_current; return *this; } template PtrIteratorValue PtrIteratorValue::operator++(int) { return RandomPtrIterator(d_current++); } //= template inline bool operator==(PtrIterator const &lhs, PtrIterator const &rhs) { return lhs.d_current == rhs.d_current; } template int operator-(PtrIterator const &lhs, PtrIterator const &rhs) { return lhs.d_current - rhs.d_current; } template PtrIteratorValue &PtrIteratorValue::operator-=(int step) { d_current -= step; return *this; } template PtrIteratorValue &PtrIteratorValue::operator+=(int step) { d_current += step; return *this; } template value_type *PtrIteratorValue::operator->() const { return *d_current; } #undef PtrIteratorValue #undef PtrIterator #endif c++-annotations-13.02.01/yo/concrete/examples/selector.h0000664000175000017500000000453614771010714021701 0ustar frankfrank #ifndef INCLUDED_SELECTOR_H_ #define INCLUDED_SELECTOR_H_ //HEADERS #include #include #include #include //= //CLASS class Selector { fd_set d_read; fd_set d_write; fd_set d_except; fd_set d_ret_read; fd_set d_ret_write; fd_set d_ret_except; timeval d_alarm; int d_max; int d_ret; int d_readidx; int d_writeidx; int d_exceptidx; public: Selector(); int exceptFd(); int nReady(); int readFd(); int wait(); int writeFd(); void addExceptFd(int fd); void addReadFd(int fd); void addWriteFd(int fd); void noAlarm(); void rmExceptFd(int fd); void rmReadFd(int fd); void rmWriteFd(int fd); void setAlarm(int sec, int usec = 0); private: int checkSet(int *index, fd_set &set); void addFd(fd_set *set, int fd); }; //= //NREADY inline int Selector::nReady() { return d_ret; } //= //READFD inline int Selector::readFd() { return checkSet(&d_readidx, d_ret_read); } //= inline int Selector::writeFd() { return checkSet(&d_writeidx, d_ret_write); } inline int Selector::exceptFd() { return checkSet(&d_exceptidx, d_ret_except); } //SETALARM inline void Selector::setAlarm(int sec, int usec) { d_alarm.tv_sec = sec; d_alarm.tv_usec = usec; } //= //NOALARM inline void Selector::noAlarm() { setAlarm(-1, -1); } //= //ADDREAD inline void Selector::addReadFd(int fd) { addFd(&d_read, fd); } //= inline void Selector::addWriteFd(int fd) { addFd(&d_write, fd); } inline void Selector::addExceptFd(int fd) { addFd(&d_except, fd); } //RMREAD inline void Selector::rmReadFd(int fd) { FD_CLR(fd, &d_read); } //= inline void Selector::rmWriteFd(int fd) { FD_CLR(fd, &d_write); } inline void Selector::rmExceptFd(int fd) { FD_CLR(fd, &d_except); } #endif c++-annotations-13.02.01/yo/concrete/examples/ifdbuf.h0000664000175000017500000000124714771010714021314 0ustar frankfrank #include #include //CLASS class IFdStreambuf: public std::streambuf { protected: int d_fd; char d_buffer[1]; public: IFdStreambuf(int fd); private: int underflow() override; }; //= //CONS inline IFdStreambuf::IFdStreambuf(int fd) : d_fd(fd) { setg(d_buffer, d_buffer + 1, d_buffer + 1); } //= //UFLOW inline int IFdStreambuf::underflow() { if (read(d_fd, d_buffer, 1) <= 0) return EOF; setg(d_buffer, d_buffer, d_buffer + 1); return static_cast(*gptr()); } //= c++-annotations-13.02.01/yo/concrete/examples/a2x.cc0000664000175000017500000000172114771010716020704 0ustar frankfrank#include #include "a2x.h" using namespace std; // compile with a2xis.cc int main() { //MAIN int x = A2x{ "12" }; // initialize int x from a string "12" A2x a2x{ "12.50" }; // explicitly create an A2x object double d; d = a2x; // assign a variable using an A2x object cout << d << '\n'; a2x = "err"; d = a2x; // d is 0: the conversion failed, cout << d << '\n'; // and a2x.good() == false a2x = " a"; // reassign a2x to new text char c = a2x; // c now 'a': internally operator>>() is used cout << c << '\n'; // so initial blanks are skipped. int expectsInt(int x); // initialize a parameter using an expectsInt(A2x{ "1200" }); // anonymous A2x object d = A2x{ "12.45" }.to(); // d is 12, not 12.45 cout << d << '\n'; //= } int expectsInt(int x) { cout << x << '\n'; return x; } c++-annotations-13.02.01/yo/concrete/examples/waitforchild.cc0000664000175000017500000000023714771010716022672 0ustar frankfrank #include "fork.ih" int Fork::waitForChild() { int status; waitpid(d_pid, &status, 0); return WEXITSTATUS(status); } c++-annotations-13.02.01/yo/concrete/examples/ifdbuf.cc0000664000175000017500000000035314771010716021451 0ustar frankfrank #include #include #include "ifdbuf.h" using namespace std; //MAIN int main() { IFdStreambuf fds(STDIN_FILENO); istream is(&fds); cout << is.rdbuf(); } //= c++-annotations-13.02.01/yo/concrete/examples/oformstream.h0000664000175000017500000000046714771010714022416 0ustar frankfrank #include class oformstream: public std::ostream // 1 { public: oformstream(std::ostream &ostr) // 2 : std::ostream(ostr.rdbuf()) {} std::ostream &form(char const *fmt, ...); // 3 }; c++-annotations-13.02.01/yo/concrete/examples/ifdnbuf.cc0000664000175000017500000000102614771010716021625 0ustar frankfrank #include #include #include #include "ifdnbuf.h" using namespace std; int main() { // internally: 30 char buffer IFdNStreambuf fds(STDIN_FILENO, 30); char buf[80]; // main() reads blocks of 80 // chars while (true) { size_t n = fds.sgetn(buf, 80); if (n == 0) break; cout.write(buf, n); } } c++-annotations-13.02.01/yo/concrete/examples/fdunget.h0000664000175000017500000000264014771010714021507 0ustar frankfrank #include #include #include #include #include //CLASS class FdUnget: public std::streambuf { int d_fd; size_t d_bufsize; size_t d_reserved; char *d_buffer; char *d_base; public: FdUnget(int fd, size_t bufsz, size_t unget); ~FdUnget() override; private: int underflow() override; }; //= //CONS FdUnget::FdUnget(int fd, size_t bufsz, size_t unget) : d_fd(fd), d_reserved(unget) { size_t allocate = bufsz > d_reserved ? bufsz : d_reserved + 1; d_buffer = new char[allocate]; d_base = d_buffer + d_reserved; setg(d_base, d_base, d_base); d_bufsize = allocate - d_reserved; } //= //DESTR inline FdUnget::~FdUnget() { delete[] d_buffer; } //= //UNDERFLOW int FdUnget::underflow() { size_t ungetsize = gptr() - eback(); size_t move = std::min(ungetsize, d_reserved); memcpy(d_base - move, egptr() - move, move); int nread = read(d_fd, d_base, d_bufsize); if (nread <= 0) // none read -> return EOF return EOF; setg(d_base - move, d_base, d_base + nread); return static_cast(*gptr()); } //= c++-annotations-13.02.01/yo/concrete/examples/for3.cc0000664000175000017500000000130014771010716021054 0ustar frankfrank #include #include #include #include "foreach.h" using namespace std; class StringVector: public vector { public: StringVector(char **begin, char **end) : vector(begin, end) {} void operator()(string const &str) { cout << str << " "; } }; int main(int argc, char **argv) { StringVector vs{ argv, argv + argc }; ForEach(vs.begin(), vs.end(), vs); cout << '\n'; } /* Output generated when running a.out alpha bravo charley a.out alpha bravo charley */ c++-annotations-13.02.01/yo/concrete/examples/ipipe.h0000664000175000017500000000072414771010714021162 0ustar frankfrank#ifndef INCLUDED_IPIPE_H_ #define INCLUDED_IPIPE_H_ #ifndef INCLUDED_PIPE_H_ #include "../pipe/pipe.h" #endif #ifndef INCLUDED_IFDSTREAMBUF_H_ #include "../ifdstreambuf/ifdstreambuf.h" #endif #ifndef SYSINC_ISTREAM_ #include #define SYSINC_ISTREAM_ #endif namespace FBB { class IPipe: public Pipe, private IFdStreambuf, public std::istream { public: IPipe(size_t size = 500); void closeWriteFd(); }; } #endif c++-annotations-13.02.01/yo/concrete/examples/bitfunctional0000664000175000017500000000327514735537670022512 0ustar frankfrank#ifndef BITFUNCTIONAL__ #define BITFUNCTIONAL__ #include /* Frank B. Brokken, july 19, 2001. f.b.brokken@rug.nl This file predefines function-objects that are non-standard. The following function objects are defined: name operator ---------------------------- shift_left << shift_right >> bit_not ~ bit_and & bit_or | bit_xor ^ ---------------------------- In order to make these objects available, install this file in a directory where your compiler finds it, and let sources do: #include This include directive implies #include */ template struct shift_left : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x << __y; } }; template struct shift_right : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x >> __y; } }; template struct bit_not : public unary_function<_Tp,_Tp> { _Tp operator()(const _Tp& __x) const { return ~__x; } }; template struct bit_and : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x & __y; } }; template struct bit_or : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x | __y; } }; template struct bit_xor : public binary_function<_Tp,_Tp,_Tp> { _Tp operator()(const _Tp& __x, const _Tp& __y) const { return __x ^ __y; } }; #endif c++-annotations-13.02.01/yo/concrete/examples/forkvirtual.cc0000664000175000017500000000022614771010716022561 0ustar frankfrank #include "fork.ih" //REDIRECT void Fork::childRedirections() {} void Fork::parentRedirections() {} //= Fork::~Fork() {} c++-annotations-13.02.01/yo/concrete/examples/oformstream.cc0000664000175000017500000000144514771010716022553 0ustar frankfrank #include "oformstream.h" #include #include std::ostream &oformstream::form(char const *fmt, ...) // 1 { va_list list; va_start(list, fmt); size_t n = vsnprintf(0, 0, fmt, list); // 2 std::auto_ptr buf(new char[n + 1]); // 3 vsprintf(buf.get(), fmt, list); // 4 return *this << buf.get(); // 5 } using namespace std; int main() { oformstream of(cout); of << "Hello world\n"; cout << "Ok, "; of << "That's all, folks\n"; of.form("%s\n", "Hello world of C++") << '\n'; }; /* Generated output: Hello world Ok, That's all, folks Hello world of C++ */ c++-annotations-13.02.01/yo/concrete/examples/a2xis.cc0000664000175000017500000000035514771010716021242 0ustar frankfrank#include "a2x.h" A2x &A2x::operator=(char const *txt) { clear(); // very important!!! If a conversion failed, the object // remains useless until executing this statement str(txt); return *this; } c++-annotations-13.02.01/yo/concrete/examples/fork.cc0000664000175000017500000000072514771010716021156 0ustar frankfrank #include "fork.ih" void Fork::fork() { if ((d_pid = ::fork()) < 0) throw "Fork::fork() failed"; if (d_pid == 0) // childprocess has pid == 0 { childRedirections(); childProcess(); exit(1); // we shouldn't come here: } // childProcess() should exit parentRedirections(); parentProcess(); } c++-annotations-13.02.01/yo/concrete/examples/predobj.cc0000664000175000017500000000367414771010716021650 0ustar frankfrank #include #include #include #include #include "predicates.h" using namespace std; //CONTAINS class Contains { string d_target; size_t d_count; public: Contains(char const *target) : d_target(target), d_count(0) {} bool operator()(string const &str) { d_count++; return str.find_first_of(d_target) != string::npos; } bool operator()(string const &s1, string const &s2) { d_count++; return s1.find_first_of(s2) != string::npos; } size_t count() const { return d_count; } }; //= //MAIN int main(int argc, char **argv) { Contains contains{ "aeiou" }; if (argc == 1) cout << "Counted " << count_if(istream_iterator{ cin }, istream_iterator{}, PredicateObject1{contains} ) << " words containing vowels "; else cout << "Counted " << count_if(istream_iterator{ cin }, istream_iterator{}, [&](string const &target) { return PredicateObject2 { contains }(target, "aeiou"); } ) << " words containing vowels "; cout << "(read " << contains.count() << " strings)\n"; } /* Generated output after executing (predobj.cc being this soure file) a.out < predobj.cc or a.out 2 < predobj.cc Counted 107 words containing vowels (read 163 strings) */ //= c++-annotations-13.02.01/yo/concrete/examples/for2.cc0000664000175000017500000000133314771010716021061 0ustar frankfrank #include #include #include #include "foreach.h" using namespace std; class StringVector: public vector { public: StringVector(char **begin, char **end) : vector(begin, end) {} void display(string const &str) const { cout << str << " "; } }; int main(int argc, char **argv) { StringVector vs{ argv, argv + argc }; ForEach(vs.begin(), vs.end(), vs, &StringVector::display); cout << '\n'; } /* Output generated when running a.out alpha bravo charley a.out alpha bravo charley */ c++-annotations-13.02.01/yo/concrete/examples/fdinseek.cc0000664000175000017500000000132414771010716022001 0ustar frankfrank #include "fdinseek.h" #include #include #include #include using namespace std; int main() { IFdSeek fds(0); istream is(&fds); string s; while (true) { if (!getline(is, s)) break; streampos pos = is.tellg(); cout << setw(5) << pos << ": `" << s << "'\n"; if (!getline(is, s)) break; streampos pos2 = is.tellg(); cout << setw(5) << pos2 << ": `" << s << "'\n"; if (!is.seekg(pos)) { cout << "Seek failed\n"; break; } } } c++-annotations-13.02.01/yo/concrete/examples/selector.cc0000664000175000017500000000203514771010716022031 0ustar frankfrank #include "selector.h" //SELECTOR Selector::Selector() { FD_ZERO(&d_read); FD_ZERO(&d_write); FD_ZERO(&d_except); noAlarm(); d_max = 0; } //= //WAIT int Selector::wait() { timeval t = d_alarm; d_ret_read = d_read; d_ret_write = d_write; d_ret_except = d_except; d_readidx = 0; d_writeidx = 0; d_exceptidx = 0; d_ret = select(d_max, &d_ret_read, &d_ret_write, &d_ret_except, t.tv_sec == -1 && t.tv_usec == -1 ? 0 : &t); if (d_ret < 0) throw "Selector::wait()/select() failed"; return d_ret; } //= //ADDFD void Selector::addFd(fd_set *set, int fd) { FD_SET(fd, set); if (fd >= d_max) d_max = fd + 1; } //= //CHECKSET int Selector::checkSet(int *index, fd_set &set) { int &idx = *index; while (idx < d_max && !FD_ISSET(idx, &set)) ++idx; return idx == d_max ? -1 : idx++; } //= c++-annotations-13.02.01/yo/concrete/examples/fdinseek.h0000664000175000017500000000231314771010714021640 0ustar frankfrank #include "ifdbuf.h" #include #include //CLASS class IFdSeek: public IFdStreambuf { using pos_type = std::streambuf::pos_type; using off_type = std::streambuf::off_type; using seekdir = std::ios::seekdir; using openmode = std::ios::openmode; public: IFdSeek(int fd); private: pos_type seekoff(off_type offset, seekdir dir, openmode); pos_type seekpos(pos_type offset, openmode mode); }; //= //CONS inline IFdSeek::IFdSeek(int fd) : IFdStreambuf(fd) {} //= //SEEKOFF IFdSeek::pos_type IFdSeek::seekoff(off_type off, seekdir dir, openmode) { pos_type pos = lseek ( d_fd, off, (dir == std::ios::beg) ? SEEK_SET : (dir == std::ios::cur) ? SEEK_CUR : SEEK_END ); if (pos < 0) return -1; setg(d_buffer, d_buffer + 1, d_buffer + 1); return pos; } //= //SEEKPOS inline IFdSeek::pos_type IFdSeek::seekpos(pos_type off, openmode mode) { return seekoff(off, std::ios::beg, mode); } //= c++-annotations-13.02.01/yo/concrete/examples/pipe.h0000664000175000017500000000070114771010714021004 0ustar frankfrank#include //HEAD class Pipe { enum RW { READ, WRITE }; int d_fd[2]; //= public: Pipe(); int readOnly(); void readFrom(int fileDescriptor); int writeOnly(); void writtenBy(int fileDescriptor); void writtenBy(int const *fileDescriptors, size_t n = 2); private: void redirect(int d_fd, int alternateFd); }; c++-annotations-13.02.01/yo/concrete/a2x.yo0000664000175000017500000000673414735537670017156 0ustar frankfrank The standard bf(C) library offers conversion functions like ti(atoi), ti(atol), and other functions that can be used to convert NTB strings to numeric values. In bf(C++), these functions are still available, but a more em(type safe) way to convert text to other types uses objects of the class hi(istringstream)tt(std::istringsteam). Using the class tt(istringstream) instead of the bf(C) standard conversion functions may have the advantage of type-safety, but it also appears to be a rather cumbersome alternative. After all, we first have to construct and initialize a tt(std::istringstream) object before we're able to extract a value of some type from it. This requires us to use a variable. Then, in cases where the extracted value is only needed to initialize some function-parameter, one might wonder whether the added variable and the tt(istringstream) construction can somehow be avoided. In this section we'll develop a class hi(A2x)(tt(A2x)) preventing all the disadvantages of the standard bf(C) library functions, without requiring the cumbersome definitions of tt(istringstream) objects over and over again. The class is called tt(A2x), meaning hi(ascii to anything) `i(ascii to anything)'. tt(A2x) objects can be used to extract values of any type extractable from tt(std::istream) objects. Since tt(A2x) represents the object-variant of the bf(C) functions, it is not only type-safe but em(also) extensible. So its use is greatly preferred over using the standard bf(C) functions. Here are its characteristics: itemization( it() tt(A2x) is derived from tt(std::istringstream), and so all members of the class tt(istringstream) are available for tt(A2x) objects. Extractions of values of variables can always effortlessly be performed. Here's the class's interface: verbinclude(//CLASS examples/a2x.h) it() tt(A2x) has a default constructor and a constructor expecting a tt(std::string) argument. The latter constructor may be used to initialize tt(A2x) objects with text to be converted (e.g., a line of text obtained from reading a configuration file): verbinclude(//CONS examples/a2x.h) it() tt(A2x)'s real strength comes from its tt(operator Type()) conversion member template. As it is a member template, it automatically adapts itself to the type of the variable that should be given a value, obtained by converting the text stored inside the tt(A2x) object to the variable's type. When the extraction fails, tt(A2x)'s inherited tt(good) member returns tt(false). it() Occasionally the compiler may not be able to determine which type to convert to. In that case, an em(explicit template type) could be used: verb( A2x.operator int(); // or just: A2x.operator int();) As neither syntax looks attractive, the member template tt(to) is provided too, allowing constructions like: verb( A2x.to();) Here is its implementation: verbinclude(//TO examples/a2x.h) it() The tt(to) member makes it easy to implement tt(operator Type()): verbinclude(//TYPE examples/a2x.h) it() Once an tt(A2x) object is available, it may be reinitialized using tt(operator=): verbinclude(-a examples/a2xis.cc) ) Here are some examples showing tt(A2x) being used: verbinclude(//MAIN examples/a2x.cc) A complementary class hi(X2a) (tt(X2a)), converting values to text, can be constructed as well. Its construction is left as an exercise to the reader. c++-annotations-13.02.01/yo/concrete/fdinput.yo0000664000175000017500000000122414735537670020122 0ustar frankfrank When classes for input operation are derived from hi(streambuf)tt(std::streambuf), they should be provided with an input buffer of at least one character. The one-character input buffer allows for the use of the member functions tt(istream::putback) or tt(istream::ungetc). Strictly speaking it is not necessary to implement a buffer in classes derived from tt(streambuf). But using buffers in these classes is strongly advised. Their implementation is very simple and straightforward and the applicability of such classes is greatly improved. Therefore, all our classes derived from the class tt(streambuf) define a buffer of em(at least) one character. c++-annotations-13.02.01/yo/concrete/select.yo0000664000175000017500000000256014735537670017734 0ustar frankfrank The ti(select) system call was developed to handle asynchronous hi(multiplexing)emi(I/O multiplexing). The tt(select) system call is used to handle, e.g., input appearing simultaneously at a set of file descriptors. The tt(select) function is rather complex, and its full discussion is beyond the annotations()' scope. By encapsulating tt(select) in a tt(class Selector), hiding its details and offering an intuitively attractive interface, its use is simplified. The tt(Selector) class has these features: itemization( it() Efficiency. As most of tt(Select)'s members are very small, most members can be implemented inline. The class requires quite a few data members. Most of these data members belong to types that require some system headers to be included first: verbinclude(//HEADERS examples/selector.h) it() The class interface can now be defined. The data type tt(fd_set) is a type designed to be used by tt(select) and variables of this type contain the set of file descriptors on which tt(select) may sense some activity. Furthermore, tt(select) allows us to fire an emi(asynchronous alarm). To set the alarm time, the class tt(Selector) defines a ti(timeval) data member. Other members are used for internal bookkeeping purposes. Here is the class tt(Selector)'s interface: verbinclude(//CLASS examples/selector.h) ) c++-annotations-13.02.01/yo/concrete/oformstream.yo0000664000175000017500000000355614735537670021021 0ustar frankfrankIn the i(ANSI/ISO) standard does not include the previously available i(GNU) extension ti(form()) (and ti(scan())) for stream objects. In this section the construction of a class ti(oformstream) is described, which is derived from hi(derived class) ti(ostream) and does support tt(form()) and ti(vform()). Analogously to tt(oformstream) a tt(class) ti(iscanstream) can be developed, supporting tt(scan()) and ti(vscan()). The contruction of this latter class is left as an i(exercise) to the reader. Here is the class interface and definition. It is annotated below: verbinclude(-a examples/oformstream.h) itemization( it() At 1 the class is defined: it is derived from tt(ostream), so it inherits tt(ostream)'s capabilities. it() At 2 a simple constructor is defined. It expects a reference to a tt(std::ostream) object. it() At 3 the member tt(form()) is declared. Its definition is given shortly. ) A program using the class tt(oformstream) is given in the next example. It prints a well-known string and some marker text: verbinclude(-a examples/oformstream.cc) In the above example: itemization( it() At 1 the function tt(form()) is defined. it() At 2 the function ti(vsnprintf()) is given a buffer size of 0 and tt(0) as the pointer to the buffer. According to the ti(ISO/IEC 9899:1999) standard, the function tt(vsnprintf()) returns the number of required characters for the formatted string (not including the final 0-valued character) (see the tt(vsnprintf()) man page for details and possible alternative implementations of tt(vsnprintf())). it() At 3 an ti(auto_ptr) is used to manage the dynamically hi(dynamic allocation) allocated buffer. it() At 4 the text is formatted. it() At 5 the content of the buffer are written to the tt(ostream) base class, and the tt(oformstream) object is returned. ) c++-annotations-13.02.01/yo/concrete/insertion.yo0000664000175000017500000000400414735537670020462 0ustar frankfrankClasses also frequently define overloaded insertion and extraction operators. Since there are no `compound insertion operators' the design shown so far cannot be used when overloading these operators. Instead using standardized member function signatures is advocated: tt(void insert(std::ostream &out) const) to insert an object into an tt(ostream) and tt(void extract(std::istream &in) const) to extract an object from an tt(istream). As these functions are only used by, respectively, the insertion and extraction operators, they can be declared in the tt(Derived) class's private interface. Instead of declaring the insertion and extraction operators friends of the class tt(Derived) a single tt(friend Binops) is specified. This allows tt(Binops) to define private, inline tt(iWrap) and tt(eWrap) members, merely calling, respectively, tt(Derived's insert) and tt(extract) members: verb( template inline void Binops::iWrap(std::ostream &out) const { static_cast(*this).insert(out); }) tt(Binops) then declares the insertion and extraction operators as its friends, allowing these operators to call, respectively, tt(iWrap) and tt(eWrap). Note that the software engineer designing the class tt(Derived) only has to provide a tt(friend Binops) declaration. Here is the implementation of the overloaded insertion operator: verb( template std::ostream &operator<<(std::ostream &out, Binops const &obj) { obj.iWrap(out); return out; }) This completes the coverage of the essentials of a class template tt(Binops) potentially offering binary operators and insertion/extraction operators for any class derived from tt(Binops). Finally, as noted at the beginning of this section, a complete implementation of a class offering addition and insertion operators is provided in the file tt(annotations/yo/concrete/examples/binopclasses.cc) in the annotations()' source archive. c++-annotations-13.02.01/yo/concrete/parserh.yo0000664000175000017500000000117414735537670020121 0ustar frankfrankSeveral class members called from the grammar are defined as member templates. tt(Bisonc++) generates multiple files, among which the file defining the parser's class. Functions called from the production rule's action blocks are usually member functions of the parser. These member functions must be declared and defined. Once tt(bisonc++) has generated the header file defining the parser's class, that header file isn't automatically rewritten, allowing the programmer to add new members to the parser class whenever required. Here is `tt(parser.h)' as used in our little calculator: verbinclude(-a bisonc++/parser/parser.h) c++-annotations-13.02.01/yo/concrete/streambuf/0000775000175000017500000000000014735537670020071 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/0000775000175000017500000000000014771010711022351 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdin2cout.cc0000664000175000017500000000055714771010716024571 0ustar frankfrank#include "fdstreambuf.h" #include #include #include using namespace std; // Calls uflow() repeatedly int main(int argc) { fdstreambuf fds(0, ios::in); istream is(&fds); cout << "START\n"; char c; while (is.get(c)) cout << "GOT " << c << '\n'; cout << "Using fds(0)\n"; } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinrdbuf.cc0000664000175000017500000000057014771010716024632 0ustar frankfrank#include "inok/buf.1.h" #include #include #include using namespace std; // Calls uflow() repeatedly int main(int argc) { fdstreambuf fds(0, ios::in); istream is(&fds); cout << "START\n"; cout << &fds;//is.rdbuf(); cout.clear(); // because of cerr.eof() cout << "Using fds(0)\n"; } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinbuf100.cc0000664000175000017500000000077014771010716024527 0ustar frankfrank#include "fdstreambuf.h" #include #include #include using namespace std; int main(int argc) { fdstreambuf fds(0, 5, ios::in); istream is(&fds); string s; cout << "START\n"; for (size_t line = 0; getline(is, s); line++) { cout << s << '\n'; if ((line & 3) == 0) { is.unget(); is.unget(); is.unget(); is.unget(); } is.clear(); } } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdstreambuf.h0000664000175000017500000000403514771010714025031 0ustar frankfrank#include #include #include #include using namespace std; class fdstreambuf: public std::streambuf { public: fdstreambuf(int fd, size_t bufsize, size_t minimum, std::ios::openmode mode = std::ios::in | std::ios::out) : fd(fd), bufsize(bufsize), minimum(minimum), buffer(new char[bufsize]) { /* initialize buffer from minimum position to beyond, set gptr() to beyond, so the buffer is filled immediately Assume bufsize - minimum > minimum */ if (mode & std::ios::in) setg(buffer + minimum, buffer + bufsize, buffer + bufsize); } ~fdstreambuf() { delete buffer; } int underflow() // inspects the character { if (gptr() < egptr()) return static_cast(*gptr()); // return next char waiting in the buffer /* Now that the buffer is refilled, what do we have? buffer eback() gptr() == egptr() ^ ^ ^ ------------------------------- n m <= bufsize - minimum n characters at chars before gptr() are moved left, eback() is moved left over n filling starts are buffer + minimum */ size_t n2move = min(minimum, (size_t)(gptr() - eback())); memcpy(buffer, egptr() - n2move, n2move); /* Read chars to the area beyond the unget-buffer */ int nread = read(fd, buffer + minimum, bufsize - minimum); if (nread <= 0) // none read -> return EOF; setg(buffer + minimum - n2move, buffer + minimum, buffer + minimum + nread); return static_cast(*gptr()); } private: int fd; size_t bufsize; size_t minimum; char* buffer; }; c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/input0000664000175000017500000000000714735537670023452 0ustar frankfranks a a c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinmininum.cc0000664000175000017500000000074514771010716025210 0ustar frankfrank#include "inok/minimum.h" #include #include #include using namespace std; int main(int argc) { fdstreambuf fds(0, 12, 5, ios::in); istream is(&fds); string s; for (size_t line = 0; getline(is, s); line++) { cout << s << '\n'; if ((line & 3) == 0) { is.unget(); is.unget(); is.unget(); is.unget(); } is.clear(); } } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinextracttocout.cc0000664000175000017500000000056114771010716026440 0ustar frankfrank#include "inok/buf.1.h" #include #include #include using namespace std; // Calls uflow() repeatedly int main(int argc) { fdstreambuf fds(0, ios::in); istream is(&fds); cerr << "START\n"; char c; while (is >> c) cerr << "\t\tGOT " << c << '\n'; cerr << "Using fds(0)\n"; } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinputback.cc0000664000175000017500000000050614771010716025160 0ustar frankfrank#include "inok/buf.1.h" #include #include #include using namespace std; int main(int argc) { fdstreambuf fds(0, ios::in); istream is(&fds); cout << "START\n"; char c; is.get(c); cout << c << '\n'; is.unget(); cout << is.rdbuf(); } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fbinbufn.cc0000664000175000017500000000077014771010716024462 0ustar frankfrank#include "fdstreambuf.h" #include #include #include using namespace std; int main(int argc) { fdstreambuf fds(0, 5, ios::in); istream is(&fds); string s; cout << "START\n"; for (size_t line = 0; getline(is, s); line++) { cout << s << '\n'; if ((line & 3) == 0) { is.unget(); is.unget(); is.unget(); is.unget(); } is.clear(); } } c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdstreambuf.h00000664000175000017500000000324414735537670025131 0ustar frankfrank#include #include #include #include using std::cerr; class fdstreambuf: public std::streambuf { public: fdstreambuf(int fd, std::ios::openmode mode = std::ios::in | std::ios::out) : fd(fd), input_char(EOF), mode(mode) { std::streambuf::_M_mode = mode; // char // dummy; // if (mode & std::ios::in) // setg(&dummy, &dummy, &dummy); // if (mode & std::ios::out) // setp(&dummy, &dummy); } int uflow() // consumes the character { std::cerr << "uflow\n"; if (input_char != EOF) { int next = input_char; input_char = EOF; return next; } return underflow(); } int underflow() // inspects the character { std::cerr << "underflow, in_avail() = " << in_avail() << "\n"; char c; if (read(fd, &c, 1)) { // std::cerr << "Got " << c; input_char = c; std::cerr << ", input_char is " << input_char << " (" << (char)input_char << ")\n"; return input_char; } //std::cerr << "EOF underflow\n"; return input_char = EOF; } int overflow(int c) { if (c != EOF) { if (write(fd, &c, 1) != 1) return EOF; } return c; } private: std::ios::openmode mode; int fd, input_char; }; c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/inok/0000775000175000017500000000000014771010710023310 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/inok/seek.1.h0000664000175000017500000000333314771010714024555 0ustar frankfrank#include #include #include #include #include #include using namespace std; class fdstreambuf: public std::streambuf { public: fdstreambuf(int fd, std::ios::openmode mode = std::ios::in | std::ios::out) : fd(fd) { if (mode & std::ios::in) setg(buffer, buffer + 1, buffer + 1); } pos_type seekoff(off_type offset, ios::seekdir dir, ios_base::openmode) { pos_type pos = lseek ( fd, offset, (dir == ios::beg) ? SEEK_SET : (dir == ios::cur) ? SEEK_CUR : SEEK_END ); if (pos < 0) return -1; setg(buffer, buffer + 1, buffer + 1); return pos; } pos_type // used by seekg() seekpos(pos_type offset, ios_base::openmode mode) { return seekoff(offset, ios::beg, mode); } int underflow() // inspects the character { if (gptr() < egptr()) return static_cast(*gptr()); // return next char waiting in the buffer if (read(fd, buffer, 1) <= 0) // none read -> return EOF; setg(buffer, buffer, buffer + 1); return static_cast(*gptr()); } private: char buffer[1]; int fd; }; c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/inok/buf.n.h0000664000175000017500000000216514771010714024501 0ustar frankfrank#include #include #include class fdstreambuf: public std::streambuf { public: fdstreambuf(int fd, size_t bufsize, std::ios::openmode mode = std::ios::in | std::ios::out) : fd(fd), bufsize(bufsize), buffer(new char[bufsize]) { if (mode & std::ios::in) setg(buffer, buffer + bufsize, buffer + bufsize); } ~fdstreambuf() { delete buffer; } int underflow() // inspects the character { if (gptr() < egptr()) return static_cast(*gptr()); // return next char waiting in the buffer int nread = read(fd, buffer, bufsize); if (nread <= 0) // none read -> return EOF; setg(buffer, buffer, buffer + nread); return static_cast(*gptr()); } private: int fd; size_t bufsize; char* buffer; }; c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/inok/minimum.h0000664000175000017500000000403514771010714025142 0ustar frankfrank#include #include #include #include using namespace std; class fdstreambuf: public std::streambuf { public: fdstreambuf(int fd, size_t bufsize, size_t minimum, std::ios::openmode mode = std::ios::in | std::ios::out) : fd(fd), bufsize(bufsize), minimum(minimum), buffer(new char[bufsize]) { /* initialize buffer from minimum position to beyond, set gptr() to beyond, so the buffer is filled immediately Assume bufsize - minimum > minimum */ if (mode & std::ios::in) setg(buffer + minimum, buffer + bufsize, buffer + bufsize); } ~fdstreambuf() { delete buffer; } int underflow() // inspects the character { if (gptr() < egptr()) return static_cast(*gptr()); // return next char waiting in the buffer /* Now that the buffer is refilled, what do we have? buffer eback() gptr() == egptr() ^ ^ ^ ------------------------------- n m <= bufsize - minimum n characters at chars before gptr() are moved left, eback() is moved left over n filling starts are buffer + minimum */ size_t n2move = min(minimum, (size_t)(gptr() - eback())); memcpy(buffer, egptr() - n2move, n2move); /* Read chars to the area beyond the unget-buffer */ int nread = read(fd, buffer + minimum, bufsize - minimum); if (nread <= 0) // none read -> return EOF; setg(buffer + minimum - n2move, buffer + minimum, buffer + minimum + nread); return static_cast(*gptr()); } private: int fd; size_t bufsize; size_t minimum; char* buffer; }; c++-annotations-13.02.01/yo/concrete/streambuf/fdstreambuf/fdinseek.cc0000664000175000017500000000131214771010716024452 0ustar frankfrank#include "fdstreambuf.h" #include #include #include #include using namespace std; int main(int argc) { fdstreambuf fds(0, ios::in); istream is(&fds); string s; cout << "START\n"; while (true) { if (!getline(is, s)) break; streampos pos = is.tellg(); cout << setw(5) << pos << ": `" << s << "'\n"; if (!getline(is, s)) break; streampos pos2 = is.tellg(); cout << setw(5) << pos2 << ": `" << s << "'\n"; if (!is.seekg(pos)) { cout << "Seek failed\n"; return 1; } } } c++-annotations-13.02.01/yo/concrete/poly/0000775000175000017500000000000014771010711017042 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/input0000664000175000017500000000002514735537670020143 0ustar frankfrankabc(def); xyz = 5; c++-annotations-13.02.01/yo/concrete/poly/semantic/0000775000175000017500000000000014771010710020644 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/semantic/semantic.h0000664000175000017500000000111714771010714022624 0ustar frankfrank#ifndef INCLUDED_SEMANTIC_ #define INCLUDED_SEMANTIC_ #include #include #include "../base/base.h" class Semantic: public std::shared_ptr { friend std::ostream &operator<<(std::ostream &out, Semantic const &obj); public: Semantic(Base *bp = 0); // Semantic owns the bp ~Semantic() = default; }; inline Semantic::Semantic(Base *bp) : std::shared_ptr(bp) {} inline std::ostream &operator<<(std::ostream &out, Semantic const &obj) { if (obj) return out << *obj; return out << ""; } #endif c++-annotations-13.02.01/yo/concrete/poly/parser/0000775000175000017500000000000014771010710020335 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/parser/parser.h0000664000175000017500000000202014771010714022000 0ustar frankfrank#ifndef Parser_h_included #define Parser_h_included // $insert baseclass #include "parserbase.h" // $insert scanner.h #include "../scanner/scanner.h" #undef Parser class Parser: public ParserBase { // $insert scannerobject Scanner d_scanner; public: Parser(); int parse(); private: void error(char const *msg); // called on (syntax) errors int lex(); // returns the next token from the // lexical scanner. void print(); // use, e.g., d_token, d_loc // support functions for parse(): void executeAction(int ruleNr); void errorRecovery(); int lookup(bool recovery); void nextToken(); }; inline void Parser::error(char const *msg) { std::cerr << msg << '\n'; } // $insert lex inline int Parser::lex() { return d_scanner.yylex(); } inline void Parser::print() // use d_token, d_loc {} inline Parser::Parser() : d_scanner(&d_val__) {} #endif c++-annotations-13.02.01/yo/concrete/poly/parser/parser.ih0000664000175000017500000000017314771010714022160 0ustar frankfrank // Include this file in the sources of the class Parser. // $insert class.h #include "parser.h" using namespace std; c++-annotations-13.02.01/yo/concrete/poly/parser/grammar0000664000175000017500000000054614735537670021736 0ustar frankfrank%filenames parser %scanner ../scanner/scanner.h %baseclass-preinclude preinclude.h %stype Semantic %token INT IDENTIFIER %% rules: rules rule | rule ; rule: IDENTIFIER '(' IDENTIFIER ')' ';' { cout << $1 << " " << $3 << '\n'; } | IDENTIFIER '=' INT ';' { cout << $1 << " " << $3 << '\n'; } ; c++-annotations-13.02.01/yo/concrete/poly/parser/preinclude.h0000664000175000017500000000023414771010714022643 0ustar frankfrank#ifndef INCLUDED_PREINCLUDE_H_ #define INCLUDED_PREINCLUDE_H_ #include "../int/int.h" #include "../text/text.h" #include "../semantic/semantic.h" #endif c++-annotations-13.02.01/yo/concrete/poly/scanner/0000775000175000017500000000000014771010710020472 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/scanner/scanner.ih0000664000175000017500000000175614771010714022462 0ustar frankfrank/* Declare here what's only used in the Scanner class and let Scanner's sources include "scanner.ih" */ #include "scanner.h" //#include // #include // #include // #include /* In the current Debian distribution of flex, YY_CURRENT_BUFFER and YY_START are not available to members of the flex-generated class (See `Values Available To The User' in the flex info-file). Use the following macros to make these values available. (Note that the need for these defines may be superfluous in the near future): */ // uncomment if you want to use YY_CURRENT_BUFFER in the scanner's members: /* #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) */ // uncomment if you want to use YY_START in the scanner's members: // #define YY_START (((yy_start) - 1) / 2) // end of scanner.ih c++-annotations-13.02.01/yo/concrete/poly/scanner/scanner.h0000664000175000017500000000062714771010714022305 0ustar frankfrank#ifndef SCANNER_H_ #define SCANNER_H_ #include "../semantic/semantic.h" #if ! defined(SKIP_FLEXLEXER_) && ! defined(SYSINC_FLEXLEXER_H_) #include #define SYSINC_FLEXLEXER_H_ #endif class Scanner: public yyFlexLexer { Semantic *d_semval; public: Scanner(Semantic *semval); int yylex(); }; inline Scanner::Scanner(Semantic *semval) : d_semval(semval) {} #endif c++-annotations-13.02.01/yo/concrete/poly/scanner/lexer0000664000175000017500000000117314735537670021561 0ustar frankfrank%{ #define SKIP_FLEXLEXER_ #include "scanner.ih" #include "../parser/preinclude.h" #include "../parser/parserbase.h" %} %option yyclass="Scanner" outfile="yylex.cc" %option c++ 8bit warn noyywrap yylineno %option debug %% [ \t]+ // Often used: skip white space \n // same [0-9]+ { d_semval->reset(new Int(yytext)); return Parser::INT; } [a-zA-Z_][a-zA-Z0-9_]* { d_semval->reset(new Text(yytext)); return Parser::IDENTIFIER; } . return yytext[0]; %% c++-annotations-13.02.01/yo/concrete/poly/base/0000775000175000017500000000000014771010711017754 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/base/base.ih0000664000175000017500000000005014771010714021206 0ustar frankfrank#include "base.h" using namespace std; c++-annotations-13.02.01/yo/concrete/poly/base/clone.cc0000664000175000017500000000011114771010716021361 0ustar frankfrank#include "base.ih" Base *Base::clone() const { return ownClone(); } c++-annotations-13.02.01/yo/concrete/poly/base/base.h0000664000175000017500000000103014771010714021034 0ustar frankfrank #ifndef INCLUDED_BASE_ #define INCLUDED_BASE_ #include class Base { friend std::ostream &operator<<(std::ostream &out, Base const &obj); public: virtual ~Base() = default; Base *clone() const; private: virtual Base *ownClone() const = 0; virtual std::ostream &insert(std::ostream &os) const = 0; }; inline std::ostream &operator<<(std::ostream &out, Base const &obj) { return obj.insert(out); } #endif c++-annotations-13.02.01/yo/concrete/poly/icmconf0000664000175000017500000000675014735537670020435 0ustar frankfrank // Inspect the following #defines. Change them to taste. If you don't // need a particular option, change its value into an empty string // should commands be echoed (ON) or not (OFF) ? #define USE_ECHO ON // The final program and source containing main(): // =============================================== // define the name of the program to create: #define BINARY "../../poly" // define the name of the source containing main(): #define MAIN "main.cc" // #defines used for compilation and linking: // ========================================== // define the compiler to use: #define COMPILER "g++" // define the compiler options to use: #define COMPILER_OPTIONS "-g --std=c++0x -Wall -O2" // define the pattern to locate sources in a directory: #define SOURCES "*.cc" // define the options used for linking: #define LINKER_OPTIONS "-s" // define any additional libraries BINARY may need: #define ADD_LIBRARIES "bobcat" // define any additional paths (other than the standard paths) the // additional libraries are located in: #define ADD_LIBRARY_PATHS "" // #defines used for the final product: // ==================================== #define BIN_INSTALL "/usr/local/bin" // Some advanced #defines, used to create parsers and lexical scanners // =================================================================== // Lexical Scanner section // ======================= // Should a lexical scanner be constructed? If so, define the subdirectory // containing the scanner's specification file. #define SCANNER_DIR "scanner" // What is the program generating the lexical scanner? #define SCANGEN "flex" // Flags to provide SCANGEN with: #define SCANFLAGS "-I" // Name of the lexical scanner specification file #define SCANSPEC "lexer" // Name of the file generated by the lexical scanner #define SCANOUT "yylex.cc" // Parser section // ============== // Should a parser be constructed? If so, define the subdirectory // containing the parser's specification file #define PARSER_DIR "parser" // If a parser must be constructed, should the script (provided in the // skeleton file parser/gramspec/grambuild) `parser/gramspec/grambuild' // **NOT** be called? If it must NOT be called, comment out the following // #define directive: // #define GRAMBUILD // What it the program generating a parser? #define PARSGEN "bisonc++" // What it the grammar specificication file? #define PARSSPEC "grammar" // Flags to provide PARSGEN with: #define PARSFLAGS "-V -l" // Name of the file generated by the parser generator containing the // parser function #define PARSOUT "parse.cc" // Additional defines, which should normally not be modified // ========================================================= // Directory below this directory to contain temporary results #define TMP_DIR "tmp" // Local program library to use (change to an empty string if you want to // use the object modules themselves, rather than a library) #define LIBRARY "modules" // The extension of object modules: #define OBJ_EXT ".o" // below #define DEFCOM "program" or "library" may be added by icmstart #define DEFCOM "program" c++-annotations-13.02.01/yo/concrete/poly/main.cc0000664000175000017500000000020114771010716020273 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) { Parser parser; parser.setDebug(argc == 1); parser.parse(); } c++-annotations-13.02.01/yo/concrete/poly/main.ih0000664000175000017500000000016314771010714020313 0ustar frankfrank#include #include #include #include "parser/preinclude.h" #include "parser/parser.h" c++-annotations-13.02.01/yo/concrete/poly/int/0000775000175000017500000000000014771010710017633 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/int/int.h0000664000175000017500000000134414771010714020604 0ustar frankfrank#ifndef INCLUDED_INT_ #define INCLUDED_INT_ #include #include #include "../base/base.h" class Int: public Base { int d_value; public: Int(char const *text); Int(int v); int value() const; // directly access the value private: virtual Base *ownClone() const; virtual std::ostream &insert(std::ostream &os) const; }; inline Int::Int(char const *txt) : d_value(FBB::A2x(txt)) {} inline Int::Int(int v) : d_value(v) {} inline Base *Int::ownClone() const { return new Int(*this); } inline int Int::value() const { return d_value; } inline std::ostream &Int::insert(std::ostream &out) const { return out << d_value; } #endif c++-annotations-13.02.01/yo/concrete/poly/text/0000775000175000017500000000000014771010710020025 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly/text/text.h0000664000175000017500000000126114771010714021166 0ustar frankfrank#ifndef INCLUDED_TEXT_ #define INCLUDED_TEXT_ #include #include #include "../base/base.h" class Text: public Base { std::string d_text; public: Text(char const *id); std::string const &id() const; // directly access the name. private: virtual Base *ownClone() const; virtual std::ostream &insert(std::ostream &os) const; }; inline Text::Text(char const *id) : d_text(id) {} inline Base *Text::ownClone() const { return new Text(*this); } inline std::string const &Text::id() const { return d_text; } inline std::ostream &Text::insert(std::ostream &out) const { return out << d_text; } #endif c++-annotations-13.02.01/yo/concrete/fdout.yo0000664000175000017500000001424614735537670017602 0ustar frankfrank Reading and writing from and to em(file descriptors)hi(file descriptor) are not part of the bf(C++) standard. But on most operating systems file descriptors em(are) available and can be considered a i(device). It seems natural to use the class hi(streambuf)tt(std::streambuf) as the starting point for constructing classes interfacing such file descriptor devices. Below we'll construct classes that can be used to write to a device given its file descriptor. The devices may be files, but they could also be i(pipe)s or i(socket)s. Section ref(STRBUF) covers reading from such devices; section ref(REDIRECTION) reconsiders redirection, discussed earlier in section ref(REDIR). Using the tt(streambuf) class as a base class it is relatively easy to design classes for output operations. The only member function that em(must) be overridden is the (virtual) member hi(overflow) tt(int streambuf::overflow(int c)). This member's responsibility is to write characters to the device. If tt(fd) is an output file descriptor and if output should not be buffered then the member tt(overflow()) can simply be implemented as: verb( class UnbufferedFD: public std::streambuf { public: int overflow(int c) override; ... }; int UnbufferedFD::overflow(int c) { if (c != EOF) { if (write(d_fd, &c, 1) != 1) return EOF; } return c; }) The argument received by tt(overflow) is either written to the file descriptor (and returned from tt(overflow)), or endOfFile() is returned. This simple function does not use output buffering. For various reasons, using a buffer is usually a good idea (see also the next section). When output buffering is used, the tt(overflow) member is a bit more complex as it is only called when the buffer is full. Once the buffer is full, we em(first) have to flush the buffer. Flushing the buffer is the responsibility of the (virtual) function hi(sync)tt(streambuf::sync). Since tt(sync) is a virtual function, classes derived from tt(streambuf) may redefine tt(sync) to flush a buffer tt(streambuf) itself doesn't know about. Overriding tt(sync) and using it in tt(overflow) is not all that has to be done. When the object of the class defining the buffer reaches the end of its lifetime the buffer may be only partially full. In that situation the buffer must also be flushed. This is easily done by simply calling tt(sync) from the class's destructor. Now that we've considered the consequences of using an output buffer, we're almost ready to design our derived class. Several more features are added as well, though: itemization( it() First, we should allow the user of the class to specify the size of the output buffer. it() Second, it should be possible to construct an object of our class before the file descriptor is actually known. Later, in section ref(FORK) we'll encounter a situation where this feature is actually used. ) To save some space in the annotations(), the successful completion of the functions designed here is not checked in the example code. In `real life' implementations these checks should of course not be omitted. Our class tt(OFdnStreambuf) has the following characteristics: itemization( it() Its member functions use low-level functions operating on file descriptors. So apart from tt(streambuf) the tthi(unistd.h) header file must have been read by the compiler before its member functions can be compiled. it() The class is derived from tt(std::streambuf). it() It defines three data members. These data members keep track of, respectively, the size of the buffer, the file descriptor, and the buffer itself. Here is the full class interface verbinclude(//CLASS examples/fdout.h) it() Its default constructor merely initializes the buffer to 0. Slightly more interesting is its constructor expecting a file descriptor and a buffer size. This constructor passes its arguments on to the class's tt(open) member (see below). Here are the constructors: verbinclude(//CONS examples/fdout.h) it() The destructor calls tt(sync), flushing any characters stored in the output buffer to the device. In implementations not using a buffer the destructor can be given a default implementation: verbinclude(//DESTR examples/fdout.h) This implementation does not close the device. It is left as an exercise to the reader to change this class in such a way that the device is optionally closed (or optionally remains open). This approach was adopted by, e.g., the url(Bobcat library)(http://fbb-git.gitlab.io/bobcat/). hi(Bobcat library)hi(http://fbb-git.gitlab.io/bobcat/) See also section ref(IFDNBUF). it() The ti(open) member initializes the buffer. Using hi(setp)tt(streambuf::setp), the begin and end points of the buffer are defined. This is used by the tt(streambuf) base class to initialize hi(pbase)tt(streambuf::pbase), hi(pptr)tt(streambuf::pptr), and hi(epptr)tt(streambuf::epptr): verbinclude(//OPEN examples/fdout.h) it() The member ti(sync) flushes the as yet unflushed content of the buffer to the device. After the flush the buffer is reinitialized using tt(setp). After successfully flushing the buffer tt(sync) returns 0: verbinclude(//SYNC examples/fdout.h) it() The member hi(overflow)tt(streambuf::overflow) is also overridden. Since this member is called from the tt(streambuf) base class when the buffer is full it should first call tt(sync) to flush the buffer to the device. Next it should write the character tt(c) to the (now empty) buffer. The character tt(c) should be written using tt(pptr) and hi(pbump)tt(streambuf::pbump). Entering a character into the buffer should be implemented using available tt(streambuf) member functions, rather than `by hand' as doing so might invalidate tt(streambuf)'s internal bookkeeping. Here is tt(overflow)'s implementation: verbinclude(//OVERFLOW examples/fdout.h) ) The next program uses the tt(OFfdStreambuf) class to copy its standard input to file descriptor ti(STDOUT_FILENO), which is the symbolic name of the file descriptor used for the standard output: verbinclude(-a examples/fdout.cc) c++-annotations-13.02.01/yo/concrete/rules.yo0000664000175000017500000000233314735537670017605 0ustar frankfrank The rules and actions of the grammar are specified as usual. The grammar for our little calculator is given below. There are quite a few rules, but they illustrate various features offered by tt(bisonc++). In particular, note that no action block requires more than a single line of code. This keeps the grammar simple, and therefore enhances its readability and understandability. Even the rule defining the parser's proper termination (the empty line in the tt(line) rule) uses a single member function called tt(done). The implementation of that function is simple, but it is worth while noting that it calls bf(Parser::ACCEPT), showing that bf(ACCEPT) can be called indirectly from a production rule's action block. Here are the grammar's production rules: verbinclude(//RULES bisonc++/parser/grammar) This grammar is used to implement a simple calculator in which integer and real values can be negated, added, and multiplied and in which standard priority rules can be overruled by parentheses. The grammar shows the use of typed nonterminal symbols: tt(doubleExpr) is linked to real (double) values, tt(intExpr) is linked to integer values. Precedence and type association is defined in the parser's definition section. c++-annotations-13.02.01/yo/concrete/lexerspec.yo0000664000175000017500000000324114735537670020444 0ustar frankfrank The i(lexical scanner specification file) is organized comparably to the one used for tt(flex) in bf(C) contexts. However, in bf(C++) contexts, tt(flexc++) creates a class tt(Scanner), rather than just a scanner function. Flexc++'s specification file consists of two sections: itemization( it() The specification file's first section is tt(flexc++)'s emi(symbol area), used to define symbols, like a i(mini scanner), or emi(options). The following options are suggested: itemization( it() ti(%debug): includes em(debugging) hi(flexc++: debugging) code into the code generated by tt(flexc++). Calling the member function hi(setDebug) tt(setDebug(true)) activates this debugging code at run-time. When activated, information about the matching process is written to the standard output stream. The execution of debug code is suppressed after calling the member function tt(setDebug(false)). it() ti(%filenames): defines the base-name of the class header files generated by tt(flexc++). By default the class name (itself using the default tt(Scanner)) is used. ) Here is the specification files' symbol area: verbinclude(//SYMBOLS lexer/scanner/lexer) it() The specification file's second section is a em(rules section) in which the regular expressions and their associated actions are defined. In the example developed here, the lexer should copy information from the standard input stream (tt(std::cin)) to the standard output stream (tt(std::cout)). For this the predefined macro ti(ECHO) can be used. Here are the rules: verbinclude(//RULES lexer/scanner/lexer) ) c++-annotations-13.02.01/yo/concrete/monitorexample.yo0000664000175000017500000000755714735537670021533 0ustar frankfrank Now that tt(run)'s implementation has been covered, we'll concentrate on the various commands users might enter: itemization( it() When the tt(start) command is issued, a new child process is started. A new element is added to tt(d_child) by the member tt(createNewChild). Next, the tt(Child) object should start its activities, but the tt(Monitor) object can not wait for the child process to complete its activities, as there is no well-defined endpoint in the near future, and the user probably wants to be able to enter more commands. Therefore, the tt(Child) process must run as a emi(daemon). So the forked process terminates immediately, but its own child process continues to run (in the background). Consequently, tt(createNewChild) calls the child's tt(fork) member. Although it is the child's tt(fork) function that is called, it is still the monitor program wherein that tt(fork) function is called. So, the em(monitor) program is duplicated by tt(fork). Execution then continues: itemization( it() At the tt(Child)'s tt(parentProcess) in its parent process; it() At the tt(Child)'s tt(childProcess) in its child process ) As the tt(Child)'s tt(parentProcess) is an empty function, returning immediately, the tt(Child)'s parent process effectively continues immediately below tt(createNewChild)'s tt(cp->fork()) statement. As the child process never returns (see section ref(CHILD)), the code below tt(cp->fork()) is never executed by the tt(Child)'s child process. This is exactly as it should be. In the parent process, tt(createNewChild)'s remaining code simply adds the file descriptor that's available for reading information from the child to the set of input file descriptors monitored by tt(d_select), and uses tt(d_child) to establish the association between that file descriptor and the tt(Child) object's address: verbinclude(//CHILD examples/monitor/createnewchild.cc) it() Direct communication with the child is required for the tt(stop ) and tt( text) commands. The former command terminates child process tt(), by calling tt(stopChild). This function locates the child process having the order number using an anonymous object of the class tt(Find), nested inside tt(Monitor). The class tt(Find) simply compares the provided tt(nr) with the children's order number returned by their tt(nr) members: verbinclude(//FINDIMP examples/monitor/monitor.h) If the child process having order number tt(nr) was found, its file descriptor is removed from tt(d_selector)'s set of input file descriptors. Then the child process itself is terminated by the static member tt(killChild). The member tt(killChild) is declared as a em(static) member function, as it is used as function argument of the tt(for_each) generic algorithm by tt(exiting) (see below). Here is tt(killChild)'s implementation: verbinclude(//KILL examples/monitor/monitor.cc) Having terminated the specified child process, the corresponding tt(Child) object is destroyed and its pointer is removed from tt(d_child): verbinclude(//STOP examples/monitor/stopchild.cc) it() The command tt( text) sends tt(text) to child process tt(nr) using the member function tt(sendChild). This function also uses a tt(Find) object to locate the child-process having order number tt(nr), and simply inserts the text into the writing end of a pipe connected to that child process: verbinclude(//SEND examples/monitor/sendchild.cc) it() When users enter tt(exit) or tt(quit) the member tt(exiting) is called. It terminates all child processes using the ti(for_each) generic algorithm (see section ref(FOREACH)) to visit all elements of tt(d_child). Then the program itself ends: verbinclude(//EXIT examples/monitor/monitor.cc) ) The program's tt(main) function is simple and needs no further comment: verbinclude(//MAIN examples/monitor/main.cc) c++-annotations-13.02.01/yo/concrete/scanmain.yo0000664000175000017500000000140414735537670020242 0ustar frankfrank The program using our tt(Scanner) is very simple. It expects a filename indicating where to start the scanning process. The program first checks the number of arguments. If at least one argument was given, then that argument is passed to tt(Scanner)'s constructor, together with a second argument tt("-"), indicating that the output should go to the standard output stream. If the program receives more than one argument debug output, extensively documenting the lexical scanner's actions, is written to the standard output stream as well. Next the tt(Scanner)'s tt(lex) member is called. If anything fails, a tt(std::exception) is thrown, which is caught by tt(main)'s try-block's catch clause. Here is the program's source: verbinclude(-a lexer/lexer.cc) c++-annotations-13.02.01/yo/concrete/unrestricted/0000775000175000017500000000000014771010711020572 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/unrestricted/input0000664000175000017500000000002514735537670021673 0ustar frankfrankabc(def); xyz = 5; c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/0000775000175000017500000000000014771010711022375 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/unrestricted/semantic/semantic2.cc0000664000175000017500000000042014771010716024572 0ustar frankfrank#include "semantic.ih" Semantic::Semantic(Semantic const &other) : d_int(other.d_int) // blunt copy of d_int { if (d_int.first == IDENTIFIER) // if a string: copy it new (&d_str.second) string{ other.d_str.second }; } c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/semantic1.cc0000664000175000017500000000041514771010716024575 0ustar frankfrank#include "semantic.ih" Semantic::Semantic(Type type, char const *txt) { d_int.first = static_cast(type); if (type == IDENTIFIER) new (&d_str.second) string{ txt }; else { istringstream in(txt); in >> d_int.second; } } c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/semantic.ih0000664000175000017500000000012314771010714024521 0ustar frankfrank#include "semantic.h" #include #include using namespace std; c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/semantic.h0000664000175000017500000000122214771010714024351 0ustar frankfrank#ifndef INCLUDED_SEMANTIC_ #define INCLUDED_SEMANTIC_ #include #include union Semantic { friend std::ostream &operator<<(std::ostream &out, Semantic const &obj); std::pair d_int; std::pair d_str; public: enum Type { INT, IDENTIFIER }; Semantic(); Semantic(Type type, char const *txt); Semantic(Semantic const &other); // 2 ~Semantic(); Semantic &operator=(Semantic const &rhs); void swap(Semantic &other); }; inline Semantic::Semantic() : d_int {INT, 0} {} #endif c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/operatorinsert.cc0000664000175000017500000000035214771010716025771 0ustar frankfrank#include "semantic.ih" std::ostream &operator<<(std::ostream &out, Semantic const &obj) { if (obj.d_int.first == Semantic::IDENTIFIER) out << obj.d_str.second; else out << obj.d_int.second; return out; } c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/destructor.cc0000664000175000017500000000023414771010716025106 0ustar frankfrank#include "semantic.ih" Semantic::~Semantic() { if (d_int.first == IDENTIFIER) d_str.second.~string(); // destroy the string's memory } c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/operatorassign.cc0000664000175000017500000000020714771010716025750 0ustar frankfrank#include "semantic.ih" Semantic &Semantic::operator=(Semantic const &rhs) { Semantic tmp(rhs); swap(tmp); return *this; } c++-annotations-13.02.01/yo/concrete/unrestricted/semantic/swap.cc0000664000175000017500000000043714771010716023667 0ustar frankfrank#include "semantic.ih" void Semantic::swap(Semantic &other) { char buffer[sizeof(Semantic)]; memcpy(buffer, this, sizeof(Semantic)); memcpy(reinterpret_cast(this), &other, sizeof(Semantic)); memcpy(reinterpret_cast(&other), buffer, sizeof(Semantic)); } c++-annotations-13.02.01/yo/concrete/unrestricted/parser/0000775000175000017500000000000014771010710022065 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/unrestricted/parser/parser.h0000664000175000017500000000202014771010714023530 0ustar frankfrank#ifndef Parser_h_included #define Parser_h_included // $insert baseclass #include "parserbase.h" // $insert scanner.h #include "../scanner/scanner.h" #undef Parser class Parser: public ParserBase { // $insert scannerobject Scanner d_scanner; public: Parser(); int parse(); private: void error(char const *msg); // called on (syntax) errors int lex(); // returns the next token from the // lexical scanner. void print(); // use, e.g., d_token, d_loc // support functions for parse(): void executeAction(int ruleNr); void errorRecovery(); int lookup(bool recovery); void nextToken(); }; inline void Parser::error(char const *msg) { std::cerr << msg << '\n'; } // $insert lex inline int Parser::lex() { return d_scanner.yylex(); } inline void Parser::print() // use d_token, d_loc {} inline Parser::Parser() : d_scanner(&d_val__) {} #endif c++-annotations-13.02.01/yo/concrete/unrestricted/parser/parser.ih0000664000175000017500000000017314771010714023710 0ustar frankfrank // Include this file in the sources of the class Parser. // $insert class.h #include "parser.h" using namespace std; c++-annotations-13.02.01/yo/concrete/unrestricted/parser/grammar0000664000175000017500000000063714735537670023467 0ustar frankfrank%class-name Parser %filenames parser %parsefun-source parse.cc %scanner ../scanner/scanner.h // %debug %baseclass-preinclude preinclude.h %stype Semantic %token INT IDENTIFIER %% rules: rules rule | rule ; rule: IDENTIFIER '(' IDENTIFIER ')' ';' { cout << $1 << " " << $3 << '\n'; } | IDENTIFIER '=' INT ';' { cout << $1 << " " << $3 << '\n'; } ; c++-annotations-13.02.01/yo/concrete/unrestricted/parser/preinclude.h0000664000175000017500000000015114771010714024371 0ustar frankfrank#ifndef INCLUDED_PREINCLUDE_H_ #define INCLUDED_PREINCLUDE_H_ #include "../semantic/semantic.h" #endif c++-annotations-13.02.01/yo/concrete/unrestricted/scanner/0000775000175000017500000000000014771010710022222 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/unrestricted/scanner/scanner.ih0000664000175000017500000000175614771010714024212 0ustar frankfrank/* Declare here what's only used in the Scanner class and let Scanner's sources include "scanner.ih" */ #include "scanner.h" //#include // #include // #include // #include /* In the current Debian distribution of flex, YY_CURRENT_BUFFER and YY_START are not available to members of the flex-generated class (See `Values Available To The User' in the flex info-file). Use the following macros to make these values available. (Note that the need for these defines may be superfluous in the near future): */ // uncomment if you want to use YY_CURRENT_BUFFER in the scanner's members: /* #define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ : NULL) */ // uncomment if you want to use YY_START in the scanner's members: // #define YY_START (((yy_start) - 1) / 2) // end of scanner.ih c++-annotations-13.02.01/yo/concrete/unrestricted/scanner/scanner.h0000664000175000017500000000066514771010714024037 0ustar frankfrank#ifndef SCANNER_H_ #define SCANNER_H_ #include "../semantic/semantic.h" #if ! defined(SKIP_FLEXLEXER_) && ! defined(SYSINC_FLEXLEXER_H_) #include #define SYSINC_FLEXLEXER_H_ #endif class Scanner: public yyFlexLexer { Semantic *d_semval; // received fm the parser public: Scanner(Semantic *semval); int yylex(); }; inline Scanner::Scanner(Semantic *semval) : d_semval(semval) {} #endif c++-annotations-13.02.01/yo/concrete/unrestricted/scanner/lexer0000664000175000017500000000121314735537670023304 0ustar frankfrank%{ #define SKIP_FLEXLEXER_ #include "scanner.ih" #include "../parser/preinclude.h" #include "../parser/parserbase.h" %} %option yyclass="Scanner" outfile="yylex.cc" %option c++ 8bit warn noyywrap yylineno %option debug %% [ \t]+ // skip white space \n // same [0-9]+ { *d_semval = Semantic(Semantic::INT, yytext); return Parser::INT; } [a-zA-Z_][a-zA-Z0-9_]* { *d_semval = Semantic(Semantic::IDENTIFIER, yytext); return Parser::IDENTIFIER; } . return yytext[0]; %% c++-annotations-13.02.01/yo/concrete/unrestricted/icmconf0000664000175000017500000000675014735537670022165 0ustar frankfrank // Inspect the following #defines. Change them to taste. If you don't // need a particular option, change its value into an empty string // should commands be echoed (ON) or not (OFF) ? #define USE_ECHO ON // The final program and source containing main(): // =============================================== // define the name of the program to create: #define BINARY "../../poly" // define the name of the source containing main(): #define MAIN "main.cc" // #defines used for compilation and linking: // ========================================== // define the compiler to use: #define COMPILER "g++" // define the compiler options to use: #define COMPILER_OPTIONS "-g --std=c++0x -Wall -O2" // define the pattern to locate sources in a directory: #define SOURCES "*.cc" // define the options used for linking: #define LINKER_OPTIONS "-s" // define any additional libraries BINARY may need: #define ADD_LIBRARIES "bobcat" // define any additional paths (other than the standard paths) the // additional libraries are located in: #define ADD_LIBRARY_PATHS "" // #defines used for the final product: // ==================================== #define BIN_INSTALL "/usr/local/bin" // Some advanced #defines, used to create parsers and lexical scanners // =================================================================== // Lexical Scanner section // ======================= // Should a lexical scanner be constructed? If so, define the subdirectory // containing the scanner's specification file. #define SCANNER_DIR "scanner" // What is the program generating the lexical scanner? #define SCANGEN "flex" // Flags to provide SCANGEN with: #define SCANFLAGS "-I" // Name of the lexical scanner specification file #define SCANSPEC "lexer" // Name of the file generated by the lexical scanner #define SCANOUT "yylex.cc" // Parser section // ============== // Should a parser be constructed? If so, define the subdirectory // containing the parser's specification file #define PARSER_DIR "parser" // If a parser must be constructed, should the script (provided in the // skeleton file parser/gramspec/grambuild) `parser/gramspec/grambuild' // **NOT** be called? If it must NOT be called, comment out the following // #define directive: // #define GRAMBUILD // What it the program generating a parser? #define PARSGEN "bisonc++" // What it the grammar specificication file? #define PARSSPEC "grammar" // Flags to provide PARSGEN with: #define PARSFLAGS "-V -l" // Name of the file generated by the parser generator containing the // parser function #define PARSOUT "parse.cc" // Additional defines, which should normally not be modified // ========================================================= // Directory below this directory to contain temporary results #define TMP_DIR "tmp" // Local program library to use (change to an empty string if you want to // use the object modules themselves, rather than a library) #define LIBRARY "modules" // The extension of object modules: #define OBJ_EXT ".o" // below #define DEFCOM "program" or "library" may be added by icmstart #define DEFCOM "program" c++-annotations-13.02.01/yo/concrete/unrestricted/main.cc0000664000175000017500000000020114771010716022023 0ustar frankfrank#include "main.ih" int main(int argc, char **argv) { Parser parser; parser.setDebug(argc == 1); parser.parse(); } c++-annotations-13.02.01/yo/concrete/unrestricted/main.ih0000664000175000017500000000016314771010714022043 0ustar frankfrank#include #include #include #include "parser/preinclude.h" #include "parser/parser.h" c++-annotations-13.02.01/yo/concrete/unrestricted/CLASSES0000664000175000017500000000001114735537670021624 0ustar frankfranksemantic c++-annotations-13.02.01/yo/concrete/command.yo0000664000175000017500000000131114735537670020064 0ustar frankfrank The tt(class Command) defines the interface to be used for scanning commands from the standard input. Its constructor expects an array of strings, which are the commands to be recognized, as well as the number of commands. The command tt(\d) represents a digit, tt(*) represents any text until end of line. Blanks may appear before or after the commands. The class does nothing fancy: if anything more complex is required, a formal emi(grammar) should be specified (see section(BISONFLEX)). Its member tt(int next(std::string &text)) returns the number of the interpreted command, with tt(text) containing the actual text that was received. Here is the class interface: verbinclude(-a examples/command.h) c++-annotations-13.02.01/yo/concrete/fistream.yo0000664000175000017500000000775414735537670020301 0ustar frankfrankUsually when extracting information from tt(istream) objects oprshift(), the standard extraction operator is perfectly suited for the task as in most cases the extracted fields are white-space (or otherwise clearly) separated from each other. But this does not hold true in all situations. For example, when a web-form is posted to some processing script or program, the receiving program may receive the form field's values as em(url-encoded) characters: letters and digits are sent unaltered, blanks are sent as tt(+) characters, and all other characters start with tt(%) followed by the character's i(ascii-value) represented by its two digit hexadecimal value. When decoding url-encoded information, simple hexadecimal extraction won't work, as that extracts as many hexadecimal characters as available, instead of just two. Since the letters tt(a-f`) and tt(0-9) are legal hexadecimal characters, a text like tt(My name is `Ed'), url-encoded as verb( My+name+is+%60Ed%27) results in the extraction of the hexadecimal values tt(60ed) and tt(27), instead of tt(60) and tt(27). The name tt(Ed) disappears from view, which is clearly not what we want. In this case, having seen the tt(%), we could extract 2 characters, put them in an ti(istringstream) object, and extract the hexadecimal value from the tt(istringstream) object. A bit cumbersome, but doable. Other approaches are possible as well. The class ti(Fistream) for em(fixed-sized field istream) defines an tt(istream) class supporting both fixed-sized field extractions and blank-delimited extractions (as well as unformatted tt(read) calls). The class may be initialized as a emi(wrapper) around an existing tt(istream), or it can be initialized using the name of an existing file. The class is derived from tt(istream), allowing all extractions and operations supported by tt(istream)s in general. tt(Fistream) defines the following data members: itemization( itt(d_filebuf): a filebuffer used when tt(Fistream) reads its information from a named (existing) file. Since the filebuffer is only needed in that case, and since it must be allocated dynamically, it is defined as a tt(unique_ptr) object. itt(d_streambuf): a pointer to tt(Fistream)'s tt(streambuf). It points to tt(d_filebuf) when tt(Fistream) opens a file by name. When an existing tt(istream) is used to construct an tt(Fistream), it points to the existing tt(istream)'s tt(streambuf). itt(d_iss): an tt(istringstream) object used for the fixed field extractions. itt(d_width): a tt(size_t) indicating the width of the field to extract. If 0 no fixed field extractions is used, but information is extracted from the tt(istream) base class object using standard extractions. ) Here is the initial section of tt(Fistream)'s class interface: verbinclude(//INITIAL examples/fistream/fistream.h) As stated, tt(Fistream) objects can be constructed from either a filename or an existing tt(istream) object. The class interface therefore declares two constructors: verbinclude(//CONS examples/fistream/fistream.h) When an tt(Fistream) object is constructed using an existing tt(istream) object, the tt(Fistream)'s tt(istream) part simply uses the tt(stream)'s tt(streambuf) object: verbinclude(//CONS1 examples/fistream/fistream.cc) When an tt(fstream) object is constructed using a filename, the tt(istream) base initializer is given a new tt(filebuf) object to be used as its tt(streambuf). Since the class's data members are not initialized before the class's base class has been constructed, tt(d_filebuf) can only be initialized thereafter. By then, the tt(filebuf) is only available as tt(rdbuf), returning a tt(streambuf). However, as it is actually a tt(filebuf), a tt(static_cast) is used to cast the tt(streambuf) pointer returned by tt(rdbuf) to tt(a filebuf *), so tt(d_filebuf) can be initialized: verbinclude(//CONS2 examples/fistream/fistream.cc) c++-annotations-13.02.01/yo/concrete/addtypes.yo0000664000175000017500000000070614735537670020272 0ustar frankfrankThese are the steps to take when another semantic data type must be added to an existing set: itemization( it() Add a tag name representing the new semantic value type to the tt(enum class Tag) (section ref(TAG)); it() Add a specialization to the tt(TagTrait) trait class (section ref(TAGTRAIT)) defining the added semantic value's data type, and whether or not the data on the parser's semantic stack should be considered (im)mutable. ) c++-annotations-13.02.01/yo/concrete/proxy.yo0000664000175000017500000001300714735537670017634 0ustar frankfrankA problem with ti(operator[]) is that it can't distinguish between its hi(lvalue: distinguish from rvalue)hi(rvalue: distinguish from lvalue) use as an em(lvalue) and as an em(rvalue). It is a familiar misconception to think that verb( Type const &operator[](size_t index) const) is used as em(rvalue) (as the object isn't modified), and that verb( Type &operator[](size_t index)) is used as em(lvalue) (as the returned value can be modified). The compiler, however, distinguishes between the two operators only by the tt(const)-status of the object for which tt(operator[]) is called. With tt(const) objects the former operator is called, with non-tt(const) objects the latter is always used. It is always used, irrespective of it being used as lvalue or rvalue. Being able to distinguish between lvalues and rvalues can be very useful. Consider the situation where a class supporting tt(operator[]) stores data of a type that is very hard to copy. With data like that reference counting (e.g., using tt(shared_ptr)s) is probably used to prevent needless copying. As long as tt(operator[]) is used as rvalue there's no need to copy the data, but the information em(must) be copied if it is used as lvalue. The emi(Proxy Design Pattern) (cf. hi(Gamma, E.)em(Gamma et al.) (1995)) can be used to distinguish between lvalues and rvalues. With the Proxy Design Pattern an object of another class (the Proxy class) is used to act as a em(stand in) for the `real thing'. The proxy class offers functionality that cannot be offered by the data themselves, like distinguishing between its use as lvalue or rvalue. A proxy class can be used in many situations where access to the real data cannot or should not be directly provided. In this regard em(iterator) types are examples of proxy classes as they create a layer between the real data and the software using the data. Proxy classes could also dereference pointers in a class storing its data by pointers. In this section we concentrate on the distinction between using tt(operator[]) as lvalue and rvalue. Let's assume we have a class tt(Lines) storing lines from a file. Its constructor expects the name of a stream from which the lines are read and it offers a non-const tt(operator[]) that can be used as lvalue or rvalue (the tt(const) version of tt(operator[]) is omitted as it causes no confusion because it is always used as rvalue): verbinclude(//LINES examples/lines0.h) To distinguish between lvalues and rvalues we must find distinguishing characteristics of lvalues and rvalues that we can exploit. Such distinguishing characteristics are tt(operator=) (which is always used as lvalue) and the conversion operator (which is always used as rvalue). Rather than having tt(operator[]) return a tt(string &) we can let it return a tt(Proxy) object that is able to distinguish between its use as lvalue and rvalue. The class tt(Proxy) thus needs tt(operator=(string const &other)) (acting as lvalue) and tt(operator std::string const &() const) (acting as rvalue). Do we need more operators? The tt(std::string) class also offers tt(operator+=), so we should probably implement that operator as well. Plain characters can also be assigned to tt(string) objects (even using their numeric values). As tt(string) objects cannot be em(constructed) from plain characters em(promotion) cannot be used with tt(operator=(string const &other)) if the right-hand side argument is a character. Implementing tt(operator=(char value)) could therefore also be considered. These additional operators are left out of the current implementation but `real life' proxy classes should consider implementing these additional operators as well. Another subtlety is hi(Proxy: stream insertion and extraction) that tt(Proxy)'s tt(operator std::string const &() const) is not used when using tt(ostream)'s insertion operator or tt(istream)'s extraction operator as these operators are implemented as templates not recognizing our tt(Proxy) class type. So when stream insertion and extraction is required (it probably is) then tt(Proxy) must be given its own overloaded insertion and extraction operator. Here is an implementation of the overloaded insertion operator inserting the object for which tt(Proxy) is a stand-in: verbinclude(//INSERT examples/lines.h) There's no need for any code (except tt(Lines)) to create or copy tt(Proxy) objects. tt(Proxy)'s constructor should therefore be made private, and tt(Proxy) can declare tt(Lines) to be its friend. In fact, tt(Proxy) is intimately related to tt(Lines) and can be defined as a nested class. In the revised tt(Lines) class tt(operator[]) no longer returns a tt(string) but instead a tt(Proxy) is returned. Here is the revised tt(Lines) class, including its nested tt(Proxy) class: verbinclude(//LINES examples/lines.h) tt(Proxy)'s members are very lightweight and can usually be implemented inline: verbinclude(//MEMBERS examples/lines.h) The member tt(Lines::operator[]) can also be implemented inline: it merely returns a tt(Proxy) object initialized with the tt(string) associated with index tt(idx). Now that the class tt(Proxy) has been developed it can be used in a program. Here is an example using the tt(Proxy) object as lvalue or rvalue. On the surface tt(Lines) objects won't behave differently from tt(Lines) objects using the original implementation, but by adding an identifying tt(cout) statement to tt(Proxy)'s members it can be shown that tt(operator[]) behaves differently when used as lvalue or as rvalue: verbinclude(//MAIN examples/lines.cc) c++-annotations-13.02.01/yo/concrete/access.yo0000664000175000017500000000356314735537670017722 0ustar frankfrankHow to access the data that are actually stored inside a semantic value class that is derived from the semantic values polymorphic base class? Depending on the status (mutable or immutable) and type (basic or class type) of the actual semantic data we recognize three situations: itemization( it() If the data within the semantic value class are mutable, then an accessor should return a reference to the data stored within the semantic value class; it() Immutable non-class type values should be made available by value; it() Immutable class type values should be made available as const references. ) Next, a trait class template tt(Trait) is defined, requiring a tt(Tag) template non-type parameter. This trait class uses the tt(Tag) to determine the data type that is associated with the tt(Tag), making its local type tt(DataType) as synonym of that data type. Next, to determine whether an actual data type is a class type or a basic type template meta programming, as outlined in section ref(CLASSORNOT), is used. Using template meta programming a value tt(isBasicType) of an tt(enum: bool) anonymous enum is set to true if tt(DataType) represents a basic data type. This enum also defines a value tt(isMutable) indicating whether or not the actual data stored in a semantic value class is mutable or not. Next, conditional to the combinations of tt(isMutable) and tt(isBasicType) the tt(Trait) trait class defines the type tt(ReturnType). For this the available tt(std::conditional) trait class is used (cf. section ref(TYPETRAITS)). Now we're able, e.g., to state tt(Trait::DataType) to obtain the tt(int) data type, or to state tt(Trait::ReturnType) to obtain the `tt(std::vector> &)' return type. Here is the implementation of the trait class template tt(Trait): verbinclude(//CLASSTRAIT poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/namespace.yo0000664000175000017500000000147114735537670020411 0ustar frankfrankWhen using the function template tt(Binary operator+(Binary const &lhs, Binary const &rhs)), however, we may encounter a subtle and unexpected complication. Consider the following program. When run, it displays the value 12, rather than 1: verb( enum Values { ZERO, ONE }; template Tp operator+(Tp const &lhs, Tp const &rhs) { return static_cast(12); }; int main() { cout << (ZERO + ONE); // shows 12 }) This complication can be avoided by defining the operators in their own namespace, but then all classes using the binary operator also have to be defined in that namespace, which is not a very attractive restriction. Fortunately, there is a better alternative: using the CRTP (cf. section ref(STATICPOLY)). c++-annotations-13.02.01/yo/concrete/spsembase.yo0000664000175000017500000000051714735537670020437 0ustar frankfrankThe parser uses tt(spSemBase) as its semantic value. The class tt(spSemBase) is a wrapper around tt(std::shared_ptr), offering a constructor member template which must be given a pointer to a dynamically allocated tt(Semantic) object. Its interface is all that is required: verbinclude(-a poly2/spsembase/spsembase.h) c++-annotations-13.02.01/yo/concrete/tag.yo0000664000175000017500000000037214735537670017227 0ustar frankfrankOur program handles three types of semantic values: numbers, text, and vectors of semantic values, which are either numbers or text. These distinct types are indicated by em(tag) enumeration values: verbinclude(//TAG poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/scanner.yo0000664000175000017500000000424014735537670020103 0ustar frankfrank The tt(class Scanner) is generated once by bi(flexc++). This class has access to several members defined by its base class tt(ScannerBase). Some of these members have public access rights and can be used by code external to the class tt(Scanner). These members are extensively documented in the bf(flexc++)(1) man-page, and the reader is referred to this man-page for further information. Our scanner performs the following tasks: itemization( it() it matches regular expressions, ignoring comment, and writing the matched text to the standard output stream; it() it switches to other files, and returns to the previous file once a file has completely been processed, ending the lexical scan once the end of the first input file has been reached. ) The tt(#include) statements in the input allow the scanner to distill the name of the file where the scanning process must continue. This file name is stored in a local variable tt(d_nextSource) and a member tt(stackSource) handles the switch to the next source. Nothing else is required. Pushing and popping input files is handled by the scanner's members tt(pushStream) and tt(popStream), provided by tt(flexc++). tt(Scanner)'s interface, therefore, only needs one additional function declaration: tt(switchSource). Switching streams is handled as follows: once the scanner has extracted a filename from an tt(#include) directive, a switch to another file is realized by tt(switchSource). This member calls tt(pushStream), defined by tt(flexc++), to stack the current input stream and to switch to the stream whose name is stored in tt(d_nextSource). This also ends the tt(include) mini-scanner, so to return the scanner to its default scanning mode tt(begin(StartCondition__::INITIAL)) is called. Here is its source: verbinclude(-a lexer/scanner/switchsource.cc) The member tt(pushStream), defined by tt(flexc++), handles all necessary checks, throwing an exception if the file could not be opened or if too many files are stacked. The member performing the lexical scan is defined by tt(flexc++) in tt(Scanner::lex), and this member can be called by code to process the tokens returned by the scanner. c++-annotations-13.02.01/yo/concrete/polymorphic.yo0000664000175000017500000000755314735537670021031 0ustar frankfrankInstead of using unions to store various semantic values tt(bisonc++) could also use a polymorphic base class to handle semantic values of various types. Using a polymorphic base class is covered in this section. The described method is a direct result of a suggestion initially brought forward by Dallas A. Clement in September 2007. One may wonder why tt(union)s are still used by Bisonc++, as bf(C++) offers inherently superior ways to handle multiple semantic types: a poymorphic base class and a series of derived classes implementing the alternative data types. On the other hand, a polymorphic base class also seems to imply a lot of additional work: classes must be derived from a base class, virtual members must be declared and overridden in derived classes, and the base class must be aware of the relevant interfaces of all derived classes. All this does more to hinder than to promote the construction of reusable software. So, how to proceed? It turns out that the required effort to implement and use polymorphic semantic values is fairly small. In fact, only a very basic polymorphic semantic base class needs to be implemented. Having defined the polymorphic base class template meta programming techniques can be used to let the compiler create all derived classes we might need. The amount of works turns out to be astonishingly small. What about the `free lunch'? Well, the approach works fine in situations where we either can deduce the actual semantic value from the grammar (i.e., the syntax) itself, or where we occasionally are willing to use a switch to select the actual semantic value. This rather weak assumption holds true for the grammar used by the program developed in this section, so let's get on with it! The program developed in this section recognizes input consisting of lines suggesting assignment statements or function calls: verb( value: int | ident ; arglist: arglist ',' value | value ; rule: ident '(' arglist ')' ';' | ident '=' int ';' ;) An essential characteristic of these simple rules is that three different semantic value types are used: int-values, names, and vectors of arguments. Other types could easily be used as well: doubles, complex numbers, sets; you name it. Our semantic value must accommodate all of these different types, and must also allow us to determine the actual type that's stored in a semantic value in cases where we cannot deduce the actual type merely from the syntax (which happens, e.g., for the various semantic value types that may be contained in an tt(arglist)). In the following sections we'll develop the parser using a polymorphic base class to handle its semantic values. To prevent excessive copying of semantic values the parser's actual semantic value is not the semantic value itself but a tt(spSemBase), which is a wrapper around a tt(std::shared_ptr), where tt(SemBase) is our polymorphic base class (cf. section ref(SPSEMBASE)). We'll develop the generic tt(Semantic) class template in steps: itemization( it() In the next section we'll start by defining em(tags) for the various semantic data types; it() Next, support structs are developed allowing us to indicate whether semantic data can be modified by the parser or not; it() Following this, a trait class is developed allowing us to obtain data types from tags; it() Another trait class is needed to determine the data type that is returned by the conversion operators of the different semantic data types; it() Hereafter the polymorphic base class tt(SemBase) is developed; it() Finally, de class template tt(Semantic) is defined, allowing us to define various semantic value classes, all derived from tt(SemBase) ) The complete demo program is available in the annotations()'s source archive under the directory tt(yo/concrete/poly2). c++-annotations-13.02.01/yo/concrete/unrestricted.yo0000664000175000017500000000704714735537670021175 0ustar frankfrankUnions revived in bf(C++) with the advent of unrestricted unions. In this section we'll have a look at how to used them as semantic values in a Bisonc++ generated parser. The just developed polymorphic semantic value had to support itemization( itt(int) values; itt(textual) values of type tt(string); ) When unrestricted unions are used, the union must be able to support tt(int) and tt(string) values. Using the tt(pair) to allow the union to do `introspection' (cf. section ref(UNIONS)), we now define a em(union) tt(Semantic) having the following data members: verb( std::pair d_int; std::pair d_str;) Since an unrestricted union by default deletes all its standard constructors and operators (it must do so, as it cannot tell which data variant is currently active) they must all be implemented explicitly by the tt(Semantic) union. To aid the introspection a type is defined, indicating whether the variant is an tt(int) or a tt(string), and the default constructor simply defines an tt(INT) value 0. Here is tt(Semantic)'s interface: verbinclude(-a unrestricted/semantic/semantic.h) tt(Semantic) objects are as big as required to accommodate all its variants. However, as tt(Semantic) is a union, its constructors and destructor cannot predefine or destroy all of its variants. Rather, it must pick the appropriate field based on the tt(pair)'s tt(first) field. For tt(int) values a simple assignment is OK, but for tt(string) values a constructor and destructor must be used. For this, placement new and an explicit destructor call is required. Here are tt(Semantic)'s tt(Semantic(Type, char const *)), its copy constructor and its destructor: verbinclude(-a unrestricted/semantic/semantic1.cc) verbinclude(-a unrestricted/semantic/semantic2.cc) verbinclude(-a unrestricted/semantic/destructor.cc) Our little parser only needs to be able to insert semantic values. For this an overloaded insertion operator can be used: verbinclude(-a unrestricted/semantic/operatorinsert.cc) The remaining members (tt(operator=, swap)) are standard, and need no further explanation. As tt(Semantic) objects know what type of value they represent, the parser's grammar specification needs no modification. Minor modifications for the scanner's specification, tt(lexer), however are required. Since tt(Semantic) is no longer a wrapper class for a polymorphic base class, using a shared pointer, the previously used tt(shared_ptr)'s tt(reset) calls need to be replaced by direct assignments of tt(Semantic) values to the tt(*d_semval) semantic value. The relevant section of the scanner's specification file tt(lexer) now becomes: verb( [0-9]+ { *d_semval = Semantic(Semantic::INT, yytext); return Parser::INT; } [a-zA-Z_][a-zA-Z0-9_]* { *d_semval = Semantic(Semantic::IDENTIFIER, yytext); return Parser::IDENTIFIER; }) This is all that is required to change a parser using a polymorphic base class to a parser using an unrestricted union. As memory allocation using placement new is fast, an unrestricted union is an efficient way to store multiple data types. Moreover, the semantic value classes implementing the polymorphic semantic value behavior, tt(Base, Int), and tt(Text) are no longer required, nor is the use of the tt(shared_ptr) in a wrapper class (the previously used tt(Semantic) value) required anymore. All in, using an unrestricted union for the parser's semantic values seems like a good deal. c++-annotations-13.02.01/yo/concrete/mutable.yo0000664000175000017500000000115614735537670020106 0ustar frankfrankIn cases where the data stored in the classes derived from the polymorphic base class may either or not be mutable by the parser, there must be a way to indicate so when the derived class is created. Two small support structs define tt(isMutable) enum values indicating whether the data should be considered mutable or not. To make matters concrete, let's assume that we'll need tt(INT) and tt(TEXT) semantic values to be immutable, while tt(VECTOR) semantic values need to be mutable. Here are these structs, defined in the anonymous namespace within tt(sembase.h): verbinclude(//MUTABLE poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/fork2/0000775000175000017500000000000014735537670017124 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/parentprocess/0000775000175000017500000000000014771010710021771 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/parentprocess/parentprocess.h0000664000175000017500000000111114771010714025030 0ustar frankfrank#ifndef INCLUDED_PARENTPROCESS_H_ #define INCLUDED_PARENTPROCESS_H_ #ifndef INCLUDED_IOSFWD_ #include #define INCLUDED_IOSFWD_ #endif namespace FBB { class ParentProcess { public: virtual ~ParentProcess() {} virtual void run // pure virtual function: implement in ( // derived classes int pid, std::istream &readChildCout, std::istream &readChildCerr, std::ostream &writeChildCin ) = 0; }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/build0000775000175000017500000003031214735537670020150 0ustar frankfrank#!/usr/bin/icmake -t. // script generated by the C++ icmake script version 1.62 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += "pipe ofdnstreambuf ifdnstreambuf opipe cinredirector " "childprocess fork"; } /* COMPILER: "g++" for C++ sources. Do not change this, unless you're sure you want something else. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking USE_LIBRARY: define this if you want a library for the object modules. Undefined by default: so NO LIBRARY IS USED. PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed. (default: defined) RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ #define COMPILER "g++" // COPT: the set of C-options #define COPT "--std=c++11 -Wall" #define ECHO_REQUEST ON // #define GDB // Extra libraries required. Remove lib and .a from the library names. // E.g., #define LIBS "m Xt" to link libm.a and libXt.a explicitly // Specify libs from the most specific to the most general one. #define LIBS "" // Extra library-paths required. // E.g., #define LIBPATH "/some/path /some/other/path" to search these paths // apart from the default paths #define LIBPATH "" // uncomment if you WANT to use a library #define USE_LIBRARY // #define PROGRAM #define RELINK // DO NOT ALTER THINGS BELOW THIS LINE string // contain options for libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, lopt, libxxxa; // expanded lib-name int relink; // internally used: != 0 to relink string ofiles, // wildcards for o-files sources, // sources to be used wild, // wildcard of extension current; // contains name of current dir. /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list #ifdef USE_LIBRARY objfile = change_ext(file, "o"); // make obj-filename #else objfile = "./o/" + change_ext(file, "o"); // make obj-filename #endif if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* parser.im */ void parser() { chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); } /* scanner.im */ void scanner() { chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex", #ifdef INTERACTIVE "-I", #endif "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef USE_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { #ifndef RELINK if ( relink // new library, new main.obj || !exists(exe) // final program doesn't exist ) #endif { printf("\n"); exec(COMPILER, "-o", exe, #ifdef USE_LIBRARY "-l" + library, #else ofiles, #endif libs, "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; #ifndef USE_LIBRARY if (!exists("o")) system("mkdir o"); #endif if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) { #ifdef USE_LIBRARY exec(COMPILER, "-c " COPT + " " + copt + " " + nextfile); #else exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o") + " " COPT + " " + copt + " " + nextfile); #endif } relink = 1; printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { list arlist, objlist; string to, from; objlist = makelist("*.o"); if (!sizeof(objlist)) return; printf("\n"); relink = 1; exec("ar", "rvs", library, "*.o"); exec("rm", "*.o"); printf("\n"); } void prefix_class(string class_id) { list o_files; string o_file; int i; o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(wild, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix, .a suffix if main is given here, libmain.a is created) string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int n, index; list classes; string cwd; #ifdef BISON++ CLASSES += "parser "; if (exists("parser")) // subdir parser exists parser(); #endif #ifdef FLEX++ CLASSES += "scanner "; if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes cwd = chdir("."); ofiles = "o/*.o"; // std set of o-files classes = strtok(CLASSES, " "); // list of classes if (n = sizeof(classes)) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use wild = sources; // make library name libxxxa = chdir(".") + "lib" + library + ".a"; // first process all classes for (index = 0; index < n; index++) { current = element(index, classes); // next class to process chdir(current); // change to directory current = "subdir " + current; std_cpp (libxxxa); // compile all files chdir( cwd); // go back to parent dir } current = "auxiliary " + wild + " files"; std_cpp (libxxxa); // compile all files in current dir for (index = 0; index < n; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. #ifdef USE_LIBRARY prefix_class((string)index); // prefix class-number for .o files updatelib(libxxxa); #endif chdir(cwd); // go back to parent dir } current = ""; // no class anymore #ifdef USE_LIBRARY updatelib(libxxxa); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef FLEX++ libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); } void main() { echo(ECHO_REQUEST); sources = "*.cc"; setlibs(); #ifdef GDB copt = "-g"; #endif #ifdef PROGRAM cpp_make ( "fork.cc", // program source "fork", // program library "fork" // binary program ); #else cpp_make ( "", "fork", // program library "" ); #endif } c++-annotations-13.02.01/yo/concrete/fork2/opipe/0000775000175000017500000000000014771010711020216 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/opipe/opipe.ih0000664000175000017500000000007614771010714021662 0ustar frankfrank#include "opipe.h" using namespace FBB; using namespace std; c++-annotations-13.02.01/yo/concrete/fork2/opipe/opipe.cc0000664000175000017500000000021514771010716021644 0ustar frankfrank#include "opipe.ih" OPipe::OPipe(size_t size) : Pipe(), OFdNStreambuf(Pipe::d_fd[READ], size == 0 ? 1 : size), ostream(this) {} c++-annotations-13.02.01/yo/concrete/fork2/opipe/opipe.h0000664000175000017500000000067414771010714021515 0ustar frankfrank#ifndef INCLUDED_OPIPE_H_ #define INCLUDED_OPIPE_H_ #ifndef INCLUDED_PIPE_H_ #include "../pipe/pipe.h" #endif #ifndef INCLUDED_OFDNSTREAMBUF_H_ #include "../ofdnstreambuf/ofdnstreambuf.h" #endif #ifndef INCLUDED_OSTREAM_ #include #define INCLUDED_OSTREAM_ #endif namespace FBB { class OPipe: public Pipe, private OFdNStreambuf, public std::ostream { public: OPipe(size_t size = 500); }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/0000775000175000017500000000000014771010711021733 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/open.cc0000664000175000017500000000031214771010716023204 0ustar frankfrank#include "ifdnstreambuf.ih" void IFdNStreambuf::open(int fd, size_t n) { d_fd = fd; d_n = (n == 0) ? 1 : n; d_buffer = new char[d_n]; setg(d_buffer, d_buffer + d_n, d_buffer + d_n); } c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/xsgetn.cc0000664000175000017500000000072014771010716023556 0ustar frankfrank#include "ifdnstreambuf.ih" std::streamsize IFdNStreambuf::xsgetn(char *dest, std::streamsize n) { int nread = 0; while (n) { if (!in_avail()) { if (underflow() == EOF) break; } int avail = in_avail(); if (avail > n) avail = n; memcpy(dest + nread, gptr(), avail); gbump(avail); nread += avail; n -= avail; } return nread; } c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/ifdnstreambuf.ih0000664000175000017500000000013114771010714025104 0ustar frankfrank#include "ifdnstreambuf.h" #include #include using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/ifdnstreambuf.h0000664000175000017500000000163014771010714024740 0ustar frankfrank#ifndef INCLUDED_IFDNSTREAMBUF_H_ #define INCLUDED_IFDNSTREAMBUF_H_ #ifndef INCLUDED_STREAMBUF_ #include #define INCLUDED_STREAMBUF_ #endif namespace FBB { class IFdNStreambuf: public std::streambuf { private: int d_fd; size_t d_n; char* d_buffer; public: IFdNStreambuf() : d_n(0), d_buffer(0) {} IFdNStreambuf(int fd, size_t n = 1) { open(fd, n); } ~IFdNStreambuf(); void open(int xfd, size_t n = 1); int underflow(); std::streamsize xsgetn(char *dest, std::streamsize n); private: IFdNStreambuf(IFdNStreambuf const &other); // NI IFdNStreambuf &operator=(IFdNStreambuf const &other); // NI }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/destructor.cc0000664000175000017500000000021514771010716024443 0ustar frankfrank#include "ifdnstreambuf.ih" IFdNStreambuf::~IFdNStreambuf() { if (d_buffer) { close(d_fd); delete d_buffer; } } c++-annotations-13.02.01/yo/concrete/fork2/ifdnstreambuf/underflow.cc0000664000175000017500000000045014771010716024253 0ustar frankfrank#include "ifdnstreambuf.ih" int IFdNStreambuf::underflow() { if (gptr() < egptr()) return *gptr(); int nread = read(d_fd, d_buffer, d_n); if (nread <= 0) return EOF; setg(d_buffer, d_buffer, d_buffer + nread); return static_cast(*gptr()); } c++-annotations-13.02.01/yo/concrete/fork2/fork/0000775000175000017500000000000014771010711020043 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/fork/fork.h0000664000175000017500000000136214771010714021162 0ustar frankfrank#ifndef INCLUDED_FORK_H_ #define INCLUDED_FORK_H_ namespace FBB { class Redirector; class ChildProcess; class ParentProcess; class Fork { protected: Redirector &d_redirector; ChildProcess &d_child; ParentProcess &d_parent; public: Fork(Redirector &redirector, ChildProcess &child, ParentProcess &parent) : d_redirector(redirector), d_child(child), d_parent(parent) {} void fork() const; private: Fork(Fork const &other); // NI Fork &operator=(Fork const &other); // NI }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/fork/fork.ih0000664000175000017500000000070314771010714021331 0ustar frankfrank#include "fork.h" #ifndef INCLUDED_CHILDPROCESS_H_ #include "../childprocess/childprocess.h" #endif #ifndef INCLUDED_REDIRECTOR_H_ #include "../redirector/redirector.h" #endif #ifndef INCLUDED_PARENTPROCESS_H_ #include "../parentprocess/parentprocess.h" #endif #ifndef INCLUDED_TYPES_H_ #include #define INCLUDED_TYPES_H_ #endif #ifndef INCLUDED_UNISTD_H_ #include #define INCLUDED_UNISTD_H_ #endif using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/fork/forkfork.cc0000664000175000017500000000064414771010716022206 0ustar frankfrank#include "fork.ih" void Fork::fork() const { int pid = ::fork(); if (pid == 0) // childprocess has pid == 0 { d_redirector.childRedirections(); d_child.run(); } d_redirector.parentRedirections(); d_parent.run(pid, d_redirector.readChildCout(), d_redirector.readChildCerr(), d_redirector.writeChildCin()); } c++-annotations-13.02.01/yo/concrete/fork2/childprocess/0000775000175000017500000000000014771010711021564 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/childprocess/childprocess.ih0000664000175000017500000000017714771010714024600 0ustar frankfrank#include "childprocess.h" #ifndef INCLUDED_CSTDLIB_ #include #define INCLUDED_CSTDLIB_ #endif using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/childprocess/run.cc0000664000175000017500000000022014771010716022676 0ustar frankfrank#include "childprocess.ih" void ChildProcess::run() { executeChildProcess(); exit(-1); // doProcess itself should stop } c++-annotations-13.02.01/yo/concrete/fork2/childprocess/childprocess.h0000664000175000017500000000055614771010714024430 0ustar frankfrank#ifndef INCLUDED_CHILDPROCESS_H_ #define INCLUDED_CHILDPROCESS_H_ namespace FBB { class ChildProcess { public: virtual ~ChildProcess() {} void run(); protected: // implemented in derived classes virtual void executeChildProcess() = 0; }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/pipe/0000775000175000017500000000000014771010711020037 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/pipe/readvia.cc0000664000175000017500000000016514771010716021770 0ustar frankfrank#include "pipe.ih" void Pipe::readVia(int fd) { close(d_fd[WRITE]); dup(READ, fd); close(d_fd[READ]); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/writevia2.cc0000664000175000017500000000027414771010716022272 0ustar frankfrank#include "pipe.ih" void Pipe::writeVia(int const *fd, size_t n) { close(d_fd[READ]); for (size_t idx = 0; idx < n; idx++) dup(WRITE, fd[idx]); close(d_fd[WRITE]); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/pipe.cc0000664000175000017500000000012314771010716021304 0ustar frankfrank#include "pipe.ih" Pipe::Pipe() { if (pipe(d_fd)) throw bad_pipe(); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/pipe.ih0000664000175000017500000000017214771010714021321 0ustar frankfrank#include "pipe.h" #ifndef INCLUDED_UNISTD_H_ #include #define INCLUDED_UNISTD_H_ #endif using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/pipe/dup.cc0000664000175000017500000000017214771010716021143 0ustar frankfrank#include "pipe.ih" void Pipe::dup(RW rw, int fd) { if (dup2(d_fd[rw], fd) < 0) throw redirection_failed(); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/writevia.cc0000664000175000017500000000016714771010716022211 0ustar frankfrank#include "pipe.ih" void Pipe::writeVia(int fd) { close(d_fd[READ]); dup(WRITE, fd); close(d_fd[WRITE]); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/readvia2.cc0000664000175000017500000000027214771010716022051 0ustar frankfrank#include "pipe.ih" void Pipe::readVia(int const *fd, size_t n) { close(d_fd[WRITE]); for (size_t idx = 0; idx < n; idx++) dup(READ, fd[idx]); close(d_fd[READ]); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/pipe.h0000664000175000017500000000313514771010714021152 0ustar frankfrank#ifndef INCLUDED_PIPE_H_ #define INCLUDED_PIPE_H_ #include namespace FBB { class Pipe { protected: int d_fd[2]; public: enum bad_pipe {}; enum redirection_failed {}; Pipe(); Pipe(int socket) { d_fd[READ] = socket; d_fd[WRITE] = socket; } Pipe(int const *fd) { d_fd[READ] = fd[READ]; d_fd[WRITE] = fd[WRITE]; } // readVia(): set up redirection from d_fd[READ] to the given // filedescriptor(s): reading from d_fd[READ] // is done via the filedescriptor(s) void readVia(int filedescriptor); // not tested: void readVia(int const *filedescriptor, size_t n); // writeVia(): set up redirection from d_fd[WRITE] to the given // filedescriptor(s): writing to d_fd[WRITE] // is done via the filedescriptor(s) void writeVia(int filedescriptor); void writeVia(int const *filedescriptor, size_t n = 2); int readFd() { return d_fd[READ]; } int writeFd() { return d_fd[WRITE]; } protected: enum RW { READ, WRITE }; private: void dup(RW rw, int fd); Pipe(Pipe const &other); // NI Pipe &operator=(Pipe const &other); // NI }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/pipe/driver/0000775000175000017500000000000014771010711021332 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/pipe/driver/build0000775000175000017500000003020414735537670022400 0ustar frankfrank#!/usr/bin/icmake -t. // script generated by the C++ icmake script version 1.62 /* Configurable defines for the build script: CLASSES: string of directory-names under which sources of classes are found. E.g., CLASSES = "class1 class2" All class-names must be stored in one string. If classes are removed from the CLASSES definition or if the names in the CLASSES definition are reordered, the compilation should start again from scratch. */ string CLASSES; void setClasses() { // ADD ADDITIONAL DIRECTORIES CONTAINING SOURCES OF CLASSES HERE // Use the construction `CLASSES += "classname1 classname2";' etc. CLASSES += " "; } /* COMPILER: "g++" for C++ sources. Do not change this, unless you're sure you want something else. COPT: C-options used by COMPILER ECHO_REQUEST: ON (default) if command echoing is wanted, otherwise: set to OFF GDB: define if gdb-symbolic debug information is wanted (not defined by default) LIBS: Extra libraries used for linking LIBPATH: Extra library-searchpaths used for linking USE_LIBRARY: define this if you want a library for the object modules. Undefined by default: so NO LIBRARY IS USED. PROGRAM: define if a program is to be built. If not defined, library maintenance is assumed. (default: defined) RELINK: Defined by default, causing a program to be relinked every time the script is called. Do not define it if relinking should only occur if a source is compiled. No effect for library maintenance. Current values: */ #define COMPILER "g++" // COPT: the set of C-options #define COPT "--std=c++11 -Wall" #define ECHO_REQUEST ON // #define GDB // Extra libraries required. Remove lib and .a from the library names. // E.g., #define LIBS "m Xt" to link libm.a and libXt.a explicitly // Specify libs from the most specific to the most general one. #define LIBS "fork" // Extra library-paths required. // E.g., #define LIBPATH "/some/path /some/other/path" to search these paths // apart from the default paths #define LIBPATH "../.." // uncomment if you WANT to use a library // #define USE_LIBRARY #define PROGRAM #define RELINK // DO NOT ALTER THINGS BELOW THIS LINE string // contain options for libs, // extra libs, e.g., "-lrss -licce" libpath, // extra lib-paths, eg, "-L../rss" copt, lopt, libxxxa; // expanded lib-name int relink; // internally used: != 0 to relink string ofiles, // wildcards for o-files sources, // sources to be used wild, // wildcard of extension current; // contains name of current dir. /* O B J F I L E S . I M */ list objfiles(list files) { string file, objfile; int i; for (i = 0; i < sizeof(files); i++) { file = element(i, files); // determine element of the list #ifdef USE_LIBRARY objfile = change_ext(file, "o"); // make obj-filename #else objfile = "./o/" + change_ext(file, "o"); // make obj-filename #endif if (objfile younger file) // objfile is younger { files -= (list)file; // remove the file from the list i--; // reduce i to test the next } } return (files); } /* parser.im */ void parser() { chdir("parser/gramspec"); system("grambuild"); chdir(".."); if ( exists("grammar") && "grammar" younger "parser.cc" ) // new parser needed { exec("bison++", "-d", "-o", "parser.cc", "grammar"); printf("Note: the compilation of parser.cc may produce " "several compiler warnings.\n"); } chdir(".."); } /* scanner.im */ void scanner() { chdir("scanner"); if ( // new lexer needed exists("lexer") && ( "lexer" younger "yylex.cc" || "../parser/parser.h" younger "yylex.cc" ) ) { exec("flex", #ifdef INTERACTIVE "-I", #endif "-oyylex.cc", "lexer"); printf("Note: the compilation of yylex.cc may produce " "several compiler warnings.\n"); } chdir(".."); } /* A L T E R E D . I M */ list altered(list files, string target) { int i; string file; for (i = 0; i < sizeof(files); i++) // try all elements of the list { file = element(i, files); // use element i of the list if (file older target) // a file is older than the target { files -= (list)file; // remove the file from the list i--; // reduce i to inspect the next } // file of the list } return (files); // return the new list } /* F I L E L I S T . I M */ list file_list(string type, string library) { list files; files = makelist(type); // make all files of certain type #ifdef USE_LIBRARY files = altered(files, library); // keep all files newer than lib. #endif files = objfiles(files); // remove if younger .obj exist return (files); } /* L I N K . I M */ void link(string library, string exe) { #ifndef RELINK if ( relink // new library, new main.obj || !exists(exe) // final program doesn't exist ) #endif { printf("\n"); exec(COMPILER, "-o", exe, #ifdef USE_LIBRARY "-l" + library, #else ofiles, #endif libs, "-L.", libpath, lopt #ifndef GDB , "-s" #endif ); printf("ok: ", exe, "\n"); } } /* C C O M P I L E . I M */ void c_compile(list cfiles) { string nextfile; int i; #ifndef USE_LIBRARY if (!exists("o")) system("mkdir o"); #endif if (sizeof(cfiles)) // files to compile ? { printf("\ncompiling: ", current, "\n\n"); // compile all files separately for (i = 0; nextfile = element(i, cfiles); i++) { #ifdef USE_LIBRARY exec(COMPILER, "-c " COPT + " " + copt + " " + nextfile); #else exec(COMPILER, "-c -o o/" + change_ext(nextfile, "o") + " " COPT + " " + copt + " " + nextfile); #endif } relink = 1; printf("\n"); } printf("ok: ", current, "\n"); } /* U P D A T E L I . I M */ void updatelib(string library) { list arlist, objlist; string to, from; objlist = makelist("*.o"); if (!sizeof(objlist)) return; printf("\n"); relink = 1; exec("ar", "rvs", library, "*.o"); exec("rm", "*.o"); printf("\n"); } void prefix_class(string class_id) { list o_files; string o_file; int i; o_files = makelist("*.o"); for (i = 0; o_file = element(i, o_files); i++) exec("mv", o_file, class_id + o_file); } /* S T D C P P . I M */ void std_cpp(string library) { list cfiles; cfiles = file_list(wild, library); // make list of all cpp-files c_compile(cfiles); // compile cpp-files } /* C P P M A K E . C CPP files are processed by stdmake. Arguments of CPPMAKE: cpp_make( string mainfile, : name of the main .cpp file, or "" for library maintenance string library, : name of the local library to use/create (without lib prefix, .a suffix if main is given here, libmain.a is created) string exe, : (path) name of the exe file to create ) Both mainfile and library MUST be in the current directory */ void cpp_make(string mainfile, string library, string exe) { int n, index; list classes; string cwd; #ifdef BISON++ CLASSES += "parser "; if (exists("parser")) // subdir parser exists parser(); #endif #ifdef FLEX++ CLASSES += "scanner "; if (exists("scanner")) // subdir scannerexists scanner(); #endif setClasses(); // remaining classes cwd = chdir("."); ofiles = "o/*.o"; // std set of o-files classes = strtok(CLASSES, " "); // list of classes if (n = sizeof(classes)) ofiles += " */o/*.o"; // set ofiles for no LIBRARY use wild = sources; // make library name libxxxa = chdir(".") + "lib" + library + ".a"; // first process all classes for (index = 0; index < n; index++) { current = element(index, classes); // next class to process chdir(current); // change to directory current = "subdir " + current; std_cpp (libxxxa); // compile all files chdir( cwd); // go back to parent dir } current = "auxiliary " + wild + " files"; std_cpp (libxxxa); // compile all files in current dir for (index = 0; index < n; index++) { current = element(index, classes); // determine class name chdir( current); // chdir to a class directory. #ifdef USE_LIBRARY prefix_class((string)index); // prefix class-number for .o files updatelib(libxxxa); #endif chdir(cwd); // go back to parent dir } current = ""; // no class anymore #ifdef USE_LIBRARY updatelib(libxxxa); // update lib in current dir #endif if (mainfile != "") // mainfile -> do link { link(library, exe); printf ( "\nProgram construction completed.\n" "\n" ); } } /* S E T L I B S . I M */ void setlibs() { int n, index; list cut; cut = strtok(LIBS, " "); // cut op libraries n = sizeof(cut); for (index = 0; index < n; index++) libs += " -l" + element(index, cut); #ifdef FLEX++ libs += " -lfl"; #endif cut = strtok(LIBPATH, " "); // cut up the paths n = sizeof(cut); for (index = 0; index < n; index++) libpath += " -L" + element(index, cut); } void main() { echo(ECHO_REQUEST); sources = "*.cc"; setlibs(); #ifdef GDB copt = "-g"; #endif #ifdef PROGRAM cpp_make ( "driver.cc", // program source "driver", // program library "driver" // binary program ); #else cpp_make ( "", "driver", // program library "" ); #endif } c++-annotations-13.02.01/yo/concrete/fork2/pipe/driver/driver.cc0000664000175000017500000000174714771010716023152 0ustar frankfrank/* driver.cc */ #include "../pipe.h" #include #include #include #include #include using namespace std; using namespace FBB; int main(int argc, char **argv) { Pipe p; // construct a pipe cout << "Read file descriptor: " << p.readFd() << '\n'; cout << "Write file descriptor: " << p.writeFd() << '\n'; int pid = fork(); if (pid == -1) return 1; if (!pid) //child { p.readVia(STDIN_FILENO); // read what goes into the pipe from cin string s; getline(cin, s); cout << "Got: " << s << '\n'; getline(cin, s); cout << "Got: " << s << '\n'; return 0; } int stdfd[] = {STDOUT_FILENO, STDERR_FILENO}; p.writeVia(stdfd); // write to the pipe via cout cout << "first line" << '\n'; cerr << "second line" << '\n'; waitpid(pid, 0, 0); } c++-annotations-13.02.01/yo/concrete/fork2/pipe/driver/driver.h0000664000175000017500000000053114771010714023000 0ustar frankfrank// driver.h #ifndef H_driver_ #define H_driver_ /* $Id: driver.h 2 2003-05-27 19:11:03Z frank $ $Log$ Revision 1.1 2003/05/27 19:11:04 frank Initial revision */ //#include //#include //#include //#include //#include //using namespace std; #endif c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/0000775000175000017500000000000014771010711021741 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/ofdnstreambuf.ih0000664000175000017500000000013114771010714025120 0ustar frankfrank#include "ofdnstreambuf.h" #include #include using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/overflow.cc0000664000175000017500000000024314771010716024117 0ustar frankfrank#include "ofdnstreambuf.ih" int OFdNStreambuf::overflow(int c) { sync(); if (c != EOF) { *pptr() = c; pbump(1); } return c; } c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/open.cc0000664000175000017500000000027214771010716023217 0ustar frankfrank#include "ofdnstreambuf.ih" void OFdNStreambuf::open(int fd, size_t n) { d_fd = fd; d_n = (n == 0) ? 1 : n; d_buffer = new char[d_n]; setp(d_buffer, d_buffer + d_n); } c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/sync.cc0000664000175000017500000000031014771010716023223 0ustar frankfrank#include "ofdnstreambuf.ih" int OFdNStreambuf::sync() { if (pptr() > pbase()) { write(d_fd, d_buffer, pptr() - pbase()); setp(d_buffer, d_buffer + d_n); } return 0; } c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/destructor.cc0000664000175000017500000000021014771010716024444 0ustar frankfrank#include "ofdnstreambuf.ih" OFdNStreambuf::~OFdNStreambuf() { if (d_buffer) { sync(); delete d_buffer; } } c++-annotations-13.02.01/yo/concrete/fork2/ofdnstreambuf/ofdnstreambuf.h0000664000175000017500000000156014771010714024756 0ustar frankfrank#ifndef INCLUDED_OFDNSTREAMBUF_H_ #define INCLUDED_OFDNSTREAMBUF_H_ #ifndef INCLUDED_STREAMBUF_ #include #define INCLUDED_STREAMBUF_ #endif namespace FBB { class OFdNStreambuf: public std::streambuf { private: size_t d_n; int d_fd; char *d_buffer; public: OFdNStreambuf() : d_n(0), d_buffer(0) {} OFdNStreambuf(int fd, size_t n = 1) { open(fd, n); } ~OFdNStreambuf(); void open(int fd, size_t n = 1); int sync(); int overflow(int c); private: OFdNStreambuf(OFdNStreambuf const &other); // NI OFdNStreambuf &operator=(OFdNStreambuf const &other); // NI }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/cinredirector/0000775000175000017500000000000014771010711021736 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/cinredirector/cinredirector.h0000664000175000017500000000106014771010714024743 0ustar frankfrank#ifndef INCLUDED_CINREDIRECTOR_H_ #define INCLUDED_CINREDIRECTOR_H_ #ifndef INCLUDED_REDIRECTOR_H_ #include "../redirector/redirector.h" #endif #ifndef INCLUDED_OPIPE_H_ #include "../opipe/opipe.h" #endif namespace FBB { class CinRedirector: public Redirector { private: OPipe d_cinPipe; public: virtual void childRedirections(); virtual void parentRedirections(); virtual std::ostream &writeChildCin() { return d_cinPipe; } }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/cinredirector/childredirections.cc0000664000175000017500000000023114771010716025744 0ustar frankfrank#include "cinredirector.ih" void CinRedirector::childRedirections() { // redirect STDIN_FILENO to the pipe: d_cinPipe.readVia(STDIN_FILENO); } c++-annotations-13.02.01/yo/concrete/fork2/cinredirector/parentredirections.cc0000664000175000017500000000015114771010716026153 0ustar frankfrank#include "cinredirector.ih" void CinRedirector::parentRedirections() { close(d_cinPipe.readFd()); } c++-annotations-13.02.01/yo/concrete/fork2/cinredirector/cinredirector.ih0000664000175000017500000000020314771010714025112 0ustar frankfrank#include "cinredirector.h" #ifndef INCLUDED_UNISTD_H_ #include #define INCLUDED_UNISTD_H_ #endif using namespace FBB; c++-annotations-13.02.01/yo/concrete/fork2/redirector/0000775000175000017500000000000014771010710021243 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/redirector/redirector.h0000664000175000017500000000174214771010714023566 0ustar frankfrank#ifndef INCLUDED_REDIRECTOR_H_ #define INCLUDED_REDIRECTOR_H_ #ifndef INCLUDED_IOSFWD_ #include #define INCLUDED_IOSFWD_ #endif #ifndef INCLUDED_IOSTREAM_ #include #define INCLUDED_IOSTREAM_ #endif namespace FBB { class Redirector { public: enum { READ, WRITE }; virtual ~Redirector() {} // sets up redirections in the child virtual void childRedirections() {} // sets up redirections in the parent virtual void parentRedirections() {} virtual std::ostream &writeChildCin() { return std::cout; } virtual std::istream &readChildCout() { return std::cin; } virtual std::istream &readChildCerr() { return std::cin; } }; } #endif c++-annotations-13.02.01/yo/concrete/fork2/ipipe/0000775000175000017500000000000014771010710020207 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/fork2/ipipe/ipipe.h0000664000175000017500000000150514771010714021473 0ustar frankfrank#ifndef INCLUDED_IPIPE_H_ #define INCLUDED_IPIPE_H_ #ifndef INCLUDED_PIPE_H_ #include "../pipe/pipe.h" #endif #ifndef INCLUDED_ISTREAM_ #include #define INCLUDED_ISTREAM_ #endif namespace FBB { class IPipe: virtual public Pipe { private: IfdNstreambuf d_ibuf; std::istream d_istr; public: IPipe(size_t size = 500) : Pipe(socket), d_ibuf(d_fd[READ], size == 0 ? 1 : size), d_istr(&d_ibuf) {} IPipe(int socket, size_t size) : Pipe(socket), d_ibuf(d_fd[READ], size == 0 ? 1 : size), d_istr(&d_ibuf) {} istream &istream() { return d_istr; } }; } #endif c++-annotations-13.02.01/yo/concrete/ranger.yo0000664000175000017500000001143114735537670017730 0ustar frankfrankThe standard i(range-based for-loop) requires for its range-specificiation an array, an initializer list, or an iterator range as offered by, e.g., containers (through their tt(begin) and tt(end) members). Ranges defined by a pointer pair or by a subrange defined by iterator expressions cannot currently be used in combination with range-based for-loops. The ti(Ranger) class template developed in this section defines ranges that can be used with range-based for-loops. tt(Ranger) extends the applicability of range-based for-loops by turning pointer pairs,, an initial pointer or iterator and a pointer count, or a pair of iterators into a range that can be used by range-based for-loops. The tt(Ranger) class template can also be used to process a pair of reverse iterators, normally not supported by range-based for-loops. The tt(Ranger) class template requires but one template type parameter: tt(Iterator), representing an iterator or pointer type reaching the data when dereferenced. In practical applications users don't have to specify tt(Ranger)'s template type. The function template tt(ranger) deduces the required tt(Iterator) type and returns the appropriate tt(Ranger) object. The tt(ranger) function template can be used in various ways: itemization( itt(Ranger ranger(Iterator const &begin, Iterator const &end)) this function template returns a tt(Ranger) object for the (sub)range defined by two (reverse) iterators. Its definition is: verb(template Ranger ranger(Iter &&begin, Iter &&end) { return Ranger{ begin, end }; }) itt(Ranger ranger(Iterator const &begin, size_t count)) this function template returns a tt(Ranger) object for the (sub)range defined by the (reverse) iterator range tt(begin) and tt(begin + count). Its definition is: verb(template Ranger ranger(Data *begin, Data *end) { return Ranger{ begin, end }; }) itt(Ranger ranger(Data *begin, Data *end)) this function template returns a tt(Ranger) object for the (sub)range defined by the two pointers tt(begin) and tt(end). Its definition is: verb(template Ranger ranger(Iter &&begin, size_t count) { return Ranger{ begin, begin + count }; }) itt(Ranger ranger(Data *begin, size_t count)) this function template returns a tt(Ranger) object for the (sub)range defined by the two pointers tt(begin) and tt(begin + count). Its definition is: verb(template Ranger ranger(Data *begin, size_t count) { return Ranger{ begin, begin + count}; }) ) The tt(Ranger) class template itself offers a constructor expecting two tt(Iterator const &) parameters, where tt(Iterator) is tt(Ranger)'s template type parameter. Although named 'Iterator' it can also be a pointer to some data type (e.g., tt(std::string *)). The class only needs two members, tt(begin) and tt(end), since these are the only members called by range-based for-loops. These members can be tt(const) members, returning tt(Iterator const) references. This also is the required return type if tt(Iterator) itself was a pointer type (like tt(int *)). Since a `tt(Iterator const &)' does not imply that the dereferenced tt(Iterator) is immutable, the data to which the iterator returned by tt(begin()) can actually be modified, if tt(Iterator) unless tt(Iterator) is a tt(Type const *) or a tt(const_iterator) type. If reverse iterators are passed to tt(Ranger)'s constructor (the reversed begin iterator should be passed as tt(Ranger) constructor's first argument, the reversed end iterator as its second argument), then tt(Ranger)'s tt(begin) and tt(end) members return em(reverse iterators). Since the intended use of tt(Ranger) objects is to define a range for range-base for-loops, members like tt(rbegin) and tt(rend) were omitted from tt(Ranger)'s interface. Here is tt(Ranger)'s implementation (using in-class implementations for brevity): verb( template class Ranger { Iter d_begin; Iter d_end; public: Ranger(Iter const &begin, Iter const &end) : d_begin(begin), d_end(end) {} Iter const &begin() const { return d_begin; } Iter const &end() const { return d_end; } };) Using tt(ranger) is easy. Here is an example of a program displaying a program's command-line arguments using a range-based for-loop: verb( // insert all required declarations here int main(int argc, char **argv) { for (auto ptr: ranger(argv, argc)) cout << ptr << '\n'; }) c++-annotations-13.02.01/yo/concrete/pipes.yo0000664000175000017500000001076614735537670017604 0ustar frankfrank Redirection at the system level requires the use of em(file descriptor)hi(file descriptor), created by the ti(pipe) system call. When two processes want to communicate using such file descriptors, the following happens: itemization( it() The process constructs two em(associated file descriptors) using the tt(pipe) system call. One of the file descriptors is used for writing, the other file descriptor is used for reading. it() Forking takes place (i.e., the system tt(fork) function is called), duplicating the file descriptors. Now we have four file descriptors as the child process and the parent process both have their own copies of the two file descriptors created by tt(pipe). it() One process (say, the parent process) uses the file descriptors for em(reading). It should close its file descriptor intended for em(writing). it() The other process (say, the child process) uses the file descriptors for em(writing). It should therefore close its file descriptor intended for em(reading). it() All information written by the child process to the file descriptor intended for writing, can now be read by the parent process from the corresponding file descriptor intended for reading, thus establishing a communication channel between the child and the parent process. ) Though basically simple, errors may easily creep in. Functions of file descriptors available to the two processes (child or parent) may easily get mixed up. To prevent bookkeeping errors, the bookkeeping may be properly set up once, to be hidden thereafter inside a class like the tt(Pipe) class developed here. Let's have a look at its characteristics (before using functions like tt(pipe) and tt(dup) the compiler must have read the tthi(unistd.h) header file): itemization( it() The tt(pipe) system call expects a pointer to two tt(int) values, representing, respectively, the file descriptor used for reading and the file descriptor used for writing. To avoid confusion, the class tt(Pipe) defines an tt(enum) having values associating the indices of the array of 2-tt(int)s with symbolic constants. The two file descriptors themselves are stored in a data member tt(d_fd). Here is the initial section of the class's interface: verbinclude(//HEAD examples/pipe.h) it() The class only needs a default constructor. This constructor calls tt(pipe) to create a set of associated file descriptors used for accessing both ends of a pipe: verbinclude(//CONS examples/pipe.cc) it() The members tt(readOnly) and tt(readFrom) are used to configure the pipe's reading end. The latter function is used when using redirection. It is provided with an alternate file descriptor to be used for reading from the pipe. Usually this alternate file descriptor is ti(STDIN_FILENO), allowing tt(cin) to extract information from the pipe. The former function is merely used to configure the reading end of the pipe. It closes the matching writing end and returns a file descriptor that can be used to read from the pipe: verbinclude(//READ examples/pipe.cc) it() tt(writeOnly) and two tt(writtenBy) members are available to configure the writing end of a pipe. The former function is only used to configure the writing end of the pipe. It closes the reading end, and returns a file descriptor that can be used for writing to the pipe: verbinclude(//WRITE examples/pipe.cc) For the latter member two overloaded versions are available: itemization( itt(writtenBy(int fd)) is used to configure em(single) redirection, so that a specific file descriptor (usually ti(STDOUT_FILENO) or ti(STDERR_FILENO)) can be used to write to the pipe; itt((writtenBy(int const *fd, size_t n))) may be used to configure em(multiple) redirection, providing an array argument containing file descriptors. Information written to any of these file descriptors is actually written to the pipe. ) it() The class has one private data member, tt(redirect), used to set up redirection through the ti(dup2) system call. This function expects two file descriptors. The first file descriptor represents a file descriptor that can be used to access the device's information; the second file descriptor is an alternate file descriptor that may also be used to access the device's information. Here is tt(redirect)'s implementation: verbinclude(//REDIRECT examples/pipe.cc) ) Now that redirection can be configured easily using one or more tt(Pipe) objects, we'll use tt(Fork) and tt(Pipe) in various example programs. c++-annotations-13.02.01/yo/concrete/usingbison.yo0000664000175000017500000000506514735537670020640 0ustar frankfrankOnce an i(input language) exceeds a certain level of complexity, a emi(parser) is often used to control the complexity of the language. In this case, a emi(parser generator) can be used to generate the code verifying the input's grammatical correctness. The lexical scanner (preferably composed into the parser) provides chunks of the input, called hi(token)em(tokens). The parser then processes the series of tokens generated by the lexical scanner. Starting point when developing programs that use both parsers and scanners is the i(grammar). The grammar defines a em(set of tokens) that can be returned by the lexical scanner (called the emi(scanner) below). Finally, auxiliary code is provided to `fill in the blanks': the i(actions) performed by the parser and by the scanner are not normally specified literally in the grammar rules or lexical regular expressions, but should be implemented in em(member functions), called from the parser's rules or which are associated with the scanner's regular expressions. In the previous section we've seen an example of a bf(C++) class generated by ti(flexc++). In the current section we concentrate on the parser. The parser can be generated from a grammar specification file, processed by the program ti(bisonc++). The grammar specification file required by tt(bisonc++) is similar to the file processed by ti(bison) (or ti(bison++), tt(bisonc++)'s predecessor, written in the early nineties by hi(Coetmeur, A.) em(Alain Coetmeur)). In this section a program is developed converting em(infix expressions), where binary operators are written between their operands, to em(postfix expressions), where operators are written behind their operands. Also, the unary operator tt(-) is converted from its prefix notation to a postfix form. The unary tt(+) operator is ignored as it requires no further actions. In essence our little calculator is a micro compiler, transforming numeric expressions into assembly-like instructions. Our calculator recognizes a rather basic set of operators: multiplication, addition, parentheses, and the unary minus. We'll distinguish real numbers from integers, to illustrate a subtlety in bison-like grammar specifications. That's all. The purpose of this section is, after all, to illustrate the construction of a bf(C++) program that uses both a parser and a lexical scanner, rather than to construct a full-fledged calculator. In the coming sections we'll develop the grammar specification for tt(bisonc++). Then, the regular expressions for the scanner are specified. Following that, the final program is constructed. c++-annotations-13.02.01/yo/concrete/crtp.yo0000664000175000017500000000661614735537670017433 0ustar frankfrankWhen deriving classes from a class template tt(Binops), using the CRTP the operators are defined for arguments of the class tt(Binops): a base class receiving the derived class as its template argument. Thus the class tt(Binops) as well as the additional operators are defined, expecting tt(Binops) type of arguments: verb( template struct Binops { Derived &operator+=(Derived const &rhs) &; }; template Derived operator+(Binops const &lhs, Derived const &rhs) { return Derived{static_cast(lhs) } += rhs; } // analogous implementation for Binops &&lhs) This way, a class that derives from tt(Binops), and that provides an tt(operator+=) member which is bound to an rvalue reference object, suddenly also provides all other binary addition operators: verb( class Derived: public Binops { ... public: ... Derived &&operator+=(Derived const &rhs) && };) All, but one.... The operator that's not available is the compound addition operator, bound to an lvalue reference. As its function name is identical to the one in the class tt(Derived), it is not automatically visible at the user level. Although this problem can simply be solved by providing the class tt(Derived) with a tt(using Binops::operator+=) declaration, it is not a very attractive solution, as separate using declarations have to be provided for each binary operator that is implemented in the class tt(Derived). But a em(much) more attractive solution exists. A beautiful out-of-the-box solution, completely avoiding the hidden base class operator, was proposed by i(Wiebe-Marten Wijnja). Wiebe-Marten conjectured that tt(operator+=), bound to an lvalue reference could also very well be defined as a em(free) function. In that case no inheritance is used and therefore no function hiding occurs. Consequently, the tt(using) directive can be avoided. The implementation of this free tt(operator+=) function looks like this: verb( template Derived &operator+=(Binops &lhs, Derived const &rhs) { Derived tmp{ Derived{ static_cast(lhs) } += rhs }; tmp.swap(static_cast(lhs)); return static_cast(lhs); }) The flexibility of this design can be further augmented once we realize that the right-hand side operand doesn't have to be a tt(Derived) class object. Consider tt(operator<<): oftentimes shifts are bit-shifts, using a tt(size_t) to specify the number of bits to shift. In fact, the type of the right-hand side operand can completely be generalized by defining a second template type parameter, which is used to specify the right-hand side's operand type. It's up to the tt(Derived) class to specify the argument type of its tt(operator+=) (or any other binary compound operator), whereafter the compiler will deduce the types of the right-hand side operands for the remaining binary operators. Here is the final implementation of the free tt(operator+=) function: verb( template Derived &operator+=(Binops &lhs, Rhs const &rhs) { Derived tmp{ Derived{ static_cast(lhs) } += rhs }; tmp.swap(static_cast(lhs)); return static_cast(lhs); }) c++-annotations-13.02.01/yo/concrete/children.yo0000664000175000017500000000236014735537670020243 0ustar frankfrank The next step up the ladder is the construction of a child-process monitor. Here, the parent process is responsible for all its child processes, but it also must read their standard output. The user enters information at the standard input of the parent process. A simple emi(command language) is used for this: itemization( itt(start): this starts a new child process. The parent returns the child's ID (a number) to the user. The ID is thereupon be used to identify a particular child process; itt( text) sends ``tt(text)'' to the child process having ID tt(); itt(stop ) terminates the child process having ID tt(); itt(exit) terminates the parent as well as all its child processes. ) If a child process hasn't received text for some time it will complain by sending a message to the parent-process. Those messages are simply transmitted to the user by copying them to the standard output stream. A problem with programs like our monitor is that they allow emi(asynchronous input) from multiple sources. Input may appear at the standard input as well as at the input-sides of pipes. Also, multiple output channels are used. To handle situations like these, the ti(select) system call was developed. c++-annotations-13.02.01/yo/concrete/selectimpl.yo0000664000175000017500000001057614735537670020624 0ustar frankfrank Selector's member functions serve the following tasks: itemization( itht(Selector)(Selector()): the (default) constructor. It clears the read, write, and execute tt(fd_set) variables, and switches off the alarm. Except for tt(d_max), the remaining data members do not require specific initializations: verbinclude(//SELECTOR examples/selector.cc) itht(wait)(int wait()): this member em(blocks) until the em(alarm) times out or until activity is sensed at any of the file descriptors monitored by the tt(Selector) object. It throws an exception when the tt(select) system call itself fails: verbinclude(//WAIT examples/selector.cc) itht(nReady)(int nReady): this member function's return value is only defined when tt(wait) has returned. In that case it returns 0 for an alarm-timeout, -1 if tt(select) failed, and otherwise the number of file descriptors on which activity was sensed: verbinclude(//NREADY examples/selector.h) itht(readFd)(int readFd()): this member function's return value is also only defined after tt(wait) has returned. Its return value is -1 if no (more) input file descriptors are available. Otherwise the next file descriptor available for reading is returned: verbinclude(//READFD examples/selector.h) itht(writeFd)(int writeFd()): operating analogously to tt(readFd), it returns the next file descriptor to which output is written. It uses tt(d_writeidx) and tt(d_ret_read) and is implemented analogously to tt(readFd); itht(exceptFd)(int exceptFd()): operating analogously to tt(readFd), it returns the next exception file descriptor on which activity was sensed. It uses tt(d_except_idx) and tt(d_ret_except) and is implemented analogously to tt(readFd); itht(setAlarm)(void setAlarm(int sec, int usec = 0)): this member activates tt(Select)'s alarm facility. At least the number of seconds to wait for the alarm to go off must be specified. It simply assigns values to tt(d_alarm)'s fields. At the next tt(Select::wait) call, the alarm fires (i.e., tt(wait) returns with return value 0) once the configured alarm-interval has passed: verbinclude(//SETALARM examples/selector.h) itht(noAlarm)(void noAlarm()): this member switches off the alarm, by simply setting the alarm interval to a very long period: verbinclude(//NOALARM examples/selector.h) itht(addReadFd)(void addReadFd(int fd)): this member adds a file descriptor to the set of input file descriptors monitored by the tt(Selector) object. The member function tt(wait) returns once input is available at the indicated file descriptor: verbinclude(//ADDREAD examples/selector.h) itht(addWriteFd)(void addWriteFd(int fd)): this member adds a file descriptor to the set of output file descriptors monitored by the tt(Selector) object. The member function tt(wait) returns once output is available at the indicated file descriptor. Using tt(d_write), it is implemented analogously to tt(addReadFd); itht(addExceptFd)(void addExceptFd(int fd)): this member adds a file descriptor to the set of exception file descriptors to be monitored by the tt(Selector) object. The member function tt(wait) returns once activity is sensed at the indicated file descriptor. Using tt(d_except), it is implemented analogously to tt(addReadFd); itht(rmReadFd)(void rmReadFd(int fd)): this member removes a file descriptor from the set of input file descriptors monitored by the tt(Selector) object: verbinclude(//RMREAD examples/selector.h) itht(rmWriteFd)(void rmWriteFd(int fd)): this member removes a file descriptor from the set of output file descriptors monitored by the tt(Selector) object. Using tt(d_write), it is implemented analogously to tt(rmReadFd); itht(rmExceptFd)(void rmExceptFd(int fd)): this member removes a file descriptor from the set of exception file descriptors to be monitored by the tt(Selector) object. Using tt(d_except), it is implemented analogously to tt(rmReadFd); ) The class's remaining (two) members are support members, and should not be used by non-member functions. Therefore, they are declared in the class's tt(private) section: itemization( it() The member tt(addFd) adds a file descriptor to a tt(fd_set): verbinclude(//ADDFD examples/selector.cc) it() The member tt(checkSet) tests whether a file descriptor (tt(*index)) is found in a tt(fd_set): verbinclude(//CHECKSET examples/selector.cc) ) c++-annotations-13.02.01/yo/concrete/bisonflex.yo0000664000175000017500000001056414735537670020451 0ustar frankfrank The example discussed below digs into the peculiarities of using i(parser)- and i(scanner) generators generating bf(C++) sources. Once the input for a program exceeds a certain level of complexity, it becomes attractive to use scanner- and parser-generators generating the code which does the actual input recognition. The examples in this and subsequent sections assume that the reader knows how to use the i(scanner generator) ti(flex) and the i(parser generator) ti(bison). Both tt(bison) and tt(flex) are well documented elsewhere. The original predecessors of tt(bison) and tt(flex), called ti(yacc) and ti(lex) are described in several books, e.g. in hi(http://www.oreilly.com/catalog/lex) O'Reilly's book url(`lex & yacc')(http://www.oreilly.com/catalog/lex). Scanner- and parser generators are also available as free software. Both tt(bison) and tt(flex) are usually part of software distributions or they can be obtained from hi(ftp::/prep.ai.mit.edu/pub/non-gnu) tlurl(ftp://prep.ai.mit.edu/pub/non-gnu). tt(Flex) creates a tt(C++) class when ti(%option c++) is specified. For parser generators the program ti(bison) is available. In the early 90's em(Alain Coetmeur) (url(coetmeur@icdc.fr)(mailto:coetmeur@icdc.fr)) created a bf(C++) variant (ti(bison++)) creating a parser class. Although the tt(bison++) program produces code that can be used in bf(C++) programs it also shows many characteristics that are more suggestive of a bf(C) context than a bf(C++) context. In January 2005 I rewrote parts of Alain's tt(bison++) program, resulting in the original version of the program hi(bisonc++) bf(bisonc++). Then, in May 2005 a complete rewrite of the tt(bisonc++) parser generator was completed (version number 0.98). Current versions of tt(bisonc++) can be downloaded from tlurl(https://fbb-git.gitlab.io/bisoncpp/). Binary versions for various architectures are available as, e.g., url(Debian)(http://www.debian.org) package (including tt(bisonc++)'s documentation). tt(Bisonc++) creates a cleaner parser class than tt(bison++). In particular, it derives the parser class from a base-class, containing the parser's token- and type-definitions as well as all member functions which should not be (re)defined by the programmer. As a result of this approach, the generated parser class is very small, declaring only members that are actually defined by the programmer (as well as some other members, generated by tt(bisonc++) itself, implementing the parser's ti(parse()) member). One member that is em(not) implemented by default is tt(lex), producing the next lexical token. When the directive tt(%scanner) (see section ref(BISONDEF)) is used, tt(bisonc++) produces a standard implementation for this member; otherwise it must be implemented by the programmer. In early 2012 the program hi(flexc++) bf(flexc++) tlurl(http://flexcpp.org/) reached its initial release. Like tt(bisonc++) it is part of the url(Debian linux distribution)(http://www.debian.org). Jean-Paul van Oosten (email(jp@jpvanoosten.nl)) and Richard Berendsen (email(richardberendsen@xs4all.nl)) started the tt(flexc++) project in 2008 and the final program was completed by Jean-Paul and me between 2010 and 2012. These sections of the annotations() focus on tt(bisonc++) as our emi(parser generator) and tt(flexc++) as our lexical scanner generator. Previous releases of the annotations() were using tt(flex) as the scanner generator. Using tt(flexc++) and tt(bisonc++) tt(class)-based scanners and parsers are generated. The advantage of this approach is that the interface to the scanner and the parser tends to become cleaner than without using tt(class) interfaces. Furthermore, classes allow us to get rid of most if not all global variables, making it easy to use multiple parsers in one program. Below two example programs are developed. The first example only uses tt(flexc++). The generated scanner monitors the production of a file from several parts. That example focuses on the lexical scanner and on switching files while churning through the information. The second example uses both tt(flexc++) and tt(bisonc++) to generate a scanner and a parser transforming standard arithmetic expressions to their postfix notations, commonly used in code generated by compilers and in tt(HP)-calculators. In the second example the emphasis is mainly on tt(bisonc++) and on composing a scanner object inside a generated parser. c++-annotations-13.02.01/yo/concrete/parentslurp.yo0000664000175000017500000000570414735537670021037 0ustar frankfrank The class ti(ParentSlurp), derived from tt(Fork), starts a child process executing a stand-alone program (like tt(/bin/ls)). The (standard) output of the executed program is not shown on the screen but is read by the parent process. For demonstration purposes the parent process writes the lines it receives to its standard output stream, prepending linenumbers to the lines. It is attractive to redirect the parent's standard em(input) stream to allow the parent to read the em(output) from the child process using its tt(std::cin) em(input) stream. Therefore, the only pipe in the program is used as an em(input) pipe for the parent, and an em(output) pipe for the child. The class tt(ParentSlurp) has the following characteristics: itemization( it() It is derived from tt(Fork). Before starting tt(ParentSlurp)'s class interface, the compiler must have read tt(fork.h) and tt(pipe.h). The class only uses one data member, a tt(Pipe) object tt(d_pipe). it() As tt(Pipe)'s constructor already defines a pipe, and as tt(d_pipe) is automatically initialized by tt(ParentSlurp)'s default constructor, which is implicitly provided, all additional members only exist for tt(ParentSlurp)'s own benefit so they can be defined in the class's (implicit) tt(private) section. Here is the class's interface: verbinclude(//CLASS examples/parentslurp.h) it() The tt(childRedirections) member configures the writing end of the pipe. So, all information written to the child's standard output stream ends up in the pipe. The big advantage of this is that no additional streams are needed to write to a file descriptor: verbinclude(//CHILDREDIR examples/parentslurp.h) it() The tt(parentRedirections) member, configures the reading end of the pipe. It does so by connecting the reading end of the pipe to the parent's standard input file descriptor (tt(STDIN_FILENO)). This allows the parent to perform extractions from tt(cin), not requiring any additional streams for reading. verbinclude(//PARENTREDIR examples/parentslurp.h) it() The tt(childProcess) member only needs to concentrate on its own actions. As it only needs to execute a program (writing information to its standard output), the member can consist of one single statement: verbinclude(//CHILDPROC examples/parentslurp.h) it() The tt(parentProcess) member simply `slurps' the information appearing at its standard input. Doing so, it actually reads the child's output. It copies the received lines to its standard output stream prefixing line numbers to them: verbinclude(//PARENT examples/parentslurp.cc) ) The following program simply constructs a tt(ParentSlurp) object, and calls its tt(fork()) member. Its output consists of a numbered list of files in the directory where the program is started. Note that the program also needs the tt(fork.o, pipe.o) and tt(waitforchild.o) object files (see earlier sources): verbinclude(//MAIN examples/parentslurp.cc) c++-annotations-13.02.01/yo/concrete/basicfork.yo0000664000175000017500000001161314735537670020417 0ustar frankfrank A basic tt(Fork) class should hide all bookkeeping details of a system call like tt(fork) from its users. The class tt(Fork) developed here does just that. The class itself only ensures the proper execution of the tt(fork) system call. Normally, tt(fork) is called to start a child process, usually boiling down to the execution of a separate process. This child process may expect input at its standard input stream and/or may generate output to its standard output and/or standard error streams. tt(Fork) does not know all this, and does not have to know what the child process will do. tt(Fork) objects should be able to start their child processes. tt(Fork)'s constructor cannot know what actions its child process should perform. Similarly, it cannot know what actions the parent process should perform. For these kind of situations, the emi(template method design pattern) hi(design pattern: template method) was developed. According to Gamma c.s., the em(template method design pattern) quote( ``Define(s) the skeleton of an algorithm in an operation, deferring some steps to subclasses. [The] Template Method (design pattern) lets subclasses redefine certain steps of an algorithm, without changing the algorithm's structure.'' ) This design pattern allows us to define an emi(abstract base class) hi(base class) already providing the essential steps related to the tt(fork) system call, deferring the implementation of other parts of the tt(fork) system call to subclasses. The tt(Fork) abstract base class has the following characteristics: itemization( it() It defines a data member tt(d_pid). In the parent process this data member contains the child's emi(process id) and in the child process it has the value 0. Its public interface declares only two members: itemization( it() a ti(fork) member function, responsible for the actual forking (i.e., it creates the (new) child process); it() a tt(virtual) destructor tt(~Fork) (having an empty body). ) Here is tt(Fork)'s interface: verbinclude(//CLASS examples/fork.h) it() All other non-virtual member functions are declared in the class's tt(protected) section and can thus em(only) be used by derived classes. They are: itemization( itt(pid()): The member function tt(pid) allows derived classes to access the system tt(fork)'s return value: verbinclude(//PID examples/fork.h) itt(waitForChild()): The member tt(int waitForChild) can be called by parent processes to wait for the completion of their child processes (as discussed below). This member is declared in the class interface. Its implementation is: verbinclude(-a examples/waitforchild.cc) This simple implementation returns the child's emi(exit status) to the parent. The called system function ti(waitpid) em(blocks) until the child terminates. ) it() When tt(fork) system calls are used, em(parent processes) hi(parent process) and em(child processes) hi(child process) must always be distinguished. The main distinction between these processes is that tt(d_pid) becomes the child's process-id in the parent process, while tt(d_pid) becomes 0 in the child process itself. Since these two processes must always be distinguished (and present), their implementation by classes derived from tt(Fork) is enforced by tt(Fork)'s interface: the members tt(childProcess), defining the child process' actions and tt(parentProcess), defining the parent process' actions were defined as pure virtual functions. it() communication between parent- and child processes may use standard streams or other facilities, like em(pipes) (cf. section ref(PIPE)). To facilitate this inter-process communication, derived classes em(may) implement: itemization( itt(childRedirections()): this member should be overridden by derived classes if any standard stream (tt(cin, cout,)) or tt(cerr) must be redirected in the em(child) process (cf. section ref(REDIRECTION)). By default it has an empty implementation; itt(parentRedirections()): this member should be overridden by derived classes if any standard stream (tt(cin, cout,)) or tt(cerr) must be redirected in the em(parent) process. By default it has an empty implementation. ) Redirection of the standard streams is necessary if parent and child processes must communicate with each other via the standard streams. Here are their default definitions. Since these functions are virtual functions they should not be implemented inline, but in their own source file: verbinclude(//REDIRECT examples/forkvirtual.cc) ) c++-annotations-13.02.01/yo/concrete/monitor.yo0000664000175000017500000000232214735537670020140 0ustar frankfrank The tt(monitor) program uses a tt(Monitor) object doing most of the work. The class tt(Monitor)'s public interface only offers a default constructor and one member, tt(run), to perform its tasks. All other member functions are located in the class's tt(private) section. tt(Monitor) defines the tt(private) enum tt(Commands), symbolically listing the various commands its input language supports, as well as several data members. Among the data members are a tt(Selector) object and a tt(map) using child order numbers as its keys and pointer to tt(Child) objects (see section ref(CHILD)) as its values. Furthermore, tt(Monitor) has a static array member tt(s_handler[]), storing pointers to member functions handling user commands. A destructor should be implemented as well, but its implementation is left as an exercise to the reader. Here is tt(Monitor)'s interface, including the interface of the nested class tt(Find) that is used to create a function object: verbinclude(//CLASS examples/monitor/monitor.h) Since there's only one non-class type data member, the class's constructor is a very simple function which could be implemented inline: verbinclude(//CONS examples/monitor/monitor.h) c++-annotations-13.02.01/yo/concrete/polygram.yo0000664000175000017500000000265414735537670020313 0ustar frankfrankNow that the tt(Semantic) class template has been developed it's time to put it to use in the tt(Parser) class. The parser's semantic value is tt(spSemBase). The parser's base class must be informed about this type, for which the tt(%baseclass-preinclude) directive is used. All other directives are standard and do not require further explanations: verbinclude(//HEAD poly2/parser/grammar) The grammar's rules simply consist of a series of tt(rule) nonterminals: verbinclude(//RULES poly2/parser/grammar) tt(Int) values are stored in tt(Semantic) objects, text is stored in tt(Semantic) values: verbinclude(//INT poly2/parser/grammar) Comma separated lists of arguments are processed as follows: the first argument is stored in a tt(Semantic); additional values are added to the vector using tt(vector::push_back). Note that we've defined the vector as mutable: addition of values to the vector is OK, but the values themselves remain as-is, and so the vector stores shared pointers to tt(SemBase const) values: verbinclude(//ARGS poly2/parser/grammar) The definition of the tt(rule) production rule completes our little grammar: an alternative suggesting an assignment echoes the received names and values, and an alternative suggesting a function call uses a support member tt(display) to display the received name and arguments: verbinclude(//RULE poly2/parser/grammar) c++-annotations-13.02.01/yo/concrete/binop.yo0000664000175000017500000000266614735537670017573 0ustar frankfrankAs we've seen in section ref(OVERLOADBINARY) binary operators expecting tt(const &) arguments can be implemented using a member implementing the operation, only offering the basic exception guarantee. This latter function can in turn be implemented using the binary assignment member. The following examples illustrated this approach for a fictitious class tt(Binary): verbinclude(-a ../overloading/examples/binary4.h) Eventually, the implementation of binary operators depends on the availability of the member implementing the basic binary operation, modifying the object calling that member (i.e., tt(void Binary::add(Binary const &)) in the example). Since template functions are not instantiated before they are actually used we can call non-existing functions from template functions that are never instantiated. If such a template function is never instantiated, nothing happens; if it is (accidentally) instantiated, then the compiler generates an error message, complaining about the missing function. This allows us to implement all binary operators, movable and non-movable, as templates. In the following subsections we develop the class template tt(Binops), prividing binary operators. A complete implementation of a class tt(Derived) illustrating how addition and insertion operators can be added to a class is provided in the file tt(annotations/yo/concrete/examples/binopclasses.cc) in the annotations()' source archive. c++-annotations-13.02.01/yo/concrete/fistreamexample.yo0000664000175000017500000000641014735537670021641 0ustar frankfrank There is only one additional public member: tt(setField(field const &)). This member defines the size of the next field to extract. Its parameter is a reference to a tt(field) class, a em(manipulator class) defining the width of the next field. Since a tt(field &) is mentioned in tt(Fistream)'s interface, tt(field) must be declared before tt(Fistream)'s interface starts. The class tt(field) itself is simple and declares tt(Fistream) as its friend. It has two data members: tt(d_width) specifies the width of the next field, and tt(d_newWidth) which is set to tt(true) if tt(d_width)'s value should actually be used. If tt(d_newWidth) is false, tt(Fistream) returns to its standard extraction mode. The class tt(field) has two constructors: a default constructor, setting tt(d_newWidth) to tt(false), and a second constructor expecting the width of the next field to extract as its value. Here is the class tt(field): verbinclude(//FIELD examples/fistream/fistream.h) Since tt(field) declares tt(Fistream) as its friend, tt(setField) may inspect tt(field)'s members directly. Time to return to tt(setField). This function expects a reference to a tt(field) object, initialized in one of three different ways: itemization( itt(field()): When tt(setField)'s argument is a tt(field) object constructed by its default constructor the next extraction will use the same field width as the previous extraction. itt(field(0)): When this tt(field) object is used as tt(setField)'s argument, fixed-sized field extraction stops, and the tt(Fistream) acts like any standard tt(istream) object again. itt(field(x)): When the tt(field) object itself is initialized by a non-zero size_t value tt(x), then the next field width is tt(x) characters wide. The preparation of such a field is left to tt(setBuffer), tt(Fistream)'s only private member. ) Here is tt(setField)'s implementation: verbinclude(//SETFIELD examples/fistream/fistream.cc) The private member tt(setBuffer) defines a buffer of tt(d_width + 1) characters and uses tt(read) to fill the buffer with tt(d_width) characters. The buffer is an NTBS. This buffer is used to initialize the tt(d_iss) member. tt(Fistream)'s tt(rdbuf) member is used to extract the tt(d_str)'s data via the tt(Fistream) object itself: verbinclude(//SETBUFFER examples/fistream/fistream.cc) Although tt(setField) could be used to configure tt(Fistream) to use or not to use fixed-sized field extraction, using manipulators is probably preferable. To allow tt(field) objects to be used as manipulators an overloaded extraction operator was defined. This extraction operator accepts tt(istream &) and a tt(field const &) objects. Using this extraction operator, statements like verb(fis >> field(2) >> x >> field(0);) are possible (assuming tt(fis) is a tt(Fistream) object). Here is the overloaded oprshift(), as well as its declaration: verbinclude(//OPEX examples/fistream/fistream.cc) Declaration: verbinclude(//OPEX examples/fistream/fistream.h) Finally, an example. The following program uses a tt(Fistream) object to url-decode url-encoded information appearing at its standard input: verbinclude(//MAIN examples/fistream/main.cc) c++-annotations-13.02.01/yo/concrete/definition.yo0000664000175000017500000001631614735537670020611 0ustar frankfrank The i(declaration section) contains several sets of declarations, among which definitions of all the tokens used in the grammar and the priorities and associativities of the mathematical operators. Moreover, several new and important specifications can be used here as well. Those relevant to our current example and only available in tt(bisonc++) are discussed here. The reader is referred to tt(bisonc++)'s man-page for a full description. itemization( it() bi(%baseclass-preinclude) tt(header)nl() Use tt(header) as the pathname to the file pre-included in the parser's base-class header. This declaration is useful in situations where the base class header file refers to types which might not yet be known. E.g., with ti(%union) a tt(std::string *) field might be used. Since the class tt(std::string) might not yet be known to the compiler once it processes the base class header file we need a way to inform the compiler about these classes and types. The suggested procedure is to use a pre-include header file declaring the required types. By default tt(header) is surrounded by double quotes (using, e.g., tt(#include "header")). When the argument is surrounded by angle brackets tt(#include
) is included. In the latter case, quotes might be required to escape interpretation by the shell (e.g., using tt(-H '
')). it() bi(%filenames) tt(header) nl() Defines the generic name of all generated files, unless overridden by specific names. By default the generated files use the class-name as the generic file name. it() bi(%scanner) tt(header)nl() Use tt(header) as the pathname to the file pre-included in the parser's class header. This file should define a class tt(Scanner), offering a member tt(int lex()) producing the next token from the input stream to be analyzed by the parser generated by tt(bisonc++). When this option is used the parser's member tt(int lex()) is predefined as (assuming the default parser class name tt(Parser) is used): verb(inline int Parser::lex() { return d_scanner.lex(); }) and an object tt(Scanner d_scanner) is composed into the parser. The tt(d_scanner) object is constructed by its default constructor. If another constructor is required, the parser class may be provided with an appropriate (overloaded) parser constructor after having constructed the default parser class header file using tt(bisonc++). By default tt(header) is surrounded by double quotes (using, e.g., tt(#include "header")). When the argument is surrounded by angle brackets tt(#include
) is included. it() bi(%stype) tt(typename) nl() The type of the semantic value of tokens. The specification tt(typename) should be the name of an unstructured type (e.g., tt(size_t)). By default it is tt(int). See tt(YYSTYPE) in tt(bison). It should not be used if a tt(%union) specification is used. Within the parser class, this type may be used as tt(STYPE). it() bi(%union) tt(union-definition) nl() Acts identically to the tt(bison) declaration. As with tt(bison) this generates a union for the parser's semantic type. The union type is named tt(STYPE). If no tt(%union) is declared, a simple stack-type may be defined using the tt(%stype) declaration. If no tt(%stype) declaration is used, the default stacktype (tt(int)) is used. ) An example of a tt(%union) declaration is: verb( %union { int i; double d; };) In pre-C++11 code a i(union) cannot contain objects as its fields, as constructors cannot be called when a union is created. This means that hi(string: as union member) a tt(string) cannot be a member of the union. A tt(string *), however, em(is) a possible union member. It might also be possible to use em(unrestricted unions) (cf. section ref(UNIONS)), having class type objects as fields. As an aside: the scanner does not have to know about such a union. It can simply pass its scanned text to the parser through its ti(matched) member function. For example using a statement like verb( $$.i = A2x(d_scanner.matched());) matched text is converted to a value of an appropriate type. Tokens and non-terminals can be associated with union fields. This is strongly advised, as it prevents type mismatches, since the compiler may then check for type correctness. At the same time, the bison specific variables tt($$), tt($1), tt($2), etc. may be used, rather than the full field specification (like tt($$.i)). A non-terminal or a token may be associated with a union field using the tt() specification. E.g., verb( %token INT // token association (deprecated, see below) DOUBLE %type intExpr // non-terminal association) In the example developed here, both the tokens and the non-terminals can be associated with a union field. However, as noted before, the scanner does not have to know about all this. In our opinion, it is cleaner to let the scanner do just one thing: scan texts. The em(parser), knowing what the input is all about, may then convert strings like tt("123") to an integer value. Consequently, the association of a union field and a token is discouraged. Below, while describing the grammar's rules, this is further illustrated. In the tt(%union) discussion the ti(%token) and ti(%type) specifications should be noted. They are used to specify the tokens (terminal symbols) that can be returned by the scanner, and to specify the return types of non-terminals. Apart from tt(%token) the token declarators ti(%left), ti(%right), and ti(%nonassoc) can be used to specify the associativity of operators. The tokens mentioned at these indicators are interpreted as tokens indicating operators, associating in the indicated direction. The precedence of operators is defined by their order: the first specification has the lowest priority. To overrule a certain precedence in a certain context ti(%prec) can be used. As all this is standard tt(bisonc++) practice, it isn't further elaborated here. The documentation provided with tt(bisonc++)'s distribution should be consulted for further reference. Here is the specification of the calculator's declaration section: verbinclude(//DECLARATION bisonc++/parser/grammar) In the declaration section tt(%type) specifiers are used, associating the tt(intExpr) rule's value (see the next section) to the tt(i)-field of the semantic-value union, and associating tt(doubleExpr)'s value to the tt(d)-field. This approach, admittedly, is rather complex, as expression rules must be included for each of the supported union types. Alternatives are definitely possible, and involve the use of em(polymorphic semantic values), covered in detail in the url(Bisonc++ user guide) (http://fbb-git.gitlab.io/bisoncpp/manual/bisonc++.html). c++-annotations-13.02.01/yo/concrete/bison.yo0000664000175000017500000000567314735537670017577 0ustar frankfrankThe i(grammar specification file) required by ti(bisonc++) is comparable to the specification file required by ti(bison). Differences are related to the class nature of the resulting parser. Our calculator distinguishes real numbers from integers, and supports a basic set of arithmetic operators. tt(Bisonc++) should be used as follows: itemization( it() As usual, a grammar is defined. With tt(bisonc++) this is no different, and tt(bisonc++) grammar definitions are for all practical purposes identical to tt(bison)'s grammar definitions. it() Having specified the grammar and (usually) some declarations tt(bisonc++) can generate files defining the parser class and the implementation of the member function tt(parse). it() All class members (except those that are required for the proper functioning of the member tt(parse)) must be separately implemented. Of course, they should also be declared in the parser class's header. At the very least the member ti(lex) must be implemented. This member is called by tt(parse) to obtain the next available token. However, tt(bisonc++) offers a facility providing a standard implementation of the function tt(lex). The member function hi(error)tt(error(char const *msg)) is given a simple default implementation that may be modified by the programmer. The member function tt(error) is called when tt(parse) detects (syntactic) errors. it() The parser can now be used in a program. A very simple example would be: verb(int main() { Parser parser; return parser.parse(); }) ) The tt(bisonc++) hi(bisonc++: grammar file) specification file has two sections: itemization( it() The em(declaration section). In this section bison's tokens, and the priority rules for the operators are declared. However, tt(bisonc++) also supports several new declarations. These new declarations are important and are discussed below. it() The em(rules section). The i(grammatical rules) define the grammar. This section is identical to the one required by tt(bison), albeit that some members that were available in tt(bison) and tt(bison++) are obsolete in tt(bisonc++), while other members can be used in a wider context. For example, bf(ACCEPT) and bf(ABORT) can be called from any member called from the parser's action blocks to terminate the parsing process. ) Readers familiar with tt(bison) may note that there is no emi(header section) anymore. Header sections are used by bison to provide for the necessary declarations allowing the compiler to compile the bf(C) function generated by tt(bison). In bf(C++) declarations are part of or already used by class definitions. Therefore, a parser generator generating a bf(C++) class and some of its member functions does not require a header section anymore. c++-annotations-13.02.01/yo/concrete/run.yo0000664000175000017500000000544314735537670017264 0ustar frankfrank tt(Monitor)'s core activities are performed by tt(run). It performs the following tasks: itemization( it() Initially, the tt(Monitor) object only monitors its standard input. The set of input file descriptors to which tt(d_selector) listens is initialized to tt(STDIN_FILENO). it() Then, in a loop tt(d_selector)'s tt(wait) function is called. If input on tt(cin) is available, it is processed by tt(processInput). Otherwise, the input has arrived from a child process. Information sent by children is processed by tt(processChild). it() To prevent emi(zombie)em(s), the child processes must catch em(their) children's termination signals. This is discussed below. As noted by Ben Simons (tt(ben at mrxfx dot com)) tt(Monitor) must not catch the termination signals. Instead, the process spawning child processes has that responsibility (the underlying principle being that a parent process is responsible for its child processes; a child process, in turn, is responsible for its own child processes). it() As stated, tt(run)'s source file also defines and initializes tt(s_initialize) to ensure the proper initialization of the tt(s_handler) array. ) Here is tt(run)'s implementation and tt(s_initialize)'s definition: verbinclude(-a examples/monitor/run.cc) The member function tt(processInput) reads the commands entered by the user using the program's standard input stream. The member itself is rather simple. It calls tt(next) to obtain the next command entered by the user, and then calls the corresponding function using the matching element of the tt(s_handler[]) array. Here are the members tt(processInput) and tt(next): verbinclude(//INPUT examples/monitor/processinput.cc) verbinclude(//NEXT examples/monitor/processinput.cc) All other input sensed by tt(d_select) is created by child processes. Because tt(d_select)'s tt(readFd) member returns the corresponding input file descriptor, this descriptor can be passed to tt(processChild). Using a ti(IFdStreambuf) (see section ref(IFDBUF)), its information is read from an input stream. The communication protocol used here is rather basic. For every line of input sent to a child, the child replies by sending back exactly one line of text. This line is then read by tt(processChild): verbinclude(//CHILD examples/monitor/processchild.cc) The construction tt(d_child[fd]->pid()) used in the above source deserves some special attention. tt(Monitor) defines the data member tt(map> d_child). This map contains the child's order number as its key, and a (shared) pointer to the tt(Child) object as its value. A shared pointer is used here, rather than a tt(Child) object, since we want to use the facilities offered by the map, but don't want to copy a tt(Child) object time and again. c++-annotations-13.02.01/yo/concrete/lexer.yo0000664000175000017500000000234614735537670017576 0ustar frankfrank The function matching the i(regular expression) rules (tt(lex)) is a member of the class hi(scanner)tt(Scanner). Since tt(Scanner) is derived from tt(ScannerBase), it has access to all of tt(ScannerBase)'s protected members that execute the lexical scanner's regular expression matching algorithm. Looking at the regular expressions themselves, notice that we need rules to recognize comment, ti(#include) directives, and all remaining characters. This all is fairly standard practice. When an tt(#include) directive is sensed, the directive is parsed by the scanner. This too is common practice. Our lexical scanner performs the following tasks: itemization( it() As usual, i(preprocessor directive)s are not analyzed by a parser, but by the lexical scanner; it() The scanner uses a i(mini scanner) to extract the filename from the directive, throwing a exception if this fails; it() If the filename could be extracted, processing switches to the next stream, controlling for a maximum nesting depth. it() Once the end of the current file has been reached processing automatically returns to the previous file, restoring the previous file name and line number. The scanner returns 0 if all files have been processed. ) c++-annotations-13.02.01/yo/concrete/fork.yo0000664000175000017500000000276314735537670017423 0ustar frankfrankFrom the bf(C) programming language the ti(fork) system call is well known. When a program needs to start a new process, ti(system) can be used. The function tt(system) requires the program to wait for the emi(child process) to terminate. The more general way to spawn subprocesses is to use tt(fork). In this section we investigate how bf(C++) can be used to wrap classes around a complex system call like tt(fork). Much of what follows in this section directly applies to the Unix operating system, and the discussion therefore focuses on that operating system. Other systems usually provide comparable facilities. What follows is closely related to the em(Template Design Pattern)hi(design pattern) (cf. em(Gamma et al.) (1995) hi(Gamma, E.) i(Design Patterns), Addison-Wesley) When tt(fork) is called, the current program is duplicated in memory, thus creating a new process. Following this duplication both processes continue their execution just below the tt(fork) system call. The two processes may inspect tt(fork)'s return value: the return value in the original process (called the emi(parent process)) differs from the return value in the newly created process (called the emi(child process)): itemization( it() In the em(parent process) tt(fork) returns the emi(process ID) of the (child) process that was created by the tt(fork) system call. This is a positive integer value. it() In the em(child process) tt(fork) returns 0. it() If tt(fork) fails, -1 is returned. ) c++-annotations-13.02.01/yo/concrete/promotions.yo0000664000175000017500000001163314735537670020667 0ustar frankfrankThe function templates introduced in the previous section do not support promotions. E.g., a statement like verb( result = rhs + 2;) generates a compilation error as promotions are not recognized by the template argument deduction algorithm. Currently, the above statement needs to be rewritten to have it accepted by the compiler: verb( result = rhs + Class{ 2 };) If promotions are welcome, how can we change the arithmetic operator function templates so that promotions are performed? With promotions the arguments of the operator functions may be of any type, at least one of them must be of the class type offering the matching compound assignment operator. But when designing the function template we can't say which of the two operands has that class type. So we have to specify two template types parameters for the two parameters of the operator functions. The function template must therefore start with something like this: verb( template ReturnType operator+(LHS const &lhs, RHS const &rhs)) At this point we can't yet specify tt(ReturnType). It is tt(LHS) if tt(RHS) can be promoted to or is equal to tt(LHS), it is be tt(RHS) if tt(LHS) is promoted to tt(RHS). To determine whether tt(RHS) can be promoted to tt(LHS) we now design a simple template meta programming class tt(LpromotesR) using two template type parameters, defining the value tt(true) (1) if the second (right hand) type can be promoted to the first (left-hand) type, and defining the value tt(false) (0) if not. Here we use the same principle seen before in section ref(TYPECONV), link(type convertibility)(TYPECONV): verb( template class LpromotesR { struct Char2 { char array[2]; }; static R const &makeR(); static char test(L const &); static Char2 test(...); public: LpromotesR() = delete; enum { yes = sizeof(test(makeR())) == sizeof(char) }; };) In tt(class LpromotesR) the function tt(test(L const &)) is selected if tt(R) can be promoted to tt(L), and tt(test(...)) is selected if not. The different sizes of the return types of these two tt(test) functions allows the compiler to assign 1 or 0 to the class's tt(enum) value tt(yes). The value tt(yes) (correctly) is 0 for tt(R) types mentioned in constructors declared with the tt(explicit) keyword, and it (correctly) is 1 if tt(L) and tt(R) happen to be the same types. Now that we can determine whether a type can be promoted to another type, it is possible to select either tt(LHS) or tt(RHS) as the function template's return type. If tt(RHS) can be promoted to tt(LHS) use tt(LHS) as the function template's return type, otherwise use RHS. Of course there is a third possibility: the tt(LHS) and tt(RHS) types cannot be used by each other's constructors. In that case, unless there is another constructor lying around somewhere handling that situation, the compiler generates an error like: verb( no match for 'operator+' in '...') Back to promotable types. We are now able to determine which type can be promoted, using tt(LpromotesR). This yields a value that can be used as selector in the tt(IfElse) template meta programming class template, introduced earlier (cf. section ref(IFELSE)). Now that we can select either tt(LHS) or tt(RHS) as the operator template function's return type, we're able to construct our arithmetic operator function template supporting promotions: verb( template typename FBB::IfElse::yes, LHS, RHS>::type operator<<(LHS const &lhs, RHS const &rhs) { using Type = typename FBB::IfElse< FBB::LpromotesR< LHS, RHS >::yes, LHS, RHS >::type; Type tmp(lhs); return std::move(tmp) << type(rhs); }) The function's return type is tt(IfElse)'s tt(type), selected as either tt(LHS) (if tt(RHS) can be promoted to tt(LHS)) or tt(RHS). The same trick is used in the function's body to determine tt(tmp)'s type. Now promotions are possible. The function template defining an rvalue reference parameter remains as-is. Together they allow the compiler to make the following decisions (using tt(Class) as the intended class name, tt(Type) as a type that is promotable to tt(Class), and tt(@) as the generic indication of the used operator). Unless otherwise specified the function template defining the parameter list tt((LHS const &lhs, RHS const &rhs)) is used: verb( Class obj; Type value; obj @ obj // no promotions obj @ Class() // same obj @ value; // value is promoted to Class Class() @ value; // same value @ obj; // same value @ Class(); // same Class() @ obj; // calls operator@(Class &&, Class const &) Class() @ Class(); // same) c++-annotations-13.02.01/yo/concrete/intro.yo0000664000175000017500000000167514735537670017616 0ustar frankfrankIn this chapter concrete examples of bf(C++) programs, classes and templates are presented. Topics covered by the annotations() such as virtual functions, tt(static) members, etc. are illustrated in this chapter. The examples roughly follow the organization of earlier chapters. As an additional topic, not just providing examples of bf(C++) the subjects of i(scanner) and i(parser) generators are covered. We show how these tools may be used in bf(C++) programs. These additional examples assume a certain familiarity with the concepts underlying these tools, like grammars, parse-trees and hi(grammar) hi(parse-tree) parse-tree decoration. Once the input for a program exceeds a certain level of complexity, it's attractive to use scanner- and parser-generators to create the code doing the actual input processing. One of the link(examples)(BisonAndFlex) in this chapter describes the usage of these tools in a bf(C++) environment. c++-annotations-13.02.01/yo/concrete/child.yo0000664000175000017500000001011314735537670017531 0ustar frankfrank When the tt(Monitor) object starts a child process, it creates an object of the class tt(Child). The tt(Child) class is derived from the class tt(Fork), allowing it to operate as a emi(daemon) (as discussed in the previous section). Since tt(Child) is a daemon class, we know that its parent process must be defined as an empty function. Its tt(childProcess) member has a non-empty implementation. Here are the characteristics of the class tt(Child): itemization( it() The tt(Child) class has two tt(Pipe) data members, to handle communications between its own child- and parent processes. As these pipes are used by the tt(Child)'s child process, their names refer to the child process. The child process reads from tt(d_in), and writes to tt(d_out). Here is the interface of the class tt(Child): verbinclude(//CLASS examples/monitor/child.h) it() The tt(Child)'s constructor simply stores its argument, a child-process order number, in its own tt(d_nr) data member: verbinclude(//CONS examples/monitor/child.h) it() The tt(Child)'s child process obtains commands from its standard input stream and writes its output to its standard output stream. Since the actual communication channels are pipes, redirections must be used. The tt(childRedirections) member looks like this: verbinclude(//CHILD examples/monitor/child.cc) it() Although the parent process performs no actions, it must configure some redirections. Realizing that the names of the pipes indicate their functions in the child process. So the parent em(writes) to tt(d_in) and em(reads) from tt(d_out). Here is tt(parentRedirections): verbinclude(//PARENT examples/monitor/child.cc) it() The tt(Child) object exists until it is destroyed by the tt(Monitor)'s tt(stopChild) member. By allowing its creator, the tt(Monitor) object, to access the parent-side ends of the pipes, the tt(Monitor) object can communicate with the tt(Child)'s child process via those pipe-ends. The members tt(readFd) and tt(writeFd) allow the tt(Monitor) object to access these pipe-ends: verbinclude(//PIPES examples/monitor/child.h) it() The tt(Child) object's child process performs two tasks: itemization( it() It must reply to information appearing at its standard input stream; it() If no information has appeared within a certain time frame (the implementations uses an interval of five seconds), then a message is written to its standard output stream. ) To implement this behavior, tt(childProcess) defines a local tt(Selector) object, adding tt(STDIN_FILENO) to its set of monitored input file descriptors. Then, in an endless loop, tt(childProcess) waits for tt(selector.wait()) to return. When the alarm goes off it sends a message to its standard output (hence, into the writing pipe). Otherwise, it echoes the messages appearing at its standard input to its standard output. Here is the tt(childProcess) member: verbinclude(//PROCESS examples/monitor/child.cc) it() Two accessors are defined allowing the tt(Monitor) object to obtain the tt(Child)'s process ID and its order number: verbinclude(//PIDNR examples/monitor/child.h) it() A tt(Child) process terminates when the user enters a tt(stop) command. When an existing child process number was entered, the corresponding tt(Child) object is removed from tt(Monitor)'s tt(d_child) map. As a result, its destructor is called. tt(Child)'s destructor calls tt(kill) to terminate its child, and then waits for the child to terminate. Once its child has terminated, the destructor has completed its work and returns, thus completing the erasure from tt(d_child). The current implementation fails if the child process doesn't react to the tt(SIGTERM) signal. In this demonstration program this does not happen. In `real life' more elaborate killing-procedures may be required (e.g., using tt(SIGKILL) in addition to tt(SIGTERM)). As discussed in section ref(CONSEXCEPTIONS) it em(is) important to ensure the proper destruction. Here is the tt(Child)'s destructor: verbinclude(//CHILDDES examples/monitor/child.cc) ) c++-annotations-13.02.01/yo/concrete/lexer/0000775000175000017500000000000014771010711017176 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/lexer/build0000775000175000017500000000075214735537670020251 0ustar frankfrank#!/bin/bash case "$1" in ("") echo " usage: 'build prog' to build the program, 'build clean' to cleanup " exit 1 ;; (prog) cd scanner flexc++ lexer || exit 1 cd .. g++ --std=c++11 -Wall -olexer lexer.cc scanner/*.cc || exit 1 echo " ready; run the program as 'lexer in.1' " ;; (clean) cd scanner rm -f ../lexer lex.cc scannerbase.h echo " done " ;; esac exit 1 c++-annotations-13.02.01/yo/concrete/lexer/in.10000664000175000017500000000005514735537670017710 0ustar frankfrankbefore #include #include after c++-annotations-13.02.01/yo/concrete/lexer/lexer.cc0000664000175000017500000000051514771010716020632 0ustar frankfrank#include "lexer.ih" int main(int argc, char **argv) try { if (argc == 1) { cerr << "Filename argument required\n"; return 1; } Scanner scanner(argv[1], "-"); scanner.setDebug(argc > 2); return scanner.lex(); } catch (exception const &exc) { cerr << exc.what() << '\n'; return 1; } c++-annotations-13.02.01/yo/concrete/lexer/scanner/0000775000175000017500000000000014771010711020627 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/lexer/scanner/scanner.ih0000664000175000017500000000005314771010714022603 0ustar frankfrank#include "scanner.h" using namespace std; c++-annotations-13.02.01/yo/concrete/lexer/scanner/scanner.h0000664000175000017500000000243514771010714022440 0ustar frankfrank// Generated by Flexc++ V0.94.00 on Thu, 23 Feb 2012 16:23:09 +0100 #ifndef Scanner_H_INCLUDED_ #define Scanner_H_INCLUDED_ // $insert baseclass_h #include "scannerbase.h" // $insert classHead class Scanner: public ScannerBase { std::string d_nextSource; public: explicit Scanner(std::istream &in = std::cin, std::ostream &out = std::cout); Scanner(std::string const &infile, std::string const &outfile); // $insert lexFunctionDecl int lex(); private: int lex__(); int executeAction__(size_t ruleNr); void print(); void preCode(); // re-implement this function for code that must // be exec'ed before the patternmatching starts void switchSource(); }; // $insert scannerConstructors inline Scanner::Scanner(std::istream &in, std::ostream &out) : ScannerBase(in, out) {} inline Scanner::Scanner(std::string const &infile, std::string const &outfile) : ScannerBase(infile, outfile) {} // $insert inlineLexFunction inline int Scanner::lex() { return lex__(); } inline void Scanner::preCode() { // optionally replace by your own code } inline void Scanner::print() { print__(); } #endif // Scanner_H_INCLUDED_ c++-annotations-13.02.01/yo/concrete/lexer/scanner/lexer0000664000175000017500000000136614735537670021721 0ustar frankfrank//SYMBOLS %filenames scanner %debug %max-depth 3 %x comment %x include //= //RULES %% // The comment-rules: comment is ignored. "//".* // ignore eoln comment "/*" begin(StartCondition__::comment); { .|\n // ignore all characters in std C comment "*/" begin(StartCondition__::INITIAL); } // File switching: #include #include[ \t]+"<" begin(StartCondition__::include); { [^ \t>]+ d_nextSource = matched(); ">"[ \t]*\n switchSource(); .|\n throw runtime_error("Invalid include statement"); } // The default rule: echo anything else to std::cout .|\n echo(); //= c++-annotations-13.02.01/yo/concrete/lexer/scanner/switchsource.cc0000664000175000017500000000017414771010716023667 0ustar frankfrank#include "scanner.ih" void Scanner::switchSource() { pushStream(d_nextSource); begin(StartCondition__::INITIAL); } c++-annotations-13.02.01/yo/concrete/lexer/lexer.ih0000664000175000017500000000010714771010714020640 0ustar frankfrank#include #include "scanner/scanner.h" using namespace std; c++-annotations-13.02.01/yo/concrete/lexer/in.20000664000175000017500000000003014735537670017702 0ustar frankfrankin in.2 #include c++-annotations-13.02.01/yo/concrete/poly2/0000775000175000017500000000000014771010711017124 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly2/build0000775000175000017500000000115714735537670020177 0ustar frankfrank#!/bin/bash case "$1" in (prog) cd parser bisonc++ --print-tokens grammar || exit 1 cd ../scanner flexc++ lexer || exit 1 cd .. g++ --std=c++11 -Wall -opoly *.cc */*.cc -lbobcat || exit 1 echo " ready; run the program as './poly < input' " ;; (clean) rm -f poly cd parser rm -f parse.cc parserbase.h cd ../scanner rm -f lex.cc scannerbase.h echo " done " ;; (*) echo " usage: 'build prog' to build the program, 'build clean' to cleanup " exit 1 ;; esac exit 1 c++-annotations-13.02.01/yo/concrete/poly2/input0000664000175000017500000000006114735537670020225 0ustar frankfrankvar = 5 ; var(var, 5, ok, 18); var(5); var(ok); c++-annotations-13.02.01/yo/concrete/poly2/parser/0000775000175000017500000000000014771010711020420 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly2/parser/parser.h0000664000175000017500000000221014771010714022063 0ustar frankfrank// Generated by Bisonc++ V3.00.00 on Fri, 24 Feb 2012 15:09:41 +0100 #ifndef Parser_h_included #define Parser_h_included // $insert baseclass #include "parserbase.h" // $insert scanner.h #include "../scanner/scanner.h" #undef Parser class Parser: public ParserBase { // $insert scannerobject Scanner d_scanner; public: int parse(); private: void error(char const *msg); // called on (syntax) errors int lex(); // returns the next token from the // lexical scanner. void print(); // use, e.g., d_token, d_loc void display(STYPE__ const &id, STYPE__ &vect); // support functions for parse(): void executeAction(int ruleNr); void errorRecovery(); int lookup(bool recovery); void nextToken(); void print__(); }; inline void Parser::error(char const *msg) { std::cerr << msg << '\n'; } // $insert lex inline int Parser::lex() { return d_scanner.lex(); } inline void Parser::print() { print__(); // displays tokens if --print was specified } #endif c++-annotations-13.02.01/yo/concrete/poly2/parser/parser.ih0000664000175000017500000000024714771010714022244 0ustar frankfrank // Include this file in the sources of the class Parser. // $insert class.h #include "parser.h" #include using namespace std; using namespace FBB; c++-annotations-13.02.01/yo/concrete/poly2/parser/display.cc0000664000175000017500000000112014771010716022373 0ustar frankfrank#include "parser.ih" void Parser::display(STYPE__ const &id, STYPE__ &vect) { cout << id->as() << "("; char const *sep = ""; for (auto &sp: vect->as()) { cout << sep; switch (sp->tag()) { case Tag::INT: cout << sp->as(); break; case Tag::TEXT: cout << sp->as(); break; default: // Tag::VECTOR intentionally not handled break; } sep = ", "; } cout << ")\n"; } c++-annotations-13.02.01/yo/concrete/poly2/parser/grammar0000664000175000017500000000157514735537670022023 0ustar frankfrank//HEAD %filenames parser %scanner ../scanner/scanner.h %baseclass-preinclude ../spsembase/spsembase.h %stype spSemBase %token INT IDENT //= %% //RULES rules: rules rule | rule ; //= //INT int: INT { $$ = new Semantic(A2x(d_scanner.matched()).to()); } ; ident: IDENT { $$ = new Semantic(d_scanner.matched()); } ; //= //ARGS value: int | ident ; arglist: arglist ',' value { $1->as().push_back($3); } | value { $$ = new Semantic( vector> {$1}); } ; //= //RULE rule: ident '(' arglist ')' ';' { display($1, $3); } | ident '=' int ';' { cout << $1->as() << " = " << $3->as() << ";\n"; } ; //= c++-annotations-13.02.01/yo/concrete/poly2/scanner/0000775000175000017500000000000014771010710020554 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly2/scanner/scanner.ih0000664000175000017500000000037414771010714022537 0ustar frankfrank// Declare here // what's only used in the Scanner class // and let Scanner's sources include "scanner.ih" #include "scanner.h" #include "../parser/parserbase.h" // end of scanner.ih c++-annotations-13.02.01/yo/concrete/poly2/scanner/scanner.h0000664000175000017500000000231614771010714022364 0ustar frankfrank// Generated by Flexc++ V0.94.00 on Fri, 24 Feb 2012 15:08:50 +0100 #ifndef Scanner_H_INCLUDED_ #define Scanner_H_INCLUDED_ // $insert baseclass_h #include "scannerbase.h" // $insert classHead class Scanner: public ScannerBase { public: explicit Scanner(std::istream &in = std::cin, std::ostream &out = std::cout); Scanner(std::string const &infile, std::string const &outfile); // $insert lexFunctionDecl int lex(); private: int lex__(); int executeAction__(size_t ruleNr); void print(); void preCode(); // re-implement this function for code that must // be exec'ed before the patternmatching starts }; // $insert scannerConstructors inline Scanner::Scanner(std::istream &in, std::ostream &out) : ScannerBase(in, out) {} inline Scanner::Scanner(std::string const &infile, std::string const &outfile) : ScannerBase(infile, outfile) {} // $insert inlineLexFunction inline int Scanner::lex() { return lex__(); } inline void Scanner::preCode() { // optionally replace by your own code } inline void Scanner::print() { print__(); } #endif // Scanner_H_INCLUDED_ c++-annotations-13.02.01/yo/concrete/poly2/scanner/lexer0000664000175000017500000000035714735537670021646 0ustar frankfrank%filenames scanner %% [[:space:]]+ // skip white space [[:digit:]]+ return Parser::INT; [[:alpha:]_][[:alnum:]_]* return Parser::IDENT; . return matched()[0]; c++-annotations-13.02.01/yo/concrete/poly2/spsembase/0000775000175000017500000000000014771010710021105 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly2/spsembase/spsembase.h0000664000175000017500000000055314771010714023247 0ustar frankfrank#ifndef INCLUDED_SPSEMBASE_ #define INCLUDED_SPSEMBASE_ #include "../sembase/sembase.h" class spSemBase: public std::shared_ptr { public: spSemBase() = default; template spSemBase(Type *obj); }; template inline spSemBase::spSemBase(Type *obj) : std::shared_ptr(obj) {} #endif c++-annotations-13.02.01/yo/concrete/poly2/sembase/0000775000175000017500000000000014771010711020543 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/poly2/sembase/sembase.h0000664000175000017500000001540714771010714022345 0ustar frankfrank#ifndef INCLUDED_SEMBASE_ #define INCLUDED_SEMBASE_ #include #include #include #include class SemBase; //TAG enum class Tag // defines the various semantic values { // Tags are used to instantiate the proper INT, // Semantic type, deriving from a polymorphic base TEXT, // class VECTOR, }; //= // In separate anonymous namespace sections parts of the various semantic // types are defined. Sections labeled 'IUO' are `Internal Use Only' and // contain no serviceable parts namespace { // IUO //MUTABLE struct Mutable // Semantic values may or may { // not be mutable. By deriving enum: bool { isMutable = true }; // BasicTrait, below, from }; // either Mutable or Immutable // this trait is associated with struct Immutable // a semantic value BasicTrait. { enum: bool { isMutable = false }; }; //= // For each semantic value type define a TagTrait specialization which // is either derived from Immutable (in which case the Parser cannot // change the semantic value) or from Mutable (In which case changing the // semantic value on the semantic value stack *is* allowed) // In addition, define the data type to use, as received in the // initialization (e.g., int, std::string, vector). //TRAITTAG template struct TagTrait; template <> struct TagTrait: public Immutable { using DataType = int; }; template <> struct TagTrait: public Immutable { using DataType = std::string; }; template <> struct TagTrait: public Mutable { using DataType = std::vector>; }; //= // In this section of the anonymous namespace it is determined whether a // semantic value type is a basic type (in which case the return type of // the Semantic class's conversion operator can be equal to the type // itself) or a class-type (in which case a reference is returned). /// Its logic is based on two function templates 'test' expecting either // any type of argument or expecting a pointer to a member function of the // type provided to the template. Since basic types have no members, the // `any argument' variant is selected by the compiler for basic // types. These two functions return values having different sizes, // allowing the template to determine whether the type is a basic type or // not. The enum value 'isBasicType' is initialized accordingly. /// For the ReturnType (i.e., the conversion operator's return type the // std::conditional template meta programming function is used). For a // mutable data type a reference to the Semantic class's data memebr is // returned, for an immutable basic data type a copy of the data member's // value is returned, otherwise a const & is returned. //CLASSTRAIT struct C2 { char _[2]; }; struct C1 { char _; }; template C1 test(...); template C2 test(void (T::*)()); template struct Trait: public TagTrait { using DataType = typename Trait::DataType; enum: bool { isMutable = Trait::isMutable, isBasicType = sizeof(test(0)) == sizeof(C1) }; using ReturnType = typename std::conditional< isMutable, DataType &, typename std::conditional< isBasicType, DataType, DataType const & >::type >::type; }; //= } /// The implementation of the polymorphic semantic value in fact implements // a type-safe polymorphic semantic union. This is a non-existing data // type in C++, but the parser may handle semantic values as unions: it // always knows the actual type of semantic value that's used at a // particular point in the grammar, and if not, it can inspect the // SemBase's tag fields. Since the parser knows, or can determine what the // actual semantic type is, it can always perform a downcast, resulting in // a *very* lightweight SemBase base class: there's only a virtual // destructor. No other virtual members are required. Downcasting itself // is encapsulated in its 'as' member, allowing constructions like /// $1->as() /// to downcast the $1 SemBase to a Semantic, and then, // usually by implication, to a std::string, using the Semantic's // conversion operator. //SEMBASE class SemBase { Tag d_tag; public: SemBase(SemBase const &other) = delete; virtual ~SemBase(); Tag tag() const; template typename Trait::ReturnType as() const; protected: SemBase(Tag tag); }; //= inline Tag SemBase::tag() const { return d_tag; } inline SemBase::SemBase(Tag tag) : d_tag(tag) {} // The Semantic class template is derived from SemBase. It always defines // its data member as mutable (I can't do this under template control, but // I could define, e.g., two anonymous structs holding, respectively, a // mutable and non-mutable DataType data member, but Semantic isn't doing // anything with d_data anyway, so by always declaring d_data as mutable // it can be returned from the conversion operator, which itself is a // const member. /// Again: Semantic is extremely light-weight. Only initialization and // conversion to the embedded data member need to be supported. //SEMANTIC template class Semantic: public SemBase { using DataType = typename Trait::DataType; enum: bool { isMutable = Trait::isMutable }; mutable DataType d_data; public: using ReturnType = typename Trait::ReturnType; Semantic(DataType const &data); operator ReturnType() const; }; template Semantic::Semantic(DataType const &data) : SemBase(tg_), d_data(data) {} template Semantic::operator ReturnType() const { return d_data; } //= // The 'as' member simply performs the required downcast. It is // implemented here, since it refers to Semantic. Since this class // has just been defined, no forward declaration is required anymore. //AS template inline typename Trait::ReturnType SemBase::as() const { return dynamic_cast const &>(*this); } //= #endif c++-annotations-13.02.01/yo/concrete/poly2/sembase/destructor.cc0000664000175000017500000000005514771010716023255 0ustar frankfrank#include "sembase.h" SemBase::~SemBase() {} c++-annotations-13.02.01/yo/concrete/poly2/main.cc0000664000175000017500000000011214771010716020356 0ustar frankfrank#include "main.ih" int main() { Parser parser; parser.parse(); } c++-annotations-13.02.01/yo/concrete/poly2/main.ih0000664000175000017500000000010214771010714020366 0ustar frankfrank#include #include #include "parser/parser.h" c++-annotations-13.02.01/yo/concrete/header.yo0000664000175000017500000000030214735537670017675 0ustar frankfrank Here is the specification of the header-section of our tt(bison++) specification file. Note the inclusion of the scanner's header file. verbinclude(-a parser/parser/gramspec/header.gr0) c++-annotations-13.02.01/yo/concrete/fdninbuf.yo0000664000175000017500000001024014735537670020242 0ustar frankfrank How complex would things get if we decided to use a buffer of substantial size? Not that complex. The following class allows us to specify the size of a buffer, but apart from that it is basically the same class as tt(IFdStreambuf) developed in the previous section. To make things a bit more interesting, in the class ti(IFdNStreambuf) developed here, the member hi(xsgetn)tt(streambuf::xsgetn) is also overridden, to optimize reading a series of characters. Also a default constructor is provided that can be used in combination with the tt(open) member to construct an tt(istream) object before the file descriptor becomes available. In that case, once the descriptor becomes available, the tt(open) member can be used to initiate the object's buffer. Later, in section ref(FORK), we'll encounter such a situation. To save some space, the success of various calls was not checked. In `real life' implementations, these checks should of course not be omitted. The class tt(IFdNStreambuf) has the following characteristics: itemization( it() Its member functions use low-level functions operating on file descriptors. So apart from tt(streambuf) the tthi(unistd.h) header file must have been read by the compiler before its member functions can be compiled. it() As usual, it is derived from hi(streambuf)tt(std::streambuf). it() Like the class tt(IFdStreambuf) (section ref(IFDBUF)), its data members are protected. Since the buffer's size is configurable, this size is kept in a dedicated data member, tt(d_bufsize): verbinclude(//CLASS examples/ifdnbuf.h) it() The default constructor does not allocate a buffer. It can be used to construct an object before the file descriptor becomes known. A second constructor simply passes its arguments to tt(open). tt(Open) will then initialize the object so that it can actually be used: verbinclude(//CONS examples/ifdnbuf.h) it() Once the object has been initialized by tt(open), its destructor will both delete the object's buffer and use the file descriptor to close the device: verbinclude(//DESTR examples/ifdnbuf.h) Even though the device is closed in the above implementation this may not always be desirable. In cases where the open file descriptor is already available the intention may be to use that descriptor repeatedly, each time using a newly constructed tt(IFdNStreambuf) object. It is left as an exercise to the reader to change this class in such a way that the device may optionally be closed. This approach was followed in, e.g., the url(Bobcat library)(http://fbb-git.gitlab.io/bobcat/). hi(Bobcat library)hi(http://fbb-git.gitlab.io/bobcat/) it() The tt(open) member simply allocates the object's buffer. It is assumed that the calling program has already opened the device. Once the buffer has been allocated, the base class member ti(setg) is used to ensure that hi(eback) tt(streambuf::eback) hi(gptr) tt(streambuf::gptr) and hi(egptr) tt(streambuf::egptr) return correct values: verbinclude(//OPEN examples/ifdnbuf.h) it() The overridden member tt(underflow) is implemented almost identically to tt(IFdStreambuf)'s (section ref(IFDBUF)) member. The only difference is that the current class supports buffers of larger sizes. Therefore, more characters (up to tt(d_bufsize)) may be read from the device at once: verbinclude(//UFLOW examples/ifdnbuf.h) it() Finally ti(xsgetn) is overridden. In a loop, tt(n) is reduced until 0, at which point the function terminates. Alternatively, the member returns if tt(underflow) fails to obtain more characters. This member optimizes the reading of series of characters. Instead of calling hi(sbumpc) tt(streambuf::sbumpc) tt(n) times, a block of tt(avail) characters is copied to the destination, using hi(gbump)tt(streambuf::gbump) to consume tt(avail) characters from the buffer using one function call: verbinclude(//XSGETN examples/ifdnbuf.h) ) The member function ti(xsgetn) is called by hi(sgetn)tt(streambuf::sgetn), which is a tt(streambuf) member. Here is an example illustrating the use of this member function with an tt(IFdNStreambuf) object: verbinclude(-a examples/ifdnbuf.cc) c++-annotations-13.02.01/yo/concrete/codegeneration.yo0000664000175000017500000000205214735537670021437 0ustar frankfrankThe calculator is built using tt(bisonc++) and tt(flexc++). Here is the implementation of the calculator's tt(main) function: verbinclude(-a bisonc++/calculator.cc) The parser's files tt(parse.cc) and tt(parserbase.h) are generated by the command: verb( bisonc++ grammar) The file tt(parser.h) is created only once, to allow the developer to add members to the tt(Parser) class occe the need for them arises. The program ti(flexc++) is used to create a lexical scanner: verb( flexc++ lexer) On i(Unix) systems a command like verb( g++ -Wall -o calc *.cc -lbobcat -s) can be used to compile and link the source of the main program and the sources produced by the scanner and parser generators. The example uses the tt(A2x) class, which is part of the ti(bobcat) library (cf. section ref(BUILDFLEX)) (the bobcat library is available on systems offering either tt(bisonc++) or tt(flexc++)). tt(Bisonc++) can be downloaded from hi(http://fbb-git.gitlab.io/bisoncpp/) tlurl(http://fbb-git.gitlab.io/bisoncpp/). c++-annotations-13.02.01/yo/concrete/sembase.yo0000664000175000017500000000226214735537670020073 0ustar frankfrankThe polymorphic semantic value in fact implements a type-safe hi(union: polymorphic) emi(polymorphic semantic union). In bf(C++) this data type does not exist, but the parser may handle semantic values as unions. It always knows the actual kind of semantic value that's used at a particular point in the grammar. If not, it can inspect tt(SemBase's) tag fields. The parser, knowing what the actual semantic type is, may then perform a i(downcast), resulting in a em(very) lightweight tt(SemBase) base class. The tt(SemBase) class only requires one virtual member: an empty virtual destructor. Downcasting is encapsulated in tt(SemBase)'s 'tt(as)' member. Consequently, the parser, defining its semantic value as an tt(spSembase) (i.e., a tt(shared_ptr) to a tt(Sembase), cf. section ref(BISONSEM)), can then use constructions like verb( $1->as()) to access the tt(std::string) that is stored in the actual semantic value to which tt($1) points. Here is tt(SemBase)'s class interface (the implementation of its `tt(as)' member template follows, implementations of its remaining members are trivial): verbinclude(//SEMBASE poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/operators.yo0000664000175000017500000000226414735537670020474 0ustar frankfrankIn section ref(OVERLOADBINARY) addition operators are implemented in terms of a support member tt(add). This is less attractive when developing function templates, as tt(add) is a private member, requiring us to provide friend declarations for all function templates so they may access the private tt(add) member. At the end of section ref(OVERLOADBINARY) we saw that tt(add's) implementation can be provided by tt(operator+=(Class const &rhs) &&). This operator may thereupon be used when implementing the remaining addition operators: verb( inline Binary &operator+=(Binary const &rhs) & { return *this = Binary{*this} += rhs; } Binary operator+(Binary &&lhs, Binary const &rhs) { return std::move(lhs) += rhs; } Binary operator+(Binary const &lhs, Binary const &rhs) { return Binary{lhs} += rhs; }) In this implementation tt(add) is no longer required. The plain binary operators are free functions, which supposedly can easily be converted to function templates. E.g., verb( template Binary operator+(Binary const &lhs, Binary const &rhs) { return Binary{lhs} += rhs; }) c++-annotations-13.02.01/yo/concrete/usingflex.yo0000664000175000017500000000400214735537670020452 0ustar frankfrankThe lexical scanner developed in this section is used to monitor the production of a file from several subfiles. The setup is as follows: the input-language defines tt(#include) directives, followed by a text string specifying the file (path) which should be included at the location of the tt(#include). In order to avoid complexities irrelevant to the current example, the format of the tt(#include) statement is restricted to the form tt(#include ). The file specified between the angle brackets should be available at the location indicated by tt(filepath). If the file is not available, the program terminates after issuing an error message. The program is started with one or two filename arguments. If the program is started with just one filename argument, the output is written to the standard output stream tt(cout). Otherwise, the output is written to the stream whose name is given as the program's second argument. The program defines a maximum i(nesting depth). Once this maximum is exceeded, the program terminates after issuing an error message. In that case, the filename stack indicating where which file was included is printed. An additional feature of the program is that (standard bf(C++)) comment-lines are ignored. Include-directives in comment-lines are also ignored. The program is created in five major steps: itemization( it() First, the file tt(lexer) is constructed, containing the input-language specifications. it() From the specifications in tt(lexer) the requirements for the tt(class Scanner) evolve. The tt(Scanner) class derives from the base class ti(ScannerBase) generated by ti(flexc++). it() Next, tt(main) is constructed. A tt(Scanner) object is created inspecting the command-line arguments. If successful, the scanner's member tt(lex) is called to produce the program's output. it() Now that the global setup of the program has been specified, the member functions of the various classes are implemented. it() Finally, the program is compiled and linked. ) c++-annotations-13.02.01/yo/concrete/semantic.yo0000664000175000017500000000221714735537670020257 0ustar frankfrankFinally we reach the class template tt(Semantic), publicly derived from tt(SemBase). This class template only requires one tt(Tag) non-type parameter, defining the kind of data that can be handled by objects of the class. Like tt(SemBase) the class tt(Semantic) is extremely light-weight. Only initialization and a conversion operator to the encapsulated data member must be supported. tt(Semantic) defines its data member as mutable, which is fine as the class itself doesn't manipulate its data, and proper access to the data is guaranteed by its tt(operator ReturnType() const) conversion operator. tt(ReturnType), of course, is obtained through the tt(Trait) trait class template. Here is the class's interface and member definitions: verbinclude(//SEMANTIC poly2/sembase/sembase.h) To access the information stored in a semantic value class the hi(as (SemBase::as)) tt(SemBase::as) member template is used. This member template is provided with a tag value and returns the value stored inside the actual tt(Semantic) object. Its use was shown in the previous section. Here is its implementation: verbinclude(//AS poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/tagtrait.yo0000664000175000017500000000072514735537670020275 0ustar frankfrankThe ti(TagTrait) trait class defines, for each of the distinct semantic values, what the actual data type (tt(DataType)) is that is associated with the tag and whether the data are mutable or immutable. Mutable data on the parser's semantic stack may be modified, immutable data may not. Here is the tt(TagTrait) meta template struct template and its specializations for the three data types used by our parser. verbinclude(//TRAITTAG poly2/sembase/sembase.h) c++-annotations-13.02.01/yo/concrete/bisonflexspec.yo0000664000175000017500000000067314735537670021324 0ustar frankfrank The flex-specification file used by the calculator is simple: blanks are ignored, single characters are returned, and numeric values are returned as either tt(Parser::INT) or tt(Parser::DOUBLE) tokens. The tt(flexc++) directive tt(%interactive) is provided since the calculator is a program actively interacting with its human user. Here is the complete tt(flexc++) specification file: verbinclude(-a bisonc++/scanner/lexer) c++-annotations-13.02.01/yo/concrete/parser.yo0000664000175000017500000000314714735537670017753 0ustar frankfrankAs noted in the previous section, Bisonc++'s grammar specification declares tt(%stype), the semantic value type, as tt(spSembase). A simple grammar is defined for this illustrative example. The grammar expects input according to the following rule: verb( rule: IDENTIFIER '(' IDENTIFIER ')' ';' | IDENTIFIER '=' INT ';' ;) The rule's actions simply echo the received identifiers and tt(int) values to tt(cout). Here is an example of a decorated production rule, where due to tt(Semantic)'s overloaded insertion operator the insertion of the object controlled by tt(Semantic) is automatically performed: verb( IDENTIFIER '=' INT ';' { cout << $1 << " " << $3 << '\n'; }) Bisonc++'s parser stores em(all) semantic values on its semantic values stack (irrespective of the number of tokens that were defined in a particular production rule). At any time em(all) semantic values associated with previously recognized tokens are available in an action block. Once the semantic value stack is reduced, the tt(Semantic) class's destructor takes care of the proper destruction of the objects controlled by its tt(shared_ptr) base class. In order to assign the parser's latest semantic value, the scanner is given access to that data member, which is the parser's data member tt(d_val__). Its address or reference can be passed to the scanner when it is constructed. E.g., if the scanner's constructor expects an tt(STYPE__ &) argument, then the parser's constructor could simply be implemented as: verb( inline Parser::Parser() : d_scanner(d_val__) {}) c++-annotations-13.02.01/yo/concrete/parents.yo0000664000175000017500000000610414735537670020127 0ustar frankfrank The member function tt(fork) calls the system function tt(fork) (Caution: since the system function tt(fork) is called by a member function having the same name, the tt(::) scope resolution operator must be used to prevent a recursive call of the member function itself). The function tt(::fork)'s return value determines whether tt(parentProcess) or tt(childProcess) is called. Maybe redirection is necessary. tt(Fork::fork)'s implementation calls tt(childRedirections) just before calling tt(childProcess), and tt(parentRedirections) just before calling tt(parentProcess): verbinclude(-a examples/fork.cc) In tt(fork.cc) the class's em(internal header file)hi(internal header) tt(fork.ih) is included. This header file takes care of the inclusion of the necessary system header files, as well as the inclusion of tt(fork.h) itself. Its implementation is: verbinclude(-a examples/fork.ih) Child processes should not return: once they have completed their tasks, they should terminate. This happens automatically when the child process performs a call to a member of the ti(exec...) family, but if the child itself remains active, then it must make sure that it terminates properly. A child process normally uses ti(exit) to terminate itself, but note that tt(exit) prevents the activation of destructors of objects hi(destructor: called at exit) hi(exit: calling destructors) defined at the same or more superficial nesting levels than the level at which tt(exit) is called. Destructors of globally defined objects em(are) activated when tt(exit) is used. When using tt(exit) to terminate tt(childProcess), it should either itself call a support member function defining all nested objects it needs, or it should define all its objects in a compound statement (e.g., using a tt(throw) block) calling tt(exit) beyond the compound statement. Parent processes should normally wait for their children to complete. Terminating child processes inform their parents that they are about to terminate by sending a emi(signal) that should be caught by their parents. If child processes terminate and their parent processes do not catch those signals then such child processes remain visible as so-called emi(zombie) processes. If parent processes must wait for their children to complete, they may call the member tt(waitForChild). This member returns the exit status of a child process to its parent. There exists a situation where the em(child) process em(continues) to live, but the em(parent) dies. This is a fairly natural event: parents tend to die before their children do. In our context (i.e. bf(C++)), this is called a emi(daemon) program. In a daemon the parent process dies and the child program continues to run as a child of the basic ti(init) process. Again, when the child eventually dies a signal is sent to its `step-parent' ti(init). This does not create a zombie as tt(init) catches the termination signals of all its (step-) children. The construction of a daemon process is very simple, given the availability of the class tt(Fork) (cf. section ref(DAEMON)). c++-annotations-13.02.01/yo/concrete/bisonc++/0000775000175000017500000000000014771010711017462 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/bisonc++/build0000775000175000017500000000111514735537670020527 0ustar frankfrank#!/bin/bash case "$1" in ("") echo " usage: 'build prog' to build the program, 'build clean' to cleanup " exit 1 ;; (prog) cd parser bisonc++ grammar || exit 1 cd ../scanner flexc++ lexer || exit 1 cd .. g++ -Wall -ocalc *.cc */*.cc -lbobcat || exit 1 echo " ready; run the program as './calc' " ;; (clean) rm -f calc cd parser rm -f parse.cc parserbase.h cd ../scanner rm -f lex.cc scannerbase.h echo " done " ;; esac exit 1 c++-annotations-13.02.01/yo/concrete/bisonc++/parser/0000775000175000017500000000000014771010711020756 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/bisonc++/parser/parser.h0000664000175000017500000000307714771010714022435 0ustar frankfrank#ifndef Parser_h_included #define Parser_h_included #include #include #include #include "parserbase.h" #include "../scanner/scanner.h" #undef Parser class Parser: public ParserBase { std::ostringstream d_rpn; // $insert scannerobject Scanner d_scanner; public: int parse(); private: template Type exec(char c, Type left, Type right); template Type neg(Type op); template Type convert(); void display(int x); void display(double x); void done() const; void reset(); void error(char const *msg); int lex(); void print(); static double d(int i); // support functions for parse(): void executeAction(int d_ruleNr); void errorRecovery(); int lookup(bool recovery); void nextToken(); void print__(); }; inline double Parser::d(int i) { return i; } template Type Parser::exec(char c, Type left, Type right) { d_rpn << " " << c << " "; return c == '*' ? left * right : left + right; } template Type Parser::neg(Type op) { d_rpn << " n "; return -op; } template Type Parser::convert() { Type ret = FBB::A2x(d_scanner.matched()); d_rpn << " " << ret << " "; return ret; } inline void Parser::error(char const *msg) { std::cerr << msg << '\n'; } inline int Parser::lex() { return d_scanner.lex(); } inline void Parser::print() {} #endif c++-annotations-13.02.01/yo/concrete/bisonc++/parser/display1.cc0000664000175000017500000000023014771010716023013 0ustar frankfrank#include "parser.ih" void Parser::display(int x) { cerr << "RPN: " << d_rpn.str() << '\n'; cerr << "int: " << x << '\n'; d_rpn.str(""s); } c++-annotations-13.02.01/yo/concrete/bisonc++/parser/display2.cc0000664000175000017500000000023614771010716023022 0ustar frankfrank#include "parser.ih" void Parser::display(double x) { cerr << "RPN: " << d_rpn.str() << '\n'; cerr << "double: " << x << '\n'; d_rpn.str(""s); } c++-annotations-13.02.01/yo/concrete/bisonc++/parser/reset.cc0000664000175000017500000000012614771010716022413 0ustar frankfrank#include "parser.ih" void Parser::reset() { d_rpn.clear(); d_rpn.str(""s); } c++-annotations-13.02.01/yo/concrete/bisonc++/parser/parser.ih0000664000175000017500000000055114771010714022600 0ustar frankfrank// include this file in the sources of the class Parser, // and add any includes etc. that are only needed for // the compilation of these sources. // include the file defining the parser class: #include "parser.h" #include #include #include using FBB::A2x; using std::string; using std::cerr; using std::cout; using std::endl; c++-annotations-13.02.01/yo/concrete/bisonc++/parser/grammar0000664000175000017500000000352414735537670022355 0ustar frankfrank//DECLARATION %filenames parser %scanner ../scanner/scanner.h %union { int i; double d; }; %token INT DOUBLE %type intExpr %type doubleExpr %left '+' %left '*' %right UnaryMinus //= %% //RULES lines: lines line | line ; line: intExpr '\n' { display($1); } | doubleExpr '\n' { display($1); } | '\n' { done(); } | error '\n' { reset(); } ; intExpr: intExpr '*' intExpr { $$ = exec('*', $1, $3); } | intExpr '+' intExpr { $$ = exec('+', $1, $3); } | '(' intExpr ')' { $$ = $2; } | '-' intExpr %prec UnaryMinus { $$ = neg($2); } | INT { $$ = convert(); } ; doubleExpr: doubleExpr '*' doubleExpr { $$ = exec('*', $1, $3); } | doubleExpr '*' intExpr { $$ = exec('*', $1, d($3)); } | intExpr '*' doubleExpr { $$ = exec('*', d($1), $3); } | doubleExpr '+' doubleExpr { $$ = exec('+', $1, $3); } | doubleExpr '+' intExpr { $$ = exec('+', $1, d($3)); } | intExpr '+' doubleExpr { $$ = exec('+', d($1), $3); } | '(' doubleExpr ')' { $$ = $2; } | '-' doubleExpr %prec UnaryMinus { $$ = neg($2); } | DOUBLE { $$ = convert(); } ; //= c++-annotations-13.02.01/yo/concrete/bisonc++/parser/done.cc0000664000175000017500000000013414771010716022215 0ustar frankfrank#include "parser.ih" void Parser::done() const { cout << "Good bye\n"; ACCEPT(); } c++-annotations-13.02.01/yo/concrete/bisonc++/scanner/0000775000175000017500000000000014771010710021112 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/bisonc++/scanner/scanner.ih0000664000175000017500000000011514771010714023066 0ustar frankfrank#include "scanner.h" #include "../parser/parserbase.h" // end of scanner.ih c++-annotations-13.02.01/yo/concrete/bisonc++/scanner/scanner.h0000664000175000017500000000170014771010714022716 0ustar frankfrank// Generated by Flexc++ V0.94.00 on Fri, 24 Feb 2012 10:34:13 +0100 #ifndef Scanner_H_INCLUDED_ #define Scanner_H_INCLUDED_ // $insert baseclass_h #include "scannerbase.h" // $insert classHead class Scanner: public ScannerBase { public: explicit Scanner(std::istream &in = std::cin, std::ostream &out = std::cout); // $insert lexFunctionDecl int lex(); private: int lex__(); int executeAction__(size_t ruleNr); void print(); void preCode(); // re-implement this function for code that must // be exec'ed before the patternmatching starts }; // $insert scannerConstructors inline Scanner::Scanner(std::istream &in, std::ostream &out) : ScannerBase(in, out) {} inline void Scanner::preCode() { // optionally replace by your own code } inline void Scanner::print() { print__(); } #endif // Scanner_H_INCLUDED_ c++-annotations-13.02.01/yo/concrete/bisonc++/scanner/lexer0000664000175000017500000000040114735537670022172 0ustar frankfrank%interactive %filenames scanner %% [ \t] // ignored [0-9]+ return Parser::INT; "."[0-9]+ | [0-9]+"."[0-9]* return Parser::DOUBLE; .|\n return matched()[0]; c++-annotations-13.02.01/yo/concrete/bisonc++/calculator.cc0000664000175000017500000000041714771010716022131 0ustar frankfrank#include "parser/parser.h" using namespace std; int main() { Parser parser; cout << "Enter (nested) expressions containing ints, doubles, *, + and " "unary -\n" "operators. Enter an empty line to stop.\n"; return parser.parse(); } c++-annotations-13.02.01/yo/concrete/daemon.yo0000664000175000017500000000221014735537670017710 0ustar frankfrank Applications exist in which the only purpose of ti(fork) is to start a child process. The parent process terminates immediately after spawning the child process. If this happens, the child process continues to run as a child process of ti(init), the always running first process on i(Unix) systems. Such a process is often called a emi(daemon), running as a i(background process). Although the next example can easily be constructed as a plain bf(C) program, it was included in the bf(C++) Annotations because it is so closely related to the current discussion of the tt(Fork) class. I thought about adding a tt(daemon) member to that class, but eventually decided against it because the construction of a daemon program is very simple and requires no features other than those currently offered by the class tt(Fork). Here is an example illustrating the construction of such a daemon program. Its child process doesn't do ti(exit) but tt(throw 0) which is caught by the tt(catch) clause of the child's tt(main) function. Doing this ensures that any objects defined by the child process are properly destroyed: verbinclude(-a examples/daemon.cc) c++-annotations-13.02.01/yo/concrete/redirection.yo0000664000175000017500000000315014735537670020760 0ustar frankfrank Earlier, in section ref(REDIR) streams were hi(redirection) redirected using the hi(rdbuf)tt(ios::rdbuf) member function. By assigning the tt(streambuf) of a stream to another stream, both stream objects access the same tt(streambuf), thus implementing redirection at the level of the programming language itself. This may be fine within the context of a bf(C++) program, but once we leave that context the redirection terminates. The operating system does not know about tt(streambuf) objects. This situation is encountered, e.g., when a program uses a ti(system) call to start a subprogram. The example program at the end of this section uses bf(C++) redirection to redirect the information inserted into ti(cout) to a file, and then calls verb( system("echo hello world")) to echo a well-known line of text. Since tt(echo) writes its information to the standard output, this would be the program's redirected file if the operating system would recognize bf(C++)'s redirection. But redirection doesn't happen. Instead, tt(hello world) still appears at the program's standard output and the redirected file is left untouched. To write tt(hello world) to the redirected file redirection must be realized at the operating system level. Some operating systems (e.g., i(Unix) and friends) provide system calls like ti(dup) and ti(dup2) to accomplish this. Examples of the use of these system calls are given in section ref(PIPE). Here is the example of the em(failing redirection) at the system level following bf(C++) redirection using tt(streambuf) redirection: verbinclude(-a examples/noredir.cc) c++-annotations-13.02.01/yo/concrete/scancompile.yo0000664000175000017500000000125014735537670020745 0ustar frankfrank The final program is constructed in two steps. These steps are given for a i(Unix) system, on which ti(flexc++) and the i(GNU) bf(C++) compiler ti(g++) have been installed: itemization( it() First, the lexical scanner's source is created using tt(flexc++). For this the following command can be given: verb( flexc++ lexer) it() Next, all sources are compiled and linked: verb( g++ -Wall *.cc) ) tt(Flexc++) can be downloaded from hi(https://fbb-git.gitlab.io/flexcpp/) tlurl(https://fbb-git.gitlab.io/flexcpp/), and requires the ti(bobcat) library, which can be downloaded from tlurl(http://fbb-git.gitlab.io/bobcat/). c++-annotations-13.02.01/yo/concrete/fdinseek.yo0000664000175000017500000000516614735537670020252 0ustar frankfrank When devices support em(seek operations), classes derived from hi(streambuf) tt(std::streambuf) should override the members hi(seekoff) tt(streambuf::seekoff) and hi(seekpos)tt(streambuf::seekpos). The class ti(IFdSeek), developed in this section, can be used to read information from devices supporting seek operations. The class tt(IFdSeek) was derived from tt(IFdStreambuf), so it uses a character buffer of just one character. The facilities to perform seek operations, which are added to our new class tt(IFdSeek), ensure that the input buffer is reset when a seek operation is requested. The class could also be derived from the class tt(IFdNStreambuf). In that case the arguments to reset the input buffer must be adapted so that its second and third parameters point beyond the available input buffer. Let's have a look at the characteristics of tt(IFdSeek): itemization( it() As mentioned, tt(IFdSeek) is derived from tt(IFdStreambuf). Like the latter class, tt(IFdSeek)'s member functions use facilities declared in tt(unistd.h). So, the header file tthi(unistd.h) must have been read by the compiler before it can compile the class's members functions. To reduce the amount of typing when specifying types and constants from tt(streambuf) and hi(ios)tt(std::ios), several using-declarations are defined by the class. These using-declarations refer to types that are defined in the header file tthi(ios), which must therefore also be included before the compiler can compile tt(IFdSeek)'s class interface: verbinclude(//CLASS examples/fdinseek.h) it() The class has a very basic interface. Its (only) constructor expects the device's i(file descriptor). It has no special tasks to perform and just calls its i(base class) constructor: verbinclude(//CONS examples/fdinseek.h) it() The member ti(seek_off) is responsible for performing the actual seek operations. It calls ti(lseek) to seek a new position in a device whose file descriptor is known. If seeking succeeds, ti(setg) is called to define an already empty buffer, so that the base class's tt(underflow) member refills the buffer at the next input request. verbinclude(//SEEKOFF examples/fdinseek.h) it() Finally, the companion function ti(seekpos) is overridden as well: it is actually defined as a call to tt(seekoff): verbinclude(//SEEKPOS examples/fdinseek.h) ) Here is an example of a program using the class tt(IFdSeek). If this program is given its own source file using input redirection then seeking is supported (and with the exception of the first line, every other line is shown twice): verbinclude(-a examples/fdinseek.cc) c++-annotations-13.02.01/yo/concrete/lvalues/0000775000175000017500000000000014771010711017532 5ustar frankfrankc++-annotations-13.02.01/yo/concrete/lvalues/lvalues.cc0000664000175000017500000001121014771010716021514 0ustar frankfrank#include #include using namespace std; class Data { friend class Wrapper; // Our Wrapper class is allowed to access our data // too. vector d_v; // here are Data's data public: class Wrapper { Data & d_data; size_t d_index; public: // For all situations in which data[x] is used as lvalue, // an operator must be defined accepting data[x] as lvalue and // all acceptable types as rvalue. Here I've defined two, but // generalizations are straightforward: Wrapper &operator=(Wrapper const &other); // Use our (*this) data as lvalue, the other's data as // rvalue. This is just one situation where our data are // used as lvalue. If data[x] += data[y] is needed too, // then that operator must be defined as well. Wrapper &operator=(int value); // Our data as lvalue. This again is but one example. To // implement data[x] += y etc, those operators must be // overloaded too. // There's only one situation where data[x] is used as rvalue: // when it's returning its data[x] element. This is // accomplished by defining the appropriate conversion // operator: operator int() const; // Our data as rvalue. Can't use things like int &n = // data[3] or int *p = &data[3] here, because the data[3] // expression is parsed as an rvalue, returning an int (in // this case). so if you want to use that, define an // explicit reference and/or pointer returning member, // like int &n = data.ref(3). private: // nobody but Data has anything to do with Wrapper's // constructor so it's made private, declaring Data as its // friend. friend class Data; Wrapper(Data &data, size_t index); }; Data(); int operator[](size_t index) const; // Always rvalue: operator[] of const objects Wrapper operator[](size_t index); // With non-const objects: the Wrapper is returned, to which // a value can be assigned, in which case it's is an lvalue, or // whose value can be requested, in which case the int-conversion // operator is called. }; // I've defined all members inline, although you shouldn't do so in real life. inline Data::Wrapper &Data::Wrapper::operator=(Wrapper const &other) { cout << "data[x] = data[y], lvalue = rvalue\n"; d_data.d_v[d_index] = other.d_data.d_v[other.d_index]; cout << "assignment performed\n"; return *this; } inline Data::Wrapper &Data::Wrapper::operator=(int value) { cout << "data[x] = y, lvalue = expression\n"; d_data.d_v[d_index] = value; return *this; } inline Data::Wrapper::operator int() const { cout << "using the conversion operator, " "returning an rvalue\n"; return d_data.d_v[d_index]; } inline Data::Wrapper::Wrapper(Data &data, size_t index) : d_data(data), d_index(index) {} inline Data::Data() : d_v(5) { for (size_t idx = 0; idx < 5; ++idx) // assign some values d_v[idx] = 2 * idx; } inline int Data::operator[](size_t index) const { cout << "rvalue-only from const object\n"; return d_v[index]; } inline Data::Wrapper Data::operator[](size_t index) { return Wrapper(*this, index); } int main() { Data test; // a non-const object Data const testConst; // a const object (normally via, e.g., a // 'Data const &' parameter // insert some (r)values: cout << "Inserting rvalues:\n" << test[1] << " " << test[2] << "\n\n"; cout << "data[x] to data[y] assignment:\n"; test[1] = test[2]; cout << "Resulting in: " << test[1] << " " << test[2] << "\n\n"; cout << "Assignment from testConst:\n"; test[1] = testConst[4]; cout << "Resulting in: " << test[1] << "\n\n"; cout << "Direct assignment to test[0] (now " << test[0] << ") as an lvalue:\n"; test[0] = 11; cout << "Resulting in: " << test[0] << "\n\n"; cout << "Using test[1] (= " << test[1] << " + 2) in an expression as rvalue\n"; int n = test[1] + 2; } c++-annotations-13.02.01/yo/concrete/shandler.yo0000664000175000017500000000364214735537670020257 0ustar frankfrankThe array tt(s_handler), storing pointers to functions needs to be initialized as well. This can be accomplished in several ways: itemization( it() Since the tt(Commands) enumeration only specifies a fairly limited set of commands, compile-time initialization could be considered: verbinclude(//HANDLER examples/monitor/data.compiletime) The advantage of this is that it's simple, not requiring any run-time effort. The disadvantage is of course relatively complex maintenance. If for some reason tt(Commands) is modified, tt(s_handler) must be modified as well. In cases like these, compile-time initialization often is asking for trouble. There is a simple alternative though. it() Looking at tt(Monitor)'s interface we see a static data member tt(s_initialize) and a static member function tt(initialize). The static member function handles the initialization of the tt(s_handler) array. It explicitly assigns the array's elements and any modification in ordering of tt(enum Commands)' values is automatically accounted for by recompiling tt(initialize): verbinclude(//INIT examples/monitor/monitor.cc) The member tt(initialize) is a static member and so it can be called to initialize tt(s_initialize), a static tt(int) variable. The initialization is enforced by placing the initialization statement in the source file of a function that is known to be executed. It could be tt(main), but if we're tt(Monitor)'s maintainers and only have control over the library containing tt(Monitor)'s code then that's not an option. In those cases the source file containing the destructor is a em(very) good candidate. If a class has only one constructor and it's em(not) defined inline then the constructor's source file is a good candidate as well. In tt(Monitor)'s current implementation the initialization statement is put in tt(run)'s source file, reasoning that tt(s_handler) is only needed when tt(run) is used. ) c++-annotations-13.02.01/yo/concrete/iterators.yo0000664000175000017500000001117214735537670020470 0ustar frankfrankIn section ref(RANDOMIT) the construction of iterators and reverse iterators was discussed. In that section the iterator was constructed as an inner class in a class derived from a vector of pointers to strings. An object of this nested iterator class handles the dereferencing of the pointers stored in the vector. This allowed us to sort the em(strings) pointed to by the vector's elements rather than the em(pointers). A drawback of this is that the class implementing the iterator is closely tied to the derived class as the iterator class was implemented as a nested class. What if we would like to provide any class derived from a container class storing pointers with an iterator handling pointer-dereferencing? In this section a variant of the earlier (nested class) approach is discussed. Here the iterator class is defined as a class template, hi(iterator: as class template) not only parameterizing the data type to which the container's elements point but also the container's iterator type itself. Once again, we concentrate on developing a emi(RandomIterator) as it is the most complex iterator type. Our class is named tt(RandomPtrIterator), indicating that it is a random iterator operating on pointer values. The class template defines three template type parameters: itemization( it() The first parameter specifies the derived class type (tt(Class)). Like before, tt(RandomPtrIterator)'s constructor is private. Therefore tt(friend) declarations are needed to allow client classes to construct tt(RandomPtrIterators). However, a tt(friend class Class) cannot be used as template parameter types cannot be hi(friend: using a template parameter) used in tt(friend class ...) declarations. But this is a minor problem as not every member of the client class needs to construct iterators. In fact, only tt(Class)'s tt(begin) and tt(end) members must construct iterators. Using the template's first parameter, friend declarations can be specified for the client's tt(begin) and tt(end) members. it() The second template parameter parameterizes the container's iterator type (tt(BaseIterator)); it() The third template parameter indicates the data type to which the pointers point (tt(Type)). ) tt(RandomPtrIterator) has one private data member, a tt(BaseIterator). Here is the class interface and the constructor's implementation: verbinclude(//HEAD examples/stringptrs/iterator.h) Looking at its tt(friend) declarations, we see that the members tt(begin) and tt(end) of a class tt(Class), returning a tt(RandomPtrIterator) object for the types tt(Class, BaseIterator) and tt(Type) are granted access to tt(RandomPtrIterator)'s private constructor. That is exactly what we want. The tt(Class)'s tt(begin) and tt(end) members are declared as em(bound friends). All tt(RandomPtrIterator)'s remaining members are public. Since tt(RandomPtrIterator) is just a generalization of the nested class tt(iterator) developed in section ref(RANDOMIT), re-implementing the required member functions is easy and only requires us to change tt(iterator) into tt(RandomPtrIterator) and to change tt(std::string) into tt(Type). For example, tt(operator<), defined in the class tt(iterator) as verbinclude(//CMP ../classtemplates/examples/stringptrs/stringptr.h) is now implemented as: verbinclude(//CMP examples/stringptrs/iterator.h) Some additional examples: tt(operator*), defined in the class tt(iterator) as verbinclude(//OP* ../classtemplates/examples/stringptrs/stringptr.h) is now implemented as: verbinclude(//OP* examples/stringptrs/iterator.h) The pre- and postfix increment operators are now implemented as: verbinclude(//INC examples/stringptrs/iterator.h) Remaining members can be implemented accordingly, their actual implementations are left as exercises to the reader (or can be obtained from the tt(cplusplus.yo.zip) archive, of course). Re-implementing the class tt(StringPtr) developed in section ref(RANDOMIT) is not difficult either. Apart from including the header file defining the class template tt(RandomPtrIterator), it only requires a single modification. Its tt(iterator) using-declaration must now be associated with a tt(RandomPtrIterator). Here is the full class interface and the class's inline member definitions: verbinclude(-a examples/stringptrs/stringptr.h) Including tt(StringPtr)'s modified header file into the program given in section ref(REVERSEIT) results in a program behaving identically to its earlier version. In this case tt(StringPtr::begin) and tt(StringPtr::end) return iterator objects constructed from a template definition. c++-annotations-13.02.01/yo/concrete/fdinbuf.yo0000664000175000017500000000414514735537670020073 0ustar frankfrank When deriving a class (e.g., ti(IFdStreambuf)) from tt(streambuf) using a buffer of one character, at least its member hi(underflow) tt(streambuf::underflow) should be overridden, as this member eventually receives all requests for input. The member hi(setg) tt(streambuf::setg) is used to inform the tt(streambuf) base class of the size and location of the input buffer, so that it is able to set up its input buffer pointers accordingly. This ensures that hi(eback) tt(streambuf::eback), hi(gptr) tt(streambuf::gptr), and hi(egptr) tt(streambuf::egptr) return correct values. The class tt(IFdStreambuf) is designed like this: itemization( it() Its member functions use low-level functions operating on file descriptors. Therefore, in addition to tt(streambuf), the tthi(unistd.h) header file must have been read by the compiler before its member functions can be compiled. it() Like most classes designed for input operations, this class is derived from hi(streambuf)tt(std::streambuf) as well. it() The class defines two data members, one of them a fixed-sized one character buffer. The data members are defined as ti(protected) data members so that derived classes (e.g., see section ref(IFDSEEK)) can access them. Here is the full class interface: verbinclude(//CLASS examples/ifdbuf.h) it() The constructor initializes the buffer. However, the initialization sets ti(gptr)'s return value equal to ti(egptr)'s return value. This implies that the buffer is empty so tt(underflow) is immediately called to fill the buffer: verbinclude(//CONS examples/ifdbuf.h) it() Finally tt(underflow) is overridden. The buffer is refilled by reading from the file descriptor. If this fails (for whatever reason), endOfFile() is returned. More sophisticated implementations could act more intelligently here, of course. If the buffer could be refilled, ti(setg) is called to set up tt(streambuf)'s buffer pointers correctly: verbinclude(//UFLOW examples/ifdbuf.h) ) The following tt(main) function shows how tt(IFdStreambuf) can be used: verbinclude(//MAIN examples/ifdbuf.cc) c++-annotations-13.02.01/yo/concrete/semscanner.yo0000664000175000017500000000042314735537670020607 0ustar frankfrankThe scanner for the polymorphic parser is simple and only needs to recognize numbers, identifiers and some simple characters, returned as character tokens. Here is the scanner's complete specification file, as used by ti(flexc++): verbinclude(-a poly2/scanner/lexer) c++-annotations-13.02.01/yo/inheritance.yo0000664000175000017500000000310514735537670017140 0ustar frankfrankincludefile(inheritance/intro) lsect(VehicleSystem)(Related types) includefile(inheritance/related) subsect(Inheritance depth: desirable?) includefile(inheritance/depth) sect(Access rights: public, private, protected) includefile(inheritance/accessrights) lsubsect(DERIVATIONTYPES)(Public, protected and private derivation) includefile(inheritance/derivationtypes) lsubsect(ACCESSPROMOTION)(Promoting access rights) includefile(inheritance/accessprom) sect(The constructor of a derived class) includefile(inheritance/constructor) subsect(Move construction) includefile(inheritance/move) subsect(Move assignment) includefile(inheritance/assignment) lsubsect(BASECONS)(Inheriting constructors) includefile(inheritance/usingbase) subsect(Aggregate Initializations) includefile(inheritance/aggregate) sect(The destructor of a derived class) includefile(inheritance/destructor) lsect(Truck)(Redefining member functions) includefile(inheritance/redefining) lsect(MULTIPLE)(Multiple inheritance) includefile(inheritance/multiple) sect(Conversions between base classes and derived classes) includefile(inheritance/conversions) subsect(Conversions with object assignments) includefile(inheritance/objectconv) subsect(Conversions with pointer assignments) includefile(inheritance/pointerconv) lsect(NONDEFINIT)(Using non-default constructors with new[]) includefile(inheritance/nondefault) c++-annotations-13.02.01/yo/first/0000775000175000017500000000000014735537670015426 5ustar frankfrankc++-annotations-13.02.01/yo/first/rawstring.yo0000664000175000017500000000640314735537670020022 0ustar frankfrankStandard series of ASCII characters (a.k.a. emi(C strings)) are delimited by double quotes, supporting hi(escape sequence) escape sequences like tt(\n, \\) and tt(\"), and ending in 0-bytes. Such series of ASCII-characters are commonly known as em(null-terminated byte strings) (singular: emi(NTBS), plural: em(NTBSs)). bf(C)'s NTBS is the foundation upon which an enormous amount of code has been built In some cases it is attractive to be able to avoid having to use escape sequences (e.g., in the context of XML). bf(C++) allows this using hi(raw string literal) em(raw string literals). Raw string literals start with an tt(R), followed by a double quote, optionally followed by a label (which is an arbitrary sequence of non-blank characters, followed by tt(OPENPAR)). The raw string ends at the closing parenthesis tt(CLOSEPAR), followed by the label (if specified when starting the raw string literal), which is in turn followed by a double quote. Here are some examples: verb( R"(A Raw \ "String")" R"delimiter(Another \ Raw "(String))delimiter") In the first case, everything between tt("OPENPAR) and tt(CLOSEPAR") is part of the string. Escape sequences aren't supported so the text tt(\ ") within the first raw string literal defines three characters: a backslash, a blank character and a double quote. The second example shows a raw string defined between the markers tt("delimiter)tt(OPENPAR) and tt(CLOSEPARdelimiter"). Raw string literals come in very handy when long, complex ascii-character sequences (e.g., usage-info or long html-sequences) are used. In the end they are just that: long NTBSs. Those long raw string literals should be separated from the code that uses them, thus maintaining the readability of the using code. As an illustration: the bf(bisonc++) parser generator supports an option tt(--prompt). When specified, the code generated by bf(bisonc++) inserts prompting code when debugging is requested. Directly inserting the raw string literal into the function processing the prompting code results in code that is very hard to read: verb( void prompt(ostream &out) { if (d_genDebug) out << (d_options.prompt() ? R"( if (d_debug__) { s_out__ << "\n================\n" "? " << dflush__; std::string s; getline(std::cin, s); } )" : R"( if (d_debug__) s_out__ << '\n'; )" ) << '\n'; }) Readability is greatly enhanced by defining the raw string literals as named NTBSs, defined in the source file's anonymous namespace (cf. chapter ref(NAMESPACE)): verb( namespace { char const noPrompt[] = R"( if (d_debug__) s_out__ << '\n'; )"; char const doPrompt[] = R"( if (d_debug__) { s_out__ << "\n================\n" "? " << dflush__; std::string s; getline(std::cin, s); } )"; } // anonymous namespace void prompt(ostream &out) { if (d_genDebug) out << (d_options.prompt() ? doPrompt : noPrompt) << '\n'; }) c++-annotations-13.02.01/yo/first/unicode.yo0000664000175000017500000000234014735537670017424 0ustar frankfrankIn bf(C++) string literals can be defined as NTBSs. Prepending an NTBS by tt(L) (e.g., tt(L"hello")) defines a tt(wchar_t) string literal. bf(C++) also supports 8, 16 and 32 bit i(Unicode) encoded strings. Furthermore, two new data types are introduced: tt(char16_t) and tt(char32_t) storing, respectively, a ti(UTF-16) and a ti(UTF-32) unicode value. A tt(char) type value fits in a tt(utf_8) unicode value. For character sets exceeding 256 different values wider types (like tt(char16_t) or tt(char32_t)) should be used. String literals for the various types of unicode encodings (and associated variables) can be defined as follows: verb( char utf_8[] = u8"This is UTF-8 encoded."; char16_t utf16[] = u"This is UTF-16 encoded."; char32_t utf32[] = U"This is UTF-32 encoded.";) Alternatively, unicode constants may be defined using the ti(\u) escape sequence, followed by a hexadecimal value. Depending on the type of the unicode variable (or constant) a tt(UTF-8, UTF-16) or tt(UTF-32) value is used. E.g., verb( char utf_8[] = u8"\u2018"; char16_t utf16[] = u"\u2018"; char32_t utf32[] = U"\u2018";) Unicode strings can be delimited by double quotes but raw string literals can also be used. c++-annotations-13.02.01/yo/first/extensions.yo0000664000175000017500000000043414735537670020177 0ustar frankfrankBefore we continue with the `real' object-approach to programming, we first introduce some notable differences with the bf(C) programming language: not mere differences between bf(C) and bf(C++), but important syntactic constructs and keywords not found or differently used in bf(C). c++-annotations-13.02.01/yo/first/examples/0000775000175000017500000000000014771010712017223 5ustar frankfrankc++-annotations-13.02.01/yo/first/examples/bindings.cc0000664000175000017500000000145714771010717021343 0ustar frankfrank#include #include using namespace std; struct Fails { int d_int = 0; double d_double = 0; int (*d_is)(int) = isalnum; private: int d_private; }; struct Data { int d_int = 0; double d_double = 0; int (*d_is)(int) = isalnum; }; int main() { Fails fails; // auto &[i, d, fun, priv] = fails; // won't compile: d_private // is inaccessible // auto &[i, d, fun] = fails; // won't compile: not all of Fails's // members are used Data data; auto &[i, d, fun] = data; // OK // d_int modified through ++i cout << ++i << ' ' << data.d_int << ' ' << fun('a') << ' ' << fun(',') << '\n'; } c++-annotations-13.02.01/yo/first/examples/initializer.cc0000664000175000017500000000045214771010717022063 0ustar frankfrank#include using namespace std; void values(std::initializer_list iniValues) { } void values2(std::initializer_list> iniValues) { } int main() { values({2, 3, 5, 7, 11, 13}); values2({{1, 2}, {2, 3}, {3, 5}, {4, 7}, {5, 11}, {6, 13}}); } c++-annotations-13.02.01/yo/first/examples/rvalueref.cc0000664000175000017500000000265314771010717021540 0ustar frankfrank#include #include using namespace std; template void mswap(T &a, T &b) { T tmp{ std::move(a) }; a = std::move(b); b = std::move(tmp); } struct Data { char *text; void copy(Data const &other) { cout << "A " << (void *)other.text << '\n'; text = strdup(other.text); cout << "B " << (void *)text << '\n'; } void copy(Data &&other) { cout << "D " << (void *)other.text << '\n'; text = other.text; other.text = 0; } }; Data makeData(char const *txt) { Data ret; ret.text = strdup(txt); cout << "C " << (void *)ret.text << '\n'; return ret; } class X { public: X() { cout << "Constructor\n"; } X(X const &other) { cout << "Copycons\n"; } X(X &&other) { cout << "Move constructor\n"; } X &operator=(X const &other) { cout << "std op=\n"; return *this; }; X &operator=(X &&other) { cout << "rref op=\n"; return *this; }; }; X &&fun() { X x; return std::move(x); } int main() { int &&i = int(3); ++i; cout << i << '\n'; Data d1 = { strdup("hello") }; Data d2; d2.copy(d1); cout << "sep\n"; Data d3; d3.copy(makeData("hello")); cout << "sep 2\n"; X &&xr = X(); X x(fun()); // see memory/move.yo: // No initialization of class objects by rvalues yet cout << "sep 3\n"; mswap(xr, x); } c++-annotations-13.02.01/yo/first/examples/structured.cc0000664000175000017500000000055514771010717021750 0ustar frankfrank#include using namespace std; struct Return { int first; double second; }; Return fun() { return Return{1, 12.5}; } Return &fun2() { static Return ret{4, 5}; return ret; } int main() { auto r1 = fun(); cout << r1.first; auto [one, two] = fun(); auto &&[rone, rtwo] = fun(); auto &[lone, ltwo] = fun2(); } c++-annotations-13.02.01/yo/first/examples/byte.cc0000664000175000017500000000124514771010717020504 0ustar frankfrank#include #include #include // uint8_t using namespace std; //ostream &operator<<(ostream &out, uint8_t value) //{ // return out << static_cast(value); //} int main() { // uint8_t u8 = 40; // works great! // cout << u8 << '\n'; //init byte value{ 0x23 }; // #1 (see the text above) // byte error{ 0x123 }; // #2 char ch = 0xfb; // byte error{ ch }; // #3 byte b1 = byte( ch ); // #4 value = byte( 0x123 ); // #5 //= // cout << (value == byte{ 0 }) << '\n'; // cout << hex << static_cast(value) << '\n'; if (value > b1) value &= byte(0xf0); } c++-annotations-13.02.01/yo/first/cvscpp.yo0000664000175000017500000000262414735537670017301 0ustar frankfrankIn this section we'll discuss an important difference between bf(C) and bf(C++) structs and (member) functions. In bf(C) it is common to define several functions to process a tt(struct), which then require a pointer to the tt(struct) as one of their arguments. An imaginary bf(C) header file showing this concept is: verb( /* definition of a struct PERSON This is C */ typedef struct { char name[80]; char address[80]; } PERSON; /* some functions to manipulate PERSON structs */ /* initialize fields with a name and address */ void initialize(PERSON *p, char const *nm, char const *adr); /* print information */ void print(PERSON const *p); /* etc.. */) In bf(C++), the declarations of the involved functions are put inside the definition of the tt(struct) or tt(class). The argument denoting which tt(struct) is involved is no longer needed. verb( class Person { char d_name[80]; char d_address[80]; public: void initialize(char const *nm, char const *adr); void print(); // etc.. };) In bf(C++) the tt(struct) parameter is not used. A bf(C) function call such as: verb( PERSON x; initialize(&x, "some name", "some address");) becomes in bf(C++): verb( Person x; x.initialize("some name", "some address");) c++-annotations-13.02.01/yo/first/datatypes.yo0000664000175000017500000000755414735537670020010 0ustar frankfrankIn bf(C) the following i(built-in) data types are available: tt(void, char, short, int, long, float) and tt(double). bf(C++) extends these built-in types with several additional built-in types: the types ti(bool), ti(wchar_t), ti(long long) and ti(long double) (Cf. i(ANSI/ISO) draft (1995), par. 27.6.2.4.1 for examples of these very long types). The type ti(long long) is merely a double-long tt(long) datatype. The type ti(long double) is merely a double-long tt(double) datatype. These built-in types as well as pointer variables are called emi(primitive types)hi(type: primitive) in the annotations(). There is a subtle issue to be aware of when converting applications developed for 32-bit architectures to 64-bit architectures. When converting 32-bit programs to 64-bit programs, only tt(long) types and pointer types change in size from 32 bits to 64 bits; integers of type tt(int) remain at their size of 32 bits. This may cause data truncation when assigning pointer or tt(long) types to tt(int) types. Also, problems with sign extension can occur when assigning expressions using types shorter than the size of an tt(int) to an tt(unsigned long) or to a pointer. Except for these built-in types the class-type tt(string) is available for handling character strings. The datatypes tt(bool), and tt(wchar_t) are covered in the following sections, the datatype tt(string) is covered in chapter ref(String). Note that recent versions of bf(C) may also have adopted some of these newer data types (notably tt(bool) and tt(wchar_t)). Traditionally, however, bf(C) doesn't support them, hence they are mentioned here. Now that these new types are introduced, let's refresh your memory about em(letters) that can be used in emi(literal constants) of various hi(letters in literal constants) types. They are: itemization( it() ti(b) or tt(B): in addition to its use as a hexadecimal value, it can also be used to define a emi(binary constant). E.g., tt(0b101) equals the decimal value 5. The tt(0b) prefix can be used to specify binary constants starting with the C++14 standard. it() ti(E) or tt(e): hi(literal floating point value using E) the emi(exponentiation) character in floating point literal values. For example: tt(1.23E+3). Here, tt(E) should be pronounced (and interpreted) as: em(times 10 to the power). Therefore, tt(1.23E+3) represents the value tt(1230). it() ti(F) hi(literal float using F) can be used as em(postfix) to a non-integral numeric constant to indicate a value of type tt(float), rather than tt(double), which is the default. For example: tt(12.F) (the dot transforms 12 into a floating point value); tt(1.23E+3F) (see the previous example. tt(1.23E+3) is a tt(double) value, whereas tt(1.23E+3F) is a tt(float) value). it() ti(L) hi(literal wchar_t string L) can be used as em(prefix) to indicate a character string whose elements are tt(wchar_t)-type characters. For example: tt(L"hello world"). it() tt(L) hi(literal long int using L) can be used as em(postfix) to an integral value to indicate a value of type tt(long), rather than tt(int), which is the default. Note that there is no letter indicating a tt(short) type. For that a tt(static_cast()) must be used. it() ti(p), to specify the power hi(power specification using p) in hexadecimal floating point numbers. E.g. tt(0x10p4). The exponent itself is read as a decimal constant and can therefore not start with 0x. The exponent part is interpreted as a power of 2. So tt(0x10p2) is (decimal) equal to 64: tt(16 * 2^2). it() ti(U) hi(literal unsigned using U) can be used as em(postfix) to an integral value to indicate an tt(unsigned) value, rather than an tt(int). It may also be combined with the postfix tt(L) to produce an tt(unsigned long int) value. ) And, of course: the tt(x) and tt(a) until tt(f) characters can be used to specify hexadecimal constants (optionally using capital letters). c++-annotations-13.02.01/yo/first/bitfields.yo0000664000175000017500000000336114735537670017747 0ustar frankfrankBit-fields hi(bit-field) are used to specify series of bits in an integral value type. For example, in networking software processing IP4 packets, the first tt(uint32_t) value of IP4 packets contain: itemization( it() the version (4 bits); it() the header length (4 bits); it() the type of service (8 bits); it() the total length (16 bits) ) Rather than using complex bit and bit-shift operations, these fields inside integral values can be specified using bit-fields. E.g., verb( struct FirstIP4word { uint32_t version: 4; uint32_t header: 4; uint32_t tos: 8; uint32_t length: 16; };) To total size of a tt(FirstIP4word) object is 32 bits, or four bytes. To show the version of a tt(FirstIP4word first) object, simply do: verb( cout << first.version << '\n';) and to set its header length to 10 simply do verb( first.header = 10;) Bit fields are already available in bf(C). The C2a standard allows them to be initialized by default by using initialization expressions in their definitions. E.g., verb( struct FirstIP4word { uint32_t version: 4 = 1; // version now 1, by default uint32_t header: 4 = 10; // TCP header length now 10, by default uint32_t tos: 8; uint32_t length: 16; };) The initialization expressions are evaluated when the object using the bit-fields is defined. Also, when a variable is used to initialize a bit-field the variable must at least have been declared when the struct containing bit-fields is defined. E.g., verb( extern int value; struct FirstIP4word { ... uint32_t length: 16 = value; // OK: value has been declared };) c++-annotations-13.02.01/yo/first/stronglytyped.yo0000664000175000017500000000367014735537670020734 0ustar frankfrankEnumeration values in bf(C++) are in fact tt(int) values, thereby bypassing type safety. E.g., values of different enumeration types may be compared for (in)equality, albeit through a (static) type cast. Another problem with the current tt(enum) type is that their values are not restricted to the enum type name itself, but to the scope where the enumeration is defined. As a consequence, two enumerations having the same scope cannot have identical names. Such problems are solved by defining em(enum classes). An emi(enum class) can be defined as in the following example: verb( enum class SafeEnum { NOT_OK, // 0, by implication OK = 10, MAYBE_OK // 11, by implication };) Enum classes use tt(int) values by default, but the used value type can easily be changed using the tt(: type) notation, as in: verb( enum class CharEnum: unsigned char { NOT_OK, OK };) To use a value defined in an enum class its enumeration name must be provided as well. E.g., tt(OK) is not defined, tt(CharEnum::OK) is. Using the data type specification (noting that it defaults to tt(int)) it is possible to use enum class forward declarations. hi(forward declaration: enum class) E.g., verb( enum Enum1; // Illegal: no size available enum Enum2: unsigned int; // Legal: explicitly declared type enum class Enum3; // Legal: default int type is used enum class Enum4: char; // Legal: explicitly declared type) A sequence of symbols of a strongly typed enumeration can also be indicated in a tt(switch) using the i(ellipsis) syntax, as shown in the next example: verb( SafeEnum enumValue(); switch (enumValue()) { case SafeEnum::NOT_OK ... SafeEnum::OK: cout << "Status is known\n"; break; default: cout << "Status unknown\n"; break; }) c++-annotations-13.02.01/yo/first/public.yo0000664000175000017500000001147314735537670017263 0ustar frankfrankAs mentioned before (see section ref(Pretensions)), bf(C++) contains specialized syntactic possibilities to implement i(data hiding). Data hiding is the capability of sections of a program to hide its data from other sections. This results in very clean data definitions. It also allows these sections to enforce the integrity of their data. bf(C++) has three keywords that are related to data hiding: ti(private), ti(protected) and ti(public). These keywords can be used in the definition of tt(struct)s. The keyword tt(public) allows all subsequent fields of a structure to be accessed by all code; the keyword tt(private) only allows code that is part of the tt(struct) itself to access subsequent fields. The keyword tt(protected) is discussed in chapter ref(INHERITANCE), and is somewhat outside of the scope of the current discussion. In a tt(struct) all fields are tt(public), unless explicitly stated otherwise. Using this knowledge we can expand the tt(struct) tt(Person): verb( struct Person { private: char d_name[80]; char d_address[80]; public: void setName(char const *n); void setAddress(char const *a); void print(); char const *name(); char const *address(); };) As the data fields tt(d_name) and tt(d_address) are in a tt(private) section they are only accessible to the member functions which are defined in the tt(struct): these are the functions tt(setName), tt(setAddress) etc.. As an illustration consider the following code: verb( Person fbb; fbb.setName("Frank"); // OK, setName is public strcpy(fbb.d_name, "Knarf"); // error, x.d_name is private) Data integrity is implemented as follows: the actual data of a tt(struct) tt(Person) are mentioned in the structure definition. The data are accessed by the outside world using special functions that are also part of the definition. These member functions control all traffic between the data fields and other parts of the program and are therefore also called `interface' functions. The thus implemented data hiding is illustrated in fig(datahiding). figure(first/datahiding) (Private data and public interface functions of the class Person.) (datahiding) The members tt(setName) and tt(setAddress) are declared with tt(char const *) parameters. This indicates that the functions will not alter the strings which are supplied as their arguments. Analogously, the members tt(name) and tt(address) return tt(char const *)s: the compiler prevents callers of those members from modifying the information made accessible through the return values of those members. Two examples of member functions of the tt(struct) tt(Person) are shown below: verb( void Person::setName(char const *n) { strncpy(d_name, n, 79); d_name[79] = 0; } char const *Person::name() { return d_name; }) The power of member functions and of the concept of data hiding results from the abilities of member functions to perform special tasks, e.g., checking the validity of the data. In the above example tt(setName) copies only up to 79 characters from its argument to the data member tt(name), thereby avoiding a i(buffer overflow). Another illustration of the concept of data hiding is the following. As an alternative to member functions that keep their data in memory a library could be developed featuring member functions storing data on file. To convert a program storing tt(Person) structures in memory to one that stores the data on disk no special modifications are required. After recompilation and linking the program to a new library it is converted from storage in memory to storage on disk. This example illustrates a broader concept than data hiding; it illustrates emi(encapsulation). Data hiding is a kind of encapsulation. Encapsulation in general results in reduced coupling of different sections of a program. This in turn greatly enhances reusability and maintainability of the resulting software. By having the structure encapsulate the actual storage medium the program using the structure becomes independent of the actual storage medium that is used. Though data hiding can be implemented using tt(struct)s, more often (almost always) em(classes) are used instead. A class is a kind of struct, except that a class uses private access by default, whereas structs use public access by default. The definition of a tt(class) tt(Person) is therefore identical to the one shown above, except that the keyword tt(class) has replaced tt(struct) while the initial tt(private:) clause can be omitted. Our typographic suggestion for class names (and other type names defined by the programmer) is to start with a capital character to be followed by the remainder of the type name using lower case letters (e.g., tt(Person)). c++-annotations-13.02.01/yo/first/sizet.yo0000664000175000017500000000337214735537670017142 0ustar frankfrankThe ti(size_t) type is not really a built-in primitive data type, but a data type that is promoted by bi(POSIX) as a typename to be used for non-negative integral values answering questions like `how much' and `how many', in which case it should be used instead of ti(unsigned int). It is not a specific bf(C++) type, but also available in, e.g., bf(C). Usually it is defined implicitly when a (any) system header file is included. The header file `officially' defining tt(size_t) in the context of bf(C++) is ti(cstddef). Using tt(size_t) has the advantage of being a em(conceptual) type, rather than a standard type that is then modified by a modifier. Thus, it improves the self-documenting value of source code. Several suffixes can be used to expicitly specify the intended representation of integral constants, like tt(42UL) defining 42 as an tt(unsigned long int). Likewise, suffixes ti(uz) or tt(zu) can be used to specify that an integral constant is represented as a tt(size_t), as in: tt(cout << 42uz). Sometimes functions explictly require tt(unsigned int) to be used. E.g., on ti(amd)-architectures the i(X-windows) function ti(XQueryPointer) explicitly requires a pointer to an tt(unsigned int) variable as one of its arguments. In such situations a pointer to a tt(size_t) variable can't be used, but the address of an tt(unsigned int) must be provided. Such situations are exceptional, though. Other useful bit-represented types also exists. E.g., ti(uint32_t) is guaranteed to hold 32-bits unsigned values. Analogously, ti(int32_t) holds 32-bits signed values. Corresponding types exist for 8, 16 and 64 bits values. These types are defined in the header file ti(cstdint) and can be very useful when you need to specify or use integral value types of fixed sizes. c++-annotations-13.02.01/yo/first/using.yo0000664000175000017500000000510414735537670017124 0ustar frankfrankIn bf(C++) tt(typedef) is commonly used to define shorthand notations for complex types. Assume we want to define a shorthand for `a pointer to a function expecting a double and an int, and returning an unsigned long long int'. Such a function could be: verb( unsigned long long int compute(double, int);) A pointer to such a function has the following form: verb( unsigned long long int (*pf)(double, int);) If this kind of pointer is frequently used, consider defining it using tt(typedef): simply put tt(typedef) in front of it and the pointer's name is turned into the name of a type. It could be capitalized to let it stand out more clearly as the name of a type: verb( typedef unsigned long long int (*PF)(double, int);) After having defined this type, it can be used to declare or define such pointers: verb( PF pf = compute; // initialize the pointer to a function like // 'compute' void fun(PF pf); // fun expects a pointer to a function like // 'compute') However, including the pointer in the typedef might not be a very good idea, as it masks the fact that tt(pf) is a pointer. After all, tt(PF pf) looks more like `tt(int x)' than `tt(int *x)'. To document that tt(pf) is in fact a pointer, slightly change the tt(typedef): verb( typedef unsigned long long int FUN(double, int); FUN *pf = compute; // now pf clearly is a pointer.) The scope of typedefs is restricted to compilation units. Therefore, typedefs are usually embedded in header files which are then included by multiple source files in which the typedefs should be used. In addition to tt(typedef) bf(C++) offers the ti(using) keyword to associate a type and an identifier. In practice tt(typedef) and tt(using) can be used interchangeably. The tt(using) keyword arguably result in more readable type definitions. Consider the following three (equivalent) definitions: itemization( it() The traditional, bf(C) style definition of a type, embedding the type name in the definition (turning a variable name into a type name): verb(typedef unsigned long long int FUN(double, int);) it() Apply tt(using) to improve the visibility (for humans) of the type name, by moving the type name to the front of the definition: verb(using FUN = unsigned long long int (double, int);) it() An alternative construction, using a late-specified return type (cf. section ref(AUTO)): verb(using FUN = auto (double, int) -> unsigned long long int;) ) c++-annotations-13.02.01/yo/first/staticcast.yo0000664000175000017500000000716414735537670020151 0ustar frankfrankThe hi(static_cast)tt(static_cast(expression)) is used to convert `conceptually comparable or related types' to each other. Here as well as in other bf(C++) style casts tt(type) is the type to which the type of tt(expression) should be cast. Here are some examples of situations where the tt(static_cast) can (or should) be used: itemization( it() When converting an tt(int) to a tt(double). nl() This happens, for example when the quotient of two tt(int) values must be computed without losing the fraction part of the division. The tt(sqrt) function called in the following fragment returns 2: verb(int x = 19; int y = 4; sqrt(x / y);) whereas it returns 2.179 when a tt(static_cast) is used, as in: verb(sqrt(static_cast(x) / y);) The important point to notice here is that a tt(static_cast) is allowed to change the representation of its tt(expression) into the representation that's used by the destination type. Also note that the division is put outside of the cast expression. If the division is performed within the cast's tt(expression) (as in tt(static_cast(x / y))) an emi(integer division) has already been performed em(before) the cast has had a chance to convert the type of an operand to tt(double). it() When converting tt(enum) values to tt(int) values (in any direction). nl() Here the two types use identical representations, but different semantics. Assigning an ordinary tt(enum) value to an tt(int) doesn't require a cast, but when the enum is a em(strongly typed enum) a cast em(is) required. Conversely, a tt(static_cast) is required when assigning an tt(int) value to a variable of some enum type. Here is an example: verb(enum class Enum { VALUE }; cout << static_cast(Enum::VALUE); // show the numeric value) it() When converting related pointers to each other.nl() The tt(static_cast) is used in the context of class inheritance (cf. chapter ref(INHERITANCE)) to convert a pointer to a so-called `derived class' to a pointer to its `base class'. It cannot be used for casting unrelated types to each other (e.g., a tt(static_cast) can+em(not) be used to cast a pointer to a tt(short) to a pointer to an tt(int)). A tt(void *) is a em(generic pointer). It is frequently used by functions in the bf(C) library (e.g., bf(memcpy)(3)). Since it is the generic pointer it is related to any other pointer, and a tt(static_cast) should be used to convert a tt(void *) to an intended destination pointer. This is a somewhat awkward left-over from bf(C), which should probably only be used in that context. Here is an example: The tt(qsort) function from the bf(C) library expects a pointer to a (comparison) function having two tt(void const *) parameters. In fact, these parameters point to data elements of the array to be sorted, and so the comparison function must cast the tt(void const *) parameters to pointers to the elements of the array to be sorted. So, if the array is an tt(int array[]) and the compare function's parameters are tt(void const *p1) and tt(void const *p2) then the compare function obtains the address of the tt(int) pointed to by tt(p1) by using: verb(static_cast(p1);) it() When undoing or introducing the signed-modifier of an tt(int)-typed variable (remember that a tt(static_cast) is allowed to change the expression's representation!). nl() Here is an example: the bf(C) function tt(tolower) requires an tt(int) representing the value of an tt(unsigned char). But tt(char) by default is a signed type. To call tt(tolower) using an available tt(char ch) we should use: verb( tolower(static_cast(ch))) ) c++-annotations-13.02.01/yo/first/initializer.yo0000664000175000017500000000610514735537670020324 0ustar frankfrankThe bf(C) language defines the i(initializer list) as a list of values enclosed by curly braces, possibly themselves containing initializer lists. In bf(C) these initializer lists are commonly used to initialize arrays and structs. bf(C++) extends this concept by introducing the em(type) tt(initializer_list) where tt(Type) is replaced by the type name of the values used in the initializer list. Initializer lists in bf(C++) are, like their counterparts in bf(C), recursive, so they can also be used with multi-dimensional arrays, structs and classes. Before using the tt(initializer_list) the tthi(initializer_list) header file must be included. Like in bf(C), initializer lists consist of a list of values surrounded by curly braces. But unlike bf(C), em(functions) can define initializer list parameters. E.g., verb( void values(std::initializer_list iniValues) { }) A function like tt(values) could be called as follows: verb( values({2, 3, 5, 7, 11, 13});) The initializer list appears as an argument which is a list of values surrounded by curly braces. Due to the recursive nature of initializer lists a two-dimensional series of values can also be passes, as shown in the next example: verb( void values2(std::initializer_list> iniValues) {} values2({{1, 2}, {2, 3}, {3, 5}, {4, 7}, {5, 11}, {6, 13}});) Initializer lists are constant expressions and cannot be modified. However, their em(size) and values may be retrieved using their tt(size, begin), and tt(end) members as follows: verb( void values(initializer_list iniValues) { cout << "Initializer list having " << iniValues.size() << "values\n"; for ( initializer_list::const_iterator begin = iniValues.begin(); begin != iniValues.end(); ++begin ) cout << "Value: " << *begin << '\n'; }) Initializer lists can also be used to initialize objects of classes (cf. section ref(UNIFORMINIT), which also summarizes the facilities of initializer lists). em(Implicit conversions), also called em(narrowing conversions) hi(narrowing conversion) are not allowed when specifying values of initializer lists. Narrowing conversions are encountered when values are used of a type whose range is larger than the type specified when defining the initializer list. For example itemization( it() specifying tt(float) or tt(double) values to define initializer lists of tt(int) values; it() specifying integral values exceeding the range of tt(float) to define initializer lists of tt(float) values; it() specifying values of integral types of a wider range than the integral type that is specified for the initializer list, except if the specified values lie within the range of the initializer list's integral type ) Some examples: verb( initializer_list ii{ 1.2 }; // 1.2 isn't an int value initializer_list iu{ ~0ULL }; // unsigned long long doesn't fit ) c++-annotations-13.02.01/yo/first/binding.yo0000664000175000017500000001022114735537670017405 0ustar frankfrankUsually functions return single-valued results: tt(doubles, ints, strings), etc. When functions need to return multiple values a em(return by argument) construction is often used, where addresses of variables that live outside of the called function are passed to functions, allowing the functions to assign new values to those variables. When multiple values should be em(returned) from a function a tt(struct) can be used, but em(pairs) (cf. section ref(PAIR)) or em(tuples) (cf. section ref(TUPLES)) can also be used. Here's a simple example, where a function tt(fun) returns a tt(struct) having two data fields: verb( struct Return { int first; double second; }; Return fun() { return Return{ 1, 12.5 }; }) (Briefly forward referencing to sections ref(PAIR) and ref(TUPLES): the tt(struct) definition can completely be omitted if tt(fun) returns a tt(pair) or tt(tuple). In those cases the following code remains valid.) A function em(calling) tt(fun) traditionally defines a variable of the same type as tt(fun's) return type, and then uses that variable's fields to access tt(first) and tt(second). If you don't like the typing, tt(auto) can also be used: verb( int main() { auto r1 = fun(); cout << r1.first; }) Instead of referring to the elements of the returned tt(struct, pair) or tt(tuple) em(structured binding declarations) can also be used. Here, tt(auto) is followed by a (square brackets surrounded) comma-separated list of variables, where each variable is em(defined), and receives the value of the corresponding field or element of the called function's return value. So, the above tt(main) function can also be written like this: verb( int main() { auto [one, two] = fun(); cout << one; // one and two: now defined }) Merely specifying tt(auto) results in tt(fun's) return value being copied, and the structured bindings variables will refer to the copied value. But structured binding declarations can also be used in combination with (lvalue/rvalue) return values. The following ensures that tt(rone) and tt(rtwo) refer to the elements of tt(fun's) anonymous return value: verb( int main() { auto &&[rone, rtwo] = fun(); }) If the called function returns a value that survives the function call itself, then structured binding declarations can use em(lvalue references). E.g., verb( Return &fun2() { static Return ret{ 4, 5 }; return ret; } int main() { auto &[lone, ltwo] = fun2(); // OK: referring to ret's fields }) To use structured binding declarations it is not required to use function calls. The object providing the data can also anonymously be defined: verb( int main() { auto const &[lone, ltwo] = Return{ 4, 5 }; // or: auto &&[lone, ltwo] = Return{ 4, 5 }; }) The object doesn't even have to make its data members publicly available. In section tt(TUPLES) using structured bindings not necessarily referring to data members is covered. Another application is found in situations where nested statements of tt(for) or selection statements benefit from using locally defined variables of various types. Such variables can easily be defined using structured binding declarations that are initialized from anonymous structs, pairs or tuples. Here is an example illustrating this: verb( // define a struct: struct Three { size_t year; double firstAmount; double interest; }; // define an array of Three objects, and process each in turn: Three array[10]; fill(array); // not implemented here for (auto &[year, amount, interest]: array) cout << "Year " << year << ": amount = " << amount << '\n';) When using structured bindings the structured binding declaration must specify all elements that are available. So if a struct has four data members the structured binding declaration must define four elements. To avoid warnings of unused variables at lease one of the variables of the structured binding declaration must be used. c++-annotations-13.02.01/yo/first/spaceship.yo0000664000175000017500000000125014735537670017754 0ustar frankfrankThe C2a standard added the em(three-way comparison) operator tt(<=>), also known as the em(spaceship operator), to bf(C++). In bf(C++) operators can be defined for class-types, among which equality and comparison operators (the familiar set of tt(==, !=, <, <=, >) and tt(>=) operators). To provide classes with all comparison operators merely the equality and the spaceship operator need to be defined. Its priority hi(<=>: priority) is less than the priorities of the bit-shift operators tt(<<) and tt(>>) and larger than the priorities of the ordering operators tt(<, <=, >,) and tt(>=). Section ref(SPACESHIP) covers the construction of the three-way comparison operator. c++-annotations-13.02.01/yo/first/rangebased.yo0000664000175000017500000001032214735537670020070 0ustar frankfrankThe bf(C++) for-statement is identical to bf(C)'s for-statement: verb( for (init; cond; inc) statement) Often the initialization, condition, and increment parts are fairly obvious, as in situations where all elements of an array or vector must be processed. Many languages offer the tt(foreach) statement for that and bf(C++) offers the tt(std::for_each) generic algorithm (cf. section ref(FOREACH)). In addition to the traditional syntax bf(C++) adds new syntax for the tt(for)-statement: the emi(range-based for-loop). This new syntax can be used to process all element of a i(range) in turn. Three types of ranges are distinguished: itemization( it() Plain arrays (e.g., tt(int array[10])); it() Initializer lists; it() Standard containers (or comparable) (cf. chapter ref(CONTAINERS)); it() Any other type offering tt(begin()) and tt(end()) functions returning so-called em(iterators) (cf. section ref(ITERATORS)). ) The following additional i(for-statement) syntax is available: verb( // assume int array[30] for (auto &element: array) statement) The part to the left of the colon is called the emi(for range declaration). The declared variable (tt(element)) is a formal name; use any identifier you like. The variable is only available within the nested statement, and it refers to (or is a copy of) each of the elements of the range, from the first element up to the last. There's no formal requirement to use tt(auto), but using tt(auto) is extremely useful in many situations. Not only in situations where the range refers to elements of some complex type, but also in situations where you know what you can do with the elements in the range, but don't care about their exact type names. In the above example tt(int) could also have been used. The reference symbol (tt(&)) is important in the following cases: itemization( it() if you want to modify the elements in the nested statements it() if the elements themselves are tt(struct)s (or em(classes), cf. chapter ref(Classes)) ) When the reference symbol is omitted the variable will be a copy of each of the subsequent elements of the range. Fine, probably, if you merely need to look at the variables when they are of primitive types, but needlessly inefficient if you have an array of tt(BigStruct) elements: verb( struct BigStruct { double array[100]; int last; };) Inefficient, because you don't need to make copies of the array's elements. Instead, use references to elements: verb( BigStruct data[100]; // assume properly initialized elsewhere int countUsed() { int sum = 0; // const &: the elements aren't modified for (auto const &element: data) sum += element.last; return sum; }) Range-based for-loops can also benefit from structured bindings. If tt(struct Element) holds a tt(int key) and a tt(double value), and all the values of positive keys should be added then the following code snippet accomplishes that: verb( Element elems[100]; // somehow initialized double sum = 0; for (auto const &[key, value]: elems) { if (key > 0) sum += value; }) The C2a standard also supports an optional initialization section (like the ones already available for tt(if) and tt(switch) statements) for range-based for-loops. Assume the elements of an array must be inserted into tt(cout), but before each element we want to display the element's index. The index variable is not used outside the tt(for)-statement, and the extension offered in the C2a standard allows us to localize the index variable. Here is an example: verb( // localize idx: only visible in the for-stmnt for (size_t idx = 0; auto const &element: data) cout << idx++ << ": " << element << '\n';) COMMENT( If tt(data) is only available as a pointer to its first element in combination with the number of elements, range-based for loops can also be used, but require a little help. Section ref(RANGER) describes a generic approach to using range based for loops in such cases. END) c++-annotations-13.02.01/yo/first/reinterpretcast.yo0000664000175000017500000000523314735537670021220 0ustar frankfrankThe third new-style cast is used to change the em(interpretation) of information: the tt(reinterpret_cast). It is somewhat reminiscent of the tt(static_cast), but tt(reinterpret_cast) should only be used when it is em(known) that the information as defined in fact is or can be interpreted as something completely different. Its syntax is: verb( reinterpret_cast(pointer expression)) Think of the tt(reinterpret_cast) as a cast offering a poor-man's union: the same memory location may be interpreted in completely different ways. The tt(reinterpret_cast) is used, for example, in combination with the tt(write) function that is available for em(streams). In bf(C++) streams are the preferred interface to, e.g., disk-files. The standard streams like tt(std::cin) and tt(std::cout) also are stream objects. Streams intended for writing (`output streams' like tt(cout)) offer tt(write) members having the prototype verb( write(char const *buffer, int length)) To write the value stored within a tt(double) variable to a stream in its un-interpreted binary form the stream's tt(write) member is used. However, as a tt(double *) and a tt(char *) point to variables using different and unrelated representations, a tt(static_cast) cannot be used. In this case a tt(reinterpret_cast) is required. To write the raw bytes of a variable tt(double value) to tt(cout) we use: verb( cout.write(reinterpret_cast(&value), sizeof(double));) All casts are potentially dangerous, but the tt(reinterpret_cast) is the most dangerous of them all. Effectively we tell the compiler: back off, we know what we're doing, so stop fuzzing. All bets are off, and we'd better em(do) know what we're doing in situations like these. As a case in point consider the following code: verb( int value = 0x12345678; // assume a 32-bits int cout << "Value's first byte has value: " << hex << static_cast( *reinterpret_cast(&value) );) The above code produces different results on little and big endian computers. Little endian computers show the value 78, big endian computers the value 12. Also note that the different representations used by little and big endian computers renders the previous example (tt(cout.write(...))) non-portable over computers of different architectures. As a i(rule of thumb): if circumstances arise in which casts em(have) to be used, clearly document the reasons for their use in your code, making double sure that the cast does not eventually cause a program to misbehave. Also: avoid tt(reinterpret_casts) unless you em(have) to use them. c++-annotations-13.02.01/yo/first/wchar.yo0000664000175000017500000000102414735537670017100 0ustar frankfrankThe ti(wchar_t) type is an extension of the tt(char) built-in type, to accommodate em(wide) character values (but see also the next section). The tt(g++) compiler reports tt(sizeof(wchar_t)) as 4, which easily accommodates all 65,536 different em(Unicode) character values. Note that bf(Java)'s tt(char) data type is somewhat comparable to bf(C++)'s tt(wchar_t) type. bf(Java)'s tt(char) type is 2 bytes wide, though. On the other hand, bf(Java)'s tt(byte) data type is comparable to bf(C++)'s tt(char) type: one byte. Confusing? c++-annotations-13.02.01/yo/first/keywords.yo0000664000175000017500000000565514735537670017661 0ustar frankfrankbf(C++)'s i(keywords) are a superset of bf(C)'s keywords. Here is a list of all keywords of the language: COMMENT(table generated by src/keywordsort.cc (using -lbobcat)) verb(alignas char16_t double long reinterpret_cast true alignof char32_t dynamic_cast module requires try and class else mutable return typedef and_eq co_await enum namespace short typeid asm co_return explicit new signed typename atomic_cancel co_yield export noexcept sizeof union atomic_commit compl extern not static unsigned atomic_noexcept concept false not_eq static_assert using auto const float nullptr static_cast virtual bitand const_cast for operator struct void bitor constexpr friend or switch volatile bool continue goto or_eq synchronized wchar_t break decltype if private template while case default import protected this xor catch delete inline public thread_local xor_eq char do int register throw) Notes: itemization( COMMENT( it() The ti(export) keyword is no longer actively used by bf(C++), but it is kept as a keyword, reserved for future use. END) it() Since the i(C++17) standard the keyword ti(register) is no longer used, but it remains a reserved identifier. In other words, definitions like verb( register int index;) result in compilation errors. Also, tt(register) is no longer considered a i(storage class specifier) (storage class specifiers are tt(extern, thread_local, mutable) and tt(static)). it() the hi(operator: keywords)em(operator keywords): tt( and, and_eq, bitand, bitor, compl, not, not_eq, or, or_eq, xor) and tt(xor_eq) are symbolic alternatives for, respectively, tt(&&, &=, &, |, ~, !, !=, ||, |=, ^) and tt(^=). it() bf(C++) also recognizes the special identifiers tt(final, override, transaction_safe), and tt(transaction_safe_override). These identifiers are special in the sense that they acquire special meanings when declaring classes or polymorphic functions. Section ref(FINAL) provides further details. ) Keywords can only be used for their intended purpose and cannot be used as names for other entities (e.g., variables, functions, class-names, etc.). In addition to keywords i(identifiers starting with an underscore) and living in the emi(global namespace) (i.e., not using any explicit namespace or using the mere tt(::) namespace specification) or living in the em(std namespace) are i(reserved identifiers) in the sense that their use is a prerogative of the implementor. c++-annotations-13.02.01/yo/first/bool.yo0000664000175000017500000000514714735537670016741 0ustar frankfrank The type tt(bool) represents boolean (logical) values, for which the (now reserved) constants ti(true) and ti(false) may be used. Except for these reserved values, integral values may also be assigned to variables of type tt(bool), which are then implicitly converted to tt(true) and tt(false) according to the following i(conversion rules) (assume tt(intValue) is an tt(int)-variable, and tt(boolValue) is a tt(bool)-variable): verb( // from int to bool: boolValue = intValue ? true : false; // from bool to int: intValue = boolValue ? 1 : 0;) Furthermore, when tt(bool) values are inserted into streams then tt(true) is represented by tt(1), and tt(false) is represented by tt(0). Consider the following example: verb( cout << "A true value: " << true << "\n" "A false value: " << false << '\n';) The tt(bool) data type is found in other programming languages as well. bf(Pascal) has its type tt(Boolean); bf(Java) has a tt(boolean) type. Different from these languages, bf(C++)'s type tt(bool) acts like a kind of tt(int) type. It is primarily a documentation-improving type, having just two values tt(true) and tt(false). Actually, these values can be interpreted as tt(enum) values for tt(1) and tt(0). Doing so would ignore the philosophy behind the tt(bool) data type, but nevertheless: assigning tt(true) to an tt(int) variable neither produces warnings nor errors. Using the tt(bool)-type is usually clearer than using tt(int). Consider the following prototypes: verb( bool exists(char const *fileName); // (1) int exists(char const *fileName); // (2)) With the first prototype, readers expect the function to return tt(true) if the given filename is the name of an existing file. However, with the second prototype some ambiguity arises: intuitively the return value 1 is appealing, as it allows constructions like verb( if (exists("myfile")) cout << "myfile exists";) On the other hand, many system functions (like ti(access), ti(stat), and many other) return 0 to indicate a successful operation, reserving other values to indicate various types of errors. As a rule of thumb I suggest the following: if a function should inform its caller about the success or failure of its task, let the function return a tt(bool) value. If the function should return success or various types of errors, let the function return em(enum) values, documenting the situation by its various symbolic constants. Only when the function returns a conceptually meaningful integral value (like the sum of two tt(int) values), let the function return an tt(int) value. c++-annotations-13.02.01/yo/first/namespaces.yo0000664000175000017500000000161014735537670020114 0ustar frankfrankbf(C++) introduces the notion of a emi(namespace): all symbols are defined in a larger context, called a em(namespace). Namespaces are used to avoid i(name conflicts) that could arise when a programmer would like to define a function like tt(sin) operating on em(degrees), but does not want to lose the capability of using the standard tt(sin) function, operating on em(radians). Namespaces are covered extensively in chapter ref(NAMESPACE). For now it should be noted that most compilers require the explicit declaration of a emi(standard namespace): tt(std). So, unless otherwise indicated, it is stressed that all examples in the Annotations now implicitly use the hi(using namespace std) verb( using namespace std;) declaration. So, if you actually intend to compile examples given in the annotations(), make sure that the sources start with the above tt(using) declaration. c++-annotations-13.02.01/yo/first/longlongint.yo0000664000175000017500000000014414735537670020330 0ustar frankfrankbf(C++) also supports the type ti(long long int). On 32 bit systems it has at least 64 usable bits. c++-annotations-13.02.01/yo/first/selectinit.yo0000664000175000017500000000327014735537670020144 0ustar frankfrankThe standard tt(for) repetition statements start with an optional initialization clause. The initialization clause allows us to localize variables to the scope of the for statements. Initialization clauses can also be used in selection statements. Consider the situation where an action should be performed if the next line read from the standard input stream equals tt(go!). Traditionally, when used inside a function, intending to localize the string to contain the content of the next line as much as possible, constructions like the following had to be used: verb( void function() { // ... any set of statements { string line; // localize line if (getline(cin, line)) action(); } // ... any set of statements }) Since tt(init ;) clauses can also be used for selection statements (tt(if) and tt(switch) statements) (note that with selection statements the semicolon is part of the initialization clause, which is different from the optional tt(init) (no semicolon) clause in tt(for) statements), we can rephrase the above example as follows: verb( void function() { // ... any set of statements if (string line; getline(cin, line)) action(); // ... any set of statements }) Note that a variable may still also be defined in the actual condition clauses. This is true for both the extended tt(if) and tt(switch) statement. However, before using the condition clauses an initialization clause may be used to define additional variables (plural, as it may contain a comma-separated list of variables, similar to the syntax that's available for tt(for)-statements). c++-annotations-13.02.01/yo/first/rvalueref.yo0000664000175000017500000001561414735537670020001 0ustar frankfrankIn bf(C++), temporary (rvalue) values are indistinguishable from tt(const &) types. bf(C++) introduces a new reference type called an emi(rvalue reference), which is defined as ti(typename &&). The name em(rvalue) reference is derived from assignment statements, where the variable to the left of the assignment operator is called an emi(lvalue) and the expression to the right of the assignment operator is called an emi(rvalue). Rvalues are often temporary, anonymous values, like values returned by functions. In this parlance the bf(C++) reference should be considered an emi(lvalue reference) (using the notation tt(typename &)). They can be contrasted to em(rvalue references) (using the notation tt(typename &&)). The key to understanding rvalue references is the concept of an emi(anonymous variable). An anonymous variable has no name and this is the distinguishing feature for the compiler to associate it automatically with an rvalue reference if it has a choice. Before introducing some interesting constructions let's first have a look at some standard situations where em(lvalue) references are used. The following function returns a temporary (anonymous) value: verb( int intVal() { return 5; }) Although tt(intVal)'s return value can be assigned to an tt(int) variable it requires copying, which might become prohibitive when a function does not return an tt(int) but instead some large object. A em(reference) or em(pointer) cannot be used either to collect the anonymous return value as the return value won't survive beyond that. So the following is illegal (as noted by the compiler): verb( int &ir = intVal(); // fails: refers to a temporary int const &ic = intVal(); // OK: immutable temporary int *ip = &intVal(); // fails: no lvalue available) Apparently it is not possible to modify the temporary returned by tt(intVal). But now consider these functions: verb( void receive(int &value) // note: lvalue reference { cout << "int value parameter\n"; } void receive(int &&value) // note: rvalue reference { cout << "int R-value parameter\n"; }) and let's call this function from tt(main): verb( int main() { receive(18); int value = 5; receive(value); receive(intVal()); }) This program produces the following output: verb( int R-value parameter int value parameter int R-value parameter) The program's output shows the compiler selecting tt(receive(int &&value)) in all cases where it receives an anonymous tt(int) as its argument. Note that this includes tt(receive(18)): a value 18 has no name and thus tt(receive(int &&value)) is called. Internally, it actually uses a temporary variable to store the 18, as is shown by the following example which modifies tt(receive): verb( void receive(int &&value) { ++value; cout << "int R-value parameter, now: " << value << '\n'; // displays 19 and 6, respectively. }) Contrasting tt(receive(int &value)) with tt(receive(int &&value)) has nothing to do with tt(int &value) not being a const reference. If tt(receive(int const &value)) is used the same results are obtained. Bottom line: the compiler selects the overloaded function using the rvalue reference if the function is passed an anonymous value. The compiler runs into problems if tt(void receive(int &value)) is replaced by tt(void receive(int value)), though. When confronted with the choice between a value parameter and a reference parameter (either lvalue or rvalue) it cannot make a decision and reports an ambiguity. In practical contexts this is not a problem. Rvalue references were added to the language in order to be able to distinguish the two forms of references: named values (for which lvalue references are used) and anonymous values (for which rvalue references are used). It is this distinction that allows the implementation of emi(move semantics) and emi(perfect forwarding). At this point the concept of emi(move semantics) cannot yet fully be discussed (but see section ref(MOVE) for a more thorough discussion) but it is very well possible to illustrate the underlying ideas. Consider the situation where a function returns a tt(struct Data) containing a pointer to a dynamically allocated NTBS. We agree that tt(Data) objects are only used after initialization, for which two tt(init) functions are available. As an aside: when tt(Data) objects are no longer required the memory pointed at by tt(text) must again be returned to the operating system; assume that that task is properly performed. verb( struct Data { char *text; void init(char const *txt); // initialize text from txt void init(Data const &other) { text = strdup(other.text); } };) There's also this interesting function: verb( Data dataFactory(char const *text);) Its implementation is irrelevant, but it returns a (temporary) tt(Data) object initialized with tt(text). Such temporary objects cease to exist once the statement in which they are created end. Now we'll use tt(Data): verb( int main() { Data d1; d1.init(dataFactory("object")); }) Here the tt(init) function duplicates the NTBS stored in the temporary object. Immediately thereafter the temporary object ceases to exist. If you think about it, then you realize that that's a bit over the top: itemization( it() the tt(dataFactory) function uses tt(init) to initialize the tt(text) variable of its temporary tt(Data) object. For that it uses tt(strdup); it() the tt(d1.init) function then em(also) uses tt(strdup) to initialize tt(d1.text); it() the statement ends, and the temporary object ceases to exist. ) That's two tt(strdup) calls, but the temporary tt(Data) object thereafter is never used again. To handle cases like these em(rvalue reference) were introduced. We add the following function to the tt(struct Data): verb( void init(Data &&tmp) { text = tmp.text; // (1) tmp.text = 0; // (2) }) Now, when the compiler translates tt(d1.init(dataFactory("object"))) it notices that tt(dataFactory) returns a (temporary) object, and because of that it uses the tt(init(Data &&tmp)) function. As we know that the tt(tmp) object ceases to exist after executing the statement in which it is used, the tt(d1) object (at (1)) em(grabs) the temporary object's tt(text) value, and then (at (2)) assigns 0 to tt(other.text) so that the temporary object's tt(free(text)) action does no harm. Thus, tt(struct Data) suddenly has become emi(move-aware) and implements em(move semantics), removing the (extra copy) drawback of the previous approach, and instead of making an extra copy of the temporary object's NTBS the pointer value is simply transferred to its new owner. c++-annotations-13.02.01/yo/first/separators.yo0000664000175000017500000000077514735537670020173 0ustar frankfrankTo improve the readability of large numbers em(digit separators)hi(digit separator) for integer and floating point literals can be used. The digit separator is a single quote which may be inserted between digits of such literals to enhance human readability. Multiple digit separators may be used, but only one separator can be inserted between successive digits. E.g., verb( 1'000'000 3.141'592'653'589'793'238'5 ''123 // won't compile 1''23 // won't compile either) c++-annotations-13.02.01/yo/first/structs.yo0000664000175000017500000000316514735537670017513 0ustar frankfrankEarlier we noted that functions can be part of tt(struct)s (see section ref(FunctionInStruct)). Such functions are called hi(member function)em(member functions). This section briefly discusses how to define such functions. The code fragment below shows a tt(struct) having data fields for a person's name and address. A function tt(print) is included in the tt(struct)'s definition: verb( struct Person { char name[80]; char address[80]; void print(); };) When defining the member function tt(print) the structure's name (tt(Person)) and the scope resolution operator (tt(::)) are used: verb( void Person::print() { cout << "Name: " << name << "\n" "Address: " << address << '\n'; }) The implementation of tt(Person::print) shows how the fields of the tt(struct) can be accessed without using the structure's type name. Here the function tt(Person::print) prints a variable tt(name). Since tt(Person::print) is itself a part of tt(struct) tt(person), the variable tt(name) implicitly refers to the same type. This tt(struct Person) could be used as follows: verb( Person person; strcpy(person.name, "Karel"); strcpy(person.address, "Marskramerstraat 33"); person.print();) The advantage of member functions is that the called function automatically accesses the data fields of the structure for which it was invoked. In the statement tt(person.print()) the object tt(person) is the `substrate': the variables tt(name) and tt(address) that are used in the code of tt(print) refer to the data stored in the tt(person) object. c++-annotations-13.02.01/yo/first/sharedcast.yo0000664000175000017500000000127314735537670020123 0ustar frankfrankThis section can safely be skipped without loss of continuity. In the context of the class tt(shared_ptr), which is covered in section ref(SHAREDPTR), several more new-style casts are available. Actual coverage of these specialized casts is postponed until section ref(SHAREDCAST). These specialized casts are: itemization( itt(static_pointer_cast), returning a tt(shared_ptr) to the base-class section of a derived class object; itt(const_pointer_cast), returning a tt(shared_ptr) to a non-const object from a tt(shared_ptr) to a constant object; itt(dynamic_pointer_cast), returning a tt(shared_ptr) to a derived class object from a tt(shared_ptr) to a base class object. ) c++-annotations-13.02.01/yo/first/scope.yo0000664000175000017500000000201114735537670017102 0ustar frankfrankbf(C++) introduces several new operators, among which the i(scope resolution operator) (ti(::)). This operator can be used in situations where a global variable exists having the same name as a local variable: verb( #include double counter = 50; // global variable int main() { for (int counter = 1; // this refers to the counter != 10; // local variable ++counter) { printf("%d\n", ::counter // global variable / // divided by counter); // local variable } }) In the above program the scope operator is used to address a global variable instead of the local variable having the same name. In bf(C++) the scope operator is used extensively, but it is seldom used to reach a global variable shadowed by an identically named local variable. Its main purpose is encountered in chapter ref(Classes). c++-annotations-13.02.01/yo/first/binary.yo0000664000175000017500000000115014735537670017260 0ustar frankfrankIn addition to hexadecimal hi(hexadecimal constant) integral constants (starting with i(0x)), octal integral hi(octal constant) constants (starting with i(0)), and decimal integral hi(decimal constant) constants (starting with one of the digits 1..9), em(binary) integral hi(binary constant) constants can be defined using the prefixes tt(0b)hi(0b, 0B) or tt(0B). E.g., to represent the (decimal) value 5 the notation tt(0b101) can also be used. The binary constants come in handy in the context of, e.g., i(bit-flags), as it immediately shows which bit-fields are set, while other notations are less informative. c++-annotations-13.02.01/yo/first/lvalues.yo0000664000175000017500000001016114735537670017451 0ustar frankfrankAlthough this section contains forward references to chapters ref(String), ref(Classes), and ref(PointMembers), its topic best fits the current chapter. This section can be skipped without loss of continuity, and you might consider returning to it once you're familiar with the content of these future chapters. Historically, the bf(C) programming language distinguished between em(lvalues) and em(rvalues). The terminology was based on assignment expressions, where the expression to the left of the assignment operator receives a value (e.g., it referred to a location in memory where a value could be written into, like a variable), while the expression to the right of the assignment operator only had to represent a value (it could be a temporary variable, a constant value or the value stored in a variable): verb( lvalue = rvalue;) bf(C++) adds to this basic distinction several new ways of referring to expressions: itemization( itt(lvalue): an emi(lvalue) in bf(C++) has the same meaning as in bf(C). It refers to a location where a value can be stored, like a variable, a reference to a variable, or a dereferenced pointer. itt(xvalue): an emi(xvalue) indicates an emi(expiring value). An expiring value refers to an em(object) (cf. chapter ref(Classes)) just before its lifetime ends. Such objects normally have to make sure that resources they own (like dynamically allocated memory) also cease to exist, but such resources may, just before the object's lifetime ends, be moved to another location, thus preventing their destruction. itt(glvalue): a emi(glvalue) is a emi(generalized lvalue). A generalized lvalue refers to anything that may receive a value. It is either an lvalue or an xvalue. itt(prvalue): a emi(prvalue) is a emi(pure rvalue): a literal value (like tt(1.2e3)) or an immutable object (e.g., the value returned from a function returning a constant tt(std::string) (cf. chapter ref(String))). ) An expression's value is an xvalue if it is: itemization( it() the value returned by a function returning an rvalue reference to an object; it() an object that is cast to an rvalue reference; it() an expression accessing a non-static class data member whose object is itemization( it() an xvalue, or it() a tt(.*) (pointer-to-member) expression (cf. chapter ref(PointMembers)) in which the left-hand side operand is an xvalue and the right-hand side operand is a pointer to a data member. ) The effect of this rule is that named rvalue references are treated as lvalues and anonymous rvalue references to objects are treated as xvalues.nl() Rvalue references to functions are treated as lvalues whether anonymous or not. ) Here is a small example. Consider this simple struct: verb( struct Demo { int d_value; };) In addition we have these function declarations and definitions: verb( Demo &&operator+(Demo const &lhs, Demo const &rhs); Demo &&factory(); Demo demo; Demo &&rref = static_cast(demo);) Expressions like verb( factory(); factory().d_value; static_cast(demo); demo + demo) are xvalues. However, the expression verb( rref;) is an lvalue. In many situations it's not particularly important to know what kind of lvalue or what kind of rvalue is actually used. In the annotations() the term emi(lhs) (i(left hand side)) is frequently used to indicate an operand that's written to the left of a binary operator, while the term emi(rhs) (i(right hand side)) is frequently used to indicate an operand that's written to the right of a binary operator. Lhs and rhs operands could actually be gvalues (e.g., when representing ordinary variables), but they could also be prvalues (e.g., numeric values added together using the addition operator). Whether or not lhs and rhs operands are gvalues or lvalues can always be determined from the context in which they are used. c++-annotations-13.02.01/yo/first/first.yo0000664000175000017500000000045714735537670017134 0ustar frankfrankIn this chapter bf(C++) is further explored. The possibility to declare functions in tt(struct)s is illustrated in various examples; the concept of a tt(class) is introduced; casting is covered in detail; many new types are introduced and several important notational extensions to bf(C) are discussed. c++-annotations-13.02.01/yo/first/designated.yo0000664000175000017500000000253514735537670020113 0ustar frankfrankbf(C++), like bf(C), also supports emi(designated initialization). However, as bf(C++) requires that destruction of data members occurs in the opposite order as their construction it is required that, when using designated initialization, members are initialized in the order in which they are declared in their class or struct. E.g., verb( struct Data { int d_first; double d_second; std::string d_third; }; Data data{ .d_first = 1, .d_third = "hello" };) In this example, tt(d_first) and tt(d_third) are explicitly initialized, while tt(d_second) is implicitly initialized to its default value (so: 0.0). In bf(C++) it is not allowed to reorder the initialization of members in a desginated initialization list. So, tt(Data data{ .d_third = "hello", .d_first = 1 }) is an error, but tt(Data data{ .d_third = "hello" }) is OK, as there is no ordering conflict in the latter example (this also initializes tt(d_first) and tt(d_second) to 0). Likewise, a union hi(union: designated initialization) can be initialized using designated initialization, as illustrated by the next example: verb( union Data { int d_first; double d_second; std::string *d_third; }; // initialize the union's d_third field: Data data{ .d_third = new string{ "hello" } };) c++-annotations-13.02.01/yo/first/dynamiccast.yo0000664000175000017500000000132714735537670020301 0ustar frankfrankFinally there is a new style cast that is used in combination with polymorphism (see chapter ref(POLYMORPHISM)). Its syntax is: verb( dynamic_cast(expression)) Different from the tt(static_cast), whose actions are completely determined em(compile-time), the tt(dynamic_cast)'s actions are determined em(run-time) to convert a pointer to an object of some class (e.g., tt(Base)) to a pointer to an object of another class (e.g., tt(Derived)) which is found further down its so-called em(class hierarchy) (this is also called em(downcasting)). At this point in the em(Annotations) a tt(dynamic_cast) cannot yet be discussed extensively, but we return to this topic in section ref(DYNAMICCAST). c++-annotations-13.02.01/yo/first/cast.yo0000664000175000017500000000154514735537670016736 0ustar frankfrankTraditionally, bf(C) offers the following em(cast) syntax: verb( (typename)expression) here tt(typename) is the name of a valid em(type), and tt(expression) is an expression. bf(C) style casts are now deprecated. bf(C++) programs should merely use the new style bf(C++) casts as they offer the compiler facilities to verify the sensibility of the cast. Facilities which are not offered by the classic bf(C)-style cast. A cast should not be confused with the often used emi(constructor notation): verb( typename(expression)) the constructor notation is not a cast, but a request to the compiler to construct an (anonymous) variable of type tt(typename) from tt(expression). If casts are really necessary one of several emi(new-style casts) should be used. These new-style casts are introduced in the upcoming sections. c++-annotations-13.02.01/yo/first/references.yo0000664000175000017500000002043414735537670020123 0ustar frankfrankIn addition to the common ways to define variables (plain variables or pointers) bf(C++) introduces hi(reference)em(references) defining synonyms for variables. A reference to a variable is like an em(alias); the variable and the reference can both be used in statements involving the variable: verb( int int_value; int &ref = int_value;) In the above example a variable tt(int_value) is defined. Subsequently a reference tt(ref) is defined, which (due to its initialization) refers to the same memory location as tt(int_value). In the definition of tt(ref), the i(reference operator) hi(operator&) tt(&) indicates that tt(ref) is not itself an tt(int) but a reference to one. The two statements verb( ++int_value; ++ref;) have the same effect: they increment tt(int_value)'s value. Whether that location is called tt(int_value) or tt(ref) does not matter. References serve an important function in bf(C++) as a means to pass modifiable arguments to functions. E.g., in standard bf(C), a function that increases the value of its argument by five and returning nothing needs a pointer parameter: verb( void increase(int *valp) // expects a pointer { // to an int *valp += 5; } int main() { int x; increase(&x); // pass x's address }) This construction can em(also) be used in bf(C++) but the same effect is also achieved using a reference: verb( void increase(int &valr) // expects a reference { // to an int valr += 5; } int main() { int x; increase(x); // passed as reference }) It is arguable whether code such as the above should be preferred over bf(C)'s method, though. The statement tt(increase) tt((x)) suggests that not tt(x) itself but a em(copy) is passed. Yet the value of tt(x) changes because of the way tt(increase()) is defined. However, references can also be used to pass objects that are only inspected (without the need for a copy or a const *) or to pass objects whose modification is an accepted side-effect of their use. In those cases using references are strongly preferred over existing alternatives like copy by value or passing pointers. Behind the scenes references are implemented using pointers. So, as far as the compiler is concerned references in bf(C++) are just const pointers. With references, however, the programmer does not need to know or to bother about levels of indirection. An important distinction between plain pointers and references is of course that with references no indirection takes place. For example: verb( extern int *ip; extern int &ir; ip = 0; // reassigns ip, now a 0-pointer ir = 0; // ir unchanged, the int variable it refers to // is now 0.) In order to prevent confusion, we suggest to adhere to the following: itemization( it() In those situations where a function does not alter its parameters of a built-in or pointer type, value parameters can be used: verb(void some_func(int val) { cout << val << '\n'; } int main() { int x; some_func(x); // a copy is passed }) it() When a function explicitly must change the values of its arguments, a pointer parameter is preferred. These pointer parameters should preferably be the function's initial parameters. This is called emi(return by argument). verb(void by_pointer(int *valp) { *valp += 5; }) it() When a function doesn't change the value of its class- or struct-type arguments, or if the modification of the argument is a trivial side-effect (e.g., the argument is a stream) references can be used. Const-references should be used if the function does not modify the argument: verb(void by_reference(string const &str) { cout << str; // no modification of str } int main () { int x = 7; by_pointer(&x); // a pointer is passed // x might be changed string str("hello"); by_reference(str); // str is not altered }) References play an important role in cases where the argument is not changed by the function but where it is undesirable to copy the argument to initialize the parameter. Such a situation occurs when a large object is passed as argument, or is returned by the function. In these cases the copying operation tends to become a significant factor, as the entire object must be copied. In these cases references are preferred. If the argument isn't modified by the function, or if the caller shouldn't modify the returned information, the tt(const) keyword should be used. Consider the following example: verb(struct Person // some large structure { char name[80]; char address[90]; double salary; }; Person person[50]; // database of persons // printperson expects a // reference to a structure // but won't change it void printperson (Person const &subject) { cout << "Name: " << subject.name << '\n' << "Address: " << subject.address << '\n'; } // get a person by index value Person const &personIdx(int index) { return person[index]; // a reference is returned, } // not a copy of person[index] int main() { Person boss; printperson(boss); // no pointer is passed, // so `boss' won't be // altered by the function printperson(personIdx(5)); // references, not copies // are passed here }) it() Furthermore, note that there is yet another reason for using references when passing objects as function arguments. When passing a reference to an object, the activation of a so called em(copy constructor) is avoided. Copy constructors are covered in chapter ref(MEMORY). ) References em(could) result in extremely `ugly' code. A function may return a reference to a variable, as in the following example: verb( int &func() { static int value; return value; }) This allows the use of the following constructions: verb( func() = 20; func() += func();) It is probably superfluous to note that such constructions should normally not be used. Nonetheless, there are situations where it is useful to return a reference. We have actually already seen an example of this phenomenon in our previous discussion of streams. In a statement like tt(cout) lshift() tt("Hello") lshift() tt('\n';) the insertion operator returns a reference to tt(cout). So, in this statement first the tt("Hello") is inserted into tt(cout), producing a reference to tt(cout). Through this reference the tt('\n') is then inserted in the tt(cout) object, again producing a reference to tt(cout), which is then ignored. Several differences between pointers and references are pointed out in the next list below: itemization( it() A reference cannot exist by itself, i.e., without something to refer to. A declaration of a reference like center(tt(int &ref;)) is not allowed; what would tt(ref) refer to? it() References can be declared as tt(external). These references were initialized elsewhere. it() References may exist as parameters of functions: they are initialized when the function is called. it() References may be used in the return types of functions. In those cases the function determines what the return value refers to. it() References may be used as data members of classes. We return to this usage later. it() Pointers are variables by themselves. They point at something concrete or just ``at nothing''. it() References are aliases for other variables and cannot be re-aliased to another variable. Once a reference is defined, it refers to its particular variable. it() Pointers (except for const pointers) can be reassigned to point to different variables. it() When an i(address-of operator) hi(operator&) ti(&) is used with a reference, the expression yields the address of the variable to which the reference applies. In contrast, ordinary pointers are variables themselves, so the address of a pointer variable has nothing to do with the address of the variable pointed to. ) c++-annotations-13.02.01/yo/first/auto.yo0000664000175000017500000001350714735537670016755 0ustar frankfrankThe keyword ti(auto) can be used to simplify type definitions of variables and return types of functions if the compiler is able to determine the proper types of such variables or functions. Using tt(auto) as a storage class specifier is no longer supported by bf(C++): a variable definition like tt(auto int var) results in a compilation error. The keyword tt(auto) is used in situations where it is very hard to determine the variable's type. These situations are encountered, e.g., in the context of em(templates) (cf. chapters ref(STL) until ref(ADVANCEDTEMPL)). It is also used in situations where a known type is a very long one but also automatically available to the compiler. In such cases the programmer uses tt(auto) to avoid having to type long type definitions. At this point in the Annotations only simple examples can be given. Refer to section ref(AUTODECL) for additional information about tt(auto) (and the related tt(decltype) function). When defining and initializing a variable tt(int variable = 5) the type of the initializing expression is well known: it's an tt(int), and unless the programmer's intentions are different this could be used to define tt(variable)'s type (a somewhat contrived example as in this case it reduces rather than improves the clarity of the code): verb( auto variable = 5;) However, it is attractive to use tt(auto). In chapter ref(String) the emi(iterator) concept is introduced (see also chapters ref(CONTAINERS) and ref(STL)). Iterators frequently have long type definitions, like verb( std::vector::const_reverse_iterator) Functions may return objects having such types. Since the compiler knows about these types we may exploit this knowledge by using tt(auto). Assume that a function tt(begin()) is declared like this: verb( std::vector::const_reverse_iterator begin();) Rather than writing a long variable definition (at tt(// 1), below) a much shorter definition (at tt(// 2)) can be used: verb( std::vector::const_reverse_iterator iter = begin(); // 1 auto iter = begin(); // 2) It's also easy to define and initialize additional variables of such types. When initializing such variables tt(iter) can be used to initialize those variables, and tt(auto) can be used, so the compiler deduces their types: verb( auto start = iter;) When defining variables using tt(auto) the variable's type is deduced from the variable's initializing expression. Plain types and pointer types are used as-is, but when the initializing expression is a reference type, then the reference's basic type (without the reference, omitting tt(const) or tt(volatile) specifications) is used. If a reference type is required then tt(auto &)hi(auto &, auto &&) or tt(auto &&) can be used. Likewise, tt(const) and/or pointer specifications can be used in combination with the tt(auto) keyword itself. Here are some examples: verb( int value; auto another = value; // 'int another' is defined string const &text(); auto str = text(); // text's plain type is string, so // string str, NOT string const str // is defined str += "..."; // so, this is OK int *ip = &value; auto ip2 = ip; // int *ip2 is defined. int *const &ptr = ip; auto ip3 = ptr; // int *ip3 is defined, omitting const & auto const &ip4 = ptr; // int *const &ip4 is defined.) In the next to last tt(auto) specification, the tokens (reading right to left) from the reference to the basic type are omitted: here tt(const &) was appended to tt(ptr's) basic type (tt(int *)). Hence, tt(int *ip2) is defined. In the last tt(auto) specification tt(auto) also produces tt(int *), but in the type definition tt(const &) is added to the type produced by tt(auto), so tt(int *const &ip4) is defined. The tt(auto) keyword can also be used to postpone the definition of a function's return type. The declaration of a function tt(intArrPtr) returning a pointer to arrays of 10 tt(int)s looks like this: verb( int (*intArrPtr())[10];) Such a declaration is fairly complex. E.g., among other complexities it requires `protection of the pointer'hi(pointer protection) using parentheses in combination with the function's parameter list. In situations like these the specification of the return type can be postponed using the tt(auto) return type, followed by the specification of the function's return type after any other specification the function might receive (e.g., as a const member (cf. section ref(ConstFunctions)) or following its tt(noexcept) specification (cf. section ref(NOEXCEPT))). Using tt(auto) to declare the above function, the declaration becomes: verb( auto intArrPtr() -> int (*)[10];) A return type specification using tt(auto) is called a emi(late-specified return type). Since the C++14 standard late return type specifications are no longer required for functions returning tt(auto). Such functions can now simply be declared like this: verb( auto autoReturnFunction();) In this case some restrictions apply, both to the function definitions and the function declarations: itemization( it() If multiple return statements are used in function definitions they all must return values of identical types; it() Functions merely returning tt(auto) cannot be used before the compiler has seen their definitions. So they cannot be used after mere declarations; it() When functions returning tt(auto) are implemented as recursive function then at least one return statement must have been seen before the recursive call. E.g., verb( auto fibonacci(size_t n) { if (n <= 1) return n; return fibonacci(n - 1) + fibonacci(n - 2); }) ) c++-annotations-13.02.01/yo/first/cout.yo0000664000175000017500000001513614735537670016757 0ustar frankfrankAnalogous to bf(C), bf(C++) defines standard input- and output streams which are available when a program is executed. The streams are: itemization( it() ti(cout), analogous to ti(stdout), it() ti(cin), analogous to ti(stdin), it() ti(cerr), analogous to ti(stderr). ) Syntactically these streams are not used as functions: instead, data are written to streams or read from them using the operators lshift(), called the emi(insertion operator) and rshift(), called the emi(extraction operator). This is illustrated in the next example: verb( #include using namespace std; int main() { int ival; char sval[30]; cout << "Enter a number:\n"; cin >> ival; cout << "And now a string:\n"; cin >> sval; cout << "The number is: " << ival << "\n" "And the string is: " << sval << '\n'; }) This program reads a number and a string from the tt(cin) stream (usually the keyboard) and prints these data to tt(cout). With respect to streams, please note: itemization( it() The standard streams are declared in the header file ti(iostream). In the examples in the annotations() this header file is often not mentioned explicitly. Nonetheless, it em(must) be included (either directly or indirectly) when these streams are used. Comparable to the use of the tt(using namespace std;) clause, the reader is expected to tt(#include ) with all the examples in which the standard streams are used. it() The streams tt(cout), tt(cin) and tt(cerr) are variables of so-called emi(class)-types. Such variables are commonly called em(objects). Classes are discussed in detail in chapter ref(Classes) and are used extensively in bf(C++). it() The stream tt(cin) extracts data from a stream and copies the extracted information to variables (e.g., tt(ival) in the above example) using the extraction operator (two consecutive tt(>) characters: rshift()). Later in the Annotations we will describe how operators in bf(C++) can perform quite different actions than what they are defined to do by the language, as is the case here. Function overloading has already been mentioned. In bf(C++) em(operators) can also have multiple definitions, which is called em(operator overloading). it() The operators which manipulate tt(cin), tt(cout) and tt(cerr) (i.e., rshift() and lshift()) also manipulate variables of different types. In the above example tt(cout) lshift() tt(ival) results in the printing of an integer value, whereas tt(cout) lshift() tt("Enter a number") results in the printing of a string. The actions of the operators therefore depend on the types of supplied variables. it() The emi(extraction operator) (rshift()) performs a so called emi(type safe) assignment to a variable by `extracting' its value from a text stream. Normally, the extraction operator skips all emi(whitespace) hi(skipping leading blanks) characters preceding the values to be extracted. it() Special i(symbolic constants) are used for special situations. Normally a line is terminated by inserting tt("\n") or tt('\n'). But when inserting the ti(endl) symbol the line is terminated followed by the flushing of the stream's internal buffer. Thus, tt(endl) can usually be avoided in favor of tt('\n') resulting in somewhat more efficient code. ) The stream objects tt(cin), tt(cout) and tt(cerr) are not part of the bf(C++) grammar proper. The streams are part of the definitions in the header file tt(iostream). This is comparable to functions like tt(printf) that are not part of the bf(C) grammar, but were originally written by people who considered such functions important and collected them in a run-time library. A program may still use the old-style functions like tt(printf) and tt(scanf) rather than the new-style streams. The two styles can even be mixed. But streams offer several clear advantages and in many bf(C++) programs have completely replaced the old-style bf(C) functions. Some advantages of using streams are: itemization( it() Using insertion and extraction operators is emi(type-safe). The format strings which are used with tt(printf) and tt(scanf) can define wrong format specifiers for their arguments, for which the compiler sometimes can't warn. In contrast, argument checking with tt(cin), tt(cout) and tt(cerr) is performed by the compiler. Consequently it isn't possible to err by providing an tt(int) argument in places where, according to the format string, a string argument should appear. With streams there are no format strings. it() The functions tt(printf) and tt(scanf) (and other functions using format strings) in fact implement a em(mini-language) which is interpreted at run-time. In contrast, with streams the bf(C++) compiler knows exactly which in- or output action to perform given the arguments used. No mini-language here. it() In addition the possibilities of the insertion and extraction operators may be em(extended) allowing objects of classes that didn't exist when the streams were originally designed to be inserted into or extracted from streams. Mini languages as used with tt(printf) cannot be extended. it() The usage of the left-shift and right-shift operators in the context of the streams illustrates yet another capability of bf(C++): operator overloading allowing us to redefine the actions an operator performs in certain contexts. Coming from bf(C) operator overloading requires some getting used to, but after a short little while these overloaded operators feel rather comfortable. it() Streams are independent of the media they operate upon. This (at this point somewhat abstract) notion means that the same code can be used without em(any) modification at all to interface your code to em(any) kind of device. The code using streams can be used when the device is a file on disk; an Internet connection; a digital camera; a DVD device; a satellite link; and much more: you name it. Streams allow your code to be decoupled (independent) of the devices your code is supposed to operate on, which eases maintenance and allows reuse of the same code in new situations. ) The em(iostream library) has a lot more to offer than just tt(cin, cout) and tt(cerr). In chapter ref(IOStreams) em(iostreams) are covered in greater detail. Even though ti(printf) and friends can still be used in bf(C++) programs, streams have practically replaced the old-style bf(C) tt(I/O) functions like tt(printf). If you em(think) you still need to use tt(printf) and related functions, think again: in that case you've probably not yet completely grasped the possibilities of stream objects. c++-annotations-13.02.01/yo/first/byte.yo0000664000175000017500000000470514735537670016750 0ustar frankfrankhi(byte) Quite often 8-bit variables are required, usually to access memory locations. Traditionally the tt(char) type has been used for that, but tt(char) is a signed type and when inserting a tt(char) variable into a stream the character's representation instead of its value is used. Maybe more important is the inherent confusion when using tt(char) type variables when only using its (unsigned) value: a tt(char) documents to the reader that text is used instead of mere 8-bit values, as used by the smallest addressable memory locations. Different from the tt(char) type the tt(std::byte) type intends to merely represent an 8-bit value. In order to use tt(std::byte) the tthi(cstddef) header file must be included. The tt(byte) is defined as a strongly typed enum, simply embedding an tt(unsigned char): verb( enum class byte: unsigned char {};) As a tt(byte) is an enum without predefined enum values plain assignments can only be used between tt(byte) values. tt(Byte) variables can be initialized using curly braces around an existing tt(byte) or around fixed values of at most 8 bits (see #1 in the following example). If the specified value doesn't fit in 8 bits (#2) or if the specified value is neither a tt(byte) nor an tt(unsigned char) type variable (#3) the compiler reports an error. Assignments or assignment-like initializations using rvalues which are tt(bytes) initialized using parentheses with values not fitting in 8 bits are accepted (#4, #5). In these cases, the specified values are truncated to their lowest 8 bits. Here are the illustrations: verbinsert(-s4 //init examples/byte.cc) The tt(byte) type supports all bit-wise operations, but the right-hand operand of the bit-wise operator must also be a tt(byte). E.g., verb( value &= byte(0xf0);) tt(Byte) type values can also be ordered and compared for (in)equality. Unfortunately, no other operations are supported. E.g., tt(bytes) cannot be added and cannot be inserted into or extracted from streams, which somehow renders the tt(std::byte) less useful than ordinary types (like tt(unsigned int, uint16_t)). When needed such operations em(can) be supported using casts (covered in section ref(CPPCASTS)), but it's considered good practice to avoid casts whenever possible. However, bf(C++) allows us to define a byte-type that em(does) behave like an ordinary numeric type, including and extracting its values into and from streams. In section ref(BYTE) such a type is developed. c++-annotations-13.02.01/yo/first/attributes.yo0000664000175000017500000001277114735537670020175 0ustar frankfrankAttributes hi(attribute) are compiler directives that are inserted into source files to inform the compiler of some peculiarity of the code (variable or function) that follows the specified attribute. Attributes are used to inform the compiler about situations that are intentional, and thus prevent the compiler from issuing warnings. The following attributes are recognized: itemization( ithtq(carries_dependency)([[carries_dependency]]) (This attribute is currently not yet covered by the annotations(). At this point in the annotations() it can safely be ignored. COMMENT( tt([[carries_dependency]]) Indicates that dependency chain in release-consume std::memory_order propagates in and out of the function, which allows the compiler to skip unnecessary memory fence instructions. This attribute may appear in two situations: (1) it may apply to the parameter declarations of a function or lambda-expressions, in which case it indicates that initialization of the parameter carries dependency into lvalue-to-rvalue conversion of that object. (2) It may apply to the function declaration as a whole, in which case it indicates that the return value carries dependency to the evaluation of the function call expression. This attribute must appear on the first declaration of a function or one of its parameters in any translation unit. If it is not used on the first declaration of a function or one of its parameters in another translation unit, the program is ill-formed; no diagnostic required. See std::kill_dependency for example usage END) ) ithtq(deprecated)([[deprecated]]) (This attribute (and its alternative form tt([[deprecated("reason")]])) is available since the C++14 standard. It indicates that the use of the name or entity declared with this attribute is allowed, but discouraged for some reason. This attribute can be used for classes, typedef-names, variables, non-static data members, functions, enumerations, and template specializations. An existing non-deprecated entity may be redeclared deprecated, but once an entity has been declared deprecated it cannot be redeclared as `undeprecated'. When encountering the tt([[deprecated]]) attribute the compiler generates a warning, e.g., verb( demo.cc:12:24: warning: 'void deprecatedFunction()' is deprecated [-Wdeprecated-declarations] deprecatedFunction(); demo.cc:5:21: note: declared here [[deprecated]] void deprecatedFunction()) When using the alternative form (e.g., tt([[deprecated("do not use")]] void fun())) the compiler generates a warning showing the text between the double quotes, e.g., verb( demo.cc:12:24: warning: 'void deprecatedFunction()' is deprecated: do not use [-Wdeprecated-declarations] deprecatedFunction(); demo.cc:5:38: note: declared here [[deprecated("do not use")]] void deprecatedFunction()) ) itt([[fallthrough]])hi(fallthrough)nl() When statements nested under tt(case) entries in tt(switch) statements continue into subsequent tt(case) or tt(default) entries the compiler issues a `falling through' warning. If falling through is intentional the attribute tt([[fallthrough]]), which then must be followed by a semicolon, should be used. Here is an annotated example: verb(void function(int selector) { switch (selector) { case 1: case 2: // no falling through, but merged entry points cout << "cases 1 and 2\n"; [[fallthrough]]; // no warning: intentionally falling through case 3: cout << "case 3\n"; case 4: // a warning is issued: falling through not // announced. cout << "case 4\n"; [[fallthrough]]; // error: there's nothing beyond } }) itt([[maybe_unused]])hi(maybe_unused)nl() This attribute can be applied to a class, typedef-name, variable, parameter, non-static data member, a function, an enumeration or an enumerator. When it is applied to an entity no warning is generated when the entity is not used. Example: verb(void fun([[maybe_unused]] size_t argument) { // argument isn't used, but no warning // telling you so is issued }) itt([[nodiscard]])hi(nodiscard)nl() The attribute tt([[nodiscard]]) may be specified when declaring a function, class or enumeration. If a function is declared tt([[nodiscard]]) or if a function returns an entity previously declared using tt([[nodiscard]]) then the return value of such a function may only be ignored when explicitly cast to void. Otherwise, when the return value is not used a warning is issued. Example: verb(int [[nodiscard]] importantInt(); struct [[nodiscard]] ImportantStruct { ... }; ImportantStruct factory(); int main() { importantInt(); // warning issued factory(); // warning issued }) ithtq(noreturn)([[noreturn]]) (tt([[noreturn]]) indicates that the function does not return. tt([[noreturn]]'s) behavior is undefined if the function declared with this attribute actually returns. The following standard functions have this attribute: tt(std::_Exit, std::abort, std::exit, std::quick_exit, std::unexpected, std::terminate, std::rethrow_exception, std::throw_with_nested, std::nested_exception::rethrow_nested), Here is an example of a function declaration and definition using the tt([[noreturn]]) attribute: verb( [[noreturn]] void doesntReturn(); [[noreturn]] void doesntReturn() { exit(0); }) ) ) c++-annotations-13.02.01/yo/first/constcast.yo0000664000175000017500000000210314735537670017774 0ustar frankfrankThe tt(const) keyword has been given a special place in casting. Normally anything tt(const) is tt(const) for a good reason. Nonetheless situations may be encountered where the tt(const) can be ignored. For these special situations the tt(const_cast) should be used. Its syntax is: verb( const_cast(expression)) A ti(const_cast(expression)) expression is used to undo the tt(const) attribute of a (pointer) type. The need for a tt(const_cast) may occur in combination with functions from the standard bf(C) library which traditionally weren't always as const-aware as they should. A function tt(strfun(char *s)) might be available, performing some operation on its tt(char *s) parameter without actually modifying the characters pointed to by tt(s). Passing tt(char const hello[] = "hello";) to tt(strfun) produces the warning verb( passing `const char *' as argument 1 of `fun(char *)' discards const) A tt(const_cast) is the appropriate way to prevent the warning: verb( strfun(const_cast(hello));) c++-annotations-13.02.01/yo/first/const.yo0000664000175000017500000001561314735537670017133 0ustar frankfrankEven though the keyword ti(const) is part of the bf(C) grammar, its use is more important and much more common and strictly used in bf(C++) than it is in bf(C). The tt(const) keyword is a modifier stating that the value of a variable or of an argument may not be modified. In the following example the intent is to change the value of a variable tt(ival), which fails: verb( int main() { int const ival = 3; // a constant int // initialized to 3 ival = 4; // assignment produces // an error message }) This example shows how tt(ival) may be initialized to a given value in its definition; attempts to change the value later (in an assignment) are not permitted. Variables that are declared tt(const) can, in contrast to bf(C), be used to specify the size of an array, as in the following example: verb( int const size = 20; char buf[size]; // 20 chars big) Another use of the keyword tt(const) is seen in the declaration of pointers, e.g., in pointer-arguments. In the declaration verb( char const *buf;) tt(buf) is a pointer variable pointing to tt(char)s. Whatever is pointed to by tt(buf) may not be changed through tt(buf): the tt(char)s are declared as tt(const). The pointer tt(buf) itself however may be changed. A statement like tt(*buf = 'a';) is therefore not allowed, while tt(++buf) is. In the declaration verb( char *const buf;) tt(buf) itself is a tt(const) pointer which may not be changed. Whatever tt(char)s are pointed to by tt(buf) may be changed at will. Finally, the declaration verb( char const *const buf;) is also possible; here, neither the pointer nor what it points to may be changed. The i(rule of thumb) for the placement of the keyword tt(const) is the following: what's written to the em(left) of tt(const) may not be changed. Although simple, this rule of thumb is, unfortunately, not often used. For example, hi(Stroustrup) Bjarne Stroustrup states (in hi(http://www.stroustrup.com/...) tlurl(https://www.stroustrup.com/bs_faq2.html#constplacement)): quote( em(Should I put "const" before or after the type?) em(I put it before, but that's a matter of taste. "const T" and "T const" were always (both) allowed and equivalent. For example:) verb( const int a = 1; // OK int const b = 2; // also OK) em(My guess is that using the first version will confuse fewer programmers (``is more idiomatic'').) ) But we've already seen an example where applying this simple `before' placement rule for the keyword tt(const) produces unexpected (i.e., unwanted) results as we will shortly see (below). Furthermore, the `idiomatic' before-placement also conflicts with the notion of emi(const functions), which we will encounter in section ref(ConstFunctions). With const functions the keyword tt(const) is also placed behind rather than before the name of the function. The definition or declaration (either or not containing tt(const)) should always be read from the variable or function identifier back to the type identifier: quote( ``Buf is a const pointer to const characters'' ) This rule of thumb is especially useful in cases where confusion may occur. In examples of bf(C++) code published in other places one often encounters the reverse: tt(const) em(preceding) what should not be altered. That this may result in sloppy code is indicated by our second example above: verb( char const *buf;) What must remain constant here? According to the sloppy interpretation, the pointer cannot be altered (as tt(const) precedes the pointer). In fact, the char values are the constant entities here, as becomes clear when we try to compile the following program: verb( int main() { char const *buf = "hello"; ++buf; // accepted by the compiler *buf = 'u'; // rejected by the compiler }) Compilation fails on the statement tt(*buf = 'u';) and em(not) on the statement tt(++buf). hi(Cline, M.) hi(http://www/parashift.com/c++-faq-lite/) i(Marshall Cline)'s turl(C++ FAQ) (http://www.parashift.com/c++-faq-lite/const-correctness.html) gives the same rule (paragraph 18.5) , in a similar context: quote(em( [18.5] What's the difference between "const Fred* p", "Fred* const p" and "const Fred* const p"?) em(You have to read pointer declarations right-to-left.) ) Marshall Cline's advice can be improved, though. Here's a recipe that will effortlessly dissect even the most complex declaration: enumeration( eit() start reading at the variable's name eit() read as far as possible until you reach the end of the declaration or an (as yet unmatched) closing parenthesis. eit() return to the point where you started reading, and read backwards until you reach the beginning of the declaration or a matching opening parenthesis. eit() If you reached an opening parenthesis, continue at step 2 beyond the parenthesis where you previously stopped. ) Let's apply this recipe to the following (by itself irrelevant) complex declaration. Little arrows indicate how far we should read at each step and the direction of the arrow indicates the reading direction: verb( char const *(* const (*(*ip)())[])[] ip Start at the variable's name: 'ip' is ip+CHAR(41) Hitting a closing paren: revert --> (*ip) Find the matching open paren: <- 'a pointer to' (*ip)()CHAR(41) The next unmatched closing par: --> 'a function (not expecting arguments)' (*(*ip)()) Find the matching open paren: <- 'returning a pointer to' (*(*ip)())[]CHAR(41) The next closing par: --> 'an array of' (* const (*(*ip)())[]) Find the matching open paren: <-------- 'const pointers to' (* const (*(*ip)())[])[] Read until the end: -> 'an array of' char const *(* const (*(*ip)())[])[] Read backwards what's left: <----------- 'pointers to const chars') Collecting all the parts, we get for tt(char const *(* const (*(*ip)())[])[]): em(ip is a pointer to a function (not expecting arguments), returning a pointer to an array of const pointers to an array of pointers to const chars). This is what tt(ip) represents; the recipe can be used to parse any declaration you ever encounter. c++-annotations-13.02.01/yo/string/0000775000175000017500000000000014735537670015605 5ustar frankfrankc++-annotations-13.02.01/yo/string/examples/0000775000175000017500000000000014771010713017403 5ustar frankfrankc++-annotations-13.02.01/yo/string/examples/stringreplace.cc0000664000175000017500000000213314771010720022551 0ustar frankfrank #include #include using namespace std; int main(int argc, char **argv) { if (argc != 3) { cerr << "Usage: to process " "stdin\n"; return 1; } string search(argv[1]); string replace(argv[2]); if (search == replace) { cerr << "The replace and search texts should be different\n"; return 1; } string line; while (getline(cin, line)) { string::size_type idx = 0; while (true) { idx = line.find(search, idx); // find(): another string member // see `searching' below if (idx == string::npos) break; line.replace(idx, search.size(), replace); idx += replace.length(); // don't change the replacement } cout << line << '\n'; } } c++-annotations-13.02.01/yo/string/examples/stringempty.cc0000664000175000017500000000077714771010720022310 0ustar frankfrank #include #include using namespace std; int main() { string stringOne; cout << "The length of the stringOne string is " << stringOne.size() << " characters\n" "It is " << (stringOne.empty() ? "" : " not ") << "empty\n"; stringOne = ""; cout << "After assigning a \"\"-string to a string-object\n" "it is " << (stringOne.empty() ? "also" : " not") << " empty\n"; } c++-annotations-13.02.01/yo/string/examples/stringinsert.cc0000664000175000017500000000071614771010720022447 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hell ok."); // Insert "o " at position 4 stringOne.insert(4, "o "); string world("The World of C++"); // insert "World" into stringOne stringOne.insert(6, world, 4, 5); cout << "Guess what ? It is: " << stringOne << '\n'; } c++-annotations-13.02.01/yo/string/examples/stringcompare.cc0000664000175000017500000000163214771010720022567 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); string stringTwo; if (stringOne != stringTwo) stringTwo = stringOne; if (stringOne == stringTwo) stringTwo = "Something else"; if (stringOne.compare(stringTwo) > 0) cout << "stringOne after stringTwo in the alphabet\n"; else if (stringOne.compare(stringTwo) < 0) cout << "stringOne before stringTwo in the alphabet\n"; else cout << "The two strings are the same\n"; // Alternatively: if (stringOne > stringTwo) cout << "stringOne after stringTwo in the alphabet\n"; else if (stringOne < stringTwo) cout << "stringOne before stringTwo in the alphabet\n"; else cout << "The two strings are the same\n"; } c++-annotations-13.02.01/yo/string/examples/stringswap.cc0000664000175000017500000000063614771010720022116 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello"); string stringTwo("World"); cout << "Before: stringOne: " << stringOne << ", stringTwo: " << stringTwo << '\n'; stringOne.swap(stringTwo); cout << "After: stringOne: " << stringOne << ", stringTwo: " << stringTwo << '\n'; } c++-annotations-13.02.01/yo/string/examples/stringsubstr.cc0000664000175000017500000000043614771010720022464 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); cout << stringOne.substr(0, 5) << '\n' << stringOne.substr(6) << '\n' << stringOne.substr() << '\n'; } c++-annotations-13.02.01/yo/string/examples/stringsize.cc0000664000175000017500000000037214771010720022113 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); cout << "The length of the stringOne string is " << stringOne.size() << " characters\n"; } c++-annotations-13.02.01/yo/string/examples/stringdata.cc0000664000175000017500000000166414771010720022057 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World 12345678901234567890 "), stringTwo(5, 'a'), stringThree(stringOne.rbegin(), stringOne.rend()); stringOne.resize(20, 'z'); cout << "World at: " << stringOne.find("World") << '\n'; cout << stringOne << '\n'; stringTwo.append("hello world", 3, 5); stringTwo.insert(1, "..."); cout << stringTwo << '\n'; cout << (stringOne.data() ? "not a 0 ptr." : "0 ptr.") << '\n'; cout << (stringTwo.data() ? "not a 0 ptr." : "0 ptr.") << '\n'; cout << stringOne.data() << '\n' << "'" << stringTwo.data() << "'" << '\n'; cout << stringOne.max_size() << ", " << stringOne.capacity() << '\n'; cout << stringTwo.max_size() << ", " << stringTwo.capacity() << '\n'; return (0); } c++-annotations-13.02.01/yo/string/examples/stringassign.cc0000664000175000017500000000043214771010720022422 0ustar frankfrank #include using namespace std; int main() { string stringOne("Hello World"); string stringTwo; stringTwo = stringOne; // assign stringOne to stringTwo stringTwo = "Hello world"; // assign a C-string to StringTwo } c++-annotations-13.02.01/yo/string/examples/stringcompare2.cc0000664000175000017500000000346514771010720022657 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); // comparing from a certain offset in stringOne if (!stringOne.compare(1, stringOne.length() - 1, "ello World")) cout << "comparing 'Hello world' from index 1" " to 'ello World': ok\n"; // the number of characters to compare (2nd arg.) // may exceed the number of available characters: if (!stringOne.compare(1, string::npos, "ello World")) cout << "comparing 'Hello world' from index 1" " to 'ello World': ok\n"; // comparing from a certain offset in stringOne over a // certain number of characters with a second C-string // This fails, as 3 chars in stringOne starting at // index 6 are compared with "World" if (!stringOne.compare(6, 3, "World")) cout << "comparing 'Hello World' from index 6 over" " 3 positions to 'World and more': ok\n"; else cout << "Unequal (sub)strings\n"; // This one will report a match, as only 5 characters are // compared of the source and target strings if (!stringOne.compare(6, 5, "World and more", 0, 5)) cout << "comparing 'Hello World' from index 6 over" " 5 positions to 'World and more': ok\n"; else cout << "Unequal (sub)strings\n"; } /* Generated output: comparing 'Hello world' from index 1 to 'ello World': ok comparing 'Hello world' from index 1 to 'ello World': ok Unequal (sub)strings comparing 'Hello World' from index 6 over 5 positions to 'World and more': ok */ c++-annotations-13.02.01/yo/string/examples/stringerase.cc0000664000175000017500000000043614771010720022241 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello Cruel World"); stringOne.erase(5, 6); cout << stringOne << '\n'; stringOne.erase(); cout << "'" << stringOne << "'\n"; } c++-annotations-13.02.01/yo/string/examples/stringcstr.cc0000664000175000017500000000033714771010720022115 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); char const *cString = stringOne.c_str(); cout << cString << '\n'; } c++-annotations-13.02.01/yo/string/examples/stringfindfirst.cc0000664000175000017500000000226514771010720023134 0ustar frankfrank #include #include using namespace std; int main() { string line; getline(cin, line); string::size_type pos; cout << "Line: " << line << '\n' << "Starting at the first vowel:\n" << "'" << ( (pos = line.find_first_of("aeiouAEIOU")) != string::npos ? line.substr(pos) : "*** not found ***" ) << "'\n" << "Starting at the last vowel:\n" << "'" << ( (pos = line.find_last_of("aeiouAEIOU")) != string::npos ? line.substr(pos) : "*** not found ***" ) << "'\n" << "Starting at the first non-digit:\n" << "'" << ( (pos = line.find_first_not_of("1234567890")) != string::npos ? line.substr(pos) : "*** not found ***" ) << "'\n"; } c++-annotations-13.02.01/yo/string/examples/stringappend.cc0000664000175000017500000000114414771010720022406 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello"); string stringTwo("World"); stringOne += " " + stringTwo; stringOne = "hello"; stringOne.append(" world"); // append 5 characters: stringOne.append(" ok. >This is not used<", 5); cout << stringOne << '\n'; string stringThree("Hello"); // append " world": stringThree.append(stringOne, 5, 6); cout << stringThree << '\n'; } c++-annotations-13.02.01/yo/string/examples/stringsubscript.cc0000664000175000017500000000117714771010720023163 0ustar frankfrank #include #include using namespace std; int main() { string stringOne("Hello World"); stringOne[6] = 'w'; // now "Hello world" if (stringOne[0] == 'H') stringOne[0] = 'h'; // now "hello world" // *stringOne = 'H'; // THIS WON'T COMPILE stringOne = "Hello World"; // Now using the at() // member function: stringOne.at(6) = stringOne.at(0); // now "Hello Horld" if (stringOne.at(0) == 'H') stringOne.at(0) = 'W'; // now "Wello Horld" } c++-annotations-13.02.01/yo/string/members.yo0000664000175000017500000005520714735537670017621 0ustar frankfrankThe tt(std::string) class offers many member function as well as additional non-member functions that should be considered part of the string class. All these functions are listed below in alphabetic order. The symbolic value tt(string::npos) is defined by the string class. It represents `index-not-found' when returned by member functions returning string offset positions. Example: when calling `tt(object.find('x'))' (see below) on a string object not containing the character tt('x'), tt(npos) is returned, as the requested position does not exist. The final 0-byte used in bf(C) strings to indicate the end of an NTBS is em(not) considered part of a bf(C++) string, and so the member function will return tt(npos), rather than tt(length()) when looking for 0 in a string object containing the characters of a bf(C) string. Here are the standard functions that operate on objects of the class string. When a parameter of tt(size_t) is mentioned it may be interpreted as a parameter of type tt(string::size_type), but without defining a default argument value. The type tt(size_type) should be read as tt(string::size_type). With tt(size_type) the default argument values mentioned in section ref(STRINGOVERVIEW) apply. All quoted functions are member functions of the class tt(std::string), except where indicated otherwise. itemization( ithtq(at)(char &at(size_t opos)) (a reference to the character at the indicated position is returned. When called with tt(string const) objects a tt(char const &) is returned. The member function performs range-checking, raising an exception (that by default aborts the program) if an invalid index is passed.) ithtq(append) (string &append(InputIterator begin, InputIterator end)) (the characters in the range defined by tt(begin) and tt(end) are appended to the current string object.) ittq(string &append(string const &argument, size_type apos, size_type an)) (tt(argument) (or a substring) is appended to the current string object.) ittq(string &append(char const *argument, size_type an)) (the first tt(an) characters of tt(argument) are appended to the string object.) ittq(string &append(size_type n, char ch)) (tt(n) characters tt(ch) are appended to the current string object.) ithtq(assign)(string &assign(string const &argument, size_type apos, size_type an)) (tt(argument) (or a substring) is assigned to the string object. If tt(argument) is of type tt(char const *) and one additional argument is provided the second argument is interpreted as a value initializing tt(an), using 0 to initialize tt(apos).) ittq(string &assign(size_type n, char ch)) (tt(n) characters tt(ch) are assigned to the current string object.) ithtq(back)(char &back()) (returns a reference to the last tt(char) stored inside the string object. The result is undefined for empty strings.) ithtq(begin)(string::iterator begin()) (an iterator referring to the first character of the current string object is returned. With tt(const) string objects a tt(const_iterator) is returned.) ithtq(capacity)(size_type capacity() const) (the number of characters that can currently be stored in the string object without needing to resize it is returned.) ithtq(cbegin)(string::const_iterator cbegin()) (a tt(const_iterator) referring to the first character of the current string object is returned.) ithtq(cend)(string::const_iterator cend()) (a tt(const_iterator) referring to the end of the current string object is returned.) ithtq(clear)(void clear()) (the string's content is erased.) ithtq(compare)(int compare(string const &argument) const) (the text stored in the current string object and the text stored in tt(argument) is compared using a lexicographical comparison using the ASCII character collating sequence. zero is returned if the two strings have identical content, a negative value is returned if the text in the current object should be ordered em(before) the text in tt(argument); a positive value is returned if the text in the current object should be ordered em(beyond) the text in tt(argument).) ittq(int compare(size_t opos, size_t on, string const &argument) const) (a substring of the text stored in the current string object is compared to the text stored in tt(argument). At most tt(on) characters starting at offset tt(opos) are compared to the text in tt(argument).) ittq(int compare(size_t opos, size_t on, string const &argument, size_type apos, size_type an)) (a substring of the text stored in the current string object is compared to a substring of the text stored in tt(argument). At most tt(on) characters of the current string object, starting at offset tt(opos), are compared to at most tt(an) characters of tt(argument), starting at offset tt(apos). In this case tt(argument) em(must) be a string object.) ittq(int compare(size_t opos, size_t on, char const *argument, size_t an)) (a substring of the text stored in the current string object is compared to a substring of the text stored in tt(argument). At most tt(on) characters of the current string object starting at offset tt(opos) are compared to at most tt(an) characters of tt(argument). tt(Argument) must have at least tt(an) characters. The characters may have arbitrary values: 0-valued characters have no special meanings.) ithtq(contains)(bool contains(argument) const) (returns tt(true) if the object contains tt(argument's) characters as a substring. The argument can be a tt(string), a tt(string_view) (see section ref(STRINGVIEW)), a tt(char) or an NTBS.) ithtq(copy)(size_t copy(char *argument, size_t on, size_type opos) const) (the content of the current string object are (partially) copied into tt(argument). The actual number of characters copied is returned. The second argument, specifying the number of characters to copy, from the current string object is required. No 0-valued character is appended to the copied string but can be appended to the copied text using an idiom like the following: verb( argument[object.copy(argument, string::npos)] = 0;) Of course, the programmer should make sure that tt(argument)'s size is large enough to accommodate the additional 0-byte.) ithtq(crbegin)(string::const_reverse_iterator crbegin()) (a tt(const_reverse_iterator) referring to the last character of the current string object is returned.) ithtq(crend)(string::const_reverse_iterator crend()) (a tt(const_reverse_iterator) referring to the begin of the current string object is returned.) ithtq(c_str)(char const *c_str() const) (the content of the current string object as an NTBS.) ithtq(data)(char const *data() const) (the raw content of the current string object are returned. Since this member does not return an NTBS (as tt(c_str) does), it can be used to retrieve any kind of information stored inside the current string object including, e.g., series of 0-bytes: verb( string s(2, 0); cout << static_cast(s.data()[1]) << '\n';) ) ithtq(empty)(bool empty() const) (tt(true) is returned if the current string object contains no data.) ithtq(end)(string::iterator end()) (an iterator referring to the position just beyond the last character of the current string object is returned. With tt(const) string objects a tt(const_iterator) is returned.) ithtq(ends_with)(bool ends_with(argument) const) (returns tt(true) if the object's characters end with tt(argument). The argument can be a tt(string), a tt(string_view), a tt(char) or an NTBS.) ithtq(erase)(string &erase(size_type opos, size_type on)) (a (sub)string of the information stored in the current string object is erased.) ittq(string::iterator erase(string::iterator begin, string::iterator end)) (the parameter tt(end) is optional. If omitted the value returned by the current object's tt(end) member is used. The characters defined by the tt(begin) and tt(end) iterators are erased. The iterator tt(begin) is returned, which is then referring to the position immediately following the last erased character.) ithtq(find)(size_t find(string const &argument, size_type opos) const) (the first index in the current string object is returned where tt(argument) is found.) ittq(size_t find(char const *argument, size_type opos, size_type an) const) (the first index in the current string object is returned where tt(argument) is found. When all three arguments are specified the first argument em(must) be a tt(char const *).) ittq(size_t find(char ch, size_type opos) const) (the first index in the current string object is returned where tt(ch) is found.) ithtq(find_first_of)(size_t find_first_of(string const &argument, size_type opos) const) (the first index in the current string object is returned whose character matches any character from tt(argument).) ittq(size_type find_first_of(char const *argument, size_type opos, size_type an) const) (the first index in the current string object is returned whose character matches any character from tt(argument). If tt(opos) is provided it refers to the first index in the current string object where the search for tt(argument) should start. If omitted, the string object is completely scanned. If tt(an) is provided it indicates the number of characters of the tt(char const *) argument that should be used in the search. It defines a substring starting at the beginning of tt(argument). If omitted, all of tt(argument)'s characters are used.) ittq(size_type find_first_of(char ch, size_type opos)) (the first index in the current string object is returned whose character is equal to tt(ch).) ithtq(find_first_not_of)(size_t find_first_not_of(string const &argument, size_type opos) const) (the first index in the current string object is returned whose character does not match any character from tt(argument).) ittq(size_type find_first_not_of(char const *argument, size_type opos, size_type an) const) (the first index in the current string object is returned whose character does not match any character from tt(argument). The tt(opos) and tt(an) parameters are handled as with tt(find_first_of)) ittq(size_t find_first_not_of(char ch, size_type opos) const) (the first index in the current string object is returned whose character is unequal to tt(ch).) ithtq(find_last_of)(size_t find_last_of(string const &argument, size_type opos) const) (the last index in the current string object is returned whose character matches any character from tt(argument).) ittq(size_type find_last_of(char const *argument, size_type opos, size_type an) const) (the last index in the current string object is returned whose character matches any character from tt(argument). If tt(opos) is provided it refers to the last index in the current string object where the search for tt(argument) should start (searching backward towards the beginning of the current object). If omitted, the string object is scanned completely. If tt(an) is provided it indicates the number of characters of the tt(char const *) argument that should be used in the search. It defines a substring starting at the beginning of tt(argument). If omitted, all of tt(argument)'s characters are used.) ittq(size_type find_last_of(char ch, size_type opos)) (the last index in the current string object is returned whose character is equal to tt(ch).) ithtq(find_last_not_of)(size_t find_last_not_of(string const &argument, size_type opos) const) (the last index in the current string object is returned whose character does not match any character from tt(argument).) ittq(size_type find_last_not_of(char const *argument, size_type opos, size_type an) const) (the last index in the current string object is returned whose character does not match any character from tt(argument). The tt(opos) and tt(an) parameters are handled as with tt(find_last_of).) ittq(size_t find_last_not_of(char ch, size_type opos) const) (the last index in the current string object is returned whose character is unequal to tt(ch).) ithtq(front)(char &front()) (returns a reference to the first tt(char) stored inside the string object. The result is undefined for empty strings.) ithtq(get_allocator)(allocator_type get_allocator()) (returns the allocator of the class tt(std::string)) ithtq(getline)(istream &std::getline(istream &istr, string &object, char delimiter = '\n')) (Note: this is em(not) a member function of the class tt(string).nl() A line of text is read from tt(istr). All characters until tt(delimiter) (or the end of the stream, whichever comes first) are read from tt(istr) and are stored in tt(object). If the delimiter is encountered it is removed from the stream, but is not stored in tt(object).nl() If the delimiter is not found, tt(istr.eof) returns tt(true) (see section ref(IOSTATES)). Since streams may be interpreted as tt(bool) values (cf. section ref(IOSTATES)) a commonly encountered idiom to read all lines from a stream successively into a string object tt(line) looks like this: verb( while (getline(istr, line)) process(line);) The content of the last line, whether or not it was terminated by a delimiter, is eventually also assigned to tt(object).) ithtq(insert)(string &insert(size_t opos, string const &argument, size_type apos, size_type an)) (a (sub)string of tt(argument) is inserted into the current string object at the current string object's index position tt(opos). Arguments for tt(apos) and tt(an) must either both be provided or they must both be omitted.) ittq(string &insert(size_t opos, char const *argument, size_type an)) (tt(argument) (of type tt(char const *)) is inserted at index tt(opos) into the current string object.) ittq(string &insert(size_t opos, size_t count, char ch)) (tt(Count) characters tt(ch) are inserted at index tt(opos) into the current string object.) ittq(string::iterator insert(string::iterator begin, char ch)) (the character tt(ch) is inserted at the current object's position referred to by tt(begin). tt(Begin) is returned.) ittq(string::iterator insert(string::iterator begin, size_t count, char ch)) (tt(Count) characters tt(ch) are inserted at the current object's position referred to by tt(begin). tt(Begin) is returned.) ittq(string::iterator insert(string::iterator begin, InputIterator abegin, InputIterator aend)) (the characters in the range defined by the tt(InputIterators abegin) and tt(aend) are inserted at the current object's position referred to by tt(begin). tt(Begin) is returned.) ithtq(length)(size_t length() const) (the number of characters stored in the current string object is returned.) ithtq(max_size)(size_t max_size() const) (the maximum number of characters that can be stored in the current string object is returned.) ithtq(pop_back)(void pop_back()) (The string's last character is removed from the string object.) ithtq(push_back)(void push_back(char ch)) (The character tt(ch) is appended to the string object.) ithtq(rbegin)(string::reverse_iterator rbegin()) (a reverse iterator referring to the last character of the current string object is returned. With tt(const) string objects a tt(const_reverse_iterator) is returned.) ithtq(rend)(string::reverse_iterator rend()) (a reverse iterator referring to the position just before the first character of the current string object is returned. With tt(const) string objects a tt(const_reverse_iterator) is returned.) ithtq(replace)(string &replace(size_t opos, size_t on, string const &argument, size_type apos, size_type an)) (a (sub)string of characters in tt(object) are replaced by the (subset of) characters of tt(argument). If tt(on) is specified as 0 tt(argument) is inserted into tt(object) at offset tt(opos).) ittq(string &replace(size_t opos, size_t on, char const *argument, size_type an)) (a series of characters in tt(object) are replaced by the first tt(an) characters of tt(char const *) argument.) ittq(string &replace(size_t opos, size_t on, size_type count, char ch)) (tt(on) characters of the current string object, starting at index position tt(opos), are replaced by tt(count) characters tt(ch).) ittq(string &replace(string::iterator begin, string::iterator end, string const &argument)) (the series of characters in the current string object defined by the iterators tt(begin) and tt(end) are replaced by tt(argument). If tt(argument) is a tt(char const *), an additional argument tt(an) may be used, specifying the number of characters of tt(argument) that are used in the replacement.) ittq(string &replace(string::iterator begin, string::iterator end, size_type count, char ch)) (the series of characters in the current string object defined by the iterators tt(begin) and tt(end) are replaced by tt(count) characters having values tt(ch).) ittq(string &replace(string::iterator begin, string::iterator end, InputIterator abegin, InputIterator aend)) (the series of characters in the current string object defined by the iterators tt(begin) and tt(end) are replaced by the characters in the range defined by the tt(InputIterators abegin) and tt(aend).) ithtq(reserve)(void reserve(size_t request)) (the current string object's capacity is changed to at least tt(request). After calling this member, tt(capacity)'s return value will be at least tt(request). A request for a smaller size than the value returned by tt(capacity) is ignored. A hi(length_error)tt(std::length_error) exception is thrown if tt(request) exceeds the value returned by tt(max_size) (tt(std::length_error) is defined in the ti(stdexcept) header). Calling tt(reserve()) has the effect of redefining a string's capacity: when enlarging the capacity extra memory is allocated, but not immediately available to the program. This is illustrated by the exception thrown by the string's tt(at()) member when trying to access an element exceeding the string's tt(size) but not the string's tt(capacity).) ithtq(resize)(void resize(size_t size, char ch = 0)) (the current string object is resized to tt(size) characters. If the string object is resized to a size larger than its current size the additional characters will be initialized to tt(ch). If it is reduced in size the characters having the highest indices are chopped off.) ithtq(rfind)(size_t rfind(string const &argument, size_type opos) const) (the last index in the current string object where tt(argument) is found is returned. Searching proceeds from the current object's offset tt(opos) back to its beginning.) ittq(size_t rfind(char const *argument, size_type opos, size_type an) const) (the last index in the current string object where tt(argument) is found is returned. Searching proceeds from the current object's offset tt(opos) back to its beginning. The parameter tt(an) specifies the length of the substring of tt(argument) to look for, starting at tt(argument)'s beginning.) ittq(size_t rfind(char ch, size_type opos)const) (the last index in the current string object where tt(ch) is found is returned. Searching proceeds from the current object's offset tt(opos) back to its beginning.) ithtq(shrink_to_fit)(void shrink_to_fit()) (optionally reduces the amount of memory allocated by a vector to its current size. The implementor is free to ignore or otherwise optimize this request. In order to guarantee a `shrink to fit' operation the verb( string{ stringObject }.swap(stringObject)) idiom can be used.) ithtq(size)(size_t size() const) (the number of characters stored in the current string object is returned. This member is a synonym of tt(length()).) ithtq(starts_with)(bool starts_with(argument) const) (returns tt(true) if the object's character range starts with tt(argument). The argument can be a tt(string), a tt(string_view), a tt(char) or an NTBS.) ithtq(substr)(string substr(size_type opos, size_type on) const) (a substring of the current string object of at most tt(on) characters starting at index tt(opos) is returned.) ithtq(swap)(void swap(string &argument)) (the content of the current string object are swapped with the content of tt(argument). For this member tt(argument) must be a string object and cannot be a tt(char const *).) ) COMMENT( verbinclude(-a examples/stringassign.cc) verbinclude(-a examples/stringcstr.cc) verbinclude(-a examples/stringsubscript.cc) verbinclude(-a examples/stringcompare.cc) verbinclude(-a examples/stringcompare2.cc) verbinclude(-a examples/stringappend.cc) verbinclude(-a examples/stringinsert.cc) verbinclude(-a examples/stringreplace.cc) verbinclude(-a examples/stringswap.cc) verbinclude(-a examples/stringerase.cc) verbinclude(-a examples/stringsubstr.cc) verbinclude(-a examples/stringfindfirst.cc) verbinclude(-a examples/stringsize.cc) verbinclude(-a examples/stringempty.cc) END COMMENT) c++-annotations-13.02.01/yo/string/convertors.yo0000664000175000017500000001244114735537670020364 0ustar frankfrankSeveral string conversion functions are available operating on or producing tt(std::string) objects. These functions are listed below in alphabetic order. They are not member functions, but class-less (free) functions declared in the tt(std) namespace. The tthi(string) header file must be included before they can be used. itemization( ithtq(stof)(float stof(std::string const &str, size_t *pos = 0)) (Initial whitespace characters in tt(str) are ignored. Then the following sequences of characters are converted to a tt(float) value, which is returned: itemization( it() A decimal floating point constant: itemization( it() An optional + or - character it() A series of decimal digits, possibly containing one decimal point character it() An optional e or E character, followed by an optional - or + character, followed by a series of decimal digits ) it() A hexadecimal floating point constant: itemization( it() An optional + or - character it() 0x or 0X it() A series of hexadecimal digits, possibly containing one decimal point character it() An optional p or P character, followed by an optional - or + character, followed by a series of decimal digits ) it() An infinity expression: itemization( it() An optional + or - character it() The words tt(inf) or tt(infinity) (case insensitive words) ) it() A `not a number' expression: itemization( it() An optional + or - character it() The words tt(nan) or tt(nan(alphanumeric character sequence)) (tt(nan) is a case insensitive word), resulting in a tt(NaN) floating point value ) ) If tt(pos != 0) the index of the first character in tt(str) which was not converted is returned in tt(*pos). A tt(std::invalid_argument) exception is thrown if the characters in tt(str) could not be converted to a tt(float), a tt(std::out_of_range) exception is thrown if the converted value would have exceeded the range of tt(float) values.) ithtq(stod)(double stod(std::string const &str, size_t *pos = 0)) (A conversion as described with tt(stof) is performed, but now to a value of type tt(double).) ithtq(stold)(double stold(std::string const &str, size_t *pos = 0)) (A conversion as described with tt(stof) is performed, but now to a value of type tt(long double).) ithtq(stoi)(int stoi(std::string const &str, size_t *pos = 0, int base = 10)) (Initial whitespace characters in tt(str) are ignored. Then all characters representing numeric constants of the number system whose tt(base) is specified are converted to an tt(int) value, which is returned. An optional + or - character may prefix the numeric characters. Values starting with 0 are automatically interpreted as octal values, values starting with 0x or 0X as hexadecimal characters. The value tt(base) must be between 2 and 36. If tt(pos != 0) the index of the first character in tt(str) which was not converted is returned in tt(*pos). A tt(std::invalid_argument) exception is thrown if the characters in tt(str) could not be converted to an tt(int), a tt(std::out_of_range) exception is thrown if the converted value would have exceeded the range of tt(int) values. Here is an example of its use: verb(int value = stoi(" -123"s); // assigns value -123 value = stoi(" 123"s, 0, 5); // assigns value 38) ) ithtq(stol)(long stol(std::string const &str, size_t *pos = 0, int base = 10)) (A conversion as described with tt(stoi) is performed, but now to a value of type tt(long).) ithtq(stoll)(long long stoll(std::string const &str, size_t *pos = 0, int base = 10)) (A conversion as described with tt(stoi) is performed, but now to a value of type tt(long long).) ithtq(stoul)(unsigned long stoul(std::string const &str, size_t *pos = 0, int base = 10)) (A conversion as described with tt(stoi) is performed, but now to a value of type tt(unsigned long).) ithtq(stoull)(unsigned long long stoull(std::string const &str, size_t *pos = 0, int base = 10)) (A conversion as described with tt(stoul) is performed, but now to a value of type tt(unsigned long long).) ithtq(to_string)(std::string to_string(Type value)) (Type can be of the types tt(int, long, long long, unsigned, unsigned long, unsigned long long, float, double,) or tt(long double). The value of the argument is converted to a textual representation, which is returned as a tt(std::string) value. ) ithtq(to_wstring)(std::wstring to_wstring(Type value)) (The conversion as described at tt(to_string) is performed, returning a ti(std::wstring).) ) c++-annotations-13.02.01/yo/string/string.yo0000664000175000017500000000476014735537670017473 0ustar frankfrankbf(C++) offers many solutions for common problems. Most of these facilities are part of the em(Standard Template Library) or they are implemented as em(generic algorithms) (see chapter ref(GENERIC)). Among the facilities bf(C++) programmers have developed over and over again are those manipulating chunks of text, commonly called em(strings). The bf(C) programming language offers rudimentary string support. To process text bf(C++) offers a hi(string)tt(std::string) type. In bf(C++) the traditional bf(C) library functions manipulating NTB strings are deprecated in favor of using tt(string) objects. Many problems in bf(C) programs are caused by buffer overruns, boundary errors and allocation problems that can be traced back to improperly using these traditional bf(C) string library functions. Many of these problems can be prevented using bf(C++) string objects. Actually, tt(string) objects are em(class type) variables, and in that sense they are comparable to stream objects like tt(cin) and tt(cout). In this section the use of tt(string) type objects is covered. The focus is on their definition and their use. When using tt(string) objects the emi(member function) em(syntax) is commonly used: verb( stringVariable.operation(argumentList)) For example, if tt(string1) and tt(string2) are variables of type tt(std::string), then verb( string1.compare(string2)) can be used to compare both strings. In addition to the common member functions the tt(string) class also offers a wide variety of em(operators), like the assignment (tt(=)) and the comparison operator (tt(==)). Operators often result in code that is easy to understand and their use is generally preferred over the use of member functions offering comparable functionality. E.g., rather than writing verb( if (string1.compare(string2) == 0)) the following is generally preferred: verb( if (string1 == string2)) To define and use tt(string)-type objects, sources must include the header file tthi(string). To merely hi(string: declaring) em(declare) the string type the header i(iosfwd) can be included. In addition to tt(std::string), the header file tt(string) defines the following string types: itemization( itht(wstring)(std::wstring), a string type consisting of tt(wchar_t) characters; itht(u16string)(std::u16string), a string type consisting of tt(char16_t) characters; itht(u32string)(std::u32string), a string type consisting of tt(char32_t) characters. ) c++-annotations-13.02.01/yo/string/initializers.yo0000664000175000017500000000326614735537670020673 0ustar frankfrankAfter defining string objects they are guaranteed to be in a valid state. At em(definition time) string objects may be initialized in one of the following ways: The following tt(string) constructors hi(string constructors) are available: itemization( ittq(string object) (initializes tt(object) to an empty string. When defining a tt(string) this way no argument list may be specified;) ittq(string object(string::size_type count, char ch)) (initializes tt(object) with tt(count) characters tt(ch). em(Caveat:) to initialize a string object using this constructor do not use the curly braces variant, but use the constructor as shown, to avoid selecting the initializer-list constructor (see below);) ittq(string object(string const &argument)) (initializes tt(object) with tt(argument);) ittq(string object(std::string const &argument, string::size_type apos, string::size_type an)) (initializes tt(object) with tt(argument)'s content starting at index position tt(apos), using at most tt(an) of tt(argument)'s characters;) ittq(string object(InputIterator begin, InputIterator end)) (initializes tt(object) with the characters in the range of characters defined by the two tt(InputIterators).) ittq(string object(std::initializer_list chars)) (initializes tt(object) with the characters specified in the initializer list. The string may also directly be initialized, using the curly braced initialization. Here is an example showing both forms: verb(string str1({'h', 'e', 'l', 'l', 'o'}); string str2{ 'h', 'e', 'l', 'l', 'o' };) ) ) c++-annotations-13.02.01/yo/string/operators.yo0000664000175000017500000000607114735537670020200 0ustar frankfrankString objects may be manipulated by member functions but also by operators. Using operators often results in more natural-looking code. In cases where operators are available having equivalent functionality as member function the operator is practically always preferred. The following operators are available for tt(string) objects (in the examples `object' and `argument' refer to existing tt(std::string) objects). itemization( it() plain assignment: quote(a character, bf(C) or bf(C++) string may be assigned to a tt(string) object. The assignment operator returns its left-hand side operand. Example: verb(object = argument; object = "C string"; object = 'x'; object = 120; // same as object = 'x') ) it() addition: quote(the arithmetic additive assignment operator and the addition operator add text to a tt(string) object. The compound assignment operator returns its left-hand side operand, the addition operator returns its result in a temporary string object. When using the addition operator either the left-hand side operand or the right-hand side operand must be a tt(std::string) object. The other operand may be a char, a bf(C) string or a bf(C++) string. Example: verb(object += argument; object += "hello"; object += 'x'; // integral expressions are OK argument + otherArgument; // two std::string objects argument + "hello"; // using + at least one "hello" + argument; // std::string is required argument + 'a'; // integral expressions are OK 'a' + argument;) ) it() index operator: quote(The index operator may be used to retrieve tt(object)'s individual characters, or to assign new values to individual characters of a non-const string object. There is no range-checking (use the tt(at()) member function for that). This operator returns a tt(char &) or tt(char const &). Example: verb(object[3] = argument[5];) ) it() logical operators: quote(the logical comparison operators may be applied to two string objects or to a string object and a bf(C) string to compare their content. These operators return a tt(bool) value. The tt(==, !=, >, >=, <,) and tt(<=) operators are available. The ordering operators perform a lexicographical comparison of their content using the ASCII character collating sequence. Example: verb(object == object; // true object != (object + 'x'); // true object <= (object + 'x'); // true) ) it() stream related operators: quote(the insertion-operator (cf. section ref(CoutCinCerr)) may be used to insert a tt(string) object into an tt(ostream), the extraction-operator may be used to extract a string object from an tt(istream). The extraction operator by default first ignores all whitespace characters and then extracts all consecutively non-blank characters from an tt(istream). Instead of a string a character array may be extracted as well, but the advantage of using a string object should be clear: the destination string object is automatically resized to the required number of characters. Example: verb(cin >> object; cout << object;) ) ) c++-annotations-13.02.01/yo/string/iterators.yo0000664000175000017500000000246314735537670020177 0ustar frankfrank See section ref(ITERATORS) for details about em(iterators). As a quick introduction to iterators: an iterator acts like a pointer, and pointers can often be used in situations where iterators are requested. Iterators usually come in pairs, defining a range of entities. The begin-iterator points to the first entity, the end-iterator points just beyond the last entity of the range. Their difference is equal to the number of entities in the iterator-range. Iterators play an important role in the context of em(generic algorithms) (cf. chapter ref(GENERIC)). The class tt(std::string) defines the following hi(string: iterator types)em(iterator types): itemization( itt(string::iterator) and tt(string::const_iterator): quote(these iterators are emi(forward iterators). The tt(const_iterator) is returned by tt(string const) objects, the plain tt(iterator) is returned by non-const string objects. Characters referred to by tt(iterators) may be modified;) itt(string::reverse_iterator) and tt(string::const_reverse_iterator): quote(these iterators are also emi(forward iterators) but when em(incrementing) the iterator the em(previous) character in the string object is reached. Other than that they are comparable to, respectively, tt(string::iterator) and tt(string::const_iterator).) ) c++-annotations-13.02.01/yo/string/overview.yo0000664000175000017500000000643114735537670020030 0ustar frankfrankIn this section the string members and string-related operations are referenced. The subsections cover, respectively the string's initializers, iterators, operators, and member functions. The following terminology is used throughout this section: itemization( it() tt(object) is always a tt(string)-object; it() tt(argument) is a tt(string const &) or a tt(char const *) unless indicated otherwise. The content of an tt(argument) never is modified by the operation processing the tt(argument); it() tt(opos) refers to an offset into an tt(object) string; it() tt(apos) refers to an offset into an tt(argument); it() tt(on) represents a number of characters in an tt(object) (starting at tt(opos)); it() tt(an) represents a number of characters in an tt(argument) (starting at tt(apos)). ) Both tt(opos) and tt(apos) must refer to existing offsets, or an exception (cf. chapter ref(EXCEPTIONS)) is generated. In contrast, tt(an) and tt(on) may exceed the number of available characters, in which case only the available characters are considered. Many members declare default values for tt(on, an) and tt(apos). Some members declare default values for tt(opos). Default offset values are 0, the default values of tt(on) and tt(an) is tt(string::npos), which can be interpreted as `the required number of characters to reach the end of the string'. With members starting their operations at the end of the string object's content proceeding backwards, the default value of tt(opos) is the index of the object's em(last) character, with tt(on) by default equal to tt(opos + 1), representing the length of the substring em(ending) at tt(opos). In the overview of member functions presented below it may be assumed that all these parameters accept default values unless indicated otherwise. Of course, the default argument values cannot be used if a function requires additional arguments beyond the ones otherwise accepting default values. Some members have overloaded versions expecting an initial argument of type tt(char const *). But even if that is not the case the first argument can em(always) be of type tt(char const *) where a parameter of tt(std::string) is defined. Several member functions accept em(iterators). Section ref(ITERATORS) covers the technical aspects of em(iterators), but these may be ignored at this point without loss of continuity. Like tt(apos) and tt(opos), iterators must refer to existing positions and/or to an existing range of characters within the string object's content. All tt(string)-member functions computing indices return the predefined constant tt(string::npos) on failure. The ti(s) i(literal suffix) to indicate that a tt(std::string) constant is intended when a string literal (like tt("hello world")) is used. It can be used after declaring tt(using namespace std) or, more specific, after declaring hi(literals namespace)hi(string_literals namespace) tt(using namespace std::literals::string_literals). When string literals are used when explicitly defining or using tt(std::string) objects the tt(s)-suffix is hardly ever required, but it may come in handy when using the tt(auto) keyword. E.g., tt(auto str = "hello world"s) defines tt(std::string str), whereas it would have been a tt(char const *) if the literal suffix had been omitted. c++-annotations-13.02.01/yo/string/ops.yo0000664000175000017500000001126714735537670016766 0ustar frankfrankSome of the operations that can be performed on strings return indices within the strings. Whenever such an operation fails to find an appropriate index, the em(value) hi(npos)tt(string::npos) is returned. This value is a symbolic value of type hi(size_type)ti(string::size_type), which is (for all practical purposes) an (tt(unsigned)) tt(int). All tt(string) member functions accepting tt(string) objects as arguments also accept NTBS arguments. The same usually holds true for operators accepting tt(string) objects. Some tt(string)-members use em(iterators). Iterators are formally introduced in section ref(ITERATORS). Member functions using iterators are listed in the next section (ref(STRINGOVERVIEW)), but the iterator concept itself is not further covered by this chapter. Strings support a large variety of members and operators. A short overview listing their capabilities is provided in this section, with subsequent sections offering a detailed discussion. The bottom line: bf(C++) strings are extremely versatile and there is hardly a reason for falling back on the bf(C) library to process text. bf(C++) strings handle all the required memory management and thus memory related problems, which are the #1 source of problems in bf(C) programs, can be prevented when bf(C++) strings are used. Strings do come at a price, though. The class's extensive capabilities have also turned it into a beast. It's hard to learn and master all its features and in the end you'll find that not all that you expected is actually there. For example, tt(std::string) doesn't offer case-insensitive comparisons. But in the end it isn't even as simple as that. It em(is) there, but it is somewhat hidden and at this point in the annotations() it's too early to study into that hidden corner yet. Instead, realize that bf(C)'s standard library em(does) offer useful functions that can be used as long as we're aware of their limitations and are able to avoid their traps. So for now, to perform a traditional i(case-insensitive) comparison of the content of two tt(std::string) objects tt(str1) and tt(str2) the following will do: hi(strcasecmp) verb( strcasecmp(str1.c_str(), str2.c_str());) Strings support the following functionality: itemization( ittq(initialization) (when string objects are defined they are always properly initialized. In other words, they are always in a i(valid state). Strings may be initialized empty or already existing text can be used to initialize strings.) ittq(assignment) (strings may be given new values. New values may be assigned using member functions (like tt(assign)) but a plain assignment operator (i.e., tt(=))may also be used. Furthermore, assignment em(to) a character buffer is also supported.) ittq(conversions) (the partial or complete content of string objects may be interpreted as bf(C) strings but the string's content may also be processed as a series of raw binary bytes, not necessarily terminating in a 0-valued character. Furthermore, in many situations plain characters and bf(C) strings may be used where tt(std::string)s are accepted as well.) ittq(breakdown) (the individual characters stored in a string can be accessed using the familiar index operator (tt([])) allowing us to either access or modify information in the middle of a string.) ittq(comparisons) (strings may be compared to other strings (NTBSs) using the familiar logical comparison operators tt(==, !=, <, <=, >) and tt(>=). There are also member functions available offering a more fine-grained comparison.) ittq(modification) (the content of strings may be modified in many ways. Operators are available to add information to string objects, to insert information in the middle of string objects, or to replace or erase (parts of) a string's content.) ittq(swapping) (the string's swapping capability allows us in principle to exchange the content of two string objects without a byte-by-byte copying operation of the string's content.) ittq(searching) (the locations of characters, sets of characters, or series of characters may be searched for from any position within the string object and either searching in a forward or backward direction.) ittq(housekeeping) (several housekeeping facilities are offered: the string's length, or its empty-state may be interrogated. But string objects may also be resized.) ittq(stream I/O) (strings may be extracted from or inserted into streams. In addition to plain string extraction a line of a text file may be read without running the risk of a buffer overrun. Since extraction and insertion operations are stream based the I/O facilities are em(device independent).) ) c++-annotations-13.02.01/yo/string/stringview.yo0000664000175000017500000000514614735537670020365 0ustar frankfrankIn addition to the class tt(std::string) the class tt(std::string_view) can be used as a wrapper-class of tt(char) arrays. The class tt(string_view) can be considered a light-weight tt(string) class. Before using tt(std::string_view) objects the tthi(string_view) header file must have been included. In addition to the standard constructors (default, copy, move) it offers the following constructors: itemization( itt(constexpr string_view(char const *src, size_t nChars)), constructs a tt(string_view) object from the first tt(nChars) characters of tt(src). The characters in the range rangett(src, src + nChars) may be 0-valued characters; itt(constexpr string_view(char const *src)), constructs a tt(string_view) object from the NTBS starting at tt(src). The argument passed to this constructor may not be a null pointer; itt(constexpr string_view(Iterator begin, Iterator end)), constructs a tt(string_view) object from the characters in the iterator-range rangett(begin, end). ) A tt(string_view) object does not contain its own copy of the initialized data. Instead, it refers to the characters that were used when it was initially constructed. E.g., the following program produces unpredictable output, but when the tt(hello) array is defined as a static array it shows em(hello): verb( #include #include using namespace std; string_view fun() { char hello[] = "hello"; return { hello }; } int main() { string_view obj = fun(); cout << obj << '\n'; }) The tt(std::string_view) class provides the same members as tt(std::string), except for members extending the tt(string_view's) characters (neither appending nor inserting characters is possible). However, tt(string_view) objects em(can) modify their characters (using the index operator or tt(at) member). The tt(string_view) class also offers some extra members: itemization( ithtq(remove_prefix)(remove_prefix(size_t step)) (moves the begin of the object's character range forward by tt(step) positions.) ithtq(remove_suffix)(remove_suffix(size_t step)) (moves the end of the object's character range backward by tt(step) positions.) ithtq(operator""sv)(constexpr string_view operator""sv(char const *str, size_t len)) (returns a tt(string_view) object containing tt(len) characters of tt(str).) ) Like tt(std::string) the tt(std::string_view) class provides hashing facilities, so tt(string_view) objects can be used as keys in, e.g., tt(map) containers (cf. chapter ref(CONTAINERS)). c++-annotations-13.02.01/yo/advancedtemplates/0000775000175000017500000000000014735537670017763 5ustar frankfrankc++-annotations-13.02.01/yo/advancedtemplates/errorcategory.yo0000664000175000017500000001216114735537670023224 0ustar frankfrankIn the previous section the error code enumerations tt(CatErr) and tt(Cond) were developed. The values of these enumerations specify, respectively, the direct and the platform independent causes of errors that may be encountered in the context of the new error category developed in this section. Classes derived from tt(std::error_category) are designed as singleton classes and implement their own tt(name, message) and an tt(equivalent) members. Our class tt(Category) also declares a static member tt(instance) returning a reference to the class's singleton object, which is compile-time initialized and is available by the time tt(instance) is called. Alternatively a dedicated function (like tt(Category_category)), analogously to the function tt(generic_category), returning a reference to the tt(Category) object could be defined. tt(CatErr) values, tt(Cond) values and textual descriptions of tt(CatErr's) values are combined in a tt(std::unordered_map) using tt(CatErr) as key, and a tt(struct POD) as value type. This map allows us to retrieve the platform independent error types and the descriptions that are associated with tt(CatErr) values. Here is the interface of the class tt(Category): verbinsert(-s4 //category examples/errcode/category/category.h) Its tt(unordered_map s_map) provides the tt(Cond) values and verbal descriptions of the tt(CatErr) values given those tt(CatErr) values: verbinsert(-s4 //data examples/errcode/category/data.cc) The functions tt(make_error_code) and tt(make_error_condition) return, respectively, tt(error_code) and tt(error_condition) objects from, respectively, tt(CatErr) values and tt(Cond) values. Their declarations can be provided below the tt(Category) class interface and their implementations pass the tt(Category) object to their constructors: verbinsert(-s4 //make examples/errcode/category/makeerrorcode.cc) verbinsert(-s4 //make examples/errcode/category/makeerrorcondition.cc) The member tt(name) em(must) be defined by classes derived from tt(error_category). It simply returns a short string naming the category (e.g., tt("Category") for our tt(Category) class). Likewise, the member tt(message) em(must) be redefined. Its implementation usually is slightly more complex than tt(name's) implementation: it expects a (cast to an tt(int)) tt(CatErr) value and uses that value to find the corresponding textual description in tt(s_map). If found the description is returned; if not found then a short fallback message is returned: verbinsert(-s4 //msg examples/errcode/category/message.cc) The member tt(default_error_condition) receives a (cast to tt(int)) tt(CatErr) value. That value is used to find the associated tt(Cond) value. If the tt(int) received by the function does not represent a valid tt(CatErr) value then the fallback value tt(Cond::NoCond) is used. The function returns an tt(error_condition) object created by tt(make_error_condition) which receives the determined tt(Cond) value as its argument: verbinsert(-s4 //def examples/errcode/category/defaulterrorcondition.cc) What's left is implementing the two tt(equivalent) members. The first tt(equivalent) member (receiving a reference to an tt(error_code) object and a (cast to tt(int)) tt(Cond) value) determines the equivalence of the tt(Cond) value that is associated with the tt(error_code) object and the tt(Cond) value that is specified as the function's second argument. If these values are equal and the tt(error_code) object's category is equal to tt(Category) then the equivalence has been established and tt(true) is returned. Here is its implementation: verbinsert(-s4 //equiv examples/errcode/category/equivalent1.cc) The second tt(equivalent) member (receiving (as an tt(int)) tt(CatErr) value and an tt(error_condition) object) determines the equivalence of an tt(error_condition) object that is constructed from the tt(Cond) value that is associated with the tt(CatErr) value that was passed (as tt(int)) to the function and the tt(error_condition) object that was passed to the function as its second argument. Here a prerequisite for concluding equivalence is that the error condition's category is tt(Category). If that's the case then the function returns tt(true) if its tt(int) argument equals zero and the tt(condition) object also indicates no error. Alternatively, if the tt(condition) argument is equal to the tt(error_condition) object made from the tt(Cond) value associated with the tt(CatErr) value passed to the function as its first argument the equivalence has also been established and tt(true) is returned. Here is its implementation: verbinsert(-s4 //equiv examples/errcode/category/equivalent2.cc) So, in order to define your own category: itemization( it() define an enumeration which is `promoted' to an tt(error_code_enum); it() define an enumeration which is promoted to an tt(error_condition_enum); it() define a new tt(error_category) class by deriving a class from tt(std::error_category), define it as a singleton class and override its tt(default_error_condition, equivalent, message,) and tt(name) members. ) c++-annotations-13.02.01/yo/advancedtemplates/examples/0000775000175000017500000000000014771010711021557 5ustar frankfrankc++-annotations-13.02.01/yo/advancedtemplates/examples/typeat.cc0000664000175000017500000000132214771010715023376 0ustar frankfrank#include #include #include "typeat.h" using namespace std; int main() { //EXAMPLE using list3 = TypeList; // TypeAt<3, list3>::Type invalid; TypeAt<0, list3>::Type intVariable = 13; TypeAt<2, list3>::Type boolVariable = true; cout << "The size of the first type is " << sizeof(TypeAt<0, list3>::Type) << ", " "the size of the third type is " << sizeof(TypeAt<2, list3>::Type) << "\n"; if (typeid(TypeAt<1, list3>::Type) == typeid(char)) cout << "The typelist's 2nd type is char\n"; if (typeid(TypeAt<2, list3>::Type) != typeid(char)) cout << "The typelist's 3nd type is not char\n"; //= } c++-annotations-13.02.01/yo/advancedtemplates/examples/append.h0000664000175000017500000000103714771010714023203 0ustar frankfrank#ifndef INCLUDED_APPEND_H_ #define INCLUDED_APPEND_H_ #include "typelist.h" //STRUCTS template struct Append; template struct Prefix; //= //ADDTYPE template struct Append, NewType> { using List = TypeList; }; template struct Prefix> { using List = TypeList; }; //= #endif c++-annotations-13.02.01/yo/advancedtemplates/examples/typeat.h0000664000175000017500000000130614771010714023241 0ustar frankfrank#ifndef INCLUDED_TYPEAT_H_ #define INCLUDED_TYPEAT_H_ #include "typelist.h" //TYPEAT template struct TypeAt; //= //INVALID template struct TypeAt> { static_assert(index < 0, "TypeAt index out of bounds"); using Type = TypeAt; }; //= //ZERO template struct TypeAt<0, TypeList> { using Type = Head; }; //= //TYPELIST template struct TypeAt> { using Type = typename TypeAt>::Type; }; //= #endif c++-annotations-13.02.01/yo/advancedtemplates/examples/basictraits.cc0000664000175000017500000000323614771010715024406 0ustar frankfrank#include #include "basictraits.h" using namespace std; int main() { //MAIN cout << "int: plain type? " << BasicTraits::isPlainType << "\n" "int: ptr? " << BasicTraits::isPointerType << "\n" "int: const? " << BasicTraits::isConst << "\n" "int *: ptr? " << BasicTraits::isPointerType << "\n" "int const *: ptr? " << BasicTraits::isPointerType << "\n" "int const: const? " << BasicTraits::isConst << "\n" "int: reference? " << BasicTraits::isReferenceType << "\n" "int &: reference? " << BasicTraits::isReferenceType << "\n" "int const &: ref ? " << BasicTraits::isReferenceType << "\n" "int const &: const ? " << BasicTraits::isConst << "\n" "int &&: r-reference? " << BasicTraits::isRvalueReferenceType << "\n" "int &&: const? " << BasicTraits::isConst << "\n" "int const &&: r-ref ? "<< BasicTraits:: isRvalueReferenceType << "\n" "int const &&: const ? "<< BasicTraits::isConst << "\n" "\n"; BasicTraits::ValueType value = 12; BasicTraits::RvalueRefType rvalue = int(10); BasicTraits::PtrType ptr = new int(14); cout << value << ' ' << rvalue << ' ' << *ptr << '\n'; //= } c++-annotations-13.02.01/yo/advancedtemplates/examples/userdefined.cc0000664000175000017500000000073514771010715024374 0ustar frankfrank#include using namespace std; template double _kmh(Chars ...chars); double _kmh() { return 0; } template struct factor { enum { value = 10 * factor::value }; }; template<> struct factor<0> { enum {value = 1}; }; template double _kmh(char c, Chars ...chars) { return (c - '0') * factor::value + _kmh(chars ...); } int main() { cout << _kmh('1', '2', '3') << '\n'; } c++-annotations-13.02.01/yo/advancedtemplates/examples/multi.h0000664000175000017500000000702014771010714023064 0ustar frankfrank#include template struct TypeList { TypeList(TypeList const &) = delete; enum { size = sizeof ...(Types) }; }; //VECTOR template struct Vector: public std::vector { Vector(std::initializer_list iniValues) : std::vector(iniValues) {} }; //= //UWRAP template struct UWrap: public Type { UWrap(Type const &type) : Type(type) {} }; //= //MULTIBASE template struct MultiBase; //= //MULTIBASEREC template struct MultiBase : public UWrap, public MultiBase { using Type = PolicyT1; using Base = MultiBase; MultiBase(PolicyT1 && policyt1, PolicyTypes &&...policytypes) : UWrap(std::forward(policyt1)), MultiBase( std::forward(policytypes)...) {} }; //= //MULTIBASEDONE template struct MultiBase {}; //= //MULTI template

Frank B. Brokken (f.b.brokken@rug.nl)