From 46b81f0e83cdecd655c1cfe113171bb929c8748f Mon Sep 17 00:00:00 2001 From: Yury Lysogorskiy Date: Wed, 29 Sep 2021 15:27:46 +0200 Subject: [PATCH] ver 2021.9.28 --- LICENSE | 366 +++++++ {USER-PACE => ML-PACE}/ace_abstract_basis.cpp | 77 +- {USER-PACE => ML-PACE}/ace_abstract_basis.h | 156 ++- {USER-PACE => ML-PACE}/ace_array2dlm.h | 5 +- {USER-PACE => ML-PACE}/ace_arraynd.h | 0 {USER-PACE => ML-PACE}/ace_c_basis.cpp | 522 +++++++++- {USER-PACE => ML-PACE}/ace_c_basis.h | 34 +- {USER-PACE => ML-PACE}/ace_c_basisfunction.h | 75 ++ {USER-PACE => ML-PACE}/ace_complex.h | 0 {USER-PACE => ML-PACE}/ace_contigous_array.h | 0 {USER-PACE => ML-PACE}/ace_evaluator.cpp | 11 +- {USER-PACE => ML-PACE}/ace_evaluator.h | 0 {USER-PACE => ML-PACE}/ace_flatten_basis.cpp | 0 {USER-PACE => ML-PACE}/ace_flatten_basis.h | 0 {USER-PACE => ML-PACE}/ace_radial.cpp | 221 ++++- {USER-PACE => ML-PACE}/ace_radial.h | 44 +- {USER-PACE => ML-PACE}/ace_recursive.cpp | 458 +++++---- {USER-PACE => ML-PACE}/ace_recursive.h | 26 +- {USER-PACE => ML-PACE}/ace_spherical_cart.cpp | 0 {USER-PACE => ML-PACE}/ace_spherical_cart.h | 0 {USER-PACE => ML-PACE}/ace_timing.h | 0 {USER-PACE => ML-PACE}/ace_types.h | 2 +- {USER-PACE => ML-PACE}/ace_version.h | 4 +- ML-PACE/pair_pace.cpp | 461 +++++++++ {USER-PACE => ML-PACE}/pair_pace.h | 63 +- {USER-PACE => ML-PACE}/ships_radial.cpp | 300 ++++-- {USER-PACE => ML-PACE}/ships_radial.h | 26 +- USER-PACE/pair_pace.cpp | 388 -------- yaml-cpp/.gitignore | 3 + yaml-cpp/CMakeLists.txt | 133 +++ yaml-cpp/CONTRIBUTING.md | 31 + yaml-cpp/Makefile | 39 + yaml-cpp/README.md | 74 ++ yaml-cpp/include/yaml-cpp/anchor.h | 17 + yaml-cpp/include/yaml-cpp/binary.h | 79 ++ .../include/yaml-cpp/contrib/anchordict.h | 41 + .../include/yaml-cpp/contrib/graphbuilder.h | 155 +++ yaml-cpp/include/yaml-cpp/depthguard.h | 80 ++ yaml-cpp/include/yaml-cpp/dll.h | 33 + yaml-cpp/include/yaml-cpp/emitfromevents.h | 65 ++ yaml-cpp/include/yaml-cpp/emitter.h | 343 +++++++ yaml-cpp/include/yaml-cpp/emitterdef.h | 18 + yaml-cpp/include/yaml-cpp/emittermanip.h | 144 +++ yaml-cpp/include/yaml-cpp/emitterstyle.h | 18 + yaml-cpp/include/yaml-cpp/eventhandler.h | 50 + yaml-cpp/include/yaml-cpp/exceptions.h | 317 ++++++ yaml-cpp/include/yaml-cpp/mark.h | 29 + yaml-cpp/include/yaml-cpp/node/convert.h | 374 +++++++ yaml-cpp/include/yaml-cpp/node/detail/impl.h | 226 +++++ .../include/yaml-cpp/node/detail/iterator.h | 102 ++ .../yaml-cpp/node/detail/iterator_fwd.h | 28 + .../include/yaml-cpp/node/detail/memory.h | 50 + yaml-cpp/include/yaml-cpp/node/detail/node.h | 196 ++++ .../include/yaml-cpp/node/detail/node_data.h | 151 +++ .../yaml-cpp/node/detail/node_iterator.h | 192 ++++ .../include/yaml-cpp/node/detail/node_ref.h | 118 +++ yaml-cpp/include/yaml-cpp/node/emit.h | 33 + yaml-cpp/include/yaml-cpp/node/impl.h | 435 +++++++++ yaml-cpp/include/yaml-cpp/node/iterator.h | 33 + yaml-cpp/include/yaml-cpp/node/node.h | 192 ++++ yaml-cpp/include/yaml-cpp/node/parse.h | 78 ++ yaml-cpp/include/yaml-cpp/node/ptr.h | 33 + yaml-cpp/include/yaml-cpp/node/type.h | 18 + yaml-cpp/include/yaml-cpp/noexcept.h | 18 + yaml-cpp/include/yaml-cpp/null.h | 29 + yaml-cpp/include/yaml-cpp/ostream_wrapper.h | 86 ++ yaml-cpp/include/yaml-cpp/parser.h | 96 ++ yaml-cpp/include/yaml-cpp/stlemitter.h | 51 + yaml-cpp/include/yaml-cpp/traits.h | 168 ++++ yaml-cpp/include/yaml-cpp/yaml.h | 24 + yaml-cpp/original-LICENSE | 19 + yaml-cpp/src/binary.cpp | 100 ++ yaml-cpp/src/collectionstack.h | 45 + yaml-cpp/src/contrib/graphbuilder.cpp | 17 + yaml-cpp/src/contrib/graphbuilderadapter.cpp | 94 ++ yaml-cpp/src/contrib/graphbuilderadapter.h | 101 ++ yaml-cpp/src/contrib/yaml-cpp.natvis | 32 + yaml-cpp/src/contrib/yaml-cpp.natvis.md | 12 + yaml-cpp/src/convert.cpp | 80 ++ yaml-cpp/src/depthguard.cpp | 9 + yaml-cpp/src/directives.cpp | 17 + yaml-cpp/src/directives.h | 29 + yaml-cpp/src/emit.cpp | 25 + yaml-cpp/src/emitfromevents.cpp | 120 +++ yaml-cpp/src/emitter.cpp | 910 ++++++++++++++++++ yaml-cpp/src/emitterstate.cpp | 369 +++++++ yaml-cpp/src/emitterstate.h | 251 +++++ yaml-cpp/src/emitterutils.cpp | 485 ++++++++++ yaml-cpp/src/emitterutils.h | 61 ++ yaml-cpp/src/exceptions.cpp | 32 + yaml-cpp/src/exp.cpp | 135 +++ yaml-cpp/src/exp.h | 253 +++++ yaml-cpp/src/indentation.h | 43 + yaml-cpp/src/memory.cpp | 26 + yaml-cpp/src/node.cpp | 12 + yaml-cpp/src/node_data.cpp | 317 ++++++ yaml-cpp/src/nodebuilder.cpp | 134 +++ yaml-cpp/src/nodebuilder.h | 87 ++ yaml-cpp/src/nodeevents.cpp | 101 ++ yaml-cpp/src/nodeevents.h | 76 ++ yaml-cpp/src/null.cpp | 10 + yaml-cpp/src/ostream_wrapper.cpp | 62 ++ yaml-cpp/src/parse.cpp | 72 ++ yaml-cpp/src/parser.cpp | 119 +++ yaml-cpp/src/ptr_vector.h | 52 + yaml-cpp/src/regex_yaml.cpp | 44 + yaml-cpp/src/regex_yaml.h | 107 ++ yaml-cpp/src/regeximpl.h | 185 ++++ yaml-cpp/src/scanner.cpp | 391 ++++++++ yaml-cpp/src/scanner.h | 224 +++++ yaml-cpp/src/scanscalar.cpp | 252 +++++ yaml-cpp/src/scanscalar.h | 69 ++ yaml-cpp/src/scantag.cpp | 81 ++ yaml-cpp/src/scantag.h | 21 + yaml-cpp/src/scantoken.cpp | 437 +++++++++ yaml-cpp/src/setting.h | 114 +++ yaml-cpp/src/simplekey.cpp | 132 +++ yaml-cpp/src/singledocparser.cpp | 431 +++++++++ yaml-cpp/src/singledocparser.h | 90 ++ yaml-cpp/src/stream.cpp | 455 +++++++++ yaml-cpp/src/stream.h | 104 ++ yaml-cpp/src/streamcharsource.h | 57 ++ yaml-cpp/src/stringsource.h | 50 + yaml-cpp/src/tag.cpp | 50 + yaml-cpp/src/tag.h | 34 + yaml-cpp/src/token.h | 72 ++ 126 files changed, 14509 insertions(+), 837 deletions(-) rename {USER-PACE => ML-PACE}/ace_abstract_basis.cpp (71%) rename {USER-PACE => ML-PACE}/ace_abstract_basis.h (51%) rename {USER-PACE => ML-PACE}/ace_array2dlm.h (99%) rename {USER-PACE => ML-PACE}/ace_arraynd.h (100%) rename {USER-PACE => ML-PACE}/ace_c_basis.cpp (61%) rename {USER-PACE => ML-PACE}/ace_c_basis.h (82%) rename {USER-PACE => ML-PACE}/ace_c_basisfunction.h (78%) rename {USER-PACE => ML-PACE}/ace_complex.h (100%) rename {USER-PACE => ML-PACE}/ace_contigous_array.h (100%) rename {USER-PACE => ML-PACE}/ace_evaluator.cpp (98%) rename {USER-PACE => ML-PACE}/ace_evaluator.h (100%) rename {USER-PACE => ML-PACE}/ace_flatten_basis.cpp (100%) rename {USER-PACE => ML-PACE}/ace_flatten_basis.h (100%) rename {USER-PACE => ML-PACE}/ace_radial.cpp (74%) rename {USER-PACE => ML-PACE}/ace_radial.h (89%) rename {USER-PACE => ML-PACE}/ace_recursive.cpp (77%) rename {USER-PACE => ML-PACE}/ace_recursive.h (87%) rename {USER-PACE => ML-PACE}/ace_spherical_cart.cpp (100%) rename {USER-PACE => ML-PACE}/ace_spherical_cart.h (100%) rename {USER-PACE => ML-PACE}/ace_timing.h (100%) rename {USER-PACE => ML-PACE}/ace_types.h (97%) rename {USER-PACE => ML-PACE}/ace_version.h (96%) create mode 100644 ML-PACE/pair_pace.cpp rename {USER-PACE => ML-PACE}/pair_pace.h (52%) rename {USER-PACE => ML-PACE}/ships_radial.cpp (53%) rename {USER-PACE => ML-PACE}/ships_radial.h (86%) delete mode 100644 USER-PACE/pair_pace.cpp create mode 100644 yaml-cpp/.gitignore create mode 100644 yaml-cpp/CMakeLists.txt create mode 100644 yaml-cpp/CONTRIBUTING.md create mode 100644 yaml-cpp/Makefile create mode 100644 yaml-cpp/README.md create mode 100644 yaml-cpp/include/yaml-cpp/anchor.h create mode 100644 yaml-cpp/include/yaml-cpp/binary.h create mode 100644 yaml-cpp/include/yaml-cpp/contrib/anchordict.h create mode 100644 yaml-cpp/include/yaml-cpp/contrib/graphbuilder.h create mode 100644 yaml-cpp/include/yaml-cpp/depthguard.h create mode 100644 yaml-cpp/include/yaml-cpp/dll.h create mode 100644 yaml-cpp/include/yaml-cpp/emitfromevents.h create mode 100644 yaml-cpp/include/yaml-cpp/emitter.h create mode 100644 yaml-cpp/include/yaml-cpp/emitterdef.h create mode 100644 yaml-cpp/include/yaml-cpp/emittermanip.h create mode 100644 yaml-cpp/include/yaml-cpp/emitterstyle.h create mode 100644 yaml-cpp/include/yaml-cpp/eventhandler.h create mode 100644 yaml-cpp/include/yaml-cpp/exceptions.h create mode 100644 yaml-cpp/include/yaml-cpp/mark.h create mode 100644 yaml-cpp/include/yaml-cpp/node/convert.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/impl.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/iterator.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/iterator_fwd.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/memory.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/node.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/node_data.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/node_iterator.h create mode 100644 yaml-cpp/include/yaml-cpp/node/detail/node_ref.h create mode 100644 yaml-cpp/include/yaml-cpp/node/emit.h create mode 100644 yaml-cpp/include/yaml-cpp/node/impl.h create mode 100644 yaml-cpp/include/yaml-cpp/node/iterator.h create mode 100644 yaml-cpp/include/yaml-cpp/node/node.h create mode 100644 yaml-cpp/include/yaml-cpp/node/parse.h create mode 100644 yaml-cpp/include/yaml-cpp/node/ptr.h create mode 100644 yaml-cpp/include/yaml-cpp/node/type.h create mode 100644 yaml-cpp/include/yaml-cpp/noexcept.h create mode 100644 yaml-cpp/include/yaml-cpp/null.h create mode 100644 yaml-cpp/include/yaml-cpp/ostream_wrapper.h create mode 100644 yaml-cpp/include/yaml-cpp/parser.h create mode 100644 yaml-cpp/include/yaml-cpp/stlemitter.h create mode 100644 yaml-cpp/include/yaml-cpp/traits.h create mode 100644 yaml-cpp/include/yaml-cpp/yaml.h create mode 100644 yaml-cpp/original-LICENSE create mode 100644 yaml-cpp/src/binary.cpp create mode 100644 yaml-cpp/src/collectionstack.h create mode 100644 yaml-cpp/src/contrib/graphbuilder.cpp create mode 100644 yaml-cpp/src/contrib/graphbuilderadapter.cpp create mode 100644 yaml-cpp/src/contrib/graphbuilderadapter.h create mode 100644 yaml-cpp/src/contrib/yaml-cpp.natvis create mode 100644 yaml-cpp/src/contrib/yaml-cpp.natvis.md create mode 100644 yaml-cpp/src/convert.cpp create mode 100644 yaml-cpp/src/depthguard.cpp create mode 100644 yaml-cpp/src/directives.cpp create mode 100644 yaml-cpp/src/directives.h create mode 100644 yaml-cpp/src/emit.cpp create mode 100644 yaml-cpp/src/emitfromevents.cpp create mode 100644 yaml-cpp/src/emitter.cpp create mode 100644 yaml-cpp/src/emitterstate.cpp create mode 100644 yaml-cpp/src/emitterstate.h create mode 100644 yaml-cpp/src/emitterutils.cpp create mode 100644 yaml-cpp/src/emitterutils.h create mode 100644 yaml-cpp/src/exceptions.cpp create mode 100644 yaml-cpp/src/exp.cpp create mode 100644 yaml-cpp/src/exp.h create mode 100644 yaml-cpp/src/indentation.h create mode 100644 yaml-cpp/src/memory.cpp create mode 100644 yaml-cpp/src/node.cpp create mode 100644 yaml-cpp/src/node_data.cpp create mode 100644 yaml-cpp/src/nodebuilder.cpp create mode 100644 yaml-cpp/src/nodebuilder.h create mode 100644 yaml-cpp/src/nodeevents.cpp create mode 100644 yaml-cpp/src/nodeevents.h create mode 100644 yaml-cpp/src/null.cpp create mode 100644 yaml-cpp/src/ostream_wrapper.cpp create mode 100644 yaml-cpp/src/parse.cpp create mode 100644 yaml-cpp/src/parser.cpp create mode 100644 yaml-cpp/src/ptr_vector.h create mode 100644 yaml-cpp/src/regex_yaml.cpp create mode 100644 yaml-cpp/src/regex_yaml.h create mode 100644 yaml-cpp/src/regeximpl.h create mode 100644 yaml-cpp/src/scanner.cpp create mode 100644 yaml-cpp/src/scanner.h create mode 100644 yaml-cpp/src/scanscalar.cpp create mode 100644 yaml-cpp/src/scanscalar.h create mode 100644 yaml-cpp/src/scantag.cpp create mode 100644 yaml-cpp/src/scantag.h create mode 100644 yaml-cpp/src/scantoken.cpp create mode 100644 yaml-cpp/src/setting.h create mode 100644 yaml-cpp/src/simplekey.cpp create mode 100644 yaml-cpp/src/singledocparser.cpp create mode 100644 yaml-cpp/src/singledocparser.h create mode 100644 yaml-cpp/src/stream.cpp create mode 100644 yaml-cpp/src/stream.h create mode 100644 yaml-cpp/src/streamcharsource.h create mode 100644 yaml-cpp/src/stringsource.h create mode 100644 yaml-cpp/src/tag.cpp create mode 100644 yaml-cpp/src/tag.h create mode 100644 yaml-cpp/src/token.h diff --git a/LICENSE b/LICENSE index f288702..561554c 100644 --- a/LICENSE +++ b/LICENSE @@ -1,3 +1,366 @@ +This is the DUAL-license codebase, distributed under GPL2 or GPL3 license. + +Please, chose one of the two licenses: + +============================================================================== +GPL2 +============================================================================== +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 Library 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. + +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. + +one line to give the program's name and an idea of what it does. +Copyright (C) yyyy name of author + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License version 2 as +published by the Free Software Foundation. + +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., 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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. + +signature of Ty Coon, 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 Library General Public License instead of this License. +============================================================================== + +OR + +============================================================================== +GPL3 +============================================================================== GNU GENERAL PUBLIC LICENSE Version 3, 29 June 2007 @@ -672,3 +1035,6 @@ 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. But first, please read . + + +============================================================================== diff --git a/USER-PACE/ace_abstract_basis.cpp b/ML-PACE/ace_abstract_basis.cpp similarity index 71% rename from USER-PACE/ace_abstract_basis.cpp rename to ML-PACE/ace_abstract_basis.cpp index 3a354de..4accf5b 100644 --- a/USER-PACE/ace_abstract_basis.cpp +++ b/ML-PACE/ace_abstract_basis.cpp @@ -28,6 +28,7 @@ // Created by Lysogorskiy Yury on 28.04.2020. #include "ace_abstract_basis.h" +#include "ace_radial.h" ////embedding function ////case nemb = 1 only implementation @@ -93,21 +94,27 @@ void ACEAbstractBasisSet::inner_cutoff(DOUBLE_TYPE rho_core, DOUBLE_TYPE rho_cut fcut = 1; dfcut = 0; } else { - fcut = 0.5 * (1 + cos(M_PI * (rho_core - rho_low) / drho_cut)); - dfcut = -0.5 * sin(M_PI * (rho_core - rho_low) / drho_cut) * M_PI / drho_cut; + cutoff_func_poly(rho_core, rho_cut, drho_cut, fcut, dfcut); } } void ACEAbstractBasisSet::FS_values_and_derivatives(Array1D &rhos, DOUBLE_TYPE &value, - Array1D &derivatives, DENSITY_TYPE ndensity) { + Array1D &derivatives, + SPECIES_TYPE mu_i +) { DOUBLE_TYPE F, DF = 0, wpre, mexp; + DENSITY_TYPE ndensity = map_embedding_specifications.at(mu_i).ndensity; for (int p = 0; p < ndensity; p++) { - wpre = FS_parameters.at(p * ndensity + 0); - mexp = FS_parameters.at(p * ndensity + 1); - if (this->npoti == "FinnisSinclair") + + wpre = map_embedding_specifications.at(mu_i).FS_parameters.at(p * 2 + 0); + mexp = map_embedding_specifications.at(mu_i).FS_parameters.at(p * 2 + 1); + string npoti = map_embedding_specifications.at(mu_i).npoti; + + if (npoti == "FinnisSinclair") Fexp(rhos(p), mexp, F, DF); - else if (this->npoti == "FinnisSinclairShiftedScaled") + else if (npoti == "FinnisSinclairShiftedScaled") FexpShiftedScaled(rhos(p), mexp, F, DF); + value += F * wpre; // * weight (wpre) derivatives(p) = DF * wpre;// * weight (wpre) } @@ -144,8 +151,9 @@ ACEAbstractBasisSet::~ACEAbstractBasisSet() { void ACEAbstractBasisSet::_copy_scalar_memory(const ACEAbstractBasisSet &src) { deltaSplineBins = src.deltaSplineBins; - FS_parameters = src.FS_parameters; - npoti = src.npoti; + + map_bond_specifications = src.map_bond_specifications; + map_embedding_specifications = src.map_embedding_specifications; nelements = src.nelements; rankmax = src.rankmax; @@ -157,10 +165,6 @@ void ACEAbstractBasisSet::_copy_scalar_memory(const ACEAbstractBasisSet &src) { spherical_harmonics = src.spherical_harmonics; - rho_core_cutoffs = src.rho_core_cutoffs; - drho_core_cutoffs = src.drho_core_cutoffs; - - E0vals = src.E0vals; } @@ -183,3 +187,50 @@ SPECIES_TYPE ACEAbstractBasisSet::get_species_index_by_name(const string &elemna return -1; } +bool compare(const ACEAbstractBasisFunction &b1, const ACEAbstractBasisFunction &b2) { + if (b1.rank < b2.rank) return true; + else if (b1.rank > b2.rank) return false; + //now b1.rank==b2.rank + + +// if (b1.rankL < b2.rankL) return true; +// else if (b1.rankL > b2.rankL) return false; + //now b1.rankL==b2.rankL + + if (b1.mu0 < b2.mu0) return true; + else if (b1.mu0 > b2.mu0) return false; + + for (RANK_TYPE r = 0; r < b1.rank; r++) + if (b1.mus[r] < b2.mus[r]) return true; + else if (b1.mus[r] > b2.mus[r]) return false; + // now mus are checked to be equal + + for (RANK_TYPE r = 0; r < b1.rank; r++) + if (b1.ns[r] < b2.ns[r]) return true; + else if (b1.ns[r] > b2.ns[r]) return false; + // now ns are checked to be equal + + for (RANK_TYPE r = 0; r < b1.rank; r++) + if (b1.ls[r] < b2.ls[r]) return true; + else if (b1.ls[r] > b2.ls[r]) return false; + // now ls are checked to be equal + +// for (RANK_TYPE r = 0; r < b1.rankL; r++) +// if (b1.LS[r] < b2.LS[r]) return true; +// else if (b1.LS[r] > b2.LS[r]) return false; + // now LS are checked to be equal + + if (b1.num_ms_combs < b2.num_ms_combs) return true; + else if (b1.num_ms_combs > b2.num_ms_combs) return false; + // now num_ms_combs are checked to be equal + + // ms_combs: + // size = num_ms_combs * rank, + // effective shape: [num_ms_combs][rank] + for (SHORT_INT_TYPE i = 0; i < b1.num_ms_combs * b1.rank; i++) + if (b1.ms_combs[i] < b2.ms_combs[i]) return true; + else if (b1.ms_combs[i] > b2.ms_combs[i]) return false; + + return false; // ! b1 #include +#include +#include #include "ace_c_basisfunction.h" #include "ace_contigous_array.h" @@ -42,6 +44,138 @@ using namespace std; +struct ACEEmbeddingSpecification { + DENSITY_TYPE ndensity; + vector FS_parameters; ///< parameters for cluster functional, see Eq.(3) in implementation notes or Eq.(53) in PRB 99, 014104 (2019) + string npoti = "FinnisSinclair"; ///< FS and embedding function combination + + DOUBLE_TYPE rho_core_cutoff; + DOUBLE_TYPE drho_core_cutoff; + + //TODO: update method + string to_string() const { + stringstream ss; + ss << "ACEEmbeddingSpecification(npoti=" << npoti << ", ndensity=" << ndensity << ", "; + ss << "FS_parameter=("; + for (const auto &p: FS_parameters) + ss << p << ","; + ss << "))"; + return ss.str(); + } + + YAML::Node to_YAML() const { + YAML::Node emb_yaml; + emb_yaml.SetStyle(YAML::EmitterStyle::Flow); + emb_yaml["ndensity"] = (int) this->ndensity; + emb_yaml["FS_parameters"] = this->FS_parameters; + + emb_yaml["npoti"] = this->npoti; + emb_yaml["rho_core_cutoff"] = this->rho_core_cutoff; + emb_yaml["drho_core_cutoff"] = this->drho_core_cutoff; + + return emb_yaml; + } +}; + +struct ACEBondSpecification { + NS_TYPE nradmax; + LS_TYPE lmax; + NS_TYPE nradbasemax; + + string radbasename; + + std::vector radparameters; // i.e. lambda + vector>> radcoefficients;///< crad_nlk order: [n=0..nradmax-1][l=0..lmax][k=0..nradbase-1] + + //hard-core repulsion + DOUBLE_TYPE prehc; + DOUBLE_TYPE lambdahc; + + DOUBLE_TYPE rcut; + DOUBLE_TYPE dcut; + + //inner cutoff + DOUBLE_TYPE rcut_in = 0; + DOUBLE_TYPE dcut_in = 0; + string inner_cutoff_type = "distance"; // new behaviour is default + + bool operator==(const ACEBondSpecification &another) const { + return (nradbasemax == another.nradbasemax) && (lmax == another.lmax) && + (nradbasemax == another.nradbasemax) && (radbasename == another.radbasename) && + (radparameters == another.radparameters) && (radcoefficients == another.radcoefficients) && + (prehc == another.prehc) && (lambdahc == another.lambdahc) && (rcut == another.rcut) && + (dcut == another.dcut) && (rcut_in == another.rcut_in) && (dcut_in == another.dcut_in) && + (inner_cutoff_type == another.inner_cutoff_type); + } + + bool operator!=(const ACEBondSpecification &another) const { + return !(*this == (another)); + } + + string to_string() const { + stringstream ss; + ss << "ACEBondSpecification(nradmax=" << nradmax << ", lmax=" << lmax << ", nradbasemax=" << nradbasemax + << ", radbasename=" << + radbasename << ", crad=(" << radcoefficients.at(0).at(0).at(0) << "...), "; + ss << "rcut=" << rcut << ", dcut=" << dcut; + ss << ", rcut_in=" << rcut_in << ", dcut_in=" << dcut_in; + ss << ", inner_cutoff_type=" << inner_cutoff_type; + if (prehc > 0) + ss << ", core-rep: [prehc=" << prehc << ", lambdahc=" << lambdahc << "]"; + ss << ")"; + return ss.str(); + } + + void from_YAML(YAML::Node bond_yaml) { + radbasename = bond_yaml["radbasename"].as(); + + if(radbasename=="ACE.jl.base") { + + } else { + nradmax = bond_yaml["nradmax"].as(); + lmax = bond_yaml["lmax"].as(); + nradbasemax = bond_yaml["nradbasemax"].as(); + radparameters = bond_yaml["radparameters"].as>(); + radcoefficients = bond_yaml["radcoefficients"].as>>>(); + prehc = bond_yaml["prehc"].as(); + lambdahc = bond_yaml["lambdahc"].as(); + rcut = bond_yaml["rcut"].as(); + dcut = bond_yaml["dcut"].as(); + + if (bond_yaml["rcut_in"]) rcut_in = bond_yaml["rcut_in"].as(); + if (bond_yaml["dcut_in"]) dcut_in = bond_yaml["dcut_in"].as(); + if (bond_yaml["inner_cutoff_type"]) + inner_cutoff_type = bond_yaml["inner_cutoff_type"].as(); + else + inner_cutoff_type = "density"; // default value to read for backward compatibility + } + } + + YAML::Node to_YAML() const { + YAML::Node bond_yaml; + bond_yaml.SetStyle(YAML::EmitterStyle::Flow); + bond_yaml["nradmax"] = (int) this->nradmax; + bond_yaml["lmax"] = (int) this->lmax; + bond_yaml["nradbasemax"] = (int) this->nradbasemax; + + bond_yaml["radbasename"] = this->radbasename; + bond_yaml["radparameters"] = this->radparameters; + bond_yaml["radcoefficients"] = this->radcoefficients; + + bond_yaml["prehc"] = this->prehc; + bond_yaml["lambdahc"] = this->lambdahc; + bond_yaml["rcut"] = this->rcut; + bond_yaml["dcut"] = this->dcut; + + bond_yaml["rcut_in"] = this->rcut_in; + bond_yaml["dcut_in"] = this->dcut_in; + bond_yaml["inner_cutoff_type"] = this->inner_cutoff_type; + + return bond_yaml; + } +}; + + /** * Abstract basis set class */ @@ -56,18 +190,18 @@ class ACEAbstractBasisSet { DOUBLE_TYPE cutoffmax = 0; ///< maximum value of cutoff distance among all species in basis set DOUBLE_TYPE deltaSplineBins = 0; ///< Spline interpolation density - string npoti = "FinnisSinclair"; ///< FS and embedding function combination - string *elements_name = nullptr; ///< Array of elements name for mapping from index (0..nelements-1) to element symbol (string) + map elements_to_index_map; + AbstractRadialBasis *radial_functions = nullptr; ///< object to work with radial functions ACECartesianSphericalHarmonics spherical_harmonics; ///< object to work with spherical harmonics in Cartesian representation + bool is_sort_functions = true; ///< flag to specify, whether to sort the basis functions or preserve the order + //for multispecies - Array1D rho_core_cutoffs; ///< energy-based inner cut-off - Array1D drho_core_cutoffs; ///< decay of energy-based inner cut-off - - vector FS_parameters; ///< parameters for cluster functional, see Eq.(3) in implementation notes or Eq.(53) in PRB 99, 014104 (2019) + map map_embedding_specifications; + map, ACEBondSpecification> map_bond_specifications; // E0 values Array1D E0vals; @@ -106,7 +240,7 @@ class ACEAbstractBasisSet { * @param ndensity number \f$ P \f$ of densities to use */ void FS_values_and_derivatives(Array1D &rhos, DOUBLE_TYPE &value, Array1D &derivatives, - DENSITY_TYPE ndensity); + SPECIES_TYPE mu_i); /** * Computing hard core pairwise repulsive potential \f$ f_{cut}(\rho_i^{(\textrm{core})})\f$ and its derivative, @@ -160,11 +294,19 @@ class ACEAbstractBasisSet { * @param src source object to copy from */ virtual void _copy_scalar_memory(const ACEAbstractBasisSet &src); + + virtual vector get_all_coeffs() const = 0; + + virtual vector> get_all_coeffs_mask() const = 0; + + virtual void set_all_coeffs(const vector &coeffs) = 0; }; void Fexp(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF); void FexpShiftedScaled(DOUBLE_TYPE rho, DOUBLE_TYPE mexp, DOUBLE_TYPE &F, DOUBLE_TYPE &DF); +bool compare(const ACEAbstractBasisFunction &b1, const ACEAbstractBasisFunction &b2); + #endif //ACE_EVALUATOR_ACE_ABSTRACT_BASIS_H diff --git a/USER-PACE/ace_array2dlm.h b/ML-PACE/ace_array2dlm.h similarity index 99% rename from USER-PACE/ace_array2dlm.h rename to ML-PACE/ace_array2dlm.h index e084256..7bd97d4 100644 --- a/USER-PACE/ace_array2dlm.h +++ b/ML-PACE/ace_array2dlm.h @@ -492,6 +492,7 @@ class Array4DLM : public ContiguousArrayND { } #ifdef MULTIARRAY_INDICES_CHECK + /** * Check if indices (i0, l,m) are within array */ @@ -519,10 +520,12 @@ class Array4DLM : public ContiguousArrayND { size_t ii = i0 * s[0] + i1 * s[1] + l * (l + 1) + m; if (ii >= size) { - fprintf(stderr, "%s: index = %ld out of range %ld\n", array_name.c_str(), ii, size); + fprintf(stderr, "%s: index = %ld (i0=%ld, i1=%ld, l=%d, m=%d) out of range %ld\n", array_name.c_str(), ii, i0, + i1, l, m, size); exit(EXIT_FAILURE); } } + #endif /** diff --git a/USER-PACE/ace_arraynd.h b/ML-PACE/ace_arraynd.h similarity index 100% rename from USER-PACE/ace_arraynd.h rename to ML-PACE/ace_arraynd.h diff --git a/USER-PACE/ace_c_basis.cpp b/ML-PACE/ace_c_basis.cpp similarity index 61% rename from USER-PACE/ace_c_basis.cpp rename to ML-PACE/ace_c_basis.cpp index 7c2435b..538c481 100644 --- a/USER-PACE/ace_c_basis.cpp +++ b/ML-PACE/ace_c_basis.cpp @@ -26,14 +26,25 @@ */ // Created by Yury Lysogorskiy on 1.04.20. +#include #include "ace_c_basis.h" #include "ships_radial.h" using namespace std; +inline bool ends_with(std::string const &value, std::string const &ending) { + if (ending.size() > value.size()) return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + ACECTildeBasisSet::ACECTildeBasisSet(string filename) { - load(filename); + if (ends_with(filename, ".ace")) + load(filename); + else if (ends_with(filename, ".yace")) + load_yaml(filename); + else + throw invalid_argument("Unrecognized file type of '" + filename + "'. Accept only .ace or .yace"); } ACECTildeBasisSet::ACECTildeBasisSet(const ACECTildeBasisSet &other) { @@ -287,18 +298,27 @@ void ACECTildeBasisSet::save(const string &filename) { fprintf(fptr, "lmax=%d\n\n", lmax); - fprintf(fptr, "embedding-function: %s\n", npoti.c_str()); +// fprintf(fptr, "embedding-function: %s\n", npoti.c_str()); + fprintf(fptr, "embedding-function: %s\n", map_embedding_specifications[0].npoti.c_str()); - fprintf(fptr, "%ld FS parameters: ", FS_parameters.size()); - for (int i = 0; i < FS_parameters.size(); ++i) { - fprintf(fptr, " %f", FS_parameters.at(i)); +// fprintf(fptr, "%ld FS parameters: ", FS_parameters.size()); +// for (int i = 0; i < FS_parameters.size(); ++i) { +// fprintf(fptr, " %f", FS_parameters.at(i)); +// } + + //TODO: hardcoded for single species + fprintf(fptr, "%ld FS parameters: ", map_embedding_specifications[0].FS_parameters.size()); + for (int i = 0; i < map_embedding_specifications[0].FS_parameters.size(); ++i) { + fprintf(fptr, " %f", map_embedding_specifications[0].FS_parameters.at(i)); } fprintf(fptr, "\n"); //hard-core energy cutoff repulsion fprintf(fptr, "core energy-cutoff parameters: "); - for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - fprintf(fptr, "%.18f %.18f\n", rho_core_cutoffs(mu_i), drho_core_cutoffs(mu_i)); + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) { + fprintf(fptr, "%.18f %.18f\n", map_embedding_specifications.at(mu_i).rho_core_cutoff, + map_embedding_specifications.at(mu_i).drho_core_cutoff); + } // save E0 values fprintf(fptr, "E0:"); @@ -310,7 +330,7 @@ void ACECTildeBasisSet::save(const string &filename) { fprintf(fptr, "\n"); - fprintf(fptr, "radbasename=%s\n", radial_functions->radbasename.c_str()); + fprintf(fptr, "radbasename=%s\n", radial_functions->radbasenameij(0, 0).c_str());//TODO-single species fprintf(fptr, "nradbase=%d\n", nradbase); fprintf(fptr, "nradmax=%d\n", nradmax); @@ -544,7 +564,10 @@ void ACECTildeBasisSet::load(const string filename) { throw_error(filename, "elements", "elements: Ele1 Ele2 ..."); elements_name[mu] = buffer; } - + // initialize embedding_specifications + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) { + map_embedding_specifications[mu_i] = ACEEmbeddingSpecification(); + } // load angular basis - only need spherical harmonics parameter res = fscanf(fptr, " lmax=%s\n", buffer); if (res != 1) @@ -558,18 +581,26 @@ void ACECTildeBasisSet::load(const string filename) { res = fscanf(fptr, " embedding-function: %s", buffer); if (res == 0) { //throw_error(filename, "E0", " E0: E0-species1 E0-species2 ..."); - this->npoti = "FinnisSinclair"; // default values +// this->npoti = "FinnisSinclair"; // default values + map_embedding_specifications[0].npoti = "FinnisSinclair"; // default values //printf("Warning! No embedding-function is specified, embedding-function: FinnisSinclair would be assumed\n"); is_embedding_function_specified = false; } else { - this->npoti = buffer; +// this->npoti = buffer; + map_embedding_specifications[0].npoti = buffer; is_embedding_function_specified = true; } + //TODO: hard-coded for single-species case +// this->map_embedding_specifications.at(0).npoti = this->npoti; + + int parameters_size; res = fscanf(fptr, "%s FS parameters:", buffer); if (res != 1) throw_error(filename, "FS parameters size", "[number] FS parameters: par1 par2 ..."); parameters_size = stoi_err(buffer, filename, "FS parameters size", "[number] FS parameters"); + + vector FS_parameters; FS_parameters.resize(parameters_size); for (int i = 0; i < FS_parameters.size(); ++i) { res = fscanf(fptr, "%s", buffer); @@ -578,6 +609,10 @@ void ACECTildeBasisSet::load(const string filename) { FS_parameters[i] = stod_err(buffer, filename, "FS parameter", "[number] FS parameters: [par1] [par2] ..."); } + //TODO: hard-coded for single-species case + this->map_embedding_specifications.at(0).FS_parameters = FS_parameters; +// this->map_embedding_specifications.at(0).npoti = this->npoti; + if (!is_embedding_function_specified) { // assuming non-linear potential, and embedding function type is important for (int j = 1; j < parameters_size; j += 2) @@ -594,17 +629,19 @@ void ACECTildeBasisSet::load(const string filename) { if (res != 0) throw_error(filename, "core energy-cutoff parameters", "core energy-cutoff parameters: [par1] [par2]"); - rho_core_cutoffs.init(nelements, "rho_core_cutoffs"); - drho_core_cutoffs.init(nelements, "drho_core_cutoffs"); +// rho_core_cutoffs.init(nelements, "rho_core_cutoffs"); +// drho_core_cutoffs.init(nelements, "drho_core_cutoffs"); for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) { res = fscanf(fptr, "%s %s", buffer, buffer2); if (res != 2) throw_error(filename, "core energy-cutoff parameters", "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); - rho_core_cutoffs(mu_i) = stod_err(buffer, filename, "rho core cutoff", - "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); - drho_core_cutoffs(mu_i) = stod_err(buffer2, filename, "drho_core_cutoff", - "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); + DOUBLE_TYPE rho_core_cutoff = stod_err(buffer, filename, "rho core cutoff", + "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); + DOUBLE_TYPE drho_core_cutoff = stod_err(buffer2, filename, "drho_core_cutoff", + "core energy-cutoff parameters: [rho_core_cut] [drho_core_cutoff] ..."); + map_embedding_specifications.at(mu_i).rho_core_cutoff = rho_core_cutoff; + map_embedding_specifications.at(mu_i).drho_core_cutoff = drho_core_cutoff; } // atom energy shift E0 (energy of isolated atom) @@ -660,7 +697,10 @@ void ACECTildeBasisSet::load(const string filename) { throw_error(filename, "ndensitymax", "ndensitymax=[number]"); ndensitymax = stoi_err(buffer, filename, "ndensitymax", "ndensitymax=[number]"); - // read the list of correlations to be put into the basis + //TODO: hardcoded for single-species case + this->map_embedding_specifications.at(0).ndensity = ndensitymax; + + // read the list of correlations to be put into the basis //num_c_tilde_max res = fscanf(fptr, " num_c_tilde_max="); res = fscanf(fptr, "%s\n", buffer); @@ -672,7 +712,6 @@ void ACECTildeBasisSet::load(const string filename) { res = fscanf(fptr, "%s", buffer); if (res != 1) throw_error(filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]"); -// throw invalid_argument(("File '" + filename + "': couldn't read num_ms_combinations_max").c_str()); num_ms_combinations_max = stol_err(buffer, filename, "num_ms_combinations_max", "num_ms_combinations_max=[number]"); //read total_basis_size_rank1 @@ -842,6 +881,13 @@ void ACECTildeBasisSet::flatten_basis(C_tilde_full_basis_vector2d &mu0_ctilde_ba void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, const string filename, const string radbasename) { + //initialize map_bond_specifications + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; mu_i++) + for (SPECIES_TYPE mu_j = 0; mu_j < nelements; mu_j++) { + ACEBondSpecification bondSpecification; + map_bond_specifications[make_pair(mu_i, mu_j)] = bondSpecification; + } + int res; char buffer[1024], buffer2[1024]; @@ -849,14 +895,17 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, res = fscanf(fptr, "%s", buffer); if (res != 1) throw_error(filename, "nradbase", "nradbase=[number]"); -// throw invalid_argument(("File '" + filename + "': couldn't read nradbase").c_str()); nradbase = stoi_err(buffer, filename, "nradbase", "nradbase=[number]"); + //WARNING! hardcoded for single specie + map_bond_specifications[make_pair(0, 0)].nradbasemax = nradbase; res = fscanf(fptr, " nradmax="); res = fscanf(fptr, "%s", buffer); if (res != 1) throw_error(filename, "nradmax", "nradmax=[number]"); nradmax = stoi_err(buffer, filename, "nradmax", "nradmax=[number]"); + //WARNING! hardcoded for single specie + map_bond_specifications[make_pair(0, 0)].nradmax = nradmax; res = fscanf(fptr, " cutoffmax="); res = fscanf(fptr, "%s", buffer); @@ -869,27 +918,29 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, res = fscanf(fptr, "%s", buffer); if (res != 1) throw_error(filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]"); -// throw invalid_argument(("File '" + filename + "': couldn't read ntot").c_str()); deltaSplineBins = stod_err(buffer, filename, "deltaSplineBins", "deltaSplineBins=[spline density, Angstroms]"); + //WARNING! hardcoded for single specie + map_bond_specifications[make_pair(0, 0)].lmax = lmax; + map_bond_specifications[make_pair(0, 0)].radbasename = radbasename; + map_bond_specifications[make_pair(0, 0)].inner_cutoff_type = "density"; // default, for backward compatibility if (radial_functions == nullptr) radial_functions = new ACERadialFunctions(nradbase, lmax, nradmax, deltaSplineBins, nelements, - cutoffmax, radbasename); + {{radbasename}}); else radial_functions->init(nradbase, lmax, nradmax, deltaSplineBins, nelements, - cutoffmax, radbasename); + {{radbasename}}); //hard-core repulsion res = fscanf(fptr, " core repulsion parameters:"); if (res != 0) throw_error(filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ..."); -// throw invalid_argument(("File '" + filename + "': couldn't read core repulsion parameters").c_str()); for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { @@ -900,6 +951,9 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, "core repulsion parameters: [prehc lambdahc] ..."); radial_functions->lambdahc(mu_i, mu_j) = stod_err(buffer2, filename, "core repulsion parameters", "core repulsion parameters: [prehc lambdahc] ..."); + + map_bond_specifications[make_pair(mu_i, mu_j)].prehc = radial_functions->prehc(mu_i, mu_j); + map_bond_specifications[make_pair(mu_i, mu_j)].lambdahc = radial_functions->lambdahc(mu_i, mu_j); } @@ -913,6 +967,7 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, throw_error(filename, "radparameter", "radparameter=[param_ele1] [param_ele2]"); radial_functions->lambda(mu_i, mu_j) = stod_err(buffer, filename, "radparameter", "radparameter=[param_ele1] [param_ele2]"); + map_bond_specifications[make_pair(mu_i, mu_j)].radparameters = {radial_functions->lambda(mu_i, mu_j)}; } @@ -924,6 +979,8 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, throw_error(filename, "cutoff", "cutoff=[param_ele1] [param_ele2]"); radial_functions->cut(mu_i, mu_j) = stod_err(buffer, filename, "cutoff", "cutoff=[param_ele1] [param_ele2]"); + + map_bond_specifications[make_pair(mu_i, mu_j)].rcut = radial_functions->cut(mu_i, mu_j); } @@ -934,12 +991,14 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, if (res != 1) throw_error(filename, "dcut", "dcut=[param_ele1] [param_ele2]"); radial_functions->dcut(mu_i, mu_j) = stod_err(buffer, filename, "dcut", "dcut=[param_ele1] [param_ele2]"); + map_bond_specifications[make_pair(mu_i, mu_j)].dcut = radial_functions->dcut(mu_i, mu_j); } res = fscanf(fptr, " crad="); for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) - for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) + for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { + Array3D radcoefficients(nradmax, lmax + 1, nradbase); for (NS_TYPE k = 0; k < nradbase; k++) for (NS_TYPE n = 0; n < nradmax; n++) for (LS_TYPE l = 0; l <= lmax; l++) { @@ -948,7 +1007,11 @@ void ACECTildeBasisSet::_load_radial_ACERadial(FILE *fptr, throw_error(filename, "crad", "crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times"); radial_functions->crad(mu_i, mu_j, n, l, k) = stod_err(buffer, filename, "crad", "crad=[crad_]...[crad_knl]: nradbase*nrad*(l+1) times"); + radcoefficients(n, l, k) = radial_functions->crad(mu_i, mu_j, n, l, k); } + + map_bond_specifications[make_pair(mu_i, mu_j)].radcoefficients = radcoefficients.to_vector(); + } } void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr, @@ -956,9 +1019,16 @@ void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr, const string radbasename) { // create a radial basis object, and read it from the file pointer SHIPsRadialFunctions *ships_radial_functions = new SHIPsRadialFunctions(); + + ships_radial_functions->nelements = nelements; + ships_radial_functions->radbasis.init(nelements, nelements, "SHIPsRadialFunctions::radbasis"); ships_radial_functions->fread(fptr); - //mimic ships_radial_functions to ACERadialFunctions + _post_load_radial_SHIPsBasic(ships_radial_functions); +} + +void ACECTildeBasisSet::_post_load_radial_SHIPsBasic( + SHIPsRadialFunctions *ships_radial_functions) {//mimic ships_radial_functions to ACERadialFunctions ships_radial_functions->nradial = ships_radial_functions->get_maxn(); ships_radial_functions->nradbase = ships_radial_functions->get_maxn(); @@ -967,10 +1037,16 @@ void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr, cutoffmax = ships_radial_functions->get_rcut(); deltaSplineBins = 0.001; - ships_radial_functions->init(nradbase, lmax, nradmax, - deltaSplineBins, - nelements, - cutoffmax, radbasename); + ships_radial_functions->nradbase = nradbase; + ships_radial_functions->lmax = lmax; + ships_radial_functions->nradial = nradmax; + ships_radial_functions->gr.init(nradbase, "gr"); + ships_radial_functions->dgr.init(nradbase, "dgr"); + + ships_radial_functions->fr.init(nradmax, lmax + 1, "fr"); + ships_radial_functions->dfr.init(nradmax, lmax + 1, "dfr"); + ships_radial_functions->crad.init(nelements, nelements, nradmax, (lmax + 1), nradbase, "crad"); + ships_radial_functions->crad.fill(0.); if (radial_functions) delete radial_functions; @@ -979,11 +1055,397 @@ void ACECTildeBasisSet::_load_radial_SHIPsBasic(FILE *fptr, radial_functions->lambdahc.fill(1); radial_functions->lambda.fill(0); + radial_functions->cut.init(nelements, nelements, "cut"); + radial_functions->dcut.init(nelements, nelements, "dcut"); radial_functions->cut.fill(ships_radial_functions->get_rcut()); radial_functions->dcut.fill(0); radial_functions->crad.fill(0); +} + +vector> ACECTildeBasisSet::get_all_coeffs_mask() const { + //TODO: implement + vector> all_coeffs_mask; + return all_coeffs_mask; +} + +vector ACECTildeBasisSet::get_all_coeffs() const { + auto coeffs = radial_functions->crad.to_flatten_vector(); + + for (SPECIES_TYPE mu = 0; mu < nelements; mu++) { + for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; func_ind++) { + auto ndens = basis_rank1[mu][func_ind].ndensity; + for (SHORT_INT_TYPE ms_ind = 0; ms_ind < basis_rank1[mu][func_ind].num_ms_combs; ms_ind++) { + for (DENSITY_TYPE p = 0; p < ndens; p++) + coeffs.emplace_back(basis_rank1[mu][func_ind].ctildes[ms_ind * ndens + p]); + } + } + + for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; func_ind++) { + auto ndens = basis[mu][func_ind].ndensity; + for (SHORT_INT_TYPE ms_ind = 0; ms_ind < basis[mu][func_ind].num_ms_combs; ms_ind++) { + for (DENSITY_TYPE p = 0; p < ndens; p++) + coeffs.emplace_back(basis[mu][func_ind].ctildes[ms_ind * ndens + p]); + } + } + } + + return coeffs; +} + +void ACECTildeBasisSet::set_all_coeffs(const vector &coeffs) { + size_t crad_size = radial_functions->crad.get_size(); + vector crad_flatten_vector(coeffs.begin(), coeffs.begin() + crad_size); + vector basis_coeffs_vector(coeffs.begin() + crad_size, coeffs.end()); + + radial_functions->crad = crad_flatten_vector; + radial_functions->setuplookupRadspline(); + + size_t coeffs_ind = 0; + for (SPECIES_TYPE mu = 0; mu < nelements; mu++) { + for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size_rank1[mu]; func_ind++) { + auto ndens = basis_rank1[mu][func_ind].ndensity; + for (SHORT_INT_TYPE ms_ind = 0; ms_ind < basis_rank1[mu][func_ind].num_ms_combs; ms_ind++) { + for (DENSITY_TYPE p = 0; p < ndens; p++, coeffs_ind++) { + basis_rank1[mu][func_ind].ctildes[ms_ind * ndens + p] = basis_coeffs_vector[coeffs_ind]; + } + } + } + + for (SHORT_INT_TYPE func_ind = 0; func_ind < total_basis_size[mu]; func_ind++) { + auto ndens = basis[mu][func_ind].ndensity; + for (SHORT_INT_TYPE ms_ind = 0; ms_ind < basis[mu][func_ind].num_ms_combs; ms_ind++) { + for (DENSITY_TYPE p = 0; p < ndens; p++, coeffs_ind++) { + basis[mu][func_ind].ctildes[ms_ind * ndens + p] = basis_coeffs_vector[coeffs_ind]; + } + } + } + } +} + +void ACECTildeBasisSet::save_yaml(const string &yaml_file_name) const { + YAML::Node ctilde_basis_yaml; + + vector elements_name_vec; + elements_name_vec.assign(this->elements_name, this->elements_name + this->nelements); + ctilde_basis_yaml["elements"] = elements_name_vec; + ctilde_basis_yaml["elements"].SetStyle(YAML::EmitterStyle::Flow); + + ctilde_basis_yaml["E0"] = E0vals.to_vector(); + ctilde_basis_yaml["E0"].SetStyle(YAML::EmitterStyle::Flow); + + ctilde_basis_yaml["deltaSplineBins"] = this->deltaSplineBins; + + map yaml_map_embedding_specifications; + for (const auto &p: this->map_embedding_specifications) + yaml_map_embedding_specifications[p.first] = p.second.to_YAML(); + ctilde_basis_yaml["embeddings"] = yaml_map_embedding_specifications; + + map, YAML::Node> yaml_map_bond_specifications; + for (const auto &p: this->map_bond_specifications) { + vector bond_pair = {(int) p.first.first, (int) p.first.second}; + YAML::Node bond_yaml; + bond_yaml = bond_pair; + bond_yaml.SetStyle(YAML::EmitterStyle::Flow); + yaml_map_bond_specifications[bond_pair] = p.second.to_YAML(); + } + ctilde_basis_yaml["bonds"] = yaml_map_bond_specifications; + + //iterate over keys and make them in Flow style + for (YAML::detail::iterator_value p: ctilde_basis_yaml["bonds"]) { + p.first.SetStyle(YAML::EmitterStyle::Flow); + } + + map> acebbasisfunc_map; + for (SPECIES_TYPE mu = 0; mu < this->nelements; mu++) { + vector acebbasisfunc_vec; + for (size_t ind = 0; ind < this->total_basis_size_rank1[mu]; ind++) + acebbasisfunc_vec.emplace_back(this->basis_rank1[mu][ind].to_YAML()); + + for (size_t ind = 0; ind < this->total_basis_size[mu]; ind++) + acebbasisfunc_vec.emplace_back(this->basis[mu][ind].to_YAML()); + + acebbasisfunc_map[mu] = acebbasisfunc_vec; + } + + ctilde_basis_yaml["functions"] = acebbasisfunc_map; + + YAML::Emitter yaml_emitter; + yaml_emitter << ctilde_basis_yaml; + + std::ofstream fout(yaml_file_name); + fout << yaml_emitter.c_str() << endl; +} + +void ACECTildeBasisSet::load_yaml(const string &yaml_file_name) { + //set the input file - first thing to do + ifstream f(yaml_file_name.c_str()); + if (!f.good()) { + stringstream s; + s << "Potential file " << yaml_file_name << " doesn't exists"; + cerr << "Exception: " << s.str(); + throw invalid_argument(s.str()); + } + + //load the file with yaml + YAML::Node ctilde_basis_yaml = YAML::LoadFile(yaml_file_name); + + //reading elements and mapping + auto elements_yaml = ctilde_basis_yaml["elements"]; + auto elements_name_vec = elements_yaml.as>(); + this->nelements = elements_name_vec.size(); + if (this->elements_name != nullptr) + delete[] this->elements_name; + this->elements_name = new string[nelements]; + for (int mu = 0; mu < nelements; mu++) { + this->elements_name[mu] = elements_name_vec.at(mu); + this->elements_to_index_map[elements_name_vec.at(mu)] = mu; + } + + //reading E0vals + auto e0_vec = ctilde_basis_yaml["E0"].as>(); + E0vals.init(nelements); + E0vals.fill(0); + E0vals = e0_vec; + + //reading embeddings + auto yaml_map_embedding_specifications = ctilde_basis_yaml["embeddings"].as>(); + this->ndensitymax = 0; + for (auto p: yaml_map_embedding_specifications) { + SPECIES_TYPE mu_i = p.first; + if (mu_i > nelements - 1) + throw invalid_argument("yace::embeddings has species type key larger than nelements"); + + auto &emb_yaml = p.second; + ACEEmbeddingSpecification embeddingSpecification; + + embeddingSpecification.ndensity = emb_yaml["ndensity"].as(); + embeddingSpecification.FS_parameters = emb_yaml["FS_parameters"].as>(); + embeddingSpecification.npoti = emb_yaml["npoti"].as(); + embeddingSpecification.rho_core_cutoff = emb_yaml["rho_core_cutoff"].as(); + embeddingSpecification.drho_core_cutoff = emb_yaml["drho_core_cutoff"].as(); + + map_embedding_specifications[mu_i] = embeddingSpecification; + + if (embeddingSpecification.ndensity > this->ndensitymax) + this->ndensitymax = embeddingSpecification.ndensity; + } + + //reading bonds + auto yaml_map_bond_specifications = ctilde_basis_yaml["bonds"].as, YAML::Node>>(); + this->lmax = 0; + this->nradmax = 0; + this->nradbase = 0; + this->cutoffmax = 0; + + // check, if bonds::[]::radbasename=="ACE.jl.radbase" + bool ACE_jl_radbase = false; + bool PACE_radbase = false; + for (const auto &p: yaml_map_bond_specifications) { + auto bond_yaml = p.second; + string radbasename = bond_yaml["radbasename"].as(); + if (radbasename.rfind("ACE.jl", 0) == 0) + ACE_jl_radbase = true; + else + PACE_radbase = true; + } + // check if both type of radbase -> inconsistency + if (ACE_jl_radbase & PACE_radbase) { + throw invalid_argument( + "Only ACE.jl.* or PACE's radial basis are possible, but both types are used simultaneously."); + } + + if (PACE_radbase) { + vector> radbasename_ij(nelements, vector(nelements)); + for (const auto &p: yaml_map_bond_specifications) { + pair bond_pair = make_pair(p.first[0], p.first[1]); + if (bond_pair.first > nelements - 1 || bond_pair.second > nelements - 1) + throw invalid_argument("yace::bonds has species type key larger than nelements"); + + auto bond_yaml = p.second; + ACEBondSpecification bondSpec; + bondSpec.from_YAML(bond_yaml); + + map_bond_specifications[bond_pair] = bondSpec; + + radbasename_ij.at(bond_pair.first).at(bond_pair.second) = bondSpec.radbasename; + + //update lmax, nradbase max, ... + if (bondSpec.nradmax > this->nradmax) + this->nradmax = bondSpec.nradmax; + + if (bondSpec.lmax > this->lmax) + this->lmax = bondSpec.lmax; + + if (bondSpec.nradbasemax > this->nradbase) + this->nradbase = bondSpec.nradbasemax; + + if (bondSpec.rcut > this->cutoffmax) + this->cutoffmax = bondSpec.rcut; + + } + this->deltaSplineBins = ctilde_basis_yaml["deltaSplineBins"].as(); + + + if (radial_functions == nullptr) + radial_functions = new ACERadialFunctions(nradbase, lmax, nradmax, + deltaSplineBins, + nelements, + radbasename_ij); + else + radial_functions->init(nradbase, lmax, nradmax, + deltaSplineBins, + nelements, + radbasename_ij); + + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; ++mu_i) { + for (SPECIES_TYPE mu_j = 0; mu_j < nelements; ++mu_j) { + auto bond = make_pair(mu_i, mu_j); + const auto &bondSpec = map_bond_specifications[bond]; + radial_functions->cut(mu_i, mu_j) = bondSpec.rcut; + radial_functions->dcut(mu_i, mu_j) = bondSpec.dcut; + radial_functions->prehc(mu_i, mu_j) = bondSpec.prehc; + radial_functions->lambdahc(mu_i, mu_j) = bondSpec.lambdahc; + radial_functions->lambda(mu_i, mu_j) = bondSpec.radparameters.at(0); + + radial_functions->cut_in(mu_i, mu_j) = bondSpec.rcut_in; + radial_functions->dcut_in(mu_i, mu_j) = bondSpec.dcut_in; + radial_functions->inner_cutoff_type = bondSpec.inner_cutoff_type; + + //setup crad + for (NS_TYPE n = 0; n < bondSpec.nradmax; n++) + for (LS_TYPE l = 0; l <= bondSpec.lmax; l++) + for (NS_TYPE k = 0; k < bondSpec.nradbasemax; k++) { + radial_functions->crad(mu_i, mu_j, n, l, k) = bondSpec.radcoefficients.at(n).at(l).at(k); + } + } + } + /////////////////////////////////////////////////////////////////// + } else if (ACE_jl_radbase) { + /////////////////////////////////////////////////////////////////// + //read lmax from YACE + if (ctilde_basis_yaml["lmax"]) + this->lmax = ctilde_basis_yaml["lmax"].as(); + else + throw invalid_argument( + "For `ACE.jl.*` radbase functions, `lmax` should be provided in the YACE separately."); + // no need to store map_bond_specifications, only SHIPsRadialFunctions + SHIPsRadialFunctions *ships_radial_functions = new SHIPsRadialFunctions(); + ships_radial_functions->init(nelements); + ships_radial_functions->read_yaml(ctilde_basis_yaml); + _post_load_radial_SHIPsBasic(ships_radial_functions); + } + /////////////////////////////////////////////////////////////////// + + //setup spherical_harmonics and radialBasis + spherical_harmonics.init(lmax); + radial_functions->setuplookupRadspline(); + + //reading ACECTildeBasisFunctions + //TODO:setup rankmax + map> acebbasisfunc_map = ctilde_basis_yaml["functions"].as >>(); + vector int_vec; + vector double_vec; + + total_basis_size_rank1 = new SHORT_INT_TYPE[nelements]; + basis_rank1 = new ACECTildeBasisFunction *[nelements]; + + total_basis_size = new SHORT_INT_TYPE[nelements]; + basis = new ACECTildeBasisFunction *[nelements]; + + this->rankmax = 0; + + for (const auto &p: acebbasisfunc_map) { + SPECIES_TYPE mu = p.first; + if (mu > nelements - 1) + throw invalid_argument("yace::functions has species type key larger than nelements"); + + total_basis_size_rank1[mu] = 0; + total_basis_size[mu] = 0; + + auto ctildefunc_vec_yaml = p.second; + + vector ctildefunc_vec;//TODO: read write is_half_ms_basis + for (const auto &ctildefunc_yaml: ctildefunc_vec_yaml) { + + ACECTildeBasisFunction ctildefunc; + + ctildefunc.mu0 = ctildefunc_yaml["mu0"].as(); + ctildefunc.rank = ctildefunc_yaml["rank"].as(); + ctildefunc.ndensity = ctildefunc_yaml["ndensity"].as(); + ctildefunc.num_ms_combs = ctildefunc_yaml["num_ms_combs"].as(); + + int_vec = ctildefunc_yaml["mus"].as>(); + if (int_vec.size()!=ctildefunc.rank) + throw invalid_argument("mus:: not sufficient number of values"); + ctildefunc.mus = new SPECIES_TYPE[ctildefunc.rank]; + for (int r = 0; r < ctildefunc.rank; r++) + ctildefunc.mus[r] = int_vec.at(r); + + int_vec = ctildefunc_yaml["ns"].as>(); + if (int_vec.size()!=ctildefunc.rank) + throw invalid_argument("ns:: not sufficient number of values"); + ctildefunc.ns = new NS_TYPE[ctildefunc.rank]; + for (int r = 0; r < ctildefunc.rank; r++) + ctildefunc.ns[r] = int_vec.at(r); + + + int_vec = ctildefunc_yaml["ls"].as>(); + if (int_vec.size()!=ctildefunc.rank) + throw invalid_argument("ls:: not sufficient number of values"); + ctildefunc.ls = new LS_TYPE[ctildefunc.rank]; + for (int r = 0; r < ctildefunc.rank; r++) + ctildefunc.ls[r] = int_vec.at(r); + + //this->ms_combs; //[num_ms_combs * rank] + int_vec = ctildefunc_yaml["ms_combs"].as>(); + if (int_vec.size()!=ctildefunc.rank * ctildefunc.num_ms_combs) + throw invalid_argument("ms_combs:: not sufficient number of values"); + ctildefunc.ms_combs = new MS_TYPE[ctildefunc.rank * ctildefunc.num_ms_combs]; + for (int r = 0; r < ctildefunc.rank * ctildefunc.num_ms_combs; r++) + ctildefunc.ms_combs[r] = int_vec.at(r); + + + // this->ctildes; //[num_of_ms_combs * ndensity] + double_vec = ctildefunc_yaml["ctildes"].as>(); + if (double_vec.size()!=ctildefunc.ndensity * ctildefunc.num_ms_combs) + throw invalid_argument("ctildes:: not sufficient number of values"); + ctildefunc.ctildes = new DOUBLE_TYPE[ctildefunc.ndensity * ctildefunc.num_ms_combs]; + for (int r = 0; r < ctildefunc.ndensity * ctildefunc.num_ms_combs; r++) + ctildefunc.ctildes[r] = double_vec.at(r); + + ctildefunc_vec.emplace_back(ctildefunc); + + if (ctildefunc.rank == 1) + total_basis_size_rank1[mu]++; + else + total_basis_size[mu]++; + + } // end for over ctildefunc_vec_yaml + +// cout << "total_basis_size_rank1[mu]=" << total_basis_size_rank1[mu] << endl; +// cout << "total_basis_size[mu]=" << total_basis_size[mu] << endl; + + basis_rank1[mu] = new ACECTildeBasisFunction[total_basis_size_rank1[mu]]; + basis[mu] = new ACECTildeBasisFunction[total_basis_size[mu]]; + size_t func_ind_rank1 = 0, func_ind = 0; + for (const ACECTildeBasisFunction ctildefunc: ctildefunc_vec) { + if (ctildefunc.rank == 1) { + basis_rank1[mu][func_ind_rank1] = ctildefunc; + func_ind_rank1++; + } else { + basis[mu][func_ind] = ctildefunc; + func_ind++; + } + //aggregate rankmax + if (this->rankmax < ctildefunc.rank) + this->rankmax = ctildefunc.rank; + } + } + + + pack_flatten_basis(); } diff --git a/USER-PACE/ace_c_basis.h b/ML-PACE/ace_c_basis.h similarity index 82% rename from USER-PACE/ace_c_basis.h rename to ML-PACE/ace_c_basis.h index 233c5d1..9f65c3d 100644 --- a/USER-PACE/ace_c_basis.h +++ b/ML-PACE/ace_c_basis.h @@ -31,6 +31,7 @@ #define ACE_C_BASIS_H #include "ace_flatten_basis.h" +#include "ships_radial.h" typedef vector> C_tilde_full_basis_vector2d; @@ -98,7 +99,7 @@ class ACECTildeBasisSet : public ACEFlattenBasisSet { /** * Clean contiguous arrays (full_c_tildes_rank1, full_c_tildes) and those of base class */ - void _clean_contiguous_arrays() override ; + void _clean_contiguous_arrays() override; /** * Save potential to .ace file @@ -112,6 +113,15 @@ class ACECTildeBasisSet : public ACEFlattenBasisSet { */ void load(const string filename) override; + + /** + * Save potential to YAML .yace file + * @param filename .yace file name + */ + void save_yaml(const string &yaml_file_name) const; + + void load_yaml(const string &filename); + /** * Load the ACE type radial basis */ @@ -119,9 +129,9 @@ class ACECTildeBasisSet : public ACEFlattenBasisSet { const string filename, const string radbasename); - void _load_radial_SHIPsBasic(FILE * fptr, - const string filename, - const string radbasename ); + void _load_radial_SHIPsBasic(FILE *fptr, + const string filename, + const string radbasename); /** * Re-pack the constituent dynamic arrays of all basis functions in contiguous arrays @@ -133,7 +143,7 @@ class ACECTildeBasisSet : public ACEFlattenBasisSet { * @param basis_rank1 two-dimensional array of first-rank ACECTildeBasisFunctions * @param basis two-dimensional array of higher-rank ACECTildeBasisFunctions */ - void compute_array_sizes(ACECTildeBasisFunction** basis_rank1, ACECTildeBasisFunction** basis); + void compute_array_sizes(ACECTildeBasisFunction **basis_rank1, ACECTildeBasisFunction **basis); /** * Clean basis arrays 'basis_rank1' and 'basis' @@ -144,12 +154,22 @@ class ACECTildeBasisSet : public ACEFlattenBasisSet { * Pack two-dimensional vector of ACECTildeBasisFunction into 1D dynami array with all basis functions * @param mu0_ctilde_basis_vector vector> */ - void flatten_basis(C_tilde_full_basis_vector2d& mu0_ctilde_basis_vector); + void flatten_basis(C_tilde_full_basis_vector2d &mu0_ctilde_basis_vector); /** * Empty stub implementation */ - void flatten_basis() override{}; + void flatten_basis() override {}; + + + vector get_all_coeffs() const override; + + vector> get_all_coeffs_mask() const override; + + void set_all_coeffs(const vector &coeffs) override; + + + void _post_load_radial_SHIPsBasic(SHIPsRadialFunctions *ships_radial_functions); }; #endif //ACE_C_BASIS_H diff --git a/USER-PACE/ace_c_basisfunction.h b/ML-PACE/ace_c_basisfunction.h similarity index 78% rename from USER-PACE/ace_c_basisfunction.h rename to ML-PACE/ace_c_basisfunction.h index ae1d7e5..a201488 100644 --- a/USER-PACE/ace_c_basisfunction.h +++ b/ML-PACE/ace_c_basisfunction.h @@ -30,10 +30,14 @@ #ifndef ACE_C_BASISFUNCTION_H #define ACE_C_BASISFUNCTION_H +#include #include #include #include #include +#include + +#include "yaml-cpp/yaml.h" #include "ace_types.h" @@ -142,8 +146,46 @@ struct ACEAbstractBasisFunction { ms_combs = nullptr; } + std::vector get_unique_species() const { + std::vector unique_species; + unique_species.emplace_back(this->mu0); + for (int r = 0; r < this->rank; r++) { + if (std::find(unique_species.begin(), unique_species.end(), this->mus[r]) + == unique_species.end()) { + /* v does not contain x */ + unique_species.emplace_back(this->mus[r]); + } + } + return unique_species; + } + + std::string to_string() const { + std::stringstream ss; + ss << "(" << (int) this->mu0 << "|"; + ss << "mus=("; + for (int r = 0; r < this->rank; r++) + ss << (int) this->mus[r] << ","; + ss << "), "; + + ss << "ns=("; + for (int r = 0; r < this->rank; r++) + ss << (int) this->ns[r] << ","; + ss << "), "; + + ss << "ls=("; + for (int r = 0; r < this->rank; r++) + ss << (int) this->ls[r] << ","; + ss << "), "; + + ss << this->num_ms_combs << " ms_combs, "; + ss << "ndens=" << this->ndensity; + ss << ")"; + + return ss.str(); + } }; + /** * Representation of C-tilde basis function, i.e. the function that is summed up over a group of B-functions * that differs only by intermediate coupling orbital moment \f$ L \f$ and coefficients. @@ -246,6 +288,39 @@ struct ACECTildeBasisFunction : public ACEAbstractBasisFunction { cout << "half_ms_basis"; cout << "}" << endl; } + + YAML::Node to_YAML() const { + YAML::Node ctilde_yaml; + ctilde_yaml.SetStyle(YAML::EmitterStyle::Flow); + ctilde_yaml["mu0"] = (int) this->mu0; + ctilde_yaml["rank"] = (int) this->rank; + ctilde_yaml["ndensity"] = this->ndensity; + ctilde_yaml["num_ms_combs"] = this->num_ms_combs; + + std::vector int_vec; + int_vec.assign(this->mus, this->mus + this->rank); + ctilde_yaml["mus"] = int_vec; + + int_vec.assign(this->ns, this->ns + this->rank); + ctilde_yaml["ns"] = int_vec; + + int_vec.assign(this->ls, this->ls + this->rank); + ctilde_yaml["ls"] = int_vec; + + //this->ms_combs; //[num_ms_combs * rank] + int_vec.assign(this->ms_combs, this->ms_combs + this->num_ms_combs * this->rank); + ctilde_yaml["ms_combs"] = int_vec; + + + std::vector double_vec; + // this->ctildes; //[num_of_ms_combs * ndensity] + double_vec.assign(this->ctildes, this->ctildes + this->num_ms_combs * this->ndensity); + ctilde_yaml["ctildes"] = double_vec; + + + return ctilde_yaml; + } + }; #endif //ACE_C_BASISFUNCTION_H diff --git a/USER-PACE/ace_complex.h b/ML-PACE/ace_complex.h similarity index 100% rename from USER-PACE/ace_complex.h rename to ML-PACE/ace_complex.h diff --git a/USER-PACE/ace_contigous_array.h b/ML-PACE/ace_contigous_array.h similarity index 100% rename from USER-PACE/ace_contigous_array.h rename to ML-PACE/ace_contigous_array.h diff --git a/USER-PACE/ace_evaluator.cpp b/ML-PACE/ace_evaluator.cpp similarity index 98% rename from USER-PACE/ace_evaluator.cpp rename to ML-PACE/ace_evaluator.cpp index 5ba8910..3d35138 100644 --- a/USER-PACE/ace_evaluator.cpp +++ b/ML-PACE/ace_evaluator.cpp @@ -203,8 +203,7 @@ ACECTildeEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *typ //TODO: nradbase -> nradbasei (get per-species type) const NS_TYPE nradbasei = basis_set->nradbase; - //TODO: get per-species type number of densities - const DENSITY_TYPE ndensity= basis_set->ndensitymax; + const DENSITY_TYPE ndensity = basis_set->map_embedding_specifications[mu_i].ndensity; neighbours_forces.resize(jnum, 3); neighbours_forces.fill(0); @@ -219,7 +218,9 @@ ACECTildeEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *typ #ifdef EXTRA_C_PROJECTIONS basis_projections_rank1.init(total_basis_size_rank1, ndensity, "c_projections_rank1"); + basis_projections_rank1.fill(0); basis_projections.init(total_basis_size, ndensity, "c_projections"); + basis_projections.fill(0); #endif //proxy references to spherical harmonics and radial functions arrays @@ -456,11 +457,11 @@ ACECTildeEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *typ // energy cutoff - rho_cut = basis_set->rho_core_cutoffs(mu_i); - drho_cut = basis_set->drho_core_cutoffs(mu_i); + rho_cut = basis_set->map_embedding_specifications.at(mu_i).rho_core_cutoff; + drho_cut = basis_set->map_embedding_specifications.at(mu_i).drho_core_cutoff; basis_set->inner_cutoff(rho_core, rho_cut, drho_cut, fcut, dfcut); - basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, ndensity); + basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, mu_i); dF_drho_core = evdwl * dfcut + 1; for (DENSITY_TYPE p = 0; p < ndensity; ++p) diff --git a/USER-PACE/ace_evaluator.h b/ML-PACE/ace_evaluator.h similarity index 100% rename from USER-PACE/ace_evaluator.h rename to ML-PACE/ace_evaluator.h diff --git a/USER-PACE/ace_flatten_basis.cpp b/ML-PACE/ace_flatten_basis.cpp similarity index 100% rename from USER-PACE/ace_flatten_basis.cpp rename to ML-PACE/ace_flatten_basis.cpp diff --git a/USER-PACE/ace_flatten_basis.h b/ML-PACE/ace_flatten_basis.h similarity index 100% rename from USER-PACE/ace_flatten_basis.h rename to ML-PACE/ace_flatten_basis.h diff --git a/USER-PACE/ace_radial.cpp b/ML-PACE/ace_radial.cpp similarity index 74% rename from USER-PACE/ace_radial.cpp rename to ML-PACE/ace_radial.cpp index b70920d..0cce4c7 100644 --- a/USER-PACE/ace_radial.cpp +++ b/ML-PACE/ace_radial.cpp @@ -32,24 +32,28 @@ #include "ace_radial.h" +#define sqr(x) ((x)*(x)) const DOUBLE_TYPE pi = 3.14159265358979323846264338327950288419; // pi ACERadialFunctions::ACERadialFunctions(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { - init(nradb, lmax, nradial, deltaSplineBins, nelements, cutoff, radbasename); + vector> radbasename) { + init(nradb, lmax, nradial, deltaSplineBins, nelements, radbasename); } void ACERadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, - SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { + SPECIES_TYPE nelements, vector> radbasename) { this->nradbase = nradb; this->lmax = lmax; this->nradial = nradial; this->deltaSplineBins = deltaSplineBins; this->nelements = nelements; - this->cutoff = cutoff; - this->radbasename = radbasename; + this->radbasenameij = radbasename; + auto shape = this->radbasenameij.get_shape(); + if (shape.size() != 2 || shape.at(0) != nelements || shape.at(1) != nelements) { + throw std::invalid_argument("`radbasename` array has wrong shape. It must be of shape (nelements, nelements)"); + } + gr.init(nradbase, "gr"); dgr.init(nradbase, "dgr"); @@ -79,6 +83,12 @@ void ACERadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUB dcut.init(nelements, nelements, "dcut"); dcut.fill(1.); + cut_in.init(nelements, nelements, "cut_in"); + cut_in.fill(0); + + dcut_in.init(nelements, nelements, "dcut_in"); + dcut_in.fill(1e-5); + crad.init(nelements, nelements, nradial, (lmax + 1), nradbase, "crad"); crad.fill(0.); @@ -111,7 +121,7 @@ void ACERadialFunctions::calcCheb(NS_TYPE n, DOUBLE_TYPE x) { dcheb(0) = 0.; cheb2(0) = 1.; - if (nradbase > 1) { + if (nradbase >= 1) { cheb(1) = x; cheb2(1) = twox; } @@ -129,6 +139,28 @@ void ACERadialFunctions::calcCheb(NS_TYPE n, DOUBLE_TYPE x) { #endif } +/** + * Polynomial inner cutoff function, descending from r_in-delta_in to r_in + * @param r actual r + * @param r_in inner cutoff + * @param delta_in decay of inner cutoff + * @param fc + * @param dfc + */ +void cutoff_func_poly(DOUBLE_TYPE r, DOUBLE_TYPE r_in, DOUBLE_TYPE delta_in, DOUBLE_TYPE &fc, DOUBLE_TYPE &dfc) { + if (r <= r_in-delta_in) { + fc = 1; + dfc = 0; + } else if (r >= r_in ) { + fc = 0; + dfc = 0; + } else { + DOUBLE_TYPE x = 1 - 2 * (1 + (r - r_in) / delta_in); + fc = 0.5 + 7.5 / 2. * (x / 4. - pow(x, 3) / 6. + pow(x, 5) / 20.); + dfc = -7.5 / delta_in * (0.25 - x * x / 2.0 + pow(x, 4) / 4.); + } +} + /** Function that computes radial basis. @@ -136,22 +168,42 @@ Function that computes radial basis. @returns gr, dgr */ -void ACERadialFunctions::radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { +void +ACERadialFunctions::radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, string radbasename, DOUBLE_TYPE r, + DOUBLE_TYPE cut_in, DOUBLE_TYPE dcut_in) { /*lam is given by the formula (24), that contains cut */ - - if (r < cut) { + if (r <= cut_in-dcut_in || r >= cut) { + gr.fill(0); + dgr.fill(0); + } else { // cut_in < r < cut if (radbasename == "ChebExpCos") { chebExpCos(lam, cut, dcut, r); } else if (radbasename == "ChebPow") { chebPow(lam, cut, dcut, r); } else if (radbasename == "ChebLinear") { chebLinear(lam, cut, dcut, r); + } else if (radbasename == "TEST_SBessel") { + simplified_bessel(cut, r); + } else if (radbasename.rfind("TEST_", 0) == 0) { + test_zero_func(lam, cut, dcut, r); } else { throw invalid_argument("Unknown radial basis function name: " + radbasename); } - } else { - gr.fill(0); - dgr.fill(0); + + //TODO: always take into account inner cutoff + if (inner_cutoff_type == "distance") { + //multiply by cutoff poly gr and dgr + DOUBLE_TYPE fc, dfc; + cutoff_func_poly(r, cut_in, dcut_in, fc, dfc); // ascending inner cutoff + fc=1-fc; + dfc=-dfc; + for (int i = 0; i < gr.get_dim(0); i++) { + DOUBLE_TYPE new_gr = gr(i) * fc; + DOUBLE_TYPE new_dgr = dgr(i) * fc + gr(i) * dfc; + gr(i) = new_gr; + dgr(i) = new_dgr; + } + } } } @@ -172,7 +224,7 @@ ACERadialFunctions::chebExpCos(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcu x = 1.0 - 2.0 * ((y1 - y2) / (1 - y2)); dx = 2 * (lam / cut) * (y1 / (1 - y2)); /* calculation of Chebyshev polynomials from the recursion */ - calcCheb(nradbase - 1, x); + calcCheb(nradbase, x); gr(0) = cheb(0); dgr(0) = dcheb(0) * dx; for (NS_TYPE n = 2; n <= nradbase; n++) { @@ -198,7 +250,7 @@ ACERadialFunctions::chebExpCos(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcu } /*** -* Radial function: ChebPow, Radial function: ChebPow +* Radial function: ChebPow * - argument of Chebyshev polynomials * x = 2.0*( 1.0 - (1.0 - r/rcut)^lam ) - 1.0 * - radial function @@ -247,6 +299,86 @@ ACERadialFunctions::chebLinear(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcu } } +/** + * sinc(x) = sin(x)/x + * @param x + * @return + */ +DOUBLE_TYPE sinc(DOUBLE_TYPE x) { + return x != 0.0 ? sin(x) / x : 1; +} + +/** + * Derivative of d sinc(x) / dx = (cos(x)*x - sin(x))/x^2 + * @param x + * @return + */ +DOUBLE_TYPE dsinc(DOUBLE_TYPE x) { + return x != 0.0 ? (cos(x) * x - sin(x)) / (x * x) : 0; +} + +/** + * Auxiliary function $fn$ for simplified Bessel + * @param x argument + * @param rc cutoff + * @param n degree + * @return + */ +DOUBLE_TYPE fn(DOUBLE_TYPE x, DOUBLE_TYPE rc, int n) { + return pow(-1, n) * sqrt(2) * M_PI / pow(rc, 1.5) * (n + 1) * (n + 2) / sqrt(sqr(n + 1) + sqr(n + 2)) * + (sinc(x * (n + 1) * M_PI / rc) + sinc(x * (n + 2) * M_PI / rc)); +} + +/** + * Derivative of the auxiliary function $fn$ for simplified Bessel + * @param x argument + * @param rc cutoff + * @param n degree + * @return + */ +DOUBLE_TYPE dfn(DOUBLE_TYPE x, DOUBLE_TYPE rc, int n) { + return pow(-1, n) * sqrt(2) * M_PI / pow(rc, 1.5) * (n + 1) * (n + 2) / sqrt(sqr(n + 1) + sqr(n + 2)) * + (dsinc(x * (n + 1) * M_PI / rc) * (n + 1) * M_PI / rc + + dsinc(x * (n + 2) * M_PI / rc) * (n + 2) * M_PI / rc); +} + +/** + * Simplified Bessel function + * @param rc + * @param x + */ +void ACERadialFunctions::simplified_bessel(DOUBLE_TYPE rc, DOUBLE_TYPE x) { + if (x < rc) { + gr(0) = fn(x, rc, 0); + dgr(0) = dfn(x, rc, 0); + + DOUBLE_TYPE d_prev = 1.0, en, dn; + for (NS_TYPE n = 1; n < nradbase; n++) { + en = sqr(n) * sqr(n + 2) / (4 * pow(n + 1, 4) + 1); + dn = 1 - en / d_prev; + gr(n) = 1 / sqrt(dn) * (fn(x, rc, n) + sqrt(en / d_prev) * gr(n - 1)); + dgr(n) = 1 / sqrt(dn) * (dfn(x, rc, n) + sqrt(en / d_prev) * dgr(n - 1)); + d_prev = dn; + } + } else { + gr.fill(0); + dgr.fill(0); + } +} + + +/** + * Stub zero function (for testing purposes mostly), called when radbasename starts with "TEST_" + * @param lam + * @param cut + * @param dcut + * @param r + */ +void ACERadialFunctions::test_zero_func(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r) { + gr.fill(0); + dgr.fill(0); +} + /** Function that computes radial functions. @@ -275,16 +407,21 @@ void ACERadialFunctions::all_radfunc(SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, DOUBL DOUBLE_TYPE lam = lambda(mu_i, mu_j); DOUBLE_TYPE r_cut = cut(mu_i, mu_j); DOUBLE_TYPE dr_cut = dcut(mu_i, mu_j); + + DOUBLE_TYPE r_in = cut_in(mu_i,mu_j); + DOUBLE_TYPE dr_in = dcut_in(mu_i,mu_j); + // set up radial functions - radbase(lam, r_cut, dr_cut, r); //update gr, dgr + radbase(lam, r_cut, dr_cut, radbasenameij(mu_i, mu_j), r, r_in, dr_in); //update gr, dgr radfunc(mu_i, mu_j); // update fr(nr, l), dfr(nr, l) } void ACERadialFunctions::setuplookupRadspline() { using namespace std::placeholders; - DOUBLE_TYPE lam, r_cut, dr_cut; + DOUBLE_TYPE lam, r_cut, dr_cut, r_in, delta_in; DOUBLE_TYPE cr_c, dcr_c, pre, lamhc; + string radbasename; // at r = rcut + eps the function and its derivatives is zero for (SPECIES_TYPE elei = 0; elei < nelements; elei++) { @@ -293,28 +430,33 @@ void ACERadialFunctions::setuplookupRadspline() { lam = lambda(elei, elej); r_cut = cut(elei, elej); dr_cut = dcut(elei, elej); + r_in = cut_in(elei, elej); + delta_in = dcut_in(elei, elej); + radbasename = radbasenameij(elei, elej); splines_gk(elei, elej).setupSplines(gr.get_size(), std::bind(&ACERadialFunctions::radbase, this, lam, r_cut, dr_cut, - _1),//update gr, dgr + radbasename, + _1, r_in, delta_in),//update gr, dgr gr.get_data(), - dgr.get_data(), deltaSplineBins, cutoff); + dgr.get_data(), deltaSplineBins, r_cut); splines_rnl(elei, elej).setupSplines(fr.get_size(), std::bind(&ACERadialFunctions::all_radfunc, this, elei, elej, _1), // update fr(nr, l), dfr(nr, l) fr.get_data(), - dfr.get_data(), deltaSplineBins, cutoff); + dfr.get_data(), deltaSplineBins, r_cut); pre = prehc(elei, elej); lamhc = lambdahc(elei, elej); -// radcore(r, pre, lamhc, cutoff, cr_c, dcr_c); + // radcore(r, pre, lamhc, cutoff, cr_c, dcr_c, r_cut_in, dr_cut_in); splines_hc(elei, elej).setupSplines(1, - std::bind(&ACERadialFunctions::radcore, _1, pre, lamhc, cutoff, - std::ref(cr_c), std::ref(dcr_c)), + std::bind(&ACERadialFunctions::radcore, this, + _1, pre, lamhc, r_cut, + std::ref(cr_c), std::ref(dcr_c), r_in, delta_in), &cr_c, - &dcr_c, deltaSplineBins, cutoff); + &dcr_c, deltaSplineBins, r_cut); } } @@ -357,11 +499,8 @@ ACERadialFunctions::evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_ d2cr = spline_hc.second_derivatives(0); } - -void -ACERadialFunctions::radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, - DOUBLE_TYPE &dcr) { -/* pseudocode for hard core repulsion +/** + pseudocode for hard core repulsion in: r: distance pre: prefactor: read from input, depends on pair of atoms mu_i mu_j @@ -375,10 +514,13 @@ dcr: derivative of hard core repulsion \$f f_{core} = pre \exp( - \lambda r^2 ) / r \$f */ +void +ACERadialFunctions::radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, + DOUBLE_TYPE &dcr, DOUBLE_TYPE r_in, DOUBLE_TYPE delta_in) { DOUBLE_TYPE r2, lr2, y, x0, env, denv; -// repulsion strictly positive and decaying + // repulsion strictly positive and decaying pre = abs(pre); lambda = abs(lambda); @@ -399,6 +541,19 @@ dcr: derivative of hard core repulsion dcr = 0.0; } + if (inner_cutoff_type == "distance") { + // core repulsion became non-zero only within r < cut_in + dcut_in + DOUBLE_TYPE fc, dfc; + cutoff_func_poly(r, r_in, delta_in, fc, dfc); + //inverse cutoff +// fc = 1 - fc; +// dfc = -dfc; + + DOUBLE_TYPE new_cr = cr * fc; + DOUBLE_TYPE new_dcr = dcr * fc + cr * dfc; + cr = new_cr; + dcr = new_dcr; + } } void @@ -447,6 +602,9 @@ void SplineInterpolator::setupSplines(int num_of_functions, RadialFunctions func DOUBLE_TYPE *dvalues, DOUBLE_TYPE deltaSplineBins, DOUBLE_TYPE cutoff) { this->deltaSplineBins = deltaSplineBins; + if (!deltaSplineBins > 0) { + throw invalid_argument("deltaSplineBins should be positive"); + } this->cutoff = cutoff; this->ntot = static_cast(cutoff / deltaSplineBins); @@ -475,6 +633,9 @@ void SplineInterpolator::setupSplines(int num_of_functions, RadialFunctions func if (dvalues == nullptr & num_of_functions > 0) throw invalid_argument("SplineInterpolator::setupSplines: dvalues could not be null"); + if (num_of_functions == 0) + return; + for (int n = nlut; n >= 1; n--) { r = invrscalelookup * DOUBLE_TYPE(n); func(r); //populate values and dvalues arrays diff --git a/USER-PACE/ace_radial.h b/ML-PACE/ace_radial.h similarity index 89% rename from USER-PACE/ace_radial.h rename to ML-PACE/ace_radial.h index 42dc469..e810430 100644 --- a/USER-PACE/ace_radial.h +++ b/ML-PACE/ace_radial.h @@ -32,10 +32,11 @@ #include "ace_types.h" #include + using namespace std; //typedef void (*RadialFunctions)(DOUBLE_TYPE x); -typedef std::function RadialFunctions; +typedef std::function RadialFunctions; /** * Class that implement spline interpolation and caching for radial functions @@ -97,21 +98,18 @@ class AbstractRadialBasis { SPECIES_TYPE nelements = 0; ///< number of elements Array2D cut = Array2D("cut"); ///< cutoffs, shape: [nelements][nelements] Array2D dcut = Array2D("dcut"); ///< decay of cutoff, shape: [nelements][nelements] - DOUBLE_TYPE cutoff = 0; ///< cutoff -// int ntot = 10000; ///< Number of bins for look-up tables. DOUBLE_TYPE deltaSplineBins; LS_TYPE lmax = 0; ///< maximum value of `l` NS_TYPE nradial = 0; ///< maximum number `n` of radial functions \f$ R_{nl}(r) \f$ NS_TYPE nradbase = 0; ///< number of radial basis functions \f$ g_k(r) \f$ - // Arrays for look-up tables. - Array2D splines_gk; ///< array of spline interpolator to store g_k, shape: [nelements][nelements] - Array2D splines_rnl; ///< array of spline interpolator to store R_nl, shape: [nelements][nelements] - Array2D splines_hc; ///< array of spline interpolator to store R_nl shape: [nelements][nelements] - //-------------------------------------------------------------------------- + Array2D radbasenameij;///< type of radial basis functions \f$ g_{k}(r) \f$ [nelements][nelements] + + Array2D cut_in = Array2D("cut_in"); ///< inner cutoffs, shape: [nelements][nelements] + Array2D dcut_in = Array2D("dcut_in"); ///< decay of inner cutoff, shape: [nelements][nelements] - string radbasename = "ChebExpCos"; ///< type of radial basis functions \f$ g_{k}(r) \f$ (default="ChebExpCos") + string inner_cutoff_type = "density"; //density (old) or distance(new) /** Arrays to store radial functions. @@ -127,13 +125,12 @@ class AbstractRadialBasis { "d2fr"); ///< derivatives of R_nl(r) functions, shape: [nradial][lmax+1] - DOUBLE_TYPE cr; ///< hard-core repulsion DOUBLE_TYPE dcr; ///< derivative of hard-core repulsion DOUBLE_TYPE d2cr; ///< derivative of hard-core repulsion Array5D crad = Array5D( - "crad"); ///< expansion coefficients of radial functions into radial basis function, see Eq. (27) of PRB, shape: [nelements][nelements][lmax + 1][nradial][nradbase] + "crad"); ///< expansion coefficients of radial functions into radial basis function, see Eq. (27) of PRB, shape: [nelements][nelements][nradial][lmax + 1][nradbase] Array2D lambda = Array2D( "lambda"); ///< distance scaling parameter Eq.(24) of PRB, shape: [nelements][nelements] @@ -148,8 +145,7 @@ class AbstractRadialBasis { virtual void init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename = "ChebExpCos") = 0; + vector> radbasenameij) = 0; /** * Function that sets up the look-up tables for spline-representation of radial functions. @@ -168,6 +164,10 @@ Class to store radial functions and their associated functions. \n class ACERadialFunctions final : public AbstractRadialBasis { public: + // Arrays for look-up tables. + Array2D splines_gk; + Array2D splines_rnl; + Array2D splines_hc; //-------------------------------------------------------------------------- /** @@ -208,7 +208,7 @@ class ACERadialFunctions final : public AbstractRadialBasis { */ ACERadialFunctions(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename = "ChebExpCos"); + vector> radbasename); /** * Initialize arrays for given parameters @@ -222,8 +222,7 @@ class ACERadialFunctions final : public AbstractRadialBasis { * @param radbasename type of radial basis function \f$ g_k(r) \f$ (default: "ChebExpCos") */ void init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename = "ChebExpCos") final; + vector> radbasename); /** * Destructor @@ -250,7 +249,8 @@ class ACERadialFunctions final : public AbstractRadialBasis { * * @return function fills gr and dgr arrays */ - void radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); + void radbase(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, string radbasename, DOUBLE_TYPE r, + DOUBLE_TYPE cut_in = 0, DOUBLE_TYPE dcut_in = 0); /** * Function that computes radial core repulsion \$f f_{core} = pre \exp( - \lambda r^2 ) / r \$f, @@ -263,8 +263,8 @@ class ACERadialFunctions final : public AbstractRadialBasis { * @param cr (out) hard core repulsion * @param dcr (out) derivative of hard core repulsion */ - static void radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, - DOUBLE_TYPE &dcr); + void radcore(DOUBLE_TYPE r, DOUBLE_TYPE pre, DOUBLE_TYPE lambda, DOUBLE_TYPE cutoff, DOUBLE_TYPE &cr, + DOUBLE_TYPE &dcr, DOUBLE_TYPE cut_in = 0, DOUBLE_TYPE dcut_in = 0); /** * Function that sets up the look-up tables for spline-representation of radial functions. @@ -307,6 +307,10 @@ class ACERadialFunctions final : public AbstractRadialBasis { void chebLinear(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); + void simplified_bessel(DOUBLE_TYPE cut, DOUBLE_TYPE r); + + void test_zero_func(DOUBLE_TYPE lam, DOUBLE_TYPE cut, DOUBLE_TYPE dcut, DOUBLE_TYPE r); + /** * Setup all radial functions for element pair mu_i-mu_j and distance r * @param mu_i first specie type @@ -319,7 +323,9 @@ class ACERadialFunctions final : public AbstractRadialBasis { ACERadialFunctions *clone() const override { return new ACERadialFunctions(*this); }; + }; +void cutoff_func_poly(DOUBLE_TYPE r, DOUBLE_TYPE r_in, DOUBLE_TYPE delta_in, DOUBLE_TYPE &fc, DOUBLE_TYPE &dfc); #endif diff --git a/USER-PACE/ace_recursive.cpp b/ML-PACE/ace_recursive.cpp similarity index 77% rename from USER-PACE/ace_recursive.cpp rename to ML-PACE/ace_recursive.cpp index e16c5bc..c23ed03 100644 --- a/USER-PACE/ace_recursive.cpp +++ b/ML-PACE/ace_recursive.cpp @@ -45,11 +45,11 @@ * rec3 - split nodes into interior and leaf nodes */ -void ACEDAG::init(Array2D xAspec, - Array2D AAspec, - Array1D orders, +void ACEDAG::init(Array2D xAspec, + Array2D AAspec, + Array1D orders, Array2D jl_coeffs, - int _heuristic ) { + int _heuristic) { // remember which heuristic we want to use! heuristic = _heuristic; @@ -70,7 +70,7 @@ void ACEDAG::init(Array2D xAspec, for (int iA = 0; iA < num1; iA++) { vector a(1); a[0] = iA; - DAGmap[a] = iA; + DAGmap[a] = iA; } /* For stage 2 we now want to construct the actual recursion; the @@ -83,9 +83,9 @@ void ACEDAG::init(Array2D xAspec, second stage below we reorganize. */ int num2 = AAspec.get_dim(0); int ndensity = jl_coeffs.get_dim(1); - nodes_pre.resize(2*num2, 2); - coeffs_pre.resize(2*num2, ndensity); - + nodes_pre.resize(2 * num2, 2); + coeffs_pre.resize(2 * num2, ndensity); + /* the first basis function we construct will get index num1, * since there are already num1 one-particle basis functions * to collect during stage 1 */ @@ -95,7 +95,7 @@ void ACEDAG::init(Array2D xAspec, // create a vector representing the current basis function int ord = orders(iAA); vector aa(ord); - for (int t = 0; t < ord; t++) aa[t] = AAspec(iAA, t); + for (int t = 0; t < ord; t++) aa[t] = AAspec(iAA, t); vector c(ndensity); for (int p = 0; p < ndensity; p++) c[p] = jl_coeffs(iAA, p); insert_node(DAGmap, aa, c); @@ -115,23 +115,23 @@ void ACEDAG::init(Array2D xAspec, haschild.fill(false); for (int iAA = 0; iAA < num_nodes - num1; iAA++) { if (nodes_pre(iAA, 0) >= num1) - haschild(nodes_pre(iAA, 0)-num1) = true; + haschild(nodes_pre(iAA, 0) - num1) = true; if (nodes_pre(iAA, 1) >= num1) - haschild(nodes_pre(iAA, 1)-num1) = true; + haschild(nodes_pre(iAA, 1) - num1) = true; } // to reorder the graph we need a fresh map from preordered indices to // postordered indices; for the 1-particle basis the order remains the same. // TODO: doesn't need to be a map, could be a vector. map neworder; - for (int iA = 0; iA < num1; iA++) + for (int iA = 0; iA < num1; iA++) neworder[iA] = iA; // insert all interior nodes num2_int = 0; num2_leaf = 0; dag_idx = num1; - int i1, i2, i1pre, i2pre; + int i1, i2, i1pre, i2pre; for (int iAA = 0; iAA < num_nodes - num1; iAA++) { if (haschild(iAA)) { num2_int += 1; @@ -142,11 +142,11 @@ void ACEDAG::init(Array2D xAspec, i1 = neworder[i1pre]; i2 = neworder[i2pre]; // insert the current node : iAA is old order, dag_idx is new order - neworder[num1+iAA] = dag_idx; - nodes(dag_idx-num1, 0) = i1; - nodes(dag_idx-num1, 1) = i2; + neworder[num1 + iAA] = dag_idx; + nodes(dag_idx - num1, 0) = i1; + nodes(dag_idx - num1, 1) = i2; for (int t = 0; t < ndensity; t++) - coeffs(dag_idx-num1, t) = coeffs_pre(iAA, t); + coeffs(dag_idx - num1, t) = coeffs_pre(iAA, t); dag_idx++; } } @@ -157,12 +157,12 @@ void ACEDAG::init(Array2D xAspec, num2_leaf += 1; // indices into AAbuf before reordering i1pre = nodes_pre(iAA, 0); - i2pre = nodes_pre(iAA, 1); + i2pre = nodes_pre(iAA, 1); // insert the current node : no need to remember the new order now - nodes(dag_idx-num1, 0) = neworder[i1pre]; - nodes(dag_idx-num1, 1) = neworder[i2pre]; + nodes(dag_idx - num1, 0) = neworder[i1pre]; + nodes(dag_idx - num1, 1) = neworder[i2pre]; for (int t = 0; t < ndensity; t++) - coeffs(dag_idx-num1, t) = coeffs_pre(iAA, t); + coeffs(dag_idx - num1, t) = coeffs_pre(iAA, t); dag_idx++; } } @@ -176,21 +176,21 @@ void ACEDAG::init(Array2D xAspec, /* finalize dag: allocate buffer storage */ AAbuf.resize(num1 + num2_int); - w.resize(num_nodes); + w.resize(num_nodes); // TODO: technically only need num1 + num2_int for w, this can save one // memory access later, probably not worth the crazy code duplication. } void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) { /* start with a list of all possible partitions into 2 groups - * and check whether any of these nodes are already in the dag */ + * and check whether any of these nodes are already in the dag */ auto partitions = find_2partitions(a); int ndensity = c.size(); int num1 = get_num1(); // TODO: first try to find partitions into nodes that are already parents // that way we will get more leaf nodes! - for (TPARTITION const& p : partitions) { + for (TPARTITION const &p : partitions) { /* this is the good case; the parent nodes are both already in the * graph; add the new node and return. This is also the only place in the * code where an actual insert happens. */ @@ -200,12 +200,12 @@ void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) nodes_pre.resize(newsize, 2); // grow arrays if necessary coeffs_pre.resize(newsize, ndensity); } - int i1 = DAGmap[p.first]; + int i1 = DAGmap[p.first]; int i2 = DAGmap[p.second]; nodes_pre(dag_idx - num1, 0) = i1; nodes_pre(dag_idx - num1, 1) = i2; - DAGmap[a] = dag_idx; - for (int p = 0; p < ndensity; p++) + DAGmap[a] = dag_idx; + for (int p = 0; p < ndensity; p++) coeffs_pre(dag_idx - num1, p) = c[p]; dag_idx += 1; return; @@ -221,8 +221,8 @@ void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) * .... (continue below) .... */ TPARTITION longest; - int longest_length = 0; - for (auto const& p : partitions) { + int longest_length = 0; + for (auto const &p : partitions) { int len = 0; if (DAGmap.count(p.first)) { len = p.first.size(); @@ -258,24 +258,24 @@ void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) * And we also accept it if we have a 2- or 3-correlation. */ - if ( (heuristic == 0) - || (longest_length > 1) - || (a.size() <= 3)) { + if ((heuristic == 0) + || (longest_length > 1) + || (a.size() <= 3)) { /* insert the other node that isn't in the DAG yet * this is an artificial node so it gets zero-coefficients * This step is recursive, so more than one node might be inserted here */ - vector cz(ndensity); - for (int i = 0; i < ndensity; i++) cz[i] = 0.0; + vector cz(ndensity); + for (int i = 0; i < ndensity; i++) cz[i] = 0.0; TPARTITION p = longest; - if (DAGmap.count(p.first)) + if (DAGmap.count(p.first)) insert_node(DAGmap, p.second, cz); else insert_node(DAGmap, p.first, cz); } - /* Second heuristic : heuristic == 1 - * Focus on inserting artificial 2-correlations - */ + /* Second heuristic : heuristic == 1 + * Focus on inserting artificial 2-correlations + */ else if (heuristic == 1) { // and we also know that longest_length == 1 and nu = a.size >= 4. int nu = a.size(); @@ -294,7 +294,7 @@ void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) // TODO: Throw and error here?!? return; } - + /* now we should be ready to insert the entire tuple `a` since there is now @@ -306,35 +306,35 @@ void ACEDAG::insert_node(TDAGMAP &DAGmap, vector a, vector c) } TPARTITIONS ACEDAG::find_2partitions(vector v) { - int N = v.size(); + int N = v.size(); int zo; TPARTITIONS partitions; TPARTITION part; /* This is a fun little hack to extract all subsets of the indices 1:N * the number i will have binary representation with each digit indicating * whether or not that index belongs to the selected subset */ - for (int i = 1; i < (1< v1(N1); vector v2(N2); - int i1 =0, i2 = 0; + int i1 = 0, i2 = 0; p = 1; for (int n = 0; n < N; n++) { zo = ((i / p) % 2); p *= 2; - if (zo == 1) { - v1[i1] = v[n]; + if (zo == 1) { + v1[i1] = v[n]; i1 += 1; } else { - v2[i2] = v[n]; + v2[i2] = v[n]; i2 += 1; } } @@ -345,23 +345,23 @@ TPARTITIONS ACEDAG::find_2partitions(vector v) { } void ACEDAG::print() { - cout << "DAG Specification: \n" ; - cout << " n1 : " << get_num1() << "\n"; - cout << " n2 : " << get_num2() << "\n"; - cout << " num_nodes : " << num_nodes << "\n"; + cout << "DAG Specification: \n"; + cout << " n1 : " << get_num1() << "\n"; + cout << " n2 : " << get_num2() << "\n"; + cout << " num_nodes : " << num_nodes << "\n"; cout << "--------------------\n"; cout << "A-spec: \n"; for (int iA = 0; iA < get_num1(); iA++) { - cout << iA << " : " << Aspec(iA, 0) << - Aspec(iA, 1) << Aspec(iA, 2) << Aspec(iA, 3) << "\n"; + cout << iA << " : " << Aspec(iA, 0) << + Aspec(iA, 1) << Aspec(iA, 2) << Aspec(iA, 3) << "\n"; } cout << "-----------\n"; cout << "AA-tree\n"; - + for (int iAA = 0; iAA < get_num2(); iAA++) { - cout << iAA + get_num1() << " : " << - nodes(iAA, 0) << ", " << nodes(iAA, 1) << "\n"; + cout << iAA + get_num1() << " : " << + nodes(iAA, 0) << ", " << nodes(iAA, 1) << "\n"; } } @@ -407,30 +407,43 @@ void ACERecursiveEvaluator::init(ACECTildeBasisSet *basis_set, int heuristic) { DCR_cache.fill(0); dB_flatten.init(basis_set->max_dB_array_size, "dB_flatten"); - /* convert to ACE.jl format to prepare for construction of DAG - * This will fill the arrays jl_Aspec, jl_AAspec, jl_orders - */ - acejlformat(); + // resize the arrays + species_dags.resize(basis_set->nelements); + jl_Aspec.resize(basis_set->nelements); + jl_AAspec.resize(basis_set->nelements); + jl_AAspec_flat.resize(basis_set->nelements); + jl_orders.resize(basis_set->nelements); + jl_coeffs.resize(basis_set->nelements); + + // loop over all species + for (SPECIES_TYPE mu0 = 0; mu0 < this->basis_set->nelements; mu0++) { + /* convert to ACE.jl format to prepare for construction of DAG + * This will fill the arrays jl_Aspec, jl_AAspec, jl_orders + */ + acejlformat(mu0); // TODO: acejlformat(mu0); - // test_acejlformat(); - - // now pass this info into the DAG - dag.init(jl_Aspec, jl_AAspec, jl_orders, jl_coeffs, heuristic); + // test_acejlformat(mu0); + + // now pass this info into the DAG + // dag.init(jl_Aspec, jl_AAspec, jl_orders, jl_coeffs, heuristic); + species_dags[mu0].init(jl_Aspec[mu0], jl_AAspec[mu0], + jl_orders[mu0], jl_coeffs[mu0], + heuristic); + } // end for-loop over mu0 // finally empty the temporary arrays to clear up the memory... // TODO } -void ACERecursiveEvaluator::acejlformat() { +void ACERecursiveEvaluator::acejlformat(SPECIES_TYPE mu0) { int func_ms_ind = 0; int func_ms_t_ind = 0;// index for dB int j, jj, func_ind, ms_ind; - SPECIES_TYPE mu_i = 0;//TODO: multispecies - const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu_i]; - ACECTildeBasisFunction *basis = basis_set->basis[mu_i]; + const SHORT_INT_TYPE total_basis_size = basis_set->total_basis_size[mu0]; + ACECTildeBasisFunction *basis = basis_set->basis[mu0]; int AAidx = 0; RANK_TYPE order, t; @@ -446,7 +459,7 @@ void ACERecursiveEvaluator::acejlformat() { */ /* compute max values for mu, n, l, m */ - SPECIES_TYPE maxmu = 0; //TODO: multispecies + SPECIES_TYPE maxmu = basis_set->nelements - 1; //TODO: multispecies NS_TYPE maxn = basis_set->nradmax; LS_TYPE maxl = basis_set->lmax; RANK_TYPE maxorder = basis_set->rankmax; @@ -458,21 +471,23 @@ void ACERecursiveEvaluator::acejlformat() { /* create a 4D lookup table for the 1-p basis * TODO: replace with a map?? */ - Array4D A_lookup(int(maxmu+1), int(maxn), int(maxl+1), int(2*maxl+1)); - for (int mu = 0; mu < maxmu+1; mu++) + Array4D A_lookup(int(maxmu + 1), int(maxn), int(maxl + 1), int(2 * maxl + 1)); + for (int mu = 0; mu < maxmu + 1; mu++) for (int n = 0; n < maxn; n++) - for (int l = 0; l < maxl+1; l++) - for (int m = 0; m < 2*maxl+1; m++) + for (int l = 0; l < maxl + 1; l++) + for (int m = 0; m < 2 * maxl + 1; m++) A_lookup(mu, n, l, m) = -1; int A_idx = 0; // linear index of A basis function (1-particle) for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { ACECTildeBasisFunction *func = &basis[func_ind]; -// func->print(); - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; + order = func->rank; + mus = func->mus; + ns = func->ns; + ls = func->ls; for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; + ms = &func->ms_combs[ms_ind * order]; for (t = 0; t < order; t++) { - int iA = A_lookup(mus[t], ns[t]-1, ls[t], ms[t]+ls[t]); + int iA = A_lookup(mus[t], ns[t] - 1, ls[t], ms[t] + ls[t]); if (iA == -1) { A_lookup(mus[t], ns[t] - 1, ls[t], ms[t] + ls[t]) = A_idx; A_idx += 1; @@ -484,14 +499,14 @@ void ACERecursiveEvaluator::acejlformat() { /* create the reverse list: linear indixes to mu,l,m,n this keeps only the basis functions we really need */ num1 = A_idx; - Array2D & Aspec = jl_Aspec; + Array2D &Aspec = jl_Aspec[mu0]; //TODO: get from vector[mu0] Aspec.resize(num1, 4); // Array2D Aspec(num1, 4); for (int mu = 0; mu <= maxmu; mu++) for (int n = 1; n <= maxn; n++) for (int l = 0; l <= maxl; l++) for (int m = -l; m <= l; m++) { - int iA = A_lookup(mu, n-1, l, l+m); + int iA = A_lookup(mu, n - 1, l, l + m); if (iA != -1) { Aspec(iA, 0) = mu; Aspec(iA, 1) = n; @@ -503,19 +518,22 @@ void ACERecursiveEvaluator::acejlformat() { /* ============ HALF-BASIS TRICK START ============ */ for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; - if (!( (mus[0] <= maxmu) && (ns[0] <= maxn) && (ls[0] <= maxl) )) - continue; + order = func->rank; + mus = func->mus; + ns = func->ns; + ls = func->ls; + if (!((mus[0] <= maxmu) && (ns[0] <= maxn) && (ls[0] <= maxl))) + continue; for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; + ms = &func->ms_combs[ms_ind * order]; // find first positive and negative index int pos_idx = order + 1; int neg_idx = order + 1; - for (t = order-1; t >= 0; t--) - if (ms[t] > 0) pos_idx = t; - else if (ms[t] < 0) neg_idx = t; + for (t = order - 1; t >= 0; t--) + if (ms[t] > 0) pos_idx = t; + else if (ms[t] < 0) neg_idx = t; // if neg_idx < pos_idx then this means that ms is non-zero // and that the first non-zero index is negative, hence this is @@ -525,13 +543,13 @@ void ACERecursiveEvaluator::acejlformat() { // find the opposite tuple int ms_ind2 = 0; MS_TYPE *ms2; - bool found_opposite = false; + bool found_opposite = false; for (ms_ind2 = 0; ms_ind2 < func->num_ms_combs; ++ms_ind2) { - ms2 = &func->ms_combs[ms_ind2 * order]; - bool isopposite = true; + ms2 = &func->ms_combs[ms_ind2 * order]; + bool isopposite = true; for (t = 0; t < order; t++) if (ms[t] != -ms2[t]) { - isopposite = false; + isopposite = false; break; } if (isopposite) { @@ -545,13 +563,13 @@ void ACERecursiveEvaluator::acejlformat() { } // now we need to overwrite the coefficients - if (found_opposite) { + if (found_opposite) { int sig = 1; for (t = 0; t < order; t++) if (ms[t] < 0) sig *= -1; for (int p = 0; p < ndensity; ++p) { - func->ctildes[ms_ind2 * ndensity + p] += + func->ctildes[ms_ind2 * ndensity + p] += func->ctildes[ms_ind * ndensity + p]; func->ctildes[ms_ind * ndensity + p] = 0.0; } @@ -565,11 +583,11 @@ void ACERecursiveEvaluator::acejlformat() { /* count number of basis functions, keep only non-zero!! */ int num2 = 0; - for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { + for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { ACECTildeBasisFunction *func = &basis[func_ind]; for (ms_ind = 0; ms_ind < (&basis[func_ind])->num_ms_combs; ++ms_ind, ++func_ms_ind) { // check that the coefficients are actually non-zero - bool isnonzero = false; + bool isnonzero = false; for (DENSITY_TYPE p = 0; p < ndensity; ++p) if (func->ctildes[ms_ind * ndensity + p] != 0.0) isnonzero = true; @@ -582,25 +600,28 @@ void ACERecursiveEvaluator::acejlformat() { /* Now create the AA basis links into the A basis */ num1 = A_idx; // total number of A-basis functions that we keep // Array1D AAorders(num2); - Array1D & AAorders = jl_orders; + Array1D &AAorders = jl_orders[mu0]; // TODO: get from vector[mu0] AAorders.resize(num2); // Array2D AAspec(num2, maxorder); // specs of AA basis functions - Array2D & AAspec = jl_AAspec; + Array2D &AAspec = jl_AAspec[mu0]; // TODO: get from vector[mu0] AAspec.resize(num2, maxorder); - jl_coeffs.resize(num2, ndensity); + jl_coeffs[mu0].resize(num2, ndensity); // TODO: get from vector[mu0] AAidx = 0; // linear index into AA basis function int len_flat = 0; for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; + order = func->rank; + mus = func->mus; + ns = func->ns; + ls = func->ls; if (!((mus[0] <= maxmu) && (ns[0] <= maxn) && (ls[0] <= maxl))) //fool-proofing of functions - continue; + continue; for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; + ms = &func->ms_combs[ms_ind * order]; // check that the coefficients are actually non-zero - bool iszero = true; + bool iszero = true; for (DENSITY_TYPE p = 0; p < ndensity; ++p) if (func->ctildes[ms_ind * ndensity + p] != 0.0) iszero = false; @@ -608,32 +629,32 @@ void ACERecursiveEvaluator::acejlformat() { AAorders(AAidx) = order; for (t = 0; t < order; t++) { - int Ait = A_lookup(int(mus[t]), int(ns[t]-1), int(ls[t]), int(ms[t])+int(ls[t])); - AAspec(AAidx, t) = Ait; + int Ait = A_lookup(int(mus[t]), int(ns[t] - 1), int(ls[t]), int(ms[t]) + int(ls[t])); + AAspec(AAidx, t) = Ait; len_flat += 1; } - for (t = order; t < maxorder; t++) AAspec(AAidx, t) = -1; + for (t = order; t < maxorder; t++) AAspec(AAidx, t) = -1; /* copy over the coefficients */ for (DENSITY_TYPE p = 0; p < ndensity; ++p) - jl_coeffs(AAidx, p) = func->ctildes[ms_ind * ndensity + p]; + jl_coeffs[mu0](AAidx, p) = func->ctildes[ms_ind * ndensity + p]; // TODO: get from vector[mu0] AAidx += 1; } } // flatten the AAspec array - jl_AAspec_flat.resize(len_flat); + jl_AAspec_flat[mu0].resize(len_flat); // TODO: get from vector[mu0] int idx_spec = 0; - for (int AAidx = 0; AAidx < jl_AAspec.get_dim(0); AAidx++) - for (int p = 0; p < jl_orders(AAidx); p++, idx_spec++) - jl_AAspec_flat(idx_spec) = jl_AAspec(AAidx, p); + for (int AAidx = 0; AAidx < jl_AAspec[mu0].get_dim(0); AAidx++) // TODO: get from vector[mu0] + for (int p = 0; p < jl_orders[mu0](AAidx); p++, idx_spec++) // TODO: get from vector[mu0] + jl_AAspec_flat[mu0](idx_spec) = jl_AAspec[mu0](AAidx, p); // TODO: get from vector[mu0] } -void ACERecursiveEvaluator::test_acejlformat() { +void ACERecursiveEvaluator::test_acejlformat(SPECIES_TYPE mu0) { - Array2D AAspec = jl_AAspec; - Array2D Aspec = jl_Aspec; - Array1D AAorders = jl_orders; + Array2D AAspec = jl_AAspec[mu0]; + Array2D Aspec = jl_Aspec[mu0]; + Array1D AAorders = jl_orders[mu0]; cout << "num2 = " << AAorders.get_dim(0) << "\n"; int func_ms_ind = 0; int func_ms_t_ind = 0;// index for dB @@ -650,33 +671,36 @@ void ACERecursiveEvaluator::test_acejlformat() { MS_TYPE *ms; /* ==== test by printing the basis spec ====*/ - // TODO: convert this into an automatic consistency test + // TODO: convert this into an automatic consistency test int iAA = 0; for (func_ind = 0; func_ind < total_basis_size; ++func_ind) { ACECTildeBasisFunction *func = &basis[func_ind]; - order = func->rank; mus = func->mus; ns = func->ns; ls = func->ls; + order = func->rank; + mus = func->mus; + ns = func->ns; + ls = func->ls; // func->print(); //loop over {ms} combinations in sum for (ms_ind = 0; ms_ind < func->num_ms_combs; ++ms_ind, ++func_ms_ind) { - ms = &func->ms_combs[ms_ind * order]; + ms = &func->ms_combs[ms_ind * order]; + - cout << iAA << " : |"; for (t = 0; t < order; t++) cout << mus[t] << ";" << ns[t] << "," << ls[t] << "," << ms[t] << "|"; - cout << "\n"; + cout << "\n"; - cout << " ["; - for (t = 0; t < AAorders(iAA); t++) + cout << " ["; + for (t = 0; t < AAorders(iAA); t++) cout << AAspec(iAA, int(t)) << ","; cout << "]\n"; - cout << " |"; - for (t = 0; t < AAorders(iAA); t++) { + cout << " |"; + for (t = 0; t < AAorders(iAA); t++) { int iA = AAspec(iAA, t); // cout << iA << ","; - cout << Aspec(iA, 0) << ";" - << Aspec(iA, 1) << "," - << Aspec(iA, 2) << "," + cout << Aspec(iA, 0) << ";" + << Aspec(iA, 1) << "," + << Aspec(iA, 2) << "," << Aspec(iA, 3) << "|"; } cout << "\n"; @@ -689,10 +713,8 @@ void ACERecursiveEvaluator::test_acejlformat() { } - - void ACERecursiveEvaluator::resize_neighbours_cache(int max_jnum) { - if(basis_set== nullptr) { + if (basis_set == nullptr) { throw std::invalid_argument("ACERecursiveEvaluator: basis set is not assigned"); } if (R_cache.get_dim(0) < max_jnum) { @@ -728,8 +750,9 @@ void ACERecursiveEvaluator::resize_neighbours_cache(int max_jnum) { // jnum - number of J neighbors for each I atom. jnum = numneigh[i]; void -ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, const int *jlist) { - if(basis_set== nullptr) { +ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE *type, const int jnum, + const int *jlist) { + if (basis_set == nullptr) { throw std::invalid_argument("ACERecursiveEvaluator: basis set is not assigned"); } per_atom_calc_timer.start(); @@ -760,7 +783,7 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * ACEComplex B{0.}; ACEComplex dB{0}; ACEComplex A_cache[basis_set->rankmax]; - + ACEComplex dA[basis_set->rankmax]; int spec[basis_set->rankmax]; @@ -807,8 +830,7 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * //TODO: nradbase -> nradbasei (get per-species type) const NS_TYPE nradbasei = basis_set->nradbase; - //TODO: get per-species type number of densities - const DENSITY_TYPE ndensity= basis_set->ndensitymax; + const DENSITY_TYPE ndensity = basis_set->map_embedding_specifications[mu_i].ndensity; neighbours_forces.resize(jnum, 3); neighbours_forces.fill(0); @@ -823,7 +845,9 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * #ifdef EXTRA_C_PROJECTIONS basis_projections_rank1.init(total_basis_size_rank1, ndensity, "c_projections_rank1"); + basis_projections_rank1.fill(0); basis_projections.init(total_basis_size, ndensity, "c_projections"); + basis_projections.fill(0); #endif //proxy references to spherical harmonics and radial functions arrays @@ -966,14 +990,13 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * double A_cur = A_rank1(func->mus[0], func->ns[0] - 1); #ifdef DEBUG_ENERGY_CALCULATIONS printf("A_r=1(x=%d, n=%d)=(%f)\n", func->mus[0], func->ns[0], A_cur); - printf(" coeff[0] = %f\n", func->ctildes[0]); #endif for (DENSITY_TYPE p = 0; p < ndensity; ++p) { //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 rhos(p) += func->ctildes[p] * A_cur; #ifdef EXTRA_C_PROJECTIONS //aggregate C-projections separately - basis_projections_rank1(func_rank1_ind, p)+= func->ctildes[p] * A_cur; + basis_projections_rank1(func_rank1_ind, p) += func->ctildes[p] * A_cur; #endif } } // end loop for rank=1 @@ -984,16 +1007,21 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * /* STAGE 1: * 1-particle basis is already evaluated, so we only need to * copy it into the AA value buffer - */ - int num1 = dag.get_num1(); - for (int idx = 0; idx < num1; idx++) - dag.AAbuf(idx) = A( dag.Aspec(idx, 0), - dag.Aspec(idx, 1)-1, - dag.Aspec(idx, 2), - dag.Aspec(idx, 3) ); + */ + //TODO: + ACEDAG &dag = species_dags[mu_i]; + int num1 = dag.get_num1(); // TODO: get from vector[mu0] + for (int idx = 0; idx < num1; idx++) + dag.AAbuf(idx) = A(dag.Aspec(idx, 0), + dag.Aspec(idx, 1) - 1, + dag.Aspec(idx, 2), + dag.Aspec(idx, 3)); if (recursive) { +#ifdef DEBUG_ENERGY_CALCULATIONS + printf("Recursive Julia-style evaluator\n"); +#endif /* STAGE 2: FORWARD PASS * Forward pass: go through the dag and store all intermediate results */ @@ -1002,52 +1030,66 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * ACEComplex AAcur{0.0}; int i1, i2; - int * dag_nodes = dag.nodes.get_data(); + int *dag_nodes = dag.nodes.get_data(); int idx_nodes = 0; - DOUBLE_TYPE * dag_coefs = dag.coeffs.get_data(); + DOUBLE_TYPE *dag_coefs = dag.coeffs.get_data(); int idx_coefs = 0; - + int num2_int = dag.get_num2_int(); int num2_leaf = dag.get_num2_leaf(); // interior nodes (save AA) - for (int idx = num1; idx < num1+num2_int; idx++) { - i1 = dag_nodes[idx_nodes]; idx_nodes++; - i2 = dag_nodes[idx_nodes]; idx_nodes++; + for (int idx = num1; idx < num1 + num2_int; idx++) { + i1 = dag_nodes[idx_nodes]; + idx_nodes++; + i2 = dag_nodes[idx_nodes]; + idx_nodes++; AAcur = dag.AAbuf(i1) * dag.AAbuf(i2); dag.AAbuf(idx) = AAcur; - for (int p = 0; p < ndensity; p++, idx_coefs++) + for (int p = 0; p < ndensity; p++, idx_coefs++) { +#ifdef DEBUG_ENERGY_CALCULATIONS + printf("AA_rec(idx_coefs=%d, dag_coeffs=%d)=(%f)\n", idx_coefs, dag_coefs[idx_coefs], + AAcur.real_part_product(dag_coefs[idx_coefs])); +#endif rhos(p) += AAcur.real_part_product(dag_coefs[idx_coefs]); + } } // leaf nodes -> no need to store in AAbuf DOUBLE_TYPE AAcur_re = 0.0; - for (int _idx = 0; _idx < num2_leaf; _idx++) { - i1 = dag_nodes[idx_nodes]; idx_nodes++; - i2 = dag_nodes[idx_nodes]; idx_nodes++; + for (int _idx = 0; _idx < num2_leaf; _idx++) { + i1 = dag_nodes[idx_nodes]; + idx_nodes++; + i2 = dag_nodes[idx_nodes]; + idx_nodes++; AAcur_re = dag.AAbuf(i1).real_part_product(dag.AAbuf(i2)); - for (int p = 0; p < ndensity; p++, idx_coefs++) + for (int p = 0; p < ndensity; p++, idx_coefs++) rhos(p) += AAcur_re * dag_coefs[idx_coefs]; } } else { - +#ifdef DEBUG_ENERGY_CALCULATIONS + printf("non-recursive Julia-style evaluator\n"); +#endif /* non-recursive Julia-style evaluator implementation */ // TODO: fix array access to enable bounds checking again??? ACEComplex AAcur{1.0}; - int *AAspec = jl_AAspec_flat.get_data(); - DOUBLE_TYPE *coeffs = jl_coeffs.get_data(); + int *AAspec = jl_AAspec_flat[mu_i].get_data(); // TODO: get from vector[mu0] + DOUBLE_TYPE *coeffs = jl_coeffs[mu_i].get_data(); // TODO: get from vector[mu0] int idx_spec = 0; int idx_coefs = 0; int order = 0; - int max_order = jl_AAspec.get_dim(1); - for (int iAA = 0; iAA < jl_AAspec.get_dim(0); iAA ++) { + int max_order = jl_AAspec[mu_i].get_dim(1); // TODO: get from vector[mu0] + for (int iAA = 0; iAA < jl_AAspec[mu_i].get_dim(0); iAA++) { // TODO: get from vector[mu0] AAcur = 1.0; - order = jl_orders(iAA); + order = jl_orders[mu_i](iAA); // TODO: get from vector[mu0] for (int r = 0; r < order; r++, idx_spec++) - AAcur *= dag.AAbuf( AAspec[idx_spec] ); - for (int p = 0; p < ndensity; p++, idx_coefs++) + AAcur *= dag.AAbuf(AAspec[idx_spec]); +#ifdef DEBUG_ENERGY_CALCULATIONS + printf("AAcur = %f + j %f\n",AAcur.real, AAcur.img); +#endif + for (int p = 0; p < ndensity; p++, idx_coefs++) rhos(p) += AAcur.real_part_product(coeffs[idx_coefs]); } } @@ -1057,17 +1099,17 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * #ifdef DEBUG_FORCES_CALCULATIONS printf("rhos = "); - for(DENSITY_TYPE p =0; prho_core_cutoffs(mu_i); - drho_cut = basis_set->drho_core_cutoffs(mu_i); + rho_cut = basis_set->map_embedding_specifications.at(mu_i).rho_core_cutoff; + drho_cut = basis_set->map_embedding_specifications.at(mu_i).drho_core_cutoff; basis_set->inner_cutoff(rho_core, rho_cut, drho_cut, fcut, dfcut); - basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, ndensity); + basis_set->FS_values_and_derivatives(rhos, evdwl, dF_drho, mu_i); dF_drho_core = evdwl * dfcut + 1; for (DENSITY_TYPE p = 0; p < ndensity; ++p) @@ -1091,7 +1133,7 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * #ifdef DEBUG_FORCES_CALCULATIONS printf("dFrhos = "); - for(DENSITY_TYPE p =0; pndensity; for (DENSITY_TYPE p = 0; p < ndensity; ++p) { //for rank=1 (r=0) only 1 ms-combination exists (ms_ind=0), so index of func.ctildes is 0..ndensity-1 weights_rank1(func->mus[0], func->ns[0] - 1) += dF_drho(p) * func->ctildes[p]; @@ -1119,19 +1160,21 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * /* to prepare for the backward we first need to zero the weights */ dag.w.fill({0.0}); - int * dag_nodes = dag.nodes.get_data(); + int *dag_nodes = dag.nodes.get_data(); int idx_nodes = 2 * (num2_int + num2_leaf) - 1; - DOUBLE_TYPE * dag_coefs = dag.coeffs.get_data(); + DOUBLE_TYPE *dag_coefs = dag.coeffs.get_data(); int idx_coefs = ndensity * (num2_int + num2_leaf) - 1; - - for (int idx = num1+num2_int+num2_leaf - 1; idx >= num1; idx--) { - i2 = dag_nodes[idx_nodes]; idx_nodes--; - i1 = dag_nodes[idx_nodes]; idx_nodes--; + + for (int idx = num1 + num2_int + num2_leaf - 1; idx >= num1; idx--) { + i2 = dag_nodes[idx_nodes]; + idx_nodes--; + i1 = dag_nodes[idx_nodes]; + idx_nodes--; AA1 = dag.AAbuf(i1); AA2 = dag.AAbuf(i2); wcur = dag.w(idx); // [***] - for (int p = ndensity-1; p >= 0; p--, idx_coefs--) + for (int p = ndensity - 1; p >= 0; p--, idx_coefs--) wcur += dF_drho(p) * dag_coefs[idx_coefs]; dag.w(i1) += wcur * AA2; // TODO: replace with explicit muladd? dag.w(i2) += wcur * AA1; @@ -1153,33 +1196,34 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * // (cf. Algorithm 3 in the manuscript) dag.w.fill({0.0}); - ACEComplex AAf{1.0}, AAb{1.0}, theta{0.0}; + ACEComplex AAf{1.0}, AAb{1.0}, theta{0.0}; - int *AAspec = jl_AAspec_flat.get_data(); - DOUBLE_TYPE *coeffs = jl_coeffs.get_data(); + int *AAspec = jl_AAspec_flat[mu_i].get_data(); // TODO: get from vector[mu0] + DOUBLE_TYPE *coeffs = jl_coeffs[mu_i].get_data(); // TODO: get from vector[mu0] int idx_spec = 0; int idx_coefs = 0; int order = 0; - int max_order = jl_AAspec.get_dim(1); - for (int iAA = 0; iAA < jl_AAspec.get_dim(0); iAA ++ ) { - order = jl_orders(iAA); - theta = 0.0; - for (int p = 0; p < ndensity; p++, idx_coefs++) + int max_order = jl_AAspec[mu_i].get_dim(1); // TODO: get from vector[mu0] + for (int iAA = 0; iAA < jl_AAspec[mu_i].get_dim(0); iAA++) { // TODO: get from vector[mu0] + order = jl_orders[mu_i](iAA); // TODO: get from vector[mu0] + theta = 0.0; + for (int p = 0; p < ndensity; p++, idx_coefs++) theta += dF_drho(p) * coeffs[idx_coefs]; - dA[0] = 1.0; - AAf = 1.0; - for (int t = 0; t < order-1; t++, idx_spec++) { - spec[t] = AAspec[idx_spec]; + dA[0] = 1.0; + AAf = 1.0; + for (int t = 0; t < order - 1; t++, idx_spec++) { + spec[t] = AAspec[idx_spec]; A_cache[t] = dag.AAbuf(spec[t]); - AAf *= A_cache[t]; - dA[t+1] = AAf; + AAf *= A_cache[t]; + dA[t + 1] = AAf; } - spec[order-1] = AAspec[idx_spec]; idx_spec++; - A_cache[order-1] = dag.AAbuf(spec[order-1]); + spec[order - 1] = AAspec[idx_spec]; + idx_spec++; + A_cache[order - 1] = dag.AAbuf(spec[order - 1]); AAb = 1.0; - for (int t = order-1; t >= 1; t--) { - AAb *= A_cache[t]; - dA[t-1] *= AAb; + for (int t = order - 1; t >= 1; t--) { + AAb *= A_cache[t]; + dA[t - 1] *= AAb; dag.w(spec[t]) += theta * dA[t]; } dag.w(spec[0]) += theta * dA[0]; @@ -1195,18 +1239,18 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * * into the the PACE datastructure. */ for (int idx = 0; idx < num1; idx++) { - int m = dag.Aspec(idx, 3); + int m = dag.Aspec(idx, 3); if (m >= 0) { weights(dag.Aspec(idx, 0), // mu dag.Aspec(idx, 1) - 1, // n dag.Aspec(idx, 2), // l - m ) += dag.w(idx); + m) += dag.w(idx); } else { int factor = (m % 2 == 0 ? 1 : -1); weights(dag.Aspec(idx, 0), // mu dag.Aspec(idx, 1) - 1, // n dag.Aspec(idx, 2), // l - -m ) += factor * dag.w(idx).conjugated(); + -m) += factor * dag.w(idx).conjugated(); } } @@ -1245,10 +1289,10 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * DGR = DG * Y00; DGR *= weights_rank1(mu_j, n); #ifdef DEBUG_FORCES_CALCULATIONS - printf("r=1: (n,l,m)=(%d, 0, 0)\n",n+1); - printf("\tGR(n=%d, r=%f)=%f\n",n+1,r_norm, gr(n)); - printf("\tDGR(n=%d, r=%f)=%f\n",n+1,r_norm, dgr(n)); - printf("\tdF+=(%f, %f, %f)\n",DGR * r_hat[0], DGR * r_hat[1], DGR * r_hat[2]); + printf("r=1: (n,l,m)=(%d, 0, 0)\n", n + 1); + printf("\tGR(n=%d, r=%f)=%f\n", n + 1, r_norm, gr(n)); + printf("\tDGR(n=%d, r=%f)=%f\n", n + 1, r_norm, dgr(n)); + printf("\tdF+=(%f, %f, %f)\n", DGR * r_hat[0], DGR * r_hat[1], DGR * r_hat[2]); #endif f_ji[0] += DGR * r_hat[0]; f_ji[1] += DGR * r_hat[1]; @@ -1262,7 +1306,7 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * DR = DR_cache(jj, n, l); // for m>=0 - for (m = 0; m <= l; m++) { + for (m = 0; m <= l; m++) { ACEComplex w = weights(mu_j, n, l, m); if (w == 0) continue; @@ -1276,12 +1320,12 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * grad_phi_nlm.a[1] = Y_DR * r_hat[1] + DY.a[1] * R_over_r; grad_phi_nlm.a[2] = Y_DR * r_hat[2] + DY.a[2] * R_over_r; #ifdef DEBUG_FORCES_CALCULATIONS - printf("d_phi(n=%d, l=%d, m=%d) = ((%f,%f), (%f,%f), (%f,%f))\n",n+1,l,m, + printf("d_phi(n=%d, l=%d, m=%d) = ((%f,%f), (%f,%f), (%f,%f))\n", n + 1, l, m, grad_phi_nlm.a[0].real, grad_phi_nlm.a[0].img, grad_phi_nlm.a[1].real, grad_phi_nlm.a[1].img, grad_phi_nlm.a[2].real, grad_phi_nlm.a[2].img); - printf("weights(n,l,m)(%d,%d,%d) = (%f,%f)\n", n+1, l, m, w.real, w.img); + printf("weights(n,l,m)(%d,%d,%d) = (%f,%f)\n", n + 1, l, m, w.real, w.img); //if (m>0) w*=2; printf("dF(n,l,m)(%d, %d, %d) += (%f, %f, %f)\n", n + 1, l, m, w.real_part_product(grad_phi_nlm.a[0]), @@ -1307,7 +1351,7 @@ ACERecursiveEvaluator::compute_atom(int i, DOUBLE_TYPE **x, const SPECIES_TYPE * //hard-core repulsion DCR = DCR_cache(jj); #ifdef DEBUG_FORCES_CALCULATIONS - printf("DCR = %f\n",DCR); + printf("DCR = %f\n", DCR); #endif f_ji[0] += dF_drho_core * DCR * r_hat[0]; f_ji[1] += dF_drho_core * DCR * r_hat[1]; diff --git a/USER-PACE/ace_recursive.h b/ML-PACE/ace_recursive.h similarity index 87% rename from USER-PACE/ace_recursive.h rename to ML-PACE/ace_recursive.h index 4a5af55..cd5e2a4 100644 --- a/USER-PACE/ace_recursive.h +++ b/ML-PACE/ace_recursive.h @@ -181,16 +181,17 @@ class ACERecursiveEvaluator : public ACEEvaluator { void init(ACECTildeBasisSet *basis_set, int heuristic); /* convert the PACE to the ACE.jl format to prepare for DAG construction*/ - Array2D jl_Aspec; - Array2D jl_AAspec; - Array1D jl_AAspec_flat; - Array1D jl_orders; - Array2D jl_coeffs; - void acejlformat(); - /* the main event : the computational graph */ - ACEDAG dag; + vector> jl_Aspec; // TODO: conversion to multispecies: make as vector> with [mu_0] axis + vector> jl_AAspec;// TODO: conversion to multispecies: make as vector> with [mu_0] axis + vector> jl_AAspec_flat;// TODO: conversion to multispecies: make as vector> with [mu_0] axis + vector> jl_orders;// TODO: conversion to multispecies: make as vector> with [mu_0] axis + vector> jl_coeffs; // TODO: conversion to multispecies: make as vector> with [mu_0] axis + void acejlformat(SPECIES_TYPE mu0); + /* the main event : the computational graph */ +// ACEDAG dag; // TODO: conversion to multispecies: make as vector with [mu_0] axis + vector species_dags; bool recursive = true; public: @@ -231,11 +232,16 @@ class ACERecursiveEvaluator : public ACEEvaluator { /******* public functions related to recursive evaluator ********/ // print out the DAG for visual inspection - void print_dag() {dag.print();} + void print_dag() { + for(SPECIES_TYPE mu0 = 0; mu0nelements; mu0++) { + cout<<"Specie "<. + */ + + +// +// Created by Lysogorskiy Yury on 27.02.20. +// + +#include +#include +#include +#include +#include "pair_pace.h" +#include "atom.h" +#include "neighbor.h" +#include "neigh_list.h" +#include "neigh_request.h" +#include "force.h" +#include "comm.h" +#include "memory.h" +#include "error.h" + + +#include "math_const.h" + +#include "ace_version.h" + +using namespace LAMMPS_NS; +using namespace MathConst; + +#define MAXLINE 1024 +#define DELTA 4 + +//added YL + +//keywords for ACE evaluator style +#define RECURSIVE_KEYWORD "recursive" +#define PRODUCT_KEYWORD "product" + + +int elements_num_pace = 104; +char const *const elements_pace[104] = {"X", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", + "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", + "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", + "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", + "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", + "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", + "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", + "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr" +}; + +int AtomicNumberByName_pace(char *elname) { + for (int i = 1; i < elements_num_pace; i++) + if (strcmp(elname, elements_pace[i]) == 0) + return i; + return -1; +} + + +/* ---------------------------------------------------------------------- */ +PairPACE::PairPACE(LAMMPS *lmp) : Pair(lmp) { + //single_enable = 0; + restartinfo = 0; + one_coeff = 1; + manybody_flag = 1; + + nelements = 0; + + ace = NULL; + potential_file_name = NULL; + elements = NULL; + map = NULL; +} + +/* ---------------------------------------------------------------------- + check if allocated, since class can be destructed when incomplete +------------------------------------------------------------------------- */ + +PairPACE::~PairPACE() { + if (copymode) return; + + if (elements) + for (int i = 0; i < nelements; i++) delete[] elements[i]; + delete[] elements; + + + delete[] potential_file_name; + + delete basis_set; + delete ace; + + if (allocated) { + memory->destroy(setflag); + memory->destroy(cutsq); + memory->destroy(map); + memory->destroy(scale); + } +} + +/* ---------------------------------------------------------------------- */ + +void PairPACE::compute(int eflag, int vflag) { + int i, j, ii, jj, inum, jnum; + double delx, dely, delz, evdwl; + double fij[3]; + int *ilist, *jlist, *numneigh, **firstneigh; + + ev_init(eflag, vflag); + + // downwards modified by YL + + double **x = atom->x; + double **f = atom->f; + tagint *tag = atom->tag; + int *type = atom->type; + + // number of atoms in cell + int nlocal = atom->nlocal; + + int newton_pair = force->newton_pair; + + // number of atoms including ghost atoms + int nall = nlocal + atom->nghost; + + // inum: length of the neighborlists list + inum = list->inum; + + // ilist: list of "i" atoms for which neighbor lists exist + ilist = list->ilist; + + //numneigh: the length of each these neigbor list + numneigh = list->numneigh; + + // the pointer to the list of neighbors of "i" + firstneigh = list->firstneigh; + + if (inum != nlocal) { + char str[128]; + snprintf(str, 128, "inum: %d nlocal: %d are different", inum, nlocal); + error->all(FLERR, str); + } + + + // Aidan Thompson told RD (26 July 2019) that practically always holds: + // inum = nlocal + // i = ilist(ii) < inum + // j = jlist(jj) < nall + // neighborlist contains neighbor atoms plus skin atoms, + // skin atoms can be removed by setting skin to zero but here + // they are disregarded anyway + + + //determine the maximum number of neighbours + int max_jnum = -1; + int nei = 0; + for (ii = 0; ii < list->inum; ii++) { + i = ilist[ii]; + jnum = numneigh[i]; + nei = nei + jnum; + if (jnum > max_jnum) + max_jnum = jnum; + } + + ace->resize_neighbours_cache(max_jnum); + + //loop over atoms + for (ii = 0; ii < list->inum; ii++) { + i = list->ilist[ii]; + const int itype = type[i]; + + const double xtmp = x[i][0]; + const double ytmp = x[i][1]; + const double ztmp = x[i][2]; + + jlist = firstneigh[i]; + jnum = numneigh[i]; + + // checking if neighbours are actually within cutoff range is done inside compute_atom + // mapping from LAMMPS atom types ('type' array) to ACE species is done inside compute_atom + // by using 'ace->element_type_mapping' array + // x: [r0 ,r1, r2, ..., r100] + // i = 0 ,1 + // jnum(0) = 50 + // jlist(neigh ind of 0-atom) = [1,2,10,7,99,25, .. 50 element in total] + try { + ace->compute_atom(i, x, type, jnum, jlist); + } catch (exception &e) { + error->all(FLERR, e.what()); + exit(EXIT_FAILURE); + } + // 'compute_atom' will update the `ace->e_atom` and `ace->neighbours_forces(jj, alpha)` arrays + + for (jj = 0; jj < jnum; jj++) { + j = jlist[jj]; + const int jtype = type[j]; + j &= NEIGHMASK; + delx = x[j][0] - xtmp; + dely = x[j][1] - ytmp; + delz = x[j][2] - ztmp; + + fij[0] = scale[itype][jtype] * ace->neighbours_forces(jj, 0); + fij[1] = scale[itype][jtype] * ace->neighbours_forces(jj, 1); + fij[2] = scale[itype][jtype] * ace->neighbours_forces(jj, 2); + + + f[i][0] += fij[0]; + f[i][1] += fij[1]; + f[i][2] += fij[2]; + f[j][0] -= fij[0]; + f[j][1] -= fij[1]; + f[j][2] -= fij[2]; + + // tally per-atom virial contribution + if (vflag) + ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, + fij[0], fij[1], fij[2], + -delx, -dely, -delz); + } + + // tally energy contribution + if (eflag) { + // evdwl = energy of atom I + evdwl = scale[1][1] * ace->e_atom; + ev_tally_full(i, 2.0 * evdwl, 0.0, 0.0, 0.0, 0.0, 0.0); + } + } + + if (vflag_fdotr) virial_fdotr_compute(); + + + // end modifications YL +} + +/* ---------------------------------------------------------------------- */ + +void PairPACE::allocate() { + allocated = 1; + int n = atom->ntypes; + + memory->create(setflag, n + 1, n + 1, "pair:setflag"); + memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); + memory->create(map, n + 1, "pair:map"); + memory->create(scale, n + 1, n + 1, "pair:scale"); +} + +/* ---------------------------------------------------------------------- + global settings +------------------------------------------------------------------------- */ + +void PairPACE::settings(int narg, char **arg) { + if (narg > 1) { + error->all(FLERR, + "Illegal pair_style command. Correct form:\n\tpair_style pace\nor\n\tpair_style pace "); + error->all(FLERR, RECURSIVE_KEYWORD); + error->all(FLERR, "or\n\tpair_style pace "); + error->all(FLERR, PRODUCT_KEYWORD); + } + recursive = true; // default evaluator style: RECURSIVE + if (narg > 0) { + if (strcmp(arg[0], PRODUCT_KEYWORD) == 0) { + recursive = false; + } else if (strcmp(arg[0], RECURSIVE_KEYWORD) == 0) { + recursive = true; + } else { + error->all(FLERR, + "Illegal pair_style command: pair_style pace "); + error->all(FLERR, arg[0]); + error->all(FLERR, "\nCorrect form:\n\tpair_style pace product\nor\n\tpair_style pace recursive\n"); + } + } + + if (comm->me == 0) { + if (screen) fprintf(screen, "ACE version: %d.%d.%d\n", VERSION_YEAR, VERSION_MONTH, VERSION_DAY); + if (logfile) fprintf(logfile, "ACE version: %d.%d.%d\n", VERSION_YEAR, VERSION_MONTH, VERSION_DAY); + + if (recursive) { + if (screen) fprintf(screen, "Recursive evaluator is used\n"); + if (logfile) fprintf(logfile, "Recursive evaluator is used\n"); + } else { + if (screen) fprintf(screen, "Product evaluator is used\n"); + if (logfile) fprintf(logfile, "Product evaluator is used\n"); + } + } + + +} + +/* ---------------------------------------------------------------------- + set coeffs for one or more type pairs +------------------------------------------------------------------------- */ + +void PairPACE::coeff(int narg, char **arg) { + + if (narg < 4) + error->all(FLERR, + "Incorrect args for pair coefficients. Correct form:\npair_coeff * * elem1 elem2 ..."); + + if (!allocated) allocate(); + + //number of provided elements in pair_coeff line + int ntypes_coeff = narg - 3; + + if (ntypes_coeff != atom->ntypes) { + char error_message[1024]; + snprintf(error_message, 1024, + "Incorrect args for pair coefficients. You provided %d elements in pair_coeff, but structure has %d atom types", + ntypes_coeff, atom->ntypes); + error->all(FLERR, error_message); + } + + char *type1 = arg[0]; + char *type2 = arg[1]; + char *potential_file_name = arg[2]; + char **elemtypes = &arg[3]; + + // insure I,J args are * * + + if (strcmp(type1, "*") != 0 || strcmp(type2, "*") != 0) + error->all(FLERR, "Incorrect args for pair coefficients"); + + + //load potential file + basis_set = new ACECTildeBasisSet(); + if (comm->me == 0) { + if (screen) fprintf(screen, "Loading %s\n", potential_file_name); + if (logfile) fprintf(logfile, "Loading %s\n", potential_file_name); + } + try { + basis_set->load(potential_file_name); + } catch (...) { + basis_set->load_yaml(potential_file_name); + } + + if (comm->me == 0) { + if (screen) fprintf(screen, "Total number of basis functions\n"); + if (logfile) fprintf(logfile, "Total number of basis functions\n"); + + for (SPECIES_TYPE mu = 0; mu < basis_set->nelements; mu++) { + int n_r1 = basis_set->total_basis_size_rank1[mu]; + int n = basis_set->total_basis_size[mu]; + if (screen) fprintf(screen, "\t%s: %d (r=1) %d (r>1)\n", basis_set->elements_name[mu].c_str(), n_r1, n); + if (logfile) fprintf(logfile, "\t%s: %d (r=1) %d (r>1)\n", basis_set->elements_name[mu].c_str(), n_r1, n); + } + } + + // read args that map atom types to pACE elements + // map[i] = which element the Ith atom type is, -1 if not mapped + // map[0] is not used + + ace = new ACERecursiveEvaluator(); + ace->set_recursive(recursive); + ace->element_type_mapping.init(atom->ntypes + 1); + + for (int i = 1; i <= atom->ntypes; i++) { + char *elemname = elemtypes[i - 1]; + int atomic_number = AtomicNumberByName_pace(elemname); + if (atomic_number == -1) { + char error_msg[1024]; + snprintf(error_msg, 1024, "String '%s' is not a valid element\n", elemname); + error->all(FLERR, error_msg); + } + SPECIES_TYPE mu = basis_set->get_species_index_by_name(elemname); + if (mu != -1) { + if (comm->me == 0) { + if (screen) + fprintf(screen, "Mapping LAMMPS atom type #%d(%s) -> ACE species type #%d\n", i, elemname, mu); + if (logfile) + fprintf(logfile, "Mapping LAMMPS atom type #%d(%s) -> ACE species type #%d\n", i, elemname, mu); + } + map[i] = mu; + ace->element_type_mapping(i) = mu; // set up LAMMPS atom type to ACE species mapping for ace evaluator + } else { + char error_msg[1024]; + snprintf(error_msg, 1024, "Element %s is not supported by ACE-potential from file %s", elemname, + potential_file_name); + error->all(FLERR, error_msg); + } + } + + // clear setflag since coeff() called once with I,J = * * + int n = atom->ntypes; + for (int i = 1; i <= n; i++) { + for (int j = i; j <= n; j++) { + setflag[i][j] = 1; + scale[i][j] = 1.0; + } + } + + // set setflag i,j for type pairs where both are mapped to elements + + int count = 1; + for (int i = 1; i <= n; i++) + for (int j = i; j <= n; j++) + if (map[i] >= 0 && map[j] >= 0) { + setflag[i][j] = 1; + count++; + } + + if (count == 0) error->all(FLERR, "Incorrect args for pair coefficients"); + + ace->set_basis(*basis_set); +} + +/* ---------------------------------------------------------------------- + init specific to this pair style +------------------------------------------------------------------------- */ + +void PairPACE::init_style() { + if (atom->tag_enable == 0) + error->all(FLERR, "Pair style pACE requires atom IDs"); + if (force->newton_pair == 0) + error->all(FLERR, "Pair style pACE requires newton pair on"); + + // request a full neighbor list + int irequest = neighbor->request(this, instance_me); + neighbor->requests[irequest]->half = 0; + neighbor->requests[irequest]->full = 1; +} + +/* ---------------------------------------------------------------------- + init for one type pair i,j and corresponding j,i +------------------------------------------------------------------------- */ + +double PairPACE::init_one(int i, int j) { + if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); + //cutoff from the basis set's radial functions settings + scale[j][i] = scale[i][j]; + return basis_set->radial_functions->cut(map[i], map[j]); +} + +/* ---------------------------------------------------------------------- + extract method for extracting value of scale variable + ---------------------------------------------------------------------- */ +void *PairPACE::extract(const char *str, int &dim) { + dim = 2; + if (strcmp(str, "scale") == 0) return (void *) scale; + return NULL; +} + diff --git a/USER-PACE/pair_pace.h b/ML-PACE/pair_pace.h similarity index 52% rename from USER-PACE/pair_pace.h rename to ML-PACE/pair_pace.h index 0617b5e..97b9652 100644 --- a/USER-PACE/pair_pace.h +++ b/ML-PACE/pair_pace.h @@ -39,32 +39,59 @@ PairStyle(pace,PairPACE) #define LMP_PAIR_PACE_H #include "pair.h" +#include "ace_evaluator.h" +#include "ace_recursive.h" +#include "ace_c_basis.h" namespace LAMMPS_NS { -class PairPACE : public Pair { - public: - PairPACE(class LAMMPS *); - virtual ~PairPACE(); + class PairPACE : public Pair { + public: + PairPACE(class LAMMPS *); - virtual void compute(int, int); - void settings(int, char **); - void coeff(int, char **); - virtual void init_style(); - double init_one(int, int); + virtual ~PairPACE(); - void *extract(const char *, int &); + virtual void compute(int, int); - protected: - struct ACEImpl *aceimpl; + void settings(int, char **); - virtual void allocate(); + void coeff(int, char **); + + virtual void init_style(); + + double init_one(int, int); + + void *extract(const char *, int &); + + // virtual double memory_usage(); + + protected: + ACECTildeBasisSet *basis_set = nullptr; + + ACERecursiveEvaluator* ace = nullptr; + + char *potential_file_name; + + virtual void allocate(); + + void read_files(char *, char *); + + inline int equal(double *x, double *y); + + + double rcutmax; // max cutoff for all elements + int nelements; // # of unique elements + char **elements; // names of unique elements + + int *map; // mapping from atom types to elements + int *jlist_local; + int *type_local; + double **scale; + + bool recursive = false; // "recursive" option for ACERecursiveEvaluator + }; - double **scale; - bool recursive; // "recursive" option for ACERecursiveEvaluator -}; } #endif -#endif - +#endif \ No newline at end of file diff --git a/USER-PACE/ships_radial.cpp b/ML-PACE/ships_radial.cpp similarity index 53% rename from USER-PACE/ships_radial.cpp rename to ML-PACE/ships_radial.cpp index 646d65e..1e01a6a 100644 --- a/USER-PACE/ships_radial.cpp +++ b/ML-PACE/ships_radial.cpp @@ -55,8 +55,7 @@ void SHIPsRadPolyBasis::_init(DOUBLE_TYPE r0, int p, DOUBLE_TYPE rcut, } -void SHIPsRadPolyBasis::fread(FILE *fptr) -{ +void SHIPsRadPolyBasis::fread(FILE *fptr) { int res; //for fscanf result int maxn, p, pl, pr, ntests; double r0, xl, xr, a, b, c, rcut; @@ -129,10 +128,57 @@ void SHIPsRadPolyBasis::fread(FILE *fptr) } +void SHIPsRadPolyBasis::read_YAML(YAML::Node node) { + auto rcut = node["rcut"].as(); + auto xl = node["xl"].as(); + auto pl = node["pl"].as(); + auto r0 = node["r0"].as(); + auto xr = node["xr"].as(); + auto maxn = node["maxn"].as(); + auto pr = node["pr"].as(); -size_t SHIPsRadPolyBasis::get_maxn() -{ + auto p = node["p"].as(); + + this->_init(r0, p, rcut, xl, xr, pl, pr, maxn); + + auto recursion_coefficients = node["recursion_coefficients"]; //.as>>(); + + if (!recursion_coefficients["A"]) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `recursion_coefficients::A` is not presented"); + if (!recursion_coefficients["B"]) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `recursion_coefficients::B` is not presented"); + + if (!recursion_coefficients["C"]) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `recursion_coefficients::C` is not presented"); + + auto rec_A = recursion_coefficients["A"].as>(); + auto rec_B = recursion_coefficients["B"].as>(); + auto rec_C = recursion_coefficients["C"].as>(); + + if (this->maxn != rec_A.size()) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `maxn` doesn't correspond to the size of `recursion_coefficients:A` list"); + if (this->maxn != rec_B.size()) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `maxn` doesn't correspond to the size of `recursion_coefficients:B` list"); + if (this->maxn != rec_C.size()) + throw runtime_error( + "SHIPsRadPolyBasis::read_YAML: `maxn` doesn't correspond to the size of `recursion_coefficients:C` list"); + + // read basis coefficients + for (int i = 0; i < maxn; i++) { + this->A(i) = rec_A.at(i); + this->B(i) = rec_B.at(i); + this->C(i) = rec_C.at(i); + } + +} + +size_t SHIPsRadPolyBasis::get_maxn() { return this->maxn; } @@ -144,28 +190,28 @@ void SHIPsRadPolyBasis::transform(const DOUBLE_TYPE r, DOUBLE_TYPE &x_out, DOUBL } void SHIPsRadPolyBasis::fcut(const DOUBLE_TYPE x, DOUBLE_TYPE &f_out, DOUBLE_TYPE &df_out) const { - if ( ((x < xl) && (pl > 0)) || ((x > xr) && (pr > 0)) ) { - f_out = 0.0; - df_out = 0.0; - } else { + if (((x < xl) && (pl > 0)) || ((x > xr) && (pr > 0))) { + f_out = 0.0; + df_out = 0.0; + } else { f_out = pow(x - xl, pl) * pow(x - xr, pr); df_out = pl * pow(x - xl, pl - 1) * pow(x - xr, pr) + pow(x - xl, pl) * pr * pow(x - xr, pr - 1); } } - /* ------------------------------------------------------------------------ +/* ------------------------------------------------------------------------ Julia Code P[1] = J.A[1] * _fcut_(J.pl, J.tl, J.pr, J.tr, t) if length(J) == 1; return P; end P[2] = (J.A[2] * t + J.B[2]) * P[1] @inbounds for n = 3:length(J) - P[n] = (J.A[n] * t + J.B[n]) * P[n-1] + J.C[n] * P[n-2] + P[n] = (J.A[n] * t + J.B[n]) * P[n-1] + J.C[n] * P[n-2] end return P ------------------------------------------------------------------------ */ void SHIPsRadPolyBasis::calcP(DOUBLE_TYPE r, size_t maxn, - SPECIES_TYPE z1, SPECIES_TYPE z2) { + SPECIES_TYPE z1, SPECIES_TYPE z2) { if (maxn > this->maxn) throw invalid_argument("Given maxn couldn't be larger than global maxn"); @@ -199,31 +245,34 @@ void SHIPsRadPolyBasis::calcP(DOUBLE_TYPE r, size_t maxn, bool SHIPsRadialFunctions::has_pair() { - return this->haspair; + return this->haspair; } void SHIPsRadialFunctions::load(string fname) { - FILE * fptr = fopen(fname.data(), "r"); - size_t res = fscanf(fptr, "radbasename=ACE.jl.Basic\n"); - if (res != 0) - throw("SHIPsRadialFunctions::load : couldnt read radbasename=ACE.jl.Basic"); + FILE *fptr = fopen(fname.data(), "r"); + size_t res = fscanf(fptr, "radbasename=ACE.jl.Basic\n"); + if (res != 0) + throw ("SHIPsRadialFunctions::load : couldnt read radbasename=ACE.jl.Basic"); this->fread(fptr); fclose(fptr); } -void SHIPsRadialFunctions::fread(FILE *fptr){ +void SHIPsRadialFunctions::fread(FILE *fptr) { int res; - size_t maxn; - char hasE0, haspair; - DOUBLE_TYPE c; + size_t maxn; + char hasE0, haspair; + DOUBLE_TYPE c; // check whether we have a pair potential res = fscanf(fptr, "haspair: %c\n", &haspair); - if (res != 1) - throw("SHIPsRadialFunctions::load : couldn't read haspair"); + if (res != 1) + throw ("SHIPsRadialFunctions::load : couldn't read haspair"); + if (this->radbasis.get_size() == 0) { + this->radbasis.init(1, 1, "SHIPsRadialFunctions::radbasis"); + } // read the radial basis - this->radbasis.fread(fptr); + this->radbasis(0, 0).fread(fptr); // read the pair potential if (haspair == 't') { @@ -235,50 +284,119 @@ void SHIPsRadialFunctions::fread(FILE *fptr){ maxn = pairbasis.get_maxn(); // read the coefficients res = fscanf(fptr, "coefficients\n"); - paircoeffs.resize(maxn); + paircoeffs.init(1, 1, maxn); for (size_t n = 0; n < maxn; n++) { res = fscanf(fptr, "%lf\n", &c); - paircoeffs(n) = c; + paircoeffs(0, 0, n) = c; } res = fscanf(fptr, "end polypairpot\n"); - // read the spline parameters + // read the spline parameters + ri.resize(1, 1); + e0.resize(1, 1); + A.resize(1, 1); + B.resize(1, 1); res = fscanf(fptr, "spline parameters\n"); res = fscanf(fptr, " e_0 + B exp(-A*(r/ri-1)) * (ri/r)\n"); - res = fscanf(fptr, "ri=%lf\n", &(this->ri)); - res = fscanf(fptr, "e0=%lf\n", &(this->e0)); - res = fscanf(fptr, "A=%lf\n", &(this->A)); - res = fscanf(fptr, "B=%lf\n", &(this->B)); + res = fscanf(fptr, "ri=%lf\n", &(this->ri(0, 0))); + res = fscanf(fptr, "e0=%lf\n", &(this->e0(0, 0))); + res = fscanf(fptr, "A=%lf\n", &(this->A(0, 0))); + res = fscanf(fptr, "B=%lf\n", &(this->B(0, 0))); res = fscanf(fptr, "end repulsive potential\n"); } } +void SHIPsRadialFunctions::read_yaml(YAML::Node node) { + // node - top-most YAML node + if (node["polypairpot"]) { + auto yaml_pairplot = node["polypairpot"]; + this->haspair = true; + this->pairbasis.read_YAML(yaml_pairplot); + //read paircoeffs + auto maxn = pairbasis.get_maxn(); + paircoeffs.init(nelements, nelements, maxn, "SHIPsRadialFunctions::paircoeffs"); + if (!yaml_pairplot["coefficients"]) + throw runtime_error("`polypairpot::coefficients` not provided"); + auto yaml_coefficients = yaml_pairplot["coefficients"].as, vector>>(); + + for (const auto &p: yaml_coefficients) { + SPECIES_TYPE mu_i = p.first[0]; + SPECIES_TYPE mu_j = p.first[1]; + if (mu_i > nelements - 1 || mu_j > nelements - 1) + throw invalid_argument("yace::polypairpot::coefficients has species type key larger than nelements"); + auto coefficients = p.second; + + for (int i = 0; i < maxn; i++) + this->paircoeffs(mu_i, mu_j, i) = coefficients.at(i); + } -size_t SHIPsRadialFunctions::get_maxn() -{ - return this->radbasis.get_maxn(); + if (node["reppot"] && node["reppot"]["coefficients"]) { + auto reppot_coefficients = node["reppot"]["coefficients"].as, YAML::Node>>();; + + for (const auto &p: reppot_coefficients) { + SPECIES_TYPE mu_i = p.first[0]; + SPECIES_TYPE mu_j = p.first[1]; + if (mu_i > nelements - 1 || mu_j > nelements - 1) + throw invalid_argument("yace::bonds has species type key larger than nelements"); + auto reppot_coef_yaml = p.second; + + this->ri(mu_i, mu_j) = reppot_coef_yaml["ri"].as(); + this->e0(mu_i, mu_j) = reppot_coef_yaml["e0"].as(); + this->A(mu_i, mu_j) = reppot_coef_yaml["A"].as(); + this->B(mu_i, mu_j) = reppot_coef_yaml["B"].as(); + } + } + } + //reading bonds + auto yaml_map_bond_specifications = node["bonds"].as, YAML::Node>>(); + for (const auto &p: yaml_map_bond_specifications) { + SPECIES_TYPE mu_i = p.first[0]; + SPECIES_TYPE mu_j = p.first[1]; + if (mu_i > nelements - 1 || mu_j > nelements - 1) + throw invalid_argument("yace::bonds has species type key larger than nelements"); + auto bond_yaml = p.second; + this->radbasis(mu_i, mu_j).read_YAML(bond_yaml); + } +} + +size_t SHIPsRadialFunctions::get_maxn() { + int maxn = 0; + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; mu_i++) + for (SPECIES_TYPE mu_j = 0; mu_j < nelements; mu_j++) { + int cur_maxn = this->radbasis(mu_i, mu_j).get_maxn(); + if (cur_maxn > maxn) + maxn = cur_maxn; + } + return maxn; } -DOUBLE_TYPE SHIPsRadialFunctions::get_rcut() -{ - return max(radbasis.rcut, pairbasis.rcut); +DOUBLE_TYPE SHIPsRadialFunctions::get_rcut() { + DOUBLE_TYPE rcut = 0; + + for (SPECIES_TYPE mu_i = 0; mu_i < nelements; mu_i++) + for (SPECIES_TYPE mu_j = 0; mu_j < nelements; mu_j++) { + auto cur_rcut = this->radbasis(mu_i, mu_j).rcut; + if (cur_rcut > rcut) + rcut = cur_rcut; + } + return max(rcut, pairbasis.rcut); } void SHIPsRadialFunctions::fill_gk(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2) { - radbasis.calcP(r, maxn, z1, z2); + radbasis(z1, z2).calcP(r, maxn, z1, z2); for (NS_TYPE n = 0; n < maxn; n++) { - gr(n) = radbasis.P(n); - dgr(n) = radbasis.dP_dr(n); + gr(n) = radbasis(z1, z2).P(n); + dgr(n) = radbasis(z1, z2).dP_dr(n); } } void SHIPsRadialFunctions::fill_Rnl(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1, SPECIES_TYPE z2) { - radbasis.calcP(r, maxn, z1, z2); + radbasis(z1, z2).calcP(r, maxn, z1, z2); for (NS_TYPE n = 0; n < maxn; n++) { for (LS_TYPE l = 0; l <= lmax; l++) { - fr(n, l) = radbasis.P(n); - dfr(n, l) = radbasis.dP_dr(n); + fr(n, l) = radbasis(z1, z2).P(n); + dfr(n, l) = radbasis(z1, z2).dP_dr(n); } } } @@ -287,18 +405,47 @@ void SHIPsRadialFunctions::fill_Rnl(DOUBLE_TYPE r, NS_TYPE maxn, SPECIES_TYPE z1 void SHIPsRadialFunctions::setuplookupRadspline() { } +void SHIPsRadialFunctions::init(SPECIES_TYPE nelements) { + this->nelements = nelements; + + lambda.init(nelements, nelements, "lambda"); + lambda.fill(1.); + + cut.init(nelements, nelements, "cut"); + cut.fill(1.); + + dcut.init(nelements, nelements, "dcut"); + dcut.fill(1.); + + //hard-core repulsion + prehc.init(nelements, nelements, "prehc"); + prehc.fill(0.); + + lambdahc.init(nelements, nelements, "lambdahc"); + lambdahc.fill(1.); + + radbasis.init(nelements, nelements, "SHIPsRadialFunctions::radbasis"); + ri.init(nelements, nelements, "SHIPsRadialFunctions::ri"); + e0.init(nelements, nelements, "SHIPsRadialFunctions::e0"); + A.init(nelements, nelements, "SHIPsRadialFunctions::A"); + B.init(nelements, nelements, "SHIPsRadialFunctions::B"); + ri.fill(0); + e0.fill(0); + A.fill(0); + B.fill(0); +} void SHIPsRadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, string radbasename) { + vector> radbasename) { //mimic ACERadialFunctions::init this->nradbase = nradb; this->lmax = lmax; this->nradial = nradial; this->deltaSplineBins = deltaSplineBins; - this->nelements = nelements; - this->cutoff = cutoff; - this->radbasename = radbasename; + + this->init(nelements); + gr.init(nradbase, "gr"); dgr.init(nradbase, "dgr"); @@ -307,28 +454,9 @@ void SHIPsRadialFunctions::init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DO fr.init(nradial, lmax + 1, "fr"); dfr.init(nradial, lmax + 1, "dfr"); - splines_gk.init(nelements, nelements, "splines_gk"); - splines_rnl.init(nelements, nelements, "splines_rnl"); - splines_hc.init(nelements, nelements, "splines_hc"); - - lambda.init(nelements, nelements, "lambda"); - lambda.fill(1.); - - cut.init(nelements, nelements, "cut"); - cut.fill(1.); - - dcut.init(nelements, nelements, "dcut"); - dcut.fill(1.); - - crad.init(nelements, nelements, (lmax + 1), nradial, nradbase, "crad"); + crad.init(nelements, nelements, nradial, (lmax + 1), nradbase, "crad"); crad.fill(0.); - //hard-core repulsion - prehc.init(nelements, nelements, "prehc"); - prehc.fill(0.); - - lambdahc.init(nelements, nelements, "lambdahc"); - lambdahc.fill(1.); } @@ -337,47 +465,43 @@ void SHIPsRadialFunctions::evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE n if (calc_second_derivatives) throw invalid_argument("SHIPsRadialFunctions has not `calc_second_derivatives` option"); - radbasis.calcP(r, nradbase_c, mu_i, mu_j); + radbasis(mu_i, mu_j).calcP(r, nradbase_c, mu_i, mu_j); for (NS_TYPE nr = 0; nr < nradbase_c; nr++) { - gr(nr) = radbasis.P(nr); - dgr(nr) = radbasis.dP_dr(nr); + gr(nr) = radbasis(mu_i, mu_j).P(nr); + dgr(nr) = radbasis(mu_i, mu_j).dP_dr(nr); } for (NS_TYPE nr = 0; nr < nradial_c; nr++) { for (LS_TYPE l = 0; l <= this->lmax; l++) { - fr(nr, l) = radbasis.P(nr); - dfr(nr, l) = radbasis.dP_dr(nr); + fr(nr, l) = radbasis(mu_i, mu_j).P(nr); + dfr(nr, l) = radbasis(mu_i, mu_j).dP_dr(nr); } } if (this->has_pair()) - this->evaluate_pair(r, mu_i, mu_j); + this->evaluate_pair(r, mu_i, mu_j); else { - cr = 0; + cr = 0; dcr = 0; } } -void SHIPsRadialFunctions::evaluate_pair(DOUBLE_TYPE r, +void SHIPsRadialFunctions::evaluate_pair(DOUBLE_TYPE r, SPECIES_TYPE mu_i, - SPECIES_TYPE mu_j, + SPECIES_TYPE mu_j, bool calc_second_derivatives) { - // spline_hc.calcSplines(r); - // cr = spline_hc.values(0); - // dcr = spline_hc.derivatives(0); - - // the outer polynomial potential - if (r > ri) { + // the outer polynomial potential + if (r > ri(mu_i, mu_j)) { pairbasis.calcP(r, pairbasis.get_maxn(), mu_i, mu_j); - cr = 0; + cr = 0; dcr = 0; for (size_t n = 0; n < pairbasis.get_maxn(); n++) { - cr += paircoeffs(n) * pairbasis.P(n); - dcr += paircoeffs(n) * pairbasis.dP_dr(n); + cr += paircoeffs(mu_i, mu_j, n) * pairbasis.P(n); + dcr += paircoeffs(mu_i, mu_j, n) * pairbasis.dP_dr(n); } - } - else { // the repulsive core part - cr = e0 + B * exp(-A * (r/ri - 1)) * (ri/r); - dcr = B * exp( - A * (r/ri-1) ) * ri * ( - A / ri / r - 1/(r*r) ); + } else { // the repulsive core part + cr = e0(mu_i, mu_j) + B(mu_i, mu_j) * exp(-A(mu_i, mu_j) * (r / ri(mu_i, mu_j) - 1)) * (ri(mu_i, mu_j) / r); + dcr = B(mu_i, mu_j) * exp(-A(mu_i, mu_j) * (r / ri(mu_i, mu_j) - 1)) * ri(mu_i, mu_j) * + (-A(mu_i, mu_j) / ri(mu_i, mu_j) / r - 1 / (r * r)); } // fix double-counting cr *= 0.5; diff --git a/USER-PACE/ships_radial.h b/ML-PACE/ships_radial.h similarity index 86% rename from USER-PACE/ships_radial.h rename to ML-PACE/ships_radial.h index 804b0b2..dd80a7b 100644 --- a/USER-PACE/ships_radial.h +++ b/ML-PACE/ships_radial.h @@ -34,6 +34,7 @@ #include "ace_arraynd.h" #include "ace_types.h" #include "ace_radial.h" +#include class SHIPsRadPolyBasis { @@ -75,6 +76,7 @@ class SHIPsRadPolyBasis { void fcut(const DOUBLE_TYPE x, DOUBLE_TYPE &f_out, DOUBLE_TYPE &df_out) const; void fread(FILE *fptr); + void read_YAML(YAML::Node node); void _init(DOUBLE_TYPE r0, int p, DOUBLE_TYPE rcut, DOUBLE_TYPE xl, DOUBLE_TYPE xr, @@ -93,20 +95,20 @@ class SHIPsRadialFunctions : public AbstractRadialBasis { public: // radial basis - SHIPsRadPolyBasis radbasis; + Array2D radbasis; // pair potential basis bool haspair = false; SHIPsRadPolyBasis pairbasis; - // pair potential coefficients - Array1D paircoeffs = Array1D("SHIPs pairpot coeffs: paircoeffs"); + // pair potential coefficients, shape [mu_i, mu_j, n] + Array3D paircoeffs = Array3D("SHIPs pairpot coeffs: paircoeffs"); // spline parameters for repulsive core - DOUBLE_TYPE ri = 0.0; - DOUBLE_TYPE e0 = 0.0; - DOUBLE_TYPE A = 0.0; - DOUBLE_TYPE B = 0.0; + Array2D ri = Array2D("ri"); + Array2D e0 = Array2D("e0"); + Array2D A = Array2D("A"); + Array2D B = Array2D("B"); ////////////////////////////////// @@ -116,17 +118,19 @@ class SHIPsRadialFunctions : public AbstractRadialBasis { void fread(FILE *fptr); + void read_yaml(YAML::Node node); void load(string fname); size_t get_maxn(); - DOUBLE_TYPE get_rcut(); + DOUBLE_TYPE get_rcut(); - bool has_pair(); + bool has_pair(); + + void init(SPECIES_TYPE nelements); void init(NS_TYPE nradb, LS_TYPE lmax, NS_TYPE nradial, DOUBLE_TYPE deltaSplineBins, SPECIES_TYPE nelements, - DOUBLE_TYPE cutoff, - string radbasename) override; + vector> radbasename) override; void evaluate(DOUBLE_TYPE r, NS_TYPE nradbase_c, NS_TYPE nradial_c, SPECIES_TYPE mu_i, SPECIES_TYPE mu_j, diff --git a/USER-PACE/pair_pace.cpp b/USER-PACE/pair_pace.cpp deleted file mode 100644 index 41551e4..0000000 --- a/USER-PACE/pair_pace.cpp +++ /dev/null @@ -1,388 +0,0 @@ -/* -Copyright 2021 Yury Lysogorskiy^1, Cas van der Oord^2, Anton Bochkarev^1, - Sarath Menon^1, Matteo Rinaldi^1, Thomas Hammerschmidt^1, Matous Mrovec^1, - Aidan Thompson^3, Gabor Csanyi^2, Christoph Ortner^4, Ralf Drautz^1 - -^1: Ruhr-University Bochum, Bochum, Germany -^2: University of Cambridge, Cambridge, United Kingdom -^3: Sandia National Laboratories, Albuquerque, New Mexico, USA -^4: University of British Columbia, Vancouver, BC, Canada - - - This FILENAME 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 3 of the License, or - (at your option) any later version. - - This program is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . - */ - - -// -// Created by Lysogorskiy Yury on 27.02.20. -// - -#include "pair_pace.h" - -#include "atom.h" -#include "comm.h" -#include "error.h" -#include "force.h" -#include "math_const.h" -#include "memory.h" -#include "neigh_list.h" -#include "neigh_request.h" -#include "neighbor.h" - -#include -#include - -#include "ace_evaluator.h" -#include "ace_recursive.h" -#include "ace_c_basis.h" -#include "ace_version.h" - -namespace LAMMPS_NS { - struct ACEImpl { - ACECTildeBasisSet *basis_set; - ACERecursiveEvaluator *ace; - }; -} - -using namespace LAMMPS_NS; -using namespace MathConst; - -#define MAXLINE 1024 -#define DELTA 4 - -//added YL - -//keywords for ACE evaluator style -#define RECURSIVE_KEYWORD "recursive" -#define PRODUCT_KEYWORD "product" - -static int elements_num_pace = 104; -static char const *const elements_pace[104] = {"X", "H", "He", "Li", "Be", "B", "C", "N", "O", "F", "Ne", "Na", - "Mg", "Al", "Si", "P", "S", "Cl", "Ar", "K", "Ca", "Sc", "Ti", "V", "Cr", "Mn", - "Fe", "Co", "Ni", "Cu", "Zn", "Ga", "Ge", "As", "Se", "Br", "Kr", "Rb", "Sr", - "Y", "Zr", "Nb", "Mo", "Tc", "Ru", "Rh", "Pd", "Ag", "Cd", "In", "Sn", "Sb", - "Te", "I", "Xe", "Cs", "Ba", "La", "Ce", "Pr", "Nd", "Pm", "Sm", "Eu", "Gd", - "Tb", "Dy", "Ho", "Er", "Tm", "Yb", "Lu", "Hf", "Ta", "W", "Re", "Os", "Ir", - "Pt", "Au", "Hg", "Tl", "Pb", "Bi", "Po", "At", "Rn", "Fr", "Ra", "Ac", "Th", - "Pa", "U", "Np", "Pu", "Am", "Cm", "Bk", "Cf", "Es", "Fm", "Md", "No", "Lr" -}; - -static int AtomicNumberByName_pace(char *elname) { - for (int i = 1; i < elements_num_pace; i++) - if (strcmp(elname, elements_pace[i]) == 0) - return i; - return -1; -} - -/* ---------------------------------------------------------------------- */ -PairPACE::PairPACE(LAMMPS *lmp) : Pair(lmp) { - single_enable = 0; - restartinfo = 0; - one_coeff = 1; - manybody_flag = 1; - - aceimpl = new ACEImpl; - aceimpl->ace = nullptr; - aceimpl->basis_set = nullptr; - recursive = false; - - scale = nullptr; -} - -/* ---------------------------------------------------------------------- - check if allocated, since class can be destructed when incomplete -------------------------------------------------------------------------- */ - -PairPACE::~PairPACE() { - if (copymode) return; - - delete aceimpl->basis_set; - delete aceimpl->ace; - delete aceimpl; - - if (allocated) { - memory->destroy(setflag); - memory->destroy(cutsq); - memory->destroy(scale); - } -} - -/* ---------------------------------------------------------------------- */ - -void PairPACE::compute(int eflag, int vflag) { - int i, j, ii, jj, inum, jnum; - double delx, dely, delz, evdwl; - double fij[3]; - int *ilist, *jlist, *numneigh, **firstneigh; - - ev_init(eflag, vflag); - - // downwards modified by YL - - double **x = atom->x; - double **f = atom->f; - tagint *tag = atom->tag; - int *type = atom->type; - - // number of atoms in cell - int nlocal = atom->nlocal; - - int newton_pair = force->newton_pair; - - // number of atoms including ghost atoms - int nall = nlocal + atom->nghost; - - // inum: length of the neighborlists list - inum = list->inum; - - // ilist: list of "i" atoms for which neighbor lists exist - ilist = list->ilist; - - //numneigh: the length of each these neigbor list - numneigh = list->numneigh; - - // the pointer to the list of neighbors of "i" - firstneigh = list->firstneigh; - - if (inum != nlocal) - error->all(FLERR,fmt::format("inum: {} nlocal: {} are different",inum, nlocal)); - - // Aidan Thompson told RD (26 July 2019) that practically always holds: - // inum = nlocal - // i = ilist(ii) < inum - // j = jlist(jj) < nall - // neighborlist contains neighbor atoms plus skin atoms, - // skin atoms can be removed by setting skin to zero but here - // they are disregarded anyway - - - //determine the maximum number of neighbours - int max_jnum = -1; - int nei = 0; - for (ii = 0; ii < list->inum; ii++) { - i = ilist[ii]; - jnum = numneigh[i]; - nei = nei + jnum; - if (jnum > max_jnum) - max_jnum = jnum; - } - - aceimpl->ace->resize_neighbours_cache(max_jnum); - - //loop over atoms - for (ii = 0; ii < list->inum; ii++) { - i = list->ilist[ii]; - const int itype = type[i]; - - const double xtmp = x[i][0]; - const double ytmp = x[i][1]; - const double ztmp = x[i][2]; - - jlist = firstneigh[i]; - jnum = numneigh[i]; - - // checking if neighbours are actually within cutoff range is done inside compute_atom - // mapping from LAMMPS atom types ('type' array) to ACE species is done inside compute_atom - // by using 'aceimpl->ace->element_type_mapping' array - // x: [r0 ,r1, r2, ..., r100] - // i = 0 ,1 - // jnum(0) = 50 - // jlist(neigh ind of 0-atom) = [1,2,10,7,99,25, .. 50 element in total] - - try { - aceimpl->ace->compute_atom(i, x, type, jnum, jlist); - } catch (exception &e) { - error->one(FLERR, e.what()); - } - // 'compute_atom' will update the `aceimpl->ace->e_atom` and `aceimpl->ace->neighbours_forces(jj, alpha)` arrays - - for (jj = 0; jj < jnum; jj++) { - j = jlist[jj]; - const int jtype = type[j]; - j &= NEIGHMASK; - delx = x[j][0] - xtmp; - dely = x[j][1] - ytmp; - delz = x[j][2] - ztmp; - - fij[0] = scale[itype][jtype]*aceimpl->ace->neighbours_forces(jj, 0); - fij[1] = scale[itype][jtype]*aceimpl->ace->neighbours_forces(jj, 1); - fij[2] = scale[itype][jtype]*aceimpl->ace->neighbours_forces(jj, 2); - - f[i][0] += fij[0]; - f[i][1] += fij[1]; - f[i][2] += fij[2]; - f[j][0] -= fij[0]; - f[j][1] -= fij[1]; - f[j][2] -= fij[2]; - - // tally per-atom virial contribution - if (vflag) - ev_tally_xyz(i, j, nlocal, newton_pair, 0.0, 0.0, - fij[0], fij[1], fij[2], - -delx, -dely, -delz); - } - - // tally energy contribution - if (eflag) { - // evdwl = energy of atom I - evdwl = scale[1][1]*aceimpl->ace->e_atom; - ev_tally_full(i, 2.0 * evdwl, 0.0, 0.0, 0.0, 0.0, 0.0); - } - } - - if (vflag_fdotr) virial_fdotr_compute(); - - // end modifications YL -} - -/* ---------------------------------------------------------------------- */ - -void PairPACE::allocate() { - allocated = 1; - int n = atom->ntypes; - - memory->create(setflag, n + 1, n + 1, "pair:setflag"); - memory->create(cutsq, n + 1, n + 1, "pair:cutsq"); - memory->create(scale, n + 1, n + 1,"pair:scale"); - map = new int[n+1]; -} - -/* ---------------------------------------------------------------------- - global settings -------------------------------------------------------------------------- */ - -void PairPACE::settings(int narg, char **arg) { - if (narg > 1) - error->all(FLERR,"Illegal pair_style command."); - - recursive = true; // default evaluator style: RECURSIVE - if (narg > 0) { - if (strcmp(arg[0], RECURSIVE_KEYWORD) == 0) - recursive = true; - else if (strcmp(arg[0], PRODUCT_KEYWORD) == 0) { - recursive = false; - } else error->all(FLERR,"Illegal pair_style command"); - } - - if (comm->me == 0) { - utils::logmesg(lmp,fmt::format("ACE version: {}.{}.{}\n", - VERSION_YEAR, VERSION_MONTH, VERSION_DAY)); - if (recursive) utils::logmesg(lmp,"Recursive evaluator is used\n"); - else utils::logmesg(lmp,"Product evaluator is used\n"); - } -} - -/* ---------------------------------------------------------------------- - set coeffs for one or more type pairs -------------------------------------------------------------------------- */ - -void PairPACE::coeff(int narg, char **arg) { - - if (!allocated) allocate(); - - map_element2type(narg-3,arg+3); - - auto potential_file_name = utils::get_potential_file_path(arg[2]); - char **elemtypes = &arg[3]; - - //load potential file - aceimpl->basis_set = new ACECTildeBasisSet(); - if (comm->me == 0) - utils::logmesg(lmp,fmt::format("Loading {}\n", potential_file_name)); - aceimpl->basis_set->load(potential_file_name); - - if (comm->me == 0) { - utils::logmesg(lmp,"Total number of basis functions\n"); - - for (SPECIES_TYPE mu = 0; mu < aceimpl->basis_set->nelements; mu++) { - int n_r1 = aceimpl->basis_set->total_basis_size_rank1[mu]; - int n = aceimpl->basis_set->total_basis_size[mu]; - utils::logmesg(lmp,fmt::format("\t{}: {} (r=1) {} (r>1)\n", aceimpl->basis_set->elements_name[mu], n_r1, n)); - } - } - - // read args that map atom types to pACE elements - // map[i] = which element the Ith atom type is, -1 if not mapped - // map[0] is not used - - aceimpl->ace = new ACERecursiveEvaluator(); - aceimpl->ace->set_recursive(recursive); - aceimpl->ace->element_type_mapping.init(atom->ntypes + 1); - - const int n = atom->ntypes; - for (int i = 1; i <= n; i++) { - char *elemname = elemtypes[i - 1]; - int atomic_number = AtomicNumberByName_pace(elemname); - if (atomic_number == -1) - error->all(FLERR,fmt::format("'{}' is not a valid element\n", elemname)); - - SPECIES_TYPE mu = aceimpl->basis_set->get_species_index_by_name(elemname); - if (mu != -1) { - if (comm->me == 0) - utils::logmesg(lmp,fmt::format("Mapping LAMMPS atom type #{}({}) -> " - "ACE species type #{}\n", i, elemname, mu)); - map[i] = mu; - aceimpl->ace->element_type_mapping(i) = mu; // set up LAMMPS atom type to ACE species mapping for ace evaluator - } else { - error->all(FLERR, fmt::format("Element {} is not supported by ACE-potential from file {}", elemname,potential_file_name)); - } - } - - // initialize scale factor - for (int i = 1; i <= n; i++) { - for (int j = i; j <= n; j++) { - scale[i][j] = 1.0; - } - } - - aceimpl->ace->set_basis(*aceimpl->basis_set, 1); -} - -/* ---------------------------------------------------------------------- - init specific to this pair style -------------------------------------------------------------------------- */ - -void PairPACE::init_style() { - if (atom->tag_enable == 0) - error->all(FLERR, "Pair style pACE requires atom IDs"); - if (force->newton_pair == 0) - error->all(FLERR, "Pair style pACE requires newton pair on"); - - // request a full neighbor list - int irequest = neighbor->request(this, instance_me); - neighbor->requests[irequest]->half = 0; - neighbor->requests[irequest]->full = 1; -} - -/* ---------------------------------------------------------------------- - init for one type pair i,j and corresponding j,i -------------------------------------------------------------------------- */ - -double PairPACE::init_one(int i, int j) { - if (setflag[i][j] == 0) error->all(FLERR, "All pair coeffs are not set"); - //cutoff from the basis set's radial functions settings - scale[j][i] = scale[i][j]; - return aceimpl->basis_set->radial_functions->cut(map[i], map[j]); -} - -/* ---------------------------------------------------------------------- - extract method for extracting value of scale variable - ---------------------------------------------------------------------- */ -void *PairPACE::extract(const char *str, int &dim) -{ - dim = 2; - if (strcmp(str,"scale") == 0) return (void *) scale; - return nullptr; -} - diff --git a/yaml-cpp/.gitignore b/yaml-cpp/.gitignore new file mode 100644 index 0000000..2f9d10f --- /dev/null +++ b/yaml-cpp/.gitignore @@ -0,0 +1,3 @@ +build/ +/tags +/bazel-* diff --git a/yaml-cpp/CMakeLists.txt b/yaml-cpp/CMakeLists.txt new file mode 100644 index 0000000..a8b762d --- /dev/null +++ b/yaml-cpp/CMakeLists.txt @@ -0,0 +1,133 @@ +# 3.5 is actually available almost everywhere, but this a good minimum +cmake_minimum_required(VERSION 3.4) +project(YAML_CPP VERSION 0.6.3 LANGUAGES CXX) + +include(CMakePackageConfigHelpers) +include(CMakeDependentOption) +include(CheckCXXCompilerFlag) +include(GNUInstallDirs) +include(CTest) + +find_program(YAML_CPP_CLANG_FORMAT_EXE NAMES clang-format) + +option(YAML_CPP_BUILD_CONTRIB "Enable yaml-cpp contrib in library" ON) +option(YAML_CPP_BUILD_TOOLS "Enable parse tools" ON) +option(YAML_BUILD_SHARED_LIBS "Build yaml-cpp shared library" ${BUILD_SHARED_LIBS}) + +cmake_dependent_option(YAML_CPP_BUILD_TESTS + "Enable yaml-cpp tests" ON + "BUILD_TESTING;CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) +cmake_dependent_option(YAML_CPP_INSTALL + "Enable generation of yaml-cpp install targets" ON + "CMAKE_SOURCE_DIR STREQUAL PROJECT_SOURCE_DIR" OFF) +cmake_dependent_option(YAML_MSVC_SHARED_RT + "MSVC: Build yaml-cpp with shared runtime libs (/MD)" ON + "MSVC" OFF) + +set(yaml-cpp-type STATIC) +set(yaml-cpp-label-postfix "static") +if (YAML_BUILD_SHARED_LIBS) + set(yaml-cpp-type SHARED) + set(yaml-cpp-label-postfix "shared") +endif () + +set(build-shared $) +set(build-windows-dll $,${build-shared}>) +set(not-msvc $>) + +if (NOT DEFINED CMAKE_MSVC_RUNTIME_LIBRARY) + set(CMAKE_MSVC_RUNTIME_LIBRARY + MultiThreaded$<$:Debug>$<${build-shared}:DLL>) +endif () + +set(contrib-pattern "src/contrib/*.cpp") +set(src-pattern "src/*.cpp") +if (CMAKE_VERSION VERSION_GREATER 3.12) + list(INSERT contrib-pattern 0 CONFIGURE_DEPENDS) + list(INSERT src-pattern 0 CONFIGURE_DEPENDS) +endif () + +file(GLOB yaml-cpp-contrib-sources ${contrib-pattern}) +file(GLOB yaml-cpp-sources ${src-pattern}) + +set(msvc-rt $) + +set(msvc-rt-mtd-static $) +set(msvc-rt-mt-static $) + +set(msvc-rt-mtd-dll $) +set(msvc-rt-mt-dll $) + +set(backport-msvc-runtime $) + +add_library(yaml-cpp ${yaml-cpp-type} "") +add_library(yaml-cpp::yaml-cpp ALIAS yaml-cpp) + +set_property(TARGET yaml-cpp + PROPERTY + MSVC_RUNTIME_LIBRARY ${CMAKE_MSVC_RUNTIME_LIBRARY}) +set_property(TARGET yaml-cpp + PROPERTY + CXX_STANDARD_REQUIRED ON) + +target_include_directories(yaml-cpp + PUBLIC + $ + $ + PRIVATE + $) + +if (NOT DEFINED CMAKE_CXX_STANDARD) + set_target_properties(yaml-cpp + PROPERTIES + CXX_STANDARD 11) +endif () + +target_compile_options(yaml-cpp + PRIVATE + $<${not-msvc}:-Wall -Wextra -Wshadow -Weffc++ -Wno-long-long> + $<${not-msvc}:-pedantic -pedantic-errors> + + $<$:-MTd> + $<$:-MT> + $<$:-MDd> + $<$:-MD> + + # /wd4127 = disable warning C4127 "conditional expression is constant" + # http://msdn.microsoft.com/en-us/library/6t66728h.aspx + # /wd4355 = disable warning C4355 "'this' : used in base member initializer list + # http://msdn.microsoft.com/en-us/library/3c594ae3.aspx + $<$:/W3 /wd4127 /wd4355>) + +target_compile_definitions(yaml-cpp + PRIVATE + $<${build-windows-dll}:${PROJECT_NAME}_DLL> + $<$>:YAML_CPP_NO_CONTRIB>) + +target_sources(yaml-cpp + PRIVATE + $<$:${yaml-cpp-contrib-sources}> + ${yaml-cpp-sources}) + +if (NOT DEFINED CMAKE_DEBUG_POSTFIX) + set(CMAKE_DEBUG_POSTFIX "d") +endif () + +set_target_properties(yaml-cpp PROPERTIES + VERSION "${PROJECT_VERSION}" + SOVERSION "${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}" + PROJECT_LABEL "yaml-cpp ${yaml-cpp-label-postfix}" + DEBUG_POSTFIX "${CMAKE_DEBUG_POSTFIX}") + +write_basic_package_version_file( + "${PROJECT_BINARY_DIR}/yaml-cpp-config-version.cmake" + COMPATIBILITY AnyNewerVersion) + + +if (YAML_CPP_CLANG_FORMAT_EXE) + add_custom_target(format + COMMAND clang-format --style=file -i $ + COMMAND_EXPAND_LISTS + COMMENT "Running clang-format" + VERBATIM) +endif () diff --git a/yaml-cpp/CONTRIBUTING.md b/yaml-cpp/CONTRIBUTING.md new file mode 100644 index 0000000..5900583 --- /dev/null +++ b/yaml-cpp/CONTRIBUTING.md @@ -0,0 +1,31 @@ +# Style + +This project is formatted with [clang-format][fmt] using the style file at the root of the repository. Please run +clang-format before sending a pull request. + +In general, try to follow the style of surrounding code. We mostly follow the [Google C++ style guide][cpp-style]. + +Commit messages should be in the imperative mood, as described in the [Git contributing file][git-contrib]: + +> Describe your changes in imperative mood, e.g. "make xyzzy do frotz" +> instead of "[This patch] makes xyzzy do frotz" or "[I] changed xyzzy +> to do frotz", as if you are giving orders to the codebase to change +> its behaviour. + +[fmt]: http://clang.llvm.org/docs/ClangFormat.html + +[cpp-style]: https://google.github.io/styleguide/cppguide.html + +[git-contrib]: http://git.kernel.org/cgit/git/git.git/tree/Documentation/SubmittingPatches?id=HEAD + +# Tests + +Please verify the tests pass by running the target `tests/run_tests`. + +If you are adding functionality, add tests accordingly. + +# Pull request process + +Every pull request undergoes a code review. Unfortunately, github's code review process isn't great, but we'll manage. +During the code review, if you make changes, add new commits to the pull request for each change. Once the code review +is complete, rebase against the master branch and squash into a single commit. diff --git a/yaml-cpp/Makefile b/yaml-cpp/Makefile new file mode 100644 index 0000000..73ed5a9 --- /dev/null +++ b/yaml-cpp/Makefile @@ -0,0 +1,39 @@ +SHELL = /bin/sh + +# ------ FILES ------ + +SRC = $(wildcard src/*.cpp) + + +# ------ DEFINITIONS ------ + +LIB = libyaml-cpp.a +OBJ = $(SRC:.cpp=.o) + + +# ------ SETTINGS ------ +CXXFLAGS = -O3 -fPIC -Iinclude + +ARCHIVE = ar +ARCHFLAG = -rc +USRLIB = +SYSLIB = + +# ------ MAKE PROCEDURE ------ + +lib: $(OBJ) + $(ARCHIVE) $(ARFLAGS) $(LIB) $(OBJ) + +# ------ COMPILE RULES ------ + +%.o: %.cpp + $(CXX) $(CXXFLAGS) -c $< -o $@ + +# ------ CLEAN ------ +clean: clean-all + +clean-all: + -rm -f *~ $(OBJ) $(LIB) + +clean-build: + -rm -f *~ $(OBJ) diff --git a/yaml-cpp/README.md b/yaml-cpp/README.md new file mode 100644 index 0000000..f72cd4c --- /dev/null +++ b/yaml-cpp/README.md @@ -0,0 +1,74 @@ +# yaml-cpp [![Build Status](https://travis-ci.org/jbeder/yaml-cpp.svg?branch=master)](https://travis-ci.org/jbeder/yaml-cpp) [![Documentation](https://codedocs.xyz/jbeder/yaml-cpp.svg)](https://codedocs.xyz/jbeder/yaml-cpp/) + +yaml-cpp is a [YAML](http://www.yaml.org/) parser and emitter in C++ matching +the [YAML 1.2 spec](http://www.yaml.org/spec/1.2/spec.html). + +To get a feel for how it can be used, see the [Tutorial](https://github.com/jbeder/yaml-cpp/wiki/Tutorial) +or [How to Emit YAML](https://github.com/jbeder/yaml-cpp/wiki/How-To-Emit-YAML). For the old API (version < 0.5.0), +see [How To Parse A Document](https://github.com/jbeder/yaml-cpp/wiki/How-To-Parse-A-Document-(Old-API)). + +# Problems? # + +If you find a bug, post an [issue](https://github.com/jbeder/yaml-cpp/issues)! If you have questions about how to use +yaml-cpp, please post it on http://stackoverflow.com and tag +it [`yaml-cpp`](http://stackoverflow.com/questions/tagged/yaml-cpp). + +# How to Build # + +yaml-cpp uses [CMake](http://www.cmake.org) to support cross-platform building. The basic steps to build are: + +1. Download and install [CMake](http://www.cmake.org) (Resources -> Download). + +**Note:** If you don't use the provided installer for your platform, make sure that you add CMake's bin folder to your +path. + +2. Navigate into the source directory, and type: + +``` +mkdir build +cd build +``` + +3. Run CMake. The basic syntax is: + +``` +cmake [-G generator] [-DYAML_BUILD_SHARED_LIBS=ON|OFF] .. +``` + +* The `generator` is whatever type of build system you'd like to use. To see a full list of generators on your platform, + just run `cmake` (with no arguments). For example: + * On Windows, you might use "Visual Studio 12 2013" to generate a Visual Studio 2013 solution or "Visual Studio 14 + 2015 Win64" to generate a 64-bit Visual Studio 2015 solution. + * On OS X, you might use "Xcode" to generate an Xcode project + * On a UNIX-y system, simply omit the option to generate a makefile + +* yaml-cpp defaults to building a static library, but you may build a shared library by + specifying `-DYAML_BUILD_SHARED_LIBS=ON`. + +* For more options on customizing the build, see + the [CMakeLists.txt](https://github.com/jbeder/yaml-cpp/blob/master/CMakeLists.txt) file. + +4. Build it! + +5. To clean up, just remove the `build` directory. + +# Recent Release # + +[yaml-cpp 0.6.0](https://github.com/jbeder/yaml-cpp/releases/tag/yaml-cpp-0.6.0) has been released! This release +requires C++11, and no longer depends on Boost. + +[yaml-cpp 0.3.0](https://github.com/jbeder/yaml-cpp/releases/tag/release-0.3.0) is still available if you want the old +API. + +**The old API will continue to be supported, and will still receive bugfixes!** The 0.3.x and 0.4.x versions will be old +API releases, and 0.5.x and above will all be new API releases. + +# API Documentation + +The autogenerated API reference is hosted on [CodeDocs](https://codedocs.xyz/jbeder/yaml-cpp/index.html) + +# Third Party Integrations + +The following projects are not officially supported: + +- [Qt wrapper](https://gist.github.com/brcha/d392b2fe5f1e427cc8a6) diff --git a/yaml-cpp/include/yaml-cpp/anchor.h b/yaml-cpp/include/yaml-cpp/anchor.h new file mode 100644 index 0000000..9d78932 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/anchor.h @@ -0,0 +1,17 @@ +#ifndef ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +namespace YAML { + using anchor_t = std::size_t; + const anchor_t NullAnchor = 0; +} + +#endif // ANCHOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/binary.h b/yaml-cpp/include/yaml-cpp/binary.h new file mode 100644 index 0000000..5c94b3e --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/binary.h @@ -0,0 +1,79 @@ +#ifndef BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + YAML_CPP_API std::string EncodeBase64(const unsigned char *data, + std::size_t size); + + YAML_CPP_API std::vector DecodeBase64(const std::string &input); + + class YAML_CPP_API Binary { + public: + Binary(const unsigned char *data_, std::size_t size_) + : m_data{}, m_unownedData(data_), m_unownedSize(size_) {} + + Binary() : Binary(nullptr, 0) {} + + Binary(const Binary &) = default; + + Binary(Binary &&) = default; + + Binary &operator=(const Binary &) = default; + + Binary &operator=(Binary &&) = default; + + bool owned() const { return !m_unownedData; } + + std::size_t size() const { return owned() ? m_data.size() : m_unownedSize; } + + const unsigned char *data() const { + return owned() ? &m_data[0] : m_unownedData; + } + + void swap(std::vector &rhs) { + if (m_unownedData) { + m_data.swap(rhs); + rhs.clear(); + rhs.resize(m_unownedSize); + std::copy(m_unownedData, m_unownedData + m_unownedSize, rhs.begin()); + m_unownedData = nullptr; + m_unownedSize = 0; + } else { + m_data.swap(rhs); + } + } + + bool operator==(const Binary &rhs) const { + const std::size_t s = size(); + if (s != rhs.size()) + return false; + const unsigned char *d1 = data(); + const unsigned char *d2 = rhs.data(); + for (std::size_t i = 0; i < s; i++) { + if (*d1++ != *d2++) + return false; + } + return true; + } + + bool operator!=(const Binary &rhs) const { return !(*this == rhs); } + + private: + std::vector m_data; + const unsigned char *m_unownedData; + std::size_t m_unownedSize; + }; +} // namespace YAML + +#endif // BASE64_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/contrib/anchordict.h b/yaml-cpp/include/yaml-cpp/contrib/anchordict.h new file mode 100644 index 0000000..3ae4c2c --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/contrib/anchordict.h @@ -0,0 +1,41 @@ +#ifndef ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "../anchor.h" + +namespace YAML { +/** + * An object that stores and retrieves values correlating to {@link anchor_t} + * values. + * + *

Efficient implementation that can make assumptions about how + * {@code anchor_t} values are assigned by the {@link Parser} class. + */ + template + class AnchorDict { + public: + AnchorDict() : m_data{} {} + + void Register(anchor_t anchor, T value) { + if (anchor > m_data.size()) { + m_data.resize(anchor); + } + m_data[anchor - 1] = value; + } + + T Get(anchor_t anchor) const { return m_data[anchor - 1]; } + + private: + std::vector m_data; + }; +} // namespace YAML + +#endif // ANCHORDICT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/contrib/graphbuilder.h b/yaml-cpp/include/yaml-cpp/contrib/graphbuilder.h new file mode 100644 index 0000000..f62a08d --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/contrib/graphbuilder.h @@ -0,0 +1,155 @@ +#ifndef GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/mark.h" +#include + +namespace YAML { + class Parser; + +// GraphBuilderInterface +// . Abstraction of node creation +// . pParentNode is always nullptr or the return value of one of the NewXXX() +// functions. + class GraphBuilderInterface { + public: + virtual ~GraphBuilderInterface() = 0; + + // Create and return a new node with a null value. + virtual void *NewNull(const Mark &mark, void *pParentNode) = 0; + + // Create and return a new node with the given tag and value. + virtual void *NewScalar(const Mark &mark, const std::string &tag, + void *pParentNode, const std::string &value) = 0; + + // Create and return a new sequence node + virtual void *NewSequence(const Mark &mark, const std::string &tag, + void *pParentNode) = 0; + + // Add pNode to pSequence. pNode was created with one of the NewXxx() + // functions and pSequence with NewSequence(). + virtual void AppendToSequence(void *pSequence, void *pNode) = 0; + + // Note that no moew entries will be added to pSequence + virtual void SequenceComplete(void *pSequence) { (void) pSequence; } + + // Create and return a new map node + virtual void *NewMap(const Mark &mark, const std::string &tag, + void *pParentNode) = 0; + + // Add the pKeyNode => pValueNode mapping to pMap. pKeyNode and pValueNode + // were created with one of the NewXxx() methods and pMap with NewMap(). + virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) = 0; + + // Note that no more assignments will be made in pMap + virtual void MapComplete(void *pMap) { (void) pMap; } + + // Return the node that should be used in place of an alias referencing + // pNode (pNode by default) + virtual void *AnchorReference(const Mark &mark, void *pNode) { + (void) mark; + return pNode; + } + }; + +// Typesafe wrapper for GraphBuilderInterface. Assumes that Impl defines +// Node, Sequence, and Map types. Sequence and Map must derive from Node +// (unless Node is defined as void). Impl must also implement function with +// all of the same names as the virtual functions in GraphBuilderInterface +// -- including the ones with default implementations -- but with the +// prototypes changed to accept an explicit Node*, Sequence*, or Map* where +// appropriate. + template + class GraphBuilder : public GraphBuilderInterface { + public: + typedef typename Impl::Node Node; + typedef typename Impl::Sequence Sequence; + typedef typename Impl::Map Map; + + GraphBuilder(Impl &impl) : m_impl(impl) { + Map *pMap = nullptr; + Sequence *pSeq = nullptr; + Node *pNode = nullptr; + + // Type consistency checks + pNode = pMap; + pNode = pSeq; + } + + GraphBuilderInterface &AsBuilderInterface() { return *this; } + + virtual void *NewNull(const Mark &mark, void *pParentNode) { + return CheckType(m_impl.NewNull(mark, AsNode(pParentNode))); + } + + virtual void *NewScalar(const Mark &mark, const std::string &tag, + void *pParentNode, const std::string &value) { + return CheckType( + m_impl.NewScalar(mark, tag, AsNode(pParentNode), value)); + } + + virtual void *NewSequence(const Mark &mark, const std::string &tag, + void *pParentNode) { + return CheckType( + m_impl.NewSequence(mark, tag, AsNode(pParentNode))); + } + + virtual void AppendToSequence(void *pSequence, void *pNode) { + m_impl.AppendToSequence(AsSequence(pSequence), AsNode(pNode)); + } + + virtual void SequenceComplete(void *pSequence) { + m_impl.SequenceComplete(AsSequence(pSequence)); + } + + virtual void *NewMap(const Mark &mark, const std::string &tag, + void *pParentNode) { + return CheckType(m_impl.NewMap(mark, tag, AsNode(pParentNode))); + } + + virtual void AssignInMap(void *pMap, void *pKeyNode, void *pValueNode) { + m_impl.AssignInMap(AsMap(pMap), AsNode(pKeyNode), AsNode(pValueNode)); + } + + virtual void MapComplete(void *pMap) { m_impl.MapComplete(AsMap(pMap)); } + + virtual void *AnchorReference(const Mark &mark, void *pNode) { + return CheckType(m_impl.AnchorReference(mark, AsNode(pNode))); + } + + private: + Impl &m_impl; + + // Static check for pointer to T + template + static T *CheckType(U *p) { + return p; + } + + static Node *AsNode(void *pNode) { return static_cast(pNode); } + + static Sequence *AsSequence(void *pSeq) { + return static_cast(pSeq); + } + + static Map *AsMap(void *pMap) { return static_cast(pMap); } + }; + + void *BuildGraphOfNextDocument(Parser &parser, + GraphBuilderInterface &graphBuilder); + + template + typename Impl::Node *BuildGraphOfNextDocument(Parser &parser, Impl &impl) { + GraphBuilder graphBuilder(impl); + return static_cast( + BuildGraphOfNextDocument(parser, graphBuilder)); + } +} + +#endif // GRAPHBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/depthguard.h b/yaml-cpp/include/yaml-cpp/depthguard.h new file mode 100644 index 0000000..7c2566f --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/depthguard.h @@ -0,0 +1,80 @@ +#ifndef DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 +#define DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "exceptions.h" + +namespace YAML { + +/** + * @brief The DeepRecursion class + * An exception class which is thrown by DepthGuard. Ideally it should be + * a member of DepthGuard. However, DepthGuard is a templated class which means + * that any catch points would then need to know the template parameters. It is + * simpler for clients to not have to know at the catch point what was the + * maximum depth. + */ + class DeepRecursion : public ParserException { + public: + virtual ~DeepRecursion() = default; + + DeepRecursion(int depth, const Mark &mark_, const std::string &msg_); + + // Returns the recursion depth when the exception was thrown + int depth() const { + return m_depth; + } + + private: + int m_depth = 0; + }; + +/** + * @brief The DepthGuard class + * DepthGuard takes a reference to an integer. It increments the integer upon + * construction of DepthGuard and decrements the integer upon destruction. + * + * If the integer would be incremented past max_depth, then an exception is + * thrown. This is ideally geared toward guarding against deep recursion. + * + * @param max_depth + * compile-time configurable maximum depth. + */ + template + class DepthGuard final { + public: + DepthGuard(int &depth_, const Mark &mark_, const std::string &msg_) : m_depth(depth_) { + ++m_depth; + if (max_depth <= m_depth) { + throw DeepRecursion{m_depth, mark_, msg_}; + } + } + + DepthGuard(const DepthGuard ©_ctor) = delete; + + DepthGuard(DepthGuard &&move_ctor) = delete; + + DepthGuard &operator=(const DepthGuard ©_assign) = delete; + + DepthGuard &operator=(DepthGuard &&move_assign) = delete; + + ~DepthGuard() { + --m_depth; + } + + int current_depth() const { + return m_depth; + } + + private: + int &m_depth; + }; + +} // namespace YAML + +#endif // DEPTH_GUARD_H_00000000000000000000000000000000000000000000000000000000 diff --git a/yaml-cpp/include/yaml-cpp/dll.h b/yaml-cpp/include/yaml-cpp/dll.h new file mode 100644 index 0000000..34913b3 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/dll.h @@ -0,0 +1,33 @@ +#ifndef DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +// The following ifdef block is the standard way of creating macros which make +// exporting from a DLL simpler. All files within this DLL are compiled with the +// yaml_cpp_EXPORTS symbol defined on the command line. This symbol should not +// be defined on any project that uses this DLL. This way any other project +// whose source files include this file see YAML_CPP_API functions as being +// imported from a DLL, whereas this DLL sees symbols defined with this macro as +// being exported. +#undef YAML_CPP_API + +#ifdef YAML_CPP_DLL // Using or Building YAML-CPP DLL (definition defined +// manually) +#ifdef yaml_cpp_EXPORTS // Building YAML-CPP DLL (definition created by CMake +// or defined manually) +// #pragma message( "Defining YAML_CPP_API for DLL export" ) +#define YAML_CPP_API __declspec(dllexport) +#else // yaml_cpp_EXPORTS +// #pragma message( "Defining YAML_CPP_API for DLL import" ) +#define YAML_CPP_API __declspec(dllimport) +#endif // yaml_cpp_EXPORTS +#else // YAML_CPP_DLL +#define YAML_CPP_API +#endif // YAML_CPP_DLL + +#endif // DLL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/emitfromevents.h b/yaml-cpp/include/yaml-cpp/emitfromevents.h new file mode 100644 index 0000000..0c68084 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/emitfromevents.h @@ -0,0 +1,65 @@ +#ifndef EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/eventhandler.h" + +namespace YAML { + struct Mark; +} // namespace YAML + +namespace YAML { + class Emitter; + + class EmitFromEvents : public EventHandler { + public: + EmitFromEvents(Emitter &emitter); + + void OnDocumentStart(const Mark &mark) override; + + void OnDocumentEnd() override; + + void OnNull(const Mark &mark, anchor_t anchor) override; + + void OnAlias(const Mark &mark, anchor_t anchor) override; + + void OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value) override; + + void OnSequenceStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) override; + + void OnSequenceEnd() override; + + void OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) override; + + void OnMapEnd() override; + + private: + void BeginNode(); + + void EmitProps(const std::string &tag, anchor_t anchor); + + private: + Emitter &m_emitter; + + struct State { + enum value { + WaitingForSequenceEntry, WaitingForKey, WaitingForValue + }; + }; + std::stack m_stateStack; + }; +} + +#endif // EMITFROMEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/emitter.h b/yaml-cpp/include/yaml-cpp/emitter.h new file mode 100644 index 0000000..af8684d --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/emitter.h @@ -0,0 +1,343 @@ +#ifndef EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "yaml-cpp/binary.h" +#include "yaml-cpp/dll.h" +#include "yaml-cpp/emitterdef.h" +#include "yaml-cpp/emittermanip.h" +#include "yaml-cpp/null.h" +#include "yaml-cpp/ostream_wrapper.h" + +namespace YAML { + class Binary; + + struct _Null; +} // namespace YAML + +namespace YAML { + class EmitterState; + + class YAML_CPP_API Emitter { + public: + Emitter(); + + explicit Emitter(std::ostream &stream); + + Emitter(const Emitter &) = delete; + + Emitter &operator=(const Emitter &) = delete; + + ~Emitter(); + + // output + const char *c_str() const; + + std::size_t size() const; + + // state checking + bool good() const; + + const std::string GetLastError() const; + + // global setters + bool SetOutputCharset(EMITTER_MANIP value); + + bool SetStringFormat(EMITTER_MANIP value); + + bool SetBoolFormat(EMITTER_MANIP value); + + bool SetIntBase(EMITTER_MANIP value); + + bool SetSeqFormat(EMITTER_MANIP value); + + bool SetMapFormat(EMITTER_MANIP value); + + bool SetIndent(std::size_t n); + + bool SetPreCommentIndent(std::size_t n); + + bool SetPostCommentIndent(std::size_t n); + + bool SetFloatPrecision(std::size_t n); + + bool SetDoublePrecision(std::size_t n); + + // local setters + Emitter &SetLocalValue(EMITTER_MANIP value); + + Emitter &SetLocalIndent(const _Indent &indent); + + Emitter &SetLocalPrecision(const _Precision &precision); + + // overloads of write + Emitter &Write(const std::string &str); + + Emitter &Write(bool b); + + Emitter &Write(char ch); + + Emitter &Write(const _Alias &alias); + + Emitter &Write(const _Anchor &anchor); + + Emitter &Write(const _Tag &tag); + + Emitter &Write(const _Comment &comment); + + Emitter &Write(const _Null &n); + + Emitter &Write(const Binary &binary); + + template + Emitter &WriteIntegralType(T value); + + template + Emitter &WriteStreamable(T value); + + private: + template + void SetStreamablePrecision(std::stringstream &) {} + + std::size_t GetFloatPrecision() const; + + std::size_t GetDoublePrecision() const; + + void PrepareIntegralStream(std::stringstream &stream) const; + + void StartedScalar(); + + private: + void EmitBeginDoc(); + + void EmitEndDoc(); + + void EmitBeginSeq(); + + void EmitEndSeq(); + + void EmitBeginMap(); + + void EmitEndMap(); + + void EmitNewline(); + + void EmitKindTag(); + + void EmitTag(bool verbatim, const _Tag &tag); + + void PrepareNode(EmitterNodeType::value child); + + void PrepareTopNode(EmitterNodeType::value child); + + void FlowSeqPrepareNode(EmitterNodeType::value child); + + void BlockSeqPrepareNode(EmitterNodeType::value child); + + void FlowMapPrepareNode(EmitterNodeType::value child); + + void FlowMapPrepareLongKey(EmitterNodeType::value child); + + void FlowMapPrepareLongKeyValue(EmitterNodeType::value child); + + void FlowMapPrepareSimpleKey(EmitterNodeType::value child); + + void FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child); + + void BlockMapPrepareNode(EmitterNodeType::value child); + + void BlockMapPrepareLongKey(EmitterNodeType::value child); + + void BlockMapPrepareLongKeyValue(EmitterNodeType::value child); + + void BlockMapPrepareSimpleKey(EmitterNodeType::value child); + + void BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child); + + void SpaceOrIndentTo(bool requireSpace, std::size_t indent); + + const char *ComputeFullBoolName(bool b) const; + + bool CanEmitNewline() const; + + private: + std::unique_ptr m_pState; + ostream_wrapper m_stream; + }; + + template + inline Emitter &Emitter::WriteIntegralType(T value) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + + std::stringstream stream; + PrepareIntegralStream(stream); + stream << value; + m_stream << stream.str(); + + StartedScalar(); + + return *this; + } + + template + inline Emitter &Emitter::WriteStreamable(T value) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + + std::stringstream stream; + SetStreamablePrecision(stream); + + bool special = false; + if (std::is_floating_point::value) { + if ((std::numeric_limits::has_quiet_NaN || + std::numeric_limits::has_signaling_NaN) && + std::isnan(value)) { + special = true; + stream << ".nan"; + } else if (std::numeric_limits::has_infinity && std::isinf(value)) { + special = true; + if (std::signbit(value)) { + stream << "-.inf"; + } else { + stream << ".inf"; + } + } + } + + if (!special) { + stream << value; + } + m_stream << stream.str(); + + StartedScalar(); + + return *this; + } + + template<> + inline void Emitter::SetStreamablePrecision(std::stringstream &stream) { + stream.precision(static_cast(GetFloatPrecision())); + } + + template<> + inline void Emitter::SetStreamablePrecision(std::stringstream &stream) { + stream.precision(static_cast(GetDoublePrecision())); + } + +// overloads of insertion + inline Emitter &operator<<(Emitter &emitter, const std::string &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, bool v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, char v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, unsigned char v) { + return emitter.Write(static_cast(v)); + } + + inline Emitter &operator<<(Emitter &emitter, const _Alias &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, const _Anchor &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, const _Tag &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, const _Comment &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, const _Null &v) { + return emitter.Write(v); + } + + inline Emitter &operator<<(Emitter &emitter, const Binary &b) { + return emitter.Write(b); + } + + inline Emitter &operator<<(Emitter &emitter, const char *v) { + return emitter.Write(std::string(v)); + } + + inline Emitter &operator<<(Emitter &emitter, int v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, unsigned int v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, short v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, unsigned short v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, long v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, unsigned long v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, long long v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, unsigned long long v) { + return emitter.WriteIntegralType(v); + } + + inline Emitter &operator<<(Emitter &emitter, float v) { + return emitter.WriteStreamable(v); + } + + inline Emitter &operator<<(Emitter &emitter, double v) { + return emitter.WriteStreamable(v); + } + + inline Emitter &operator<<(Emitter &emitter, EMITTER_MANIP value) { + return emitter.SetLocalValue(value); + } + + inline Emitter &operator<<(Emitter &emitter, _Indent indent) { + return emitter.SetLocalIndent(indent); + } + + inline Emitter &operator<<(Emitter &emitter, _Precision precision) { + return emitter.SetLocalPrecision(precision); + } +} // namespace YAML + +#endif // EMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/emitterdef.h b/yaml-cpp/include/yaml-cpp/emitterdef.h new file mode 100644 index 0000000..7676dec --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/emitterdef.h @@ -0,0 +1,18 @@ +#ifndef EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +namespace YAML { + struct EmitterNodeType { + enum value { + NoType, Property, Scalar, FlowSeq, BlockSeq, FlowMap, BlockMap + }; + }; +} + +#endif // EMITTERDEF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/emittermanip.h b/yaml-cpp/include/yaml-cpp/emittermanip.h new file mode 100644 index 0000000..763f0c2 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/emittermanip.h @@ -0,0 +1,144 @@ +#ifndef EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +namespace YAML { + enum EMITTER_MANIP { + // general manipulators + Auto, + TagByKind, + Newline, + + // output character set + EmitNonAscii, + EscapeNonAscii, + + // string manipulators + // Auto, // duplicate + SingleQuoted, + DoubleQuoted, + Literal, + + // bool manipulators + YesNoBool, // yes, no + TrueFalseBool, // true, false + OnOffBool, // on, off + UpperCase, // TRUE, N + LowerCase, // f, yes + CamelCase, // No, Off + LongBool, // yes, On + ShortBool, // y, t + + // int manipulators + Dec, + Hex, + Oct, + + // document manipulators + BeginDoc, + EndDoc, + + // sequence manipulators + BeginSeq, + EndSeq, + Flow, + Block, + + // map manipulators + BeginMap, + EndMap, + Key, + Value, + // Flow, // duplicate + // Block, // duplicate + // Auto, // duplicate + LongKey + }; + + struct _Indent { + _Indent(int value_) : value(value_) {} + + int value; + }; + + inline _Indent Indent(int value) { return _Indent(value); } + + struct _Alias { + _Alias(const std::string &content_) : content(content_) {} + + std::string content; + }; + + inline _Alias Alias(const std::string &content) { return _Alias(content); } + + struct _Anchor { + _Anchor(const std::string &content_) : content(content_) {} + + std::string content; + }; + + inline _Anchor Anchor(const std::string &content) { return _Anchor(content); } + + struct _Tag { + struct Type { + enum value { + Verbatim, PrimaryHandle, NamedHandle + }; + }; + + explicit _Tag(const std::string &prefix_, const std::string &content_, + Type::value type_) + : prefix(prefix_), content(content_), type(type_) {} + + std::string prefix; + std::string content; + Type::value type; + }; + + inline _Tag VerbatimTag(const std::string &content) { + return _Tag("", content, _Tag::Type::Verbatim); + } + + inline _Tag LocalTag(const std::string &content) { + return _Tag("", content, _Tag::Type::PrimaryHandle); + } + + inline _Tag LocalTag(const std::string &prefix, const std::string content) { + return _Tag(prefix, content, _Tag::Type::NamedHandle); + } + + inline _Tag SecondaryTag(const std::string &content) { + return _Tag("", content, _Tag::Type::NamedHandle); + } + + struct _Comment { + _Comment(const std::string &content_) : content(content_) {} + + std::string content; + }; + + inline _Comment Comment(const std::string &content) { return _Comment(content); } + + struct _Precision { + _Precision(int floatPrecision_, int doublePrecision_) + : floatPrecision(floatPrecision_), doublePrecision(doublePrecision_) {} + + int floatPrecision; + int doublePrecision; + }; + + inline _Precision FloatPrecision(int n) { return _Precision(n, -1); } + + inline _Precision DoublePrecision(int n) { return _Precision(-1, n); } + + inline _Precision Precision(int n) { return _Precision(n, n); } +} + +#endif // EMITTERMANIP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/emitterstyle.h b/yaml-cpp/include/yaml-cpp/emitterstyle.h new file mode 100644 index 0000000..4e89578 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/emitterstyle.h @@ -0,0 +1,18 @@ +#ifndef EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +namespace YAML { + struct EmitterStyle { + enum value { + Default, Block, Flow + }; + }; +} + +#endif // EMITTERSTYLE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/eventhandler.h b/yaml-cpp/include/yaml-cpp/eventhandler.h new file mode 100644 index 0000000..c768d05 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/eventhandler.h @@ -0,0 +1,50 @@ +#ifndef EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/emitterstyle.h" + +namespace YAML { + struct Mark; + + class EventHandler { + public: + virtual ~EventHandler() = default; + + virtual void OnDocumentStart(const Mark &mark) = 0; + + virtual void OnDocumentEnd() = 0; + + virtual void OnNull(const Mark &mark, anchor_t anchor) = 0; + + virtual void OnAlias(const Mark &mark, anchor_t anchor) = 0; + + virtual void OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value) = 0; + + virtual void OnSequenceStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) = 0; + + virtual void OnSequenceEnd() = 0; + + virtual void OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) = 0; + + virtual void OnMapEnd() = 0; + + virtual void OnAnchor(const Mark & /*mark*/, + const std::string & /*anchor_name*/) { + // empty default implementation for compatibility + } + }; +} // namespace YAML + +#endif // EVENTHANDLER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/exceptions.h b/yaml-cpp/include/yaml-cpp/exceptions.h new file mode 100644 index 0000000..ebcc0c5 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/exceptions.h @@ -0,0 +1,317 @@ +#ifndef EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/mark.h" +#include "yaml-cpp/noexcept.h" +#include "yaml-cpp/traits.h" +#include +#include +#include + +namespace YAML { +// error messages + namespace ErrorMsg { + const char *const YAML_DIRECTIVE_ARGS = + "YAML directives must have exactly one argument"; + const char *const YAML_VERSION = "bad YAML version: "; + const char *const YAML_MAJOR_VERSION = "YAML major version too large"; + const char *const REPEATED_YAML_DIRECTIVE = "repeated YAML directive"; + const char *const TAG_DIRECTIVE_ARGS = + "TAG directives must have exactly two arguments"; + const char *const REPEATED_TAG_DIRECTIVE = "repeated TAG directive"; + const char *const CHAR_IN_TAG_HANDLE = + "illegal character found while scanning tag handle"; + const char *const TAG_WITH_NO_SUFFIX = "tag handle with no suffix"; + const char *const END_OF_VERBATIM_TAG = "end of verbatim tag not found"; + const char *const END_OF_MAP = "end of map not found"; + const char *const END_OF_MAP_FLOW = "end of map flow not found"; + const char *const END_OF_SEQ = "end of sequence not found"; + const char *const END_OF_SEQ_FLOW = "end of sequence flow not found"; + const char *const MULTIPLE_TAGS = + "cannot assign multiple tags to the same node"; + const char *const MULTIPLE_ANCHORS = + "cannot assign multiple anchors to the same node"; + const char *const MULTIPLE_ALIASES = + "cannot assign multiple aliases to the same node"; + const char *const ALIAS_CONTENT = + "aliases can't have any content, *including* tags"; + const char *const INVALID_HEX = "bad character found while scanning hex number"; + const char *const INVALID_UNICODE = "invalid unicode: "; + const char *const INVALID_ESCAPE = "unknown escape character: "; + const char *const UNKNOWN_TOKEN = "unknown token"; + const char *const DOC_IN_SCALAR = "illegal document indicator in scalar"; + const char *const EOF_IN_SCALAR = "illegal EOF in scalar"; + const char *const CHAR_IN_SCALAR = "illegal character in scalar"; + const char *const TAB_IN_INDENTATION = + "illegal tab when looking for indentation"; + const char *const FLOW_END = "illegal flow end"; + const char *const BLOCK_ENTRY = "illegal block entry"; + const char *const MAP_KEY = "illegal map key"; + const char *const MAP_VALUE = "illegal map value"; + const char *const ALIAS_NOT_FOUND = "alias not found after *"; + const char *const ANCHOR_NOT_FOUND = "anchor not found after &"; + const char *const CHAR_IN_ALIAS = + "illegal character found while scanning alias"; + const char *const CHAR_IN_ANCHOR = + "illegal character found while scanning anchor"; + const char *const ZERO_INDENT_IN_BLOCK = + "cannot set zero indentation for a block scalar"; + const char *const CHAR_IN_BLOCK = "unexpected character in block scalar"; + const char *const AMBIGUOUS_ANCHOR = + "cannot assign the same alias to multiple nodes"; + const char *const UNKNOWN_ANCHOR = "the referenced anchor is not defined"; + + const char *const INVALID_NODE = + "invalid node; this may result from using a map iterator as a sequence " + "iterator, or vice-versa"; + const char *const INVALID_SCALAR = "invalid scalar"; + const char *const KEY_NOT_FOUND = "key not found"; + const char *const BAD_CONVERSION = "bad conversion"; + const char *const BAD_DEREFERENCE = "bad dereference"; + const char *const BAD_SUBSCRIPT = "operator[] call on a scalar"; + const char *const BAD_PUSHBACK = "appending to a non-sequence"; + const char *const BAD_INSERT = "inserting in a non-convertible-to-map"; + + const char *const UNMATCHED_GROUP_TAG = "unmatched group tag"; + const char *const UNEXPECTED_END_SEQ = "unexpected end sequence token"; + const char *const UNEXPECTED_END_MAP = "unexpected end map token"; + const char *const SINGLE_QUOTED_CHAR = + "invalid character in single-quoted string"; + const char *const INVALID_ANCHOR = "invalid anchor"; + const char *const INVALID_ALIAS = "invalid alias"; + const char *const INVALID_TAG = "invalid tag"; + const char *const BAD_FILE = "bad file"; + + template + inline const std::string KEY_NOT_FOUND_WITH_KEY( + const T &, typename disable_if>::type * = 0) { + return KEY_NOT_FOUND; + } + + inline const std::string KEY_NOT_FOUND_WITH_KEY(const std::string &key) { + std::stringstream stream; + stream << KEY_NOT_FOUND << ": " << key; + return stream.str(); + } + + template + inline const std::string KEY_NOT_FOUND_WITH_KEY( + const T &key, typename enable_if>::type * = 0) { + std::stringstream stream; + stream << KEY_NOT_FOUND << ": " << key; + return stream.str(); + } + + template + inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T &, typename disable_if>::type * = nullptr) { + return BAD_SUBSCRIPT; + } + + inline const std::string BAD_SUBSCRIPT_WITH_KEY(const std::string &key) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")"; + return stream.str(); + } + + template + inline const std::string BAD_SUBSCRIPT_WITH_KEY( + const T &key, typename enable_if>::type * = nullptr) { + std::stringstream stream; + stream << BAD_SUBSCRIPT << " (key: \"" << key << "\")"; + return stream.str(); + } + + inline const std::string INVALID_NODE_WITH_KEY(const std::string &key) { + std::stringstream stream; + if (key.empty()) { + return INVALID_NODE; + } + stream << "invalid node; first invalid key: \"" << key << "\""; + return stream.str(); + } + } // namespace ErrorMsg + + class YAML_CPP_API Exception : public std::runtime_error { + public: + Exception(const Mark &mark_, const std::string &msg_) + : std::runtime_error(build_what(mark_, msg_)), mark(mark_), msg(msg_) {} + + ~Exception() YAML_CPP_NOEXCEPT override; + + Exception(const Exception &) = default; + + Mark mark; + std::string msg; + + private: + static const std::string build_what(const Mark &mark, + const std::string &msg) { + if (mark.is_null()) { + return msg; + } + + std::stringstream output; + output << "yaml-cpp: error at line " << mark.line + 1 << ", column " + << mark.column + 1 << ": " << msg; + return output.str(); + } + }; + + class YAML_CPP_API ParserException : public Exception { + public: + ParserException(const Mark &mark_, const std::string &msg_) + : Exception(mark_, msg_) {} + + ParserException(const ParserException &) = default; + + ~ParserException() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API RepresentationException : public Exception { + public: + RepresentationException(const Mark &mark_, const std::string &msg_) + : Exception(mark_, msg_) {} + + RepresentationException(const RepresentationException &) = default; + + ~RepresentationException() YAML_CPP_NOEXCEPT override; + }; + +// representation exceptions + class YAML_CPP_API InvalidScalar : public RepresentationException { + public: + InvalidScalar(const Mark &mark_) + : RepresentationException(mark_, ErrorMsg::INVALID_SCALAR) {} + + InvalidScalar(const InvalidScalar &) = default; + + ~InvalidScalar() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API KeyNotFound : public RepresentationException { + public: + template + KeyNotFound(const Mark &mark_, const T &key_) + : RepresentationException(mark_, ErrorMsg::KEY_NOT_FOUND_WITH_KEY(key_)) { + } + + KeyNotFound(const KeyNotFound &) = default; + + ~KeyNotFound() YAML_CPP_NOEXCEPT override; + }; + + template + class YAML_CPP_API TypedKeyNotFound : public KeyNotFound { + public: + TypedKeyNotFound(const Mark &mark_, const T &key_) + : KeyNotFound(mark_, key_), key(key_) {} + + ~TypedKeyNotFound() YAML_CPP_NOEXCEPT override = default; + + T key; + }; + + template + inline TypedKeyNotFound MakeTypedKeyNotFound(const Mark &mark, + const T &key) { + return TypedKeyNotFound(mark, key); + } + + class YAML_CPP_API InvalidNode : public RepresentationException { + public: + InvalidNode(const std::string &key) + : RepresentationException(Mark::null_mark(), + ErrorMsg::INVALID_NODE_WITH_KEY(key)) {} + + InvalidNode(const InvalidNode &) = default; + + ~InvalidNode() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API BadConversion : public RepresentationException { + public: + explicit BadConversion(const Mark &mark_) + : RepresentationException(mark_, ErrorMsg::BAD_CONVERSION) {} + + BadConversion(const BadConversion &) = default; + + ~BadConversion() YAML_CPP_NOEXCEPT override; + }; + + template + class TypedBadConversion : public BadConversion { + public: + explicit TypedBadConversion(const Mark &mark_) : BadConversion(mark_) {} + }; + + class YAML_CPP_API BadDereference : public RepresentationException { + public: + BadDereference() + : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_DEREFERENCE) {} + + BadDereference(const BadDereference &) = default; + + ~BadDereference() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API BadSubscript : public RepresentationException { + public: + template + BadSubscript(const Mark &mark_, const Key &key) + : RepresentationException(mark_, ErrorMsg::BAD_SUBSCRIPT_WITH_KEY(key)) {} + + BadSubscript(const BadSubscript &) = default; + + ~BadSubscript() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API BadPushback : public RepresentationException { + public: + BadPushback() + : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_PUSHBACK) {} + + BadPushback(const BadPushback &) = default; + + ~BadPushback() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API BadInsert : public RepresentationException { + public: + BadInsert() + : RepresentationException(Mark::null_mark(), ErrorMsg::BAD_INSERT) {} + + BadInsert(const BadInsert &) = default; + + ~BadInsert() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API EmitterException : public Exception { + public: + EmitterException(const std::string &msg_) + : Exception(Mark::null_mark(), msg_) {} + + EmitterException(const EmitterException &) = default; + + ~EmitterException() YAML_CPP_NOEXCEPT override; + }; + + class YAML_CPP_API BadFile : public Exception { + public: + explicit BadFile(const std::string &filename) + : Exception(Mark::null_mark(), + std::string(ErrorMsg::BAD_FILE) + ": " + filename) {} + + BadFile(const BadFile &) = default; + + ~BadFile() YAML_CPP_NOEXCEPT override; + }; +} // namespace YAML + +#endif // EXCEPTIONS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/mark.h b/yaml-cpp/include/yaml-cpp/mark.h new file mode 100644 index 0000000..932abdc --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/mark.h @@ -0,0 +1,29 @@ +#ifndef MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" + +namespace YAML { + struct YAML_CPP_API Mark { + Mark() : pos(0), line(0), column(0) {} + + static const Mark null_mark() { return Mark(-1, -1, -1); } + + bool is_null() const { return pos == -1 && line == -1 && column == -1; } + + int pos; + int line, column; + + private: + Mark(int pos_, int line_, int column_) + : pos(pos_), line(line_), column(column_) {} + }; +} + +#endif // MARK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/convert.h b/yaml-cpp/include/yaml-cpp/node/convert.h new file mode 100644 index 0000000..18c2be0 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/convert.h @@ -0,0 +1,374 @@ +#ifndef NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include +#include + +#include "yaml-cpp/binary.h" +#include "yaml-cpp/node/impl.h" +#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/type.h" +#include "yaml-cpp/null.h" + + +namespace YAML { + class Binary; + + struct _Null; + template + struct convert; +} // namespace YAML + +namespace YAML { + namespace conversion { + inline bool IsInfinity(const std::string &input) { + return input == ".inf" || input == ".Inf" || input == ".INF" || + input == "+.inf" || input == "+.Inf" || input == "+.INF"; + } + + inline bool IsNegativeInfinity(const std::string &input) { + return input == "-.inf" || input == "-.Inf" || input == "-.INF"; + } + + inline bool IsNaN(const std::string &input) { + return input == ".nan" || input == ".NaN" || input == ".NAN"; + } + } + +// Node + template<> + struct convert { + static Node encode(const Node &rhs) { return rhs; } + + static bool decode(const Node &node, Node &rhs) { + rhs.reset(node); + return true; + } + }; + +// std::string + template<> + struct convert { + static Node encode(const std::string &rhs) { return Node(rhs); } + + static bool decode(const Node &node, std::string &rhs) { + if (!node.IsScalar()) + return false; + rhs = node.Scalar(); + return true; + } + }; + +// C-strings can only be encoded + template<> + struct convert { + static Node encode(const char *&rhs) { return Node(rhs); } + }; + + template + struct convert { + static Node encode(const char(&rhs)[N]) { return Node(rhs); } + }; + + template<> + struct convert<_Null> { + static Node encode(const _Null & /* rhs */) { return Node(); } + + static bool decode(const Node &node, _Null & /* rhs */) { + return node.IsNull(); + } + }; + + namespace conversion { + template + typename std::enable_if::value, void>::type + inner_encode(const T &rhs, std::stringstream &stream) { + if (std::isnan(rhs)) { + stream << ".nan"; + } else if (std::isinf(rhs)) { + if (std::signbit(rhs)) { + stream << "-.inf"; + } else { + stream << ".inf"; + } + } else { + stream << rhs; + } + } + + template + typename std::enable_if::value, void>::type + inner_encode(const T &rhs, std::stringstream &stream) { + stream << rhs; + } + } + +#define YAML_DEFINE_CONVERT_STREAMABLE(type, negative_op) \ + template <> \ + struct convert { \ + \ + static Node encode(const type& rhs) { \ + std::stringstream stream; \ + stream.precision(std::numeric_limits::max_digits10); \ + conversion::inner_encode(rhs, stream); \ + return Node(stream.str()); \ + } \ + \ + static bool decode(const Node& node, type& rhs) { \ + if (node.Type() != NodeType::Scalar) { \ + return false; \ + } \ + const std::string& input = node.Scalar(); \ + std::stringstream stream(input); \ + stream.unsetf(std::ios::dec); \ + if ((stream >> std::noskipws >> rhs) && (stream >> std::ws).eof()) { \ + return true; \ + } \ + if (std::numeric_limits::has_infinity) { \ + if (conversion::IsInfinity(input)) { \ + rhs = std::numeric_limits::infinity(); \ + return true; \ + } else if (conversion::IsNegativeInfinity(input)) { \ + rhs = negative_op std::numeric_limits::infinity(); \ + return true; \ + } \ + } \ + \ + if (std::numeric_limits::has_quiet_NaN) { \ + if (conversion::IsNaN(input)) { \ + rhs = std::numeric_limits::quiet_NaN(); \ + return true; \ + } \ + } \ + \ + return false; \ + } \ + } + +#define YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(type) \ + YAML_DEFINE_CONVERT_STREAMABLE(type, -) + +#define YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(type) \ + YAML_DEFINE_CONVERT_STREAMABLE(type, +) + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(int); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(short); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long long); + + YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned); + + YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned short); + + YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long); + + YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned long long); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(char); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(signed char); + + YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED(unsigned char); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(float); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(double); + + YAML_DEFINE_CONVERT_STREAMABLE_SIGNED(long double); + +#undef YAML_DEFINE_CONVERT_STREAMABLE_SIGNED +#undef YAML_DEFINE_CONVERT_STREAMABLE_UNSIGNED +#undef YAML_DEFINE_CONVERT_STREAMABLE + +// bool + template<> + struct convert { + static Node encode(bool rhs) { return rhs ? Node("true") : Node("false"); } + + YAML_CPP_API static bool decode(const Node &node, bool &rhs); + }; + +// std::map + template + struct convert> { + static Node encode(const std::map &rhs) { + Node node(NodeType::Map); + for (typename std::map::const_iterator it = rhs.begin(); + it != rhs.end(); ++it) + node.force_insert(it->first, it->second); + return node; + } + + static bool decode(const Node &node, std::map &rhs) { + if (!node.IsMap()) + return false; + + rhs.clear(); + for (const_iterator it = node.begin(); it != node.end(); ++it) +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs[it->first.template as()] = it->second.template as(); +#else + rhs[it->first.as()] = it->second.as(); +#endif + return true; + } + }; + +// std::vector + template + struct convert> { + static Node encode(const std::vector &rhs) { + Node node(NodeType::Sequence); + for (typename std::vector::const_iterator it = rhs.begin(); + it != rhs.end(); ++it) + node.push_back(*it); + return node; + } + + static bool decode(const Node &node, std::vector &rhs) { + if (!node.IsSequence()) + return false; + + rhs.clear(); + for (const_iterator it = node.begin(); it != node.end(); ++it) +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs.push_back(it->template as()); +#else + rhs.push_back(it->as()); +#endif + return true; + } + }; + +// std::list + template + struct convert> { + static Node encode(const std::list &rhs) { + Node node(NodeType::Sequence); + for (typename std::list::const_iterator it = rhs.begin(); + it != rhs.end(); ++it) + node.push_back(*it); + return node; + } + + static bool decode(const Node &node, std::list &rhs) { + if (!node.IsSequence()) + return false; + + rhs.clear(); + for (const_iterator it = node.begin(); it != node.end(); ++it) +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs.push_back(it->template as()); +#else + rhs.push_back(it->as()); +#endif + return true; + } + }; + +// std::array + template + struct convert> { + static Node encode(const std::array &rhs) { + Node node(NodeType::Sequence); + for (const auto &element : rhs) { + node.push_back(element); + } + return node; + } + + static bool decode(const Node &node, std::array &rhs) { + if (!isNodeValid(node)) { + return false; + } + + for (auto i = 0u; i < node.size(); ++i) { +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs[i] = node[i].template as(); +#else + rhs[i] = node[i].as(); +#endif + } + return true; + } + + private: + static bool isNodeValid(const Node &node) { + return node.IsSequence() && node.size() == N; + } + }; + +// std::pair + template + struct convert> { + static Node encode(const std::pair &rhs) { + Node node(NodeType::Sequence); + node.push_back(rhs.first); + node.push_back(rhs.second); + return node; + } + + static bool decode(const Node &node, std::pair &rhs) { + if (!node.IsSequence()) + return false; + if (node.size() != 2) + return false; + +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs.first = node[0].template as(); +#else + rhs.first = node[0].as(); +#endif +#if defined(__GNUC__) && __GNUC__ < 4 + // workaround for GCC 3: + rhs.second = node[1].template as(); +#else + rhs.second = node[1].as(); +#endif + return true; + } + }; + +// binary + template<> + struct convert { + static Node encode(const Binary &rhs) { + return Node(EncodeBase64(rhs.data(), rhs.size())); + } + + static bool decode(const Node &node, Binary &rhs) { + if (!node.IsScalar()) + return false; + + std::vector data = DecodeBase64(node.Scalar()); + if (data.empty() && !node.Scalar().empty()) + return false; + + rhs.swap(data); + return true; + } + }; +} + +#endif // NODE_CONVERT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/impl.h b/yaml-cpp/include/yaml-cpp/node/detail/impl.h new file mode 100644 index 0000000..86c57d9 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/impl.h @@ -0,0 +1,226 @@ +#ifndef NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/node/detail/node.h" +#include "yaml-cpp/node/detail/node_data.h" +#include + +namespace YAML { + namespace detail { + template + struct get_idx { + static node *get(const std::vector & /* sequence */, + const Key & /* key */, shared_memory_holder /* pMemory */) { + return nullptr; + } + }; + + template + struct get_idx::value && + !std::is_same::value>::type> { + static node *get(const std::vector &sequence, const Key &key, + shared_memory_holder /* pMemory */) { + return key < sequence.size() ? sequence[key] : nullptr; + } + + static node *get(std::vector &sequence, const Key &key, + shared_memory_holder pMemory) { + if (key > sequence.size() || (key > 0 && !sequence[key - 1]->is_defined())) + return nullptr; + if (key == sequence.size()) + sequence.push_back(&pMemory->create_node()); + return sequence[key]; + } + }; + + template + struct get_idx::value>::type> { + static node *get(const std::vector &sequence, const Key &key, + shared_memory_holder pMemory) { + return key >= 0 ? get_idx::get( + sequence, static_cast(key), pMemory) + : nullptr; + } + + static node *get(std::vector &sequence, const Key &key, + shared_memory_holder pMemory) { + return key >= 0 ? get_idx::get( + sequence, static_cast(key), pMemory) + : nullptr; + } + }; + + template + struct remove_idx { + static bool remove(std::vector &, const Key &, std::size_t &) { + return false; + } + }; + + template + struct remove_idx< + Key, typename std::enable_if::value && + !std::is_same::value>::type> { + + static bool remove(std::vector &sequence, const Key &key, + std::size_t &seqSize) { + if (key >= sequence.size()) { + return false; + } else { + sequence.erase(sequence.begin() + key); + if (seqSize > key) { + --seqSize; + } + return true; + } + } + }; + + template + struct remove_idx::value>::type> { + + static bool remove(std::vector &sequence, const Key &key, + std::size_t &seqSize) { + return key >= 0 ? remove_idx::remove( + sequence, static_cast(key), seqSize) + : false; + } + }; + + template + inline bool node::equals(const T &rhs, shared_memory_holder pMemory) { + T lhs; + if (convert::decode(Node(*this, pMemory), lhs)) { + return lhs == rhs; + } + return false; + } + + inline bool node::equals(const char *rhs, shared_memory_holder pMemory) { + return equals < std::string > (rhs, pMemory); + } + +// indexing + template + inline node *node_data::get(const Key &key, + shared_memory_holder pMemory) const { + switch (m_type) { + case NodeType::Map: + break; + case NodeType::Undefined: + case NodeType::Null: + return nullptr; + case NodeType::Sequence: + if (node *pNode = get_idx::get(m_sequence, key, pMemory)) + return pNode; + return nullptr; + case NodeType::Scalar: + throw BadSubscript(m_mark, key); + } + + for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->first->equals(key, pMemory)) { + return it->second; + } + } + + return nullptr; + } + + template + inline node &node_data::get(const Key &key, shared_memory_holder pMemory) { + switch (m_type) { + case NodeType::Map: + break; + case NodeType::Undefined: + case NodeType::Null: + case NodeType::Sequence: + if (node *pNode = get_idx::get(m_sequence, key, pMemory)) { + m_type = NodeType::Sequence; + return *pNode; + } + + convert_to_map(pMemory); + break; + case NodeType::Scalar: + throw BadSubscript(m_mark, key); + } + + for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->first->equals(key, pMemory)) { + return *it->second; + } + } + + node &k = convert_to_node(key, pMemory); + node &v = pMemory->create_node(); + insert_map_pair(k, v); + return v; + } + + template + inline bool node_data::remove(const Key &key, shared_memory_holder pMemory) { + if (m_type == NodeType::Sequence) { + return remove_idx::remove(m_sequence, key, m_seqSize); + } else if (m_type == NodeType::Map) { + kv_pairs::iterator it = m_undefinedPairs.begin(); + while (it != m_undefinedPairs.end()) { + kv_pairs::iterator jt = std::next(it); + if (it->first->equals(key, pMemory)) { + m_undefinedPairs.erase(it); + } + it = jt; + } + + for (node_map::iterator iter = m_map.begin(); iter != m_map.end(); ++iter) { + if (iter->first->equals(key, pMemory)) { + m_map.erase(iter); + return true; + } + } + } + + return false; + } + +// map + template + inline void node_data::force_insert(const Key &key, const Value &value, + shared_memory_holder pMemory) { + switch (m_type) { + case NodeType::Map: + break; + case NodeType::Undefined: + case NodeType::Null: + case NodeType::Sequence: + convert_to_map(pMemory); + break; + case NodeType::Scalar: + throw BadInsert(); + } + + node &k = convert_to_node(key, pMemory); + node &v = convert_to_node(value, pMemory); + insert_map_pair(k, v); + } + + template + inline node &node_data::convert_to_node(const T &rhs, + shared_memory_holder pMemory) { + Node value = convert::encode(rhs); + value.EnsureNodeExists(); + pMemory->merge(*value.m_pMemory); + return *value.m_pNode; + } + } +} + +#endif // NODE_DETAIL_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/iterator.h b/yaml-cpp/include/yaml-cpp/node/detail/iterator.h new file mode 100644 index 0000000..8ba98fb --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/iterator.h @@ -0,0 +1,102 @@ +#ifndef VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/detail/node_iterator.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/ptr.h" +#include +#include + + +namespace YAML { + namespace detail { + struct iterator_value; + + template + class iterator_base { + + private: + template + friend + class iterator_base; + + struct enabler { + }; + using base_type = node_iterator; + + struct proxy { + explicit proxy(const V &x) : m_ref(x) {} + + V *operator->() { return std::addressof(m_ref); } + + operator V *() { return std::addressof(m_ref); } + + V m_ref; + }; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = V; + using difference_type = std::ptrdiff_t; + using pointer = V *; + using reference = V; + + public: + iterator_base() : m_iterator(), m_pMemory() {} + + explicit iterator_base(base_type rhs, shared_memory_holder pMemory) + : m_iterator(rhs), m_pMemory(pMemory) {} + + template + iterator_base(const iterator_base &rhs, + typename std::enable_if::value, + enabler>::type = enabler()) + : m_iterator(rhs.m_iterator), m_pMemory(rhs.m_pMemory) {} + + iterator_base &operator++() { + ++m_iterator; + return *this; + } + + iterator_base operator++(int) { + iterator_base iterator_pre(*this); + ++(*this); + return iterator_pre; + } + + template + bool operator==(const iterator_base &rhs) const { + return m_iterator == rhs.m_iterator; + } + + template + bool operator!=(const iterator_base &rhs) const { + return m_iterator != rhs.m_iterator; + } + + value_type operator*() const { + const typename base_type::value_type &v = *m_iterator; + if (v.pNode) + return value_type(Node(*v, m_pMemory)); + if (v.first && v.second) + return value_type(Node(*v.first, m_pMemory), Node(*v.second, m_pMemory)); + return value_type(); + } + + proxy operator->() const { return proxy(**this); } + + private: + base_type m_iterator; + shared_memory_holder m_pMemory; + }; + } // namespace detail +} // namespace YAML + +#endif // VALUE_DETAIL_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/iterator_fwd.h b/yaml-cpp/include/yaml-cpp/node/detail/iterator_fwd.h new file mode 100644 index 0000000..ee4d067 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/iterator_fwd.h @@ -0,0 +1,28 @@ +#ifndef VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include +#include +#include + +namespace YAML { + + namespace detail { + struct iterator_value; + + template + class iterator_base; + } + + using iterator = detail::iterator_base; + using const_iterator = detail::iterator_base; +} + +#endif // VALUE_DETAIL_ITERATOR_FWD_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/memory.h b/yaml-cpp/include/yaml-cpp/node/detail/memory.h new file mode 100644 index 0000000..adc0da8 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/memory.h @@ -0,0 +1,50 @@ +#ifndef VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/ptr.h" + +namespace YAML { + namespace detail { + class node; + } // namespace detail +} // namespace YAML + +namespace YAML { + namespace detail { + class YAML_CPP_API memory { + public: + memory() : m_nodes{} {} + + node &create_node(); + + void merge(const memory &rhs); + + private: + using Nodes = std::set; + Nodes m_nodes; + }; + + class YAML_CPP_API memory_holder { + public: + memory_holder() : m_pMemory(new memory) {} + + node &create_node() { return m_pMemory->create_node(); } + + void merge(memory_holder &rhs); + + private: + shared_memory m_pMemory; + }; + } // namespace detail +} // namespace YAML + +#endif // VALUE_DETAIL_MEMORY_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/node.h b/yaml-cpp/include/yaml-cpp/node/detail/node.h new file mode 100644 index 0000000..293a7ec --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/node.h @@ -0,0 +1,196 @@ +#ifndef NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/node/detail/node_ref.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/type.h" +#include +#include + +namespace YAML { + namespace detail { + class node { + private: + struct less { + bool operator()(const node *l, const node *r) const { return l->m_index < r->m_index; } + }; + + public: + node() : m_pRef(new node_ref), m_dependencies{} {} + + node(const node &) = delete; + + node &operator=(const node &) = delete; + + bool is(const node &rhs) const { return m_pRef == rhs.m_pRef; } + + const node_ref *ref() const { return m_pRef.get(); } + + bool is_defined() const { return m_pRef->is_defined(); } + + const Mark &mark() const { return m_pRef->mark(); } + + NodeType::value type() const { return m_pRef->type(); } + + const std::string &scalar() const { return m_pRef->scalar(); } + + const std::string &tag() const { return m_pRef->tag(); } + + EmitterStyle::value style() const { return m_pRef->style(); } + + template + bool equals(const T &rhs, shared_memory_holder pMemory); + + bool equals(const char *rhs, shared_memory_holder pMemory); + + void mark_defined() { + if (is_defined()) + return; + + m_pRef->mark_defined(); + for (node *dependency : m_dependencies) + dependency->mark_defined(); + m_dependencies.clear(); + } + + void add_dependency(node &rhs) { + if (is_defined()) + rhs.mark_defined(); + else + m_dependencies.insert(&rhs); + } + + void set_ref(const node &rhs) { + if (rhs.is_defined()) + mark_defined(); + m_pRef = rhs.m_pRef; + } + + void set_data(const node &rhs) { + if (rhs.is_defined()) + mark_defined(); + m_pRef->set_data(*rhs.m_pRef); + } + + void set_mark(const Mark &mark) { m_pRef->set_mark(mark); } + + void set_type(NodeType::value type) { + if (type != NodeType::Undefined) + mark_defined(); + m_pRef->set_type(type); + } + + void set_null() { + mark_defined(); + m_pRef->set_null(); + } + + void set_scalar(const std::string &scalar) { + mark_defined(); + m_pRef->set_scalar(scalar); + } + + void set_tag(const std::string &tag) { + mark_defined(); + m_pRef->set_tag(tag); + } + + // style + void set_style(EmitterStyle::value style) { + mark_defined(); + m_pRef->set_style(style); + } + + // size/iterator + std::size_t size() const { return m_pRef->size(); } + + const_node_iterator begin() const { + return static_cast(*m_pRef).begin(); + } + + node_iterator begin() { return m_pRef->begin(); } + + const_node_iterator end() const { + return static_cast(*m_pRef).end(); + } + + node_iterator end() { return m_pRef->end(); } + + // sequence + void push_back(node &input, shared_memory_holder pMemory) { + m_pRef->push_back(input, pMemory); + input.add_dependency(*this); + m_index = m_amount.fetch_add(1); + } + + void insert(node &key, node &value, shared_memory_holder pMemory) { + m_pRef->insert(key, value, pMemory); + key.add_dependency(*this); + value.add_dependency(*this); + } + + // indexing + template + node *get(const Key &key, shared_memory_holder pMemory) const { + // NOTE: this returns a non-const node so that the top-level Node can wrap + // it, and returns a pointer so that it can be nullptr (if there is no such + // key). + return static_cast(*m_pRef).get(key, pMemory); + } + + template + node &get(const Key &key, shared_memory_holder pMemory) { + node &value = m_pRef->get(key, pMemory); + value.add_dependency(*this); + return value; + } + + template + bool remove(const Key &key, shared_memory_holder pMemory) { + return m_pRef->remove(key, pMemory); + } + + node *get(node &key, shared_memory_holder pMemory) const { + // NOTE: this returns a non-const node so that the top-level Node can wrap + // it, and returns a pointer so that it can be nullptr (if there is no such + // key). + return static_cast(*m_pRef).get(key, pMemory); + } + + node &get(node &key, shared_memory_holder pMemory) { + node &value = m_pRef->get(key, pMemory); + key.add_dependency(*this); + value.add_dependency(*this); + return value; + } + + bool remove(node &key, shared_memory_holder pMemory) { + return m_pRef->remove(key, pMemory); + } + + // map + template + void force_insert(const Key &key, const Value &value, + shared_memory_holder pMemory) { + m_pRef->force_insert(key, value, pMemory); + } + + private: + shared_node_ref m_pRef; + using nodes = std::set; + nodes m_dependencies; + size_t m_index; + static std::atomic m_amount; + }; + } // namespace detail +} // namespace YAML + +#endif // NODE_DETAIL_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/node_data.h b/yaml-cpp/include/yaml-cpp/node/detail/node_data.h new file mode 100644 index 0000000..35c6867 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/node_data.h @@ -0,0 +1,151 @@ +#ifndef VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include +#include + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/detail/node_iterator.h" +#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/type.h" + +namespace YAML { + namespace detail { + class node; + } // namespace detail +} // namespace YAML + +namespace YAML { + namespace detail { + class YAML_CPP_API node_data { + public: + node_data(); + + node_data(const node_data &) = delete; + + node_data &operator=(const node_data &) = delete; + + void mark_defined(); + + void set_mark(const Mark &mark); + + void set_type(NodeType::value type); + + void set_tag(const std::string &tag); + + void set_null(); + + void set_scalar(const std::string &scalar); + + void set_style(EmitterStyle::value style); + + bool is_defined() const { return m_isDefined; } + + const Mark &mark() const { return m_mark; } + + NodeType::value type() const { + return m_isDefined ? m_type : NodeType::Undefined; + } + + const std::string &scalar() const { return m_scalar; } + + const std::string &tag() const { return m_tag; } + + EmitterStyle::value style() const { return m_style; } + + // size/iterator + std::size_t size() const; + + const_node_iterator begin() const; + + node_iterator begin(); + + const_node_iterator end() const; + + node_iterator end(); + + // sequence + void push_back(node &node, shared_memory_holder pMemory); + + void insert(node &key, node &value, shared_memory_holder pMemory); + + // indexing + template + node *get(const Key &key, shared_memory_holder pMemory) const; + + template + node &get(const Key &key, shared_memory_holder pMemory); + + template + bool remove(const Key &key, shared_memory_holder pMemory); + + node *get(node &key, shared_memory_holder pMemory) const; + + node &get(node &key, shared_memory_holder pMemory); + + bool remove(node &key, shared_memory_holder pMemory); + + // map + template + void force_insert(const Key &key, const Value &value, + shared_memory_holder pMemory); + + public: + static const std::string &empty_scalar(); + + private: + void compute_seq_size() const; + + void compute_map_size() const; + + void reset_sequence(); + + void reset_map(); + + void insert_map_pair(node &key, node &value); + + void convert_to_map(shared_memory_holder pMemory); + + void convert_sequence_to_map(shared_memory_holder pMemory); + + template + static node &convert_to_node(const T &rhs, shared_memory_holder pMemory); + + private: + bool m_isDefined; + Mark m_mark; + NodeType::value m_type; + std::string m_tag; + EmitterStyle::value m_style; + + // scalar + std::string m_scalar; + + // sequence + using node_seq = std::vector; + node_seq m_sequence; + + mutable std::size_t m_seqSize; + + // map + using node_map = std::vector>; + node_map m_map; + + using kv_pair = std::pair; + using kv_pairs = std::list; + mutable kv_pairs m_undefinedPairs; + }; + } +} + +#endif // VALUE_DETAIL_NODE_DATA_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/node_iterator.h b/yaml-cpp/include/yaml-cpp/node/detail/node_iterator.h new file mode 100644 index 0000000..6dd966e --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/node_iterator.h @@ -0,0 +1,192 @@ +#ifndef VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/ptr.h" +#include +#include +#include +#include +#include +#include + +namespace YAML { + namespace detail { + struct iterator_type { + enum value { + NoneType, Sequence, Map + }; + }; + + template + struct node_iterator_value : public std::pair { + using kv = std::pair; + + node_iterator_value() : kv(), pNode(nullptr) {} + + explicit node_iterator_value(V &rhs) : kv(), pNode(&rhs) {} + + explicit node_iterator_value(V &key, V &value) : kv(&key, &value), pNode(nullptr) {} + + V &operator*() const { return *pNode; } + + V &operator->() const { return *pNode; } + + V *pNode; + }; + + using node_seq = std::vector; + using node_map = std::vector>; + + template + struct node_iterator_type { + using seq = node_seq::iterator; + using map = node_map::iterator; + }; + + template + struct node_iterator_type { + using seq = node_seq::const_iterator; + using map = node_map::const_iterator; + }; + + template + class node_iterator_base { + private: + struct enabler { + }; + + struct proxy { + explicit proxy(const node_iterator_value &x) : m_ref(x) {} + + node_iterator_value *operator->() { return std::addressof(m_ref); } + + operator node_iterator_value *() { return std::addressof(m_ref); } + + node_iterator_value m_ref; + }; + + public: + using iterator_category = std::forward_iterator_tag; + using value_type = node_iterator_value; + using difference_type = std::ptrdiff_t; + using pointer = node_iterator_value *; + using reference = node_iterator_value; + using SeqIter = typename node_iterator_type::seq; + using MapIter = typename node_iterator_type::map; + + node_iterator_base() + : m_type(iterator_type::NoneType), m_seqIt(), m_mapIt(), m_mapEnd() {} + + explicit node_iterator_base(SeqIter seqIt) + : m_type(iterator_type::Sequence), + m_seqIt(seqIt), + m_mapIt(), + m_mapEnd() {} + + explicit node_iterator_base(MapIter mapIt, MapIter mapEnd) + : m_type(iterator_type::Map), + m_seqIt(), + m_mapIt(mapIt), + m_mapEnd(mapEnd) { + m_mapIt = increment_until_defined(m_mapIt); + } + + template + node_iterator_base(const node_iterator_base &rhs, + typename std::enable_if::value, + enabler>::type = enabler()) + : m_type(rhs.m_type), + m_seqIt(rhs.m_seqIt), + m_mapIt(rhs.m_mapIt), + m_mapEnd(rhs.m_mapEnd) {} + + template + friend + class node_iterator_base; + + template + bool operator==(const node_iterator_base &rhs) const { + if (m_type != rhs.m_type) + return false; + + switch (m_type) { + case iterator_type::NoneType: + return true; + case iterator_type::Sequence: + return m_seqIt == rhs.m_seqIt; + case iterator_type::Map: + return m_mapIt == rhs.m_mapIt; + } + return true; + } + + template + bool operator!=(const node_iterator_base &rhs) const { + return !(*this == rhs); + } + + node_iterator_base &operator++() { + switch (m_type) { + case iterator_type::NoneType: + break; + case iterator_type::Sequence: + ++m_seqIt; + break; + case iterator_type::Map: + ++m_mapIt; + m_mapIt = increment_until_defined(m_mapIt); + break; + } + return *this; + } + + node_iterator_base operator++(int) { + node_iterator_base iterator_pre(*this); + ++(*this); + return iterator_pre; + } + + value_type operator*() const { + switch (m_type) { + case iterator_type::NoneType: + return value_type(); + case iterator_type::Sequence: + return value_type(**m_seqIt); + case iterator_type::Map: + return value_type(*m_mapIt->first, *m_mapIt->second); + } + return value_type(); + } + + proxy operator->() const { return proxy(**this); } + + MapIter increment_until_defined(MapIter it) { + while (it != m_mapEnd && !is_defined(it)) + ++it; + return it; + } + + bool is_defined(MapIter it) const { + return it->first->is_defined() && it->second->is_defined(); + } + + private: + typename iterator_type::value m_type; + + SeqIter m_seqIt; + MapIter m_mapIt, m_mapEnd; + }; + + using node_iterator = node_iterator_base; + using const_node_iterator = node_iterator_base; + } +} + +#endif // VALUE_DETAIL_NODE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/detail/node_ref.h b/yaml-cpp/include/yaml-cpp/node/detail/node_ref.h new file mode 100644 index 0000000..6faef57 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/detail/node_ref.h @@ -0,0 +1,118 @@ +#ifndef VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/type.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/detail/node_data.h" + +namespace YAML { + namespace detail { + class node_ref { + public: + node_ref() : m_pData(new node_data) {} + + node_ref(const node_ref &) = delete; + + node_ref &operator=(const node_ref &) = delete; + + bool is_defined() const { return m_pData->is_defined(); } + + const Mark &mark() const { return m_pData->mark(); } + + NodeType::value type() const { return m_pData->type(); } + + const std::string &scalar() const { return m_pData->scalar(); } + + const std::string &tag() const { return m_pData->tag(); } + + EmitterStyle::value style() const { return m_pData->style(); } + + void mark_defined() { m_pData->mark_defined(); } + + void set_data(const node_ref &rhs) { m_pData = rhs.m_pData; } + + void set_mark(const Mark &mark) { m_pData->set_mark(mark); } + + void set_type(NodeType::value type) { m_pData->set_type(type); } + + void set_tag(const std::string &tag) { m_pData->set_tag(tag); } + + void set_null() { m_pData->set_null(); } + + void set_scalar(const std::string &scalar) { m_pData->set_scalar(scalar); } + + void set_style(EmitterStyle::value style) { m_pData->set_style(style); } + + // size/iterator + std::size_t size() const { return m_pData->size(); } + + const_node_iterator begin() const { + return static_cast(*m_pData).begin(); + } + + node_iterator begin() { return m_pData->begin(); } + + const_node_iterator end() const { + return static_cast(*m_pData).end(); + } + + node_iterator end() { return m_pData->end(); } + + // sequence + void push_back(node &node, shared_memory_holder pMemory) { + m_pData->push_back(node, pMemory); + } + + void insert(node &key, node &value, shared_memory_holder pMemory) { + m_pData->insert(key, value, pMemory); + } + + // indexing + template + node *get(const Key &key, shared_memory_holder pMemory) const { + return static_cast(*m_pData).get(key, pMemory); + } + + template + node &get(const Key &key, shared_memory_holder pMemory) { + return m_pData->get(key, pMemory); + } + + template + bool remove(const Key &key, shared_memory_holder pMemory) { + return m_pData->remove(key, pMemory); + } + + node *get(node &key, shared_memory_holder pMemory) const { + return static_cast(*m_pData).get(key, pMemory); + } + + node &get(node &key, shared_memory_holder pMemory) { + return m_pData->get(key, pMemory); + } + + bool remove(node &key, shared_memory_holder pMemory) { + return m_pData->remove(key, pMemory); + } + + // map + template + void force_insert(const Key &key, const Value &value, + shared_memory_holder pMemory) { + m_pData->force_insert(key, value, pMemory); + } + + private: + shared_node_data m_pData; + }; + } +} + +#endif // VALUE_DETAIL_NODE_REF_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/emit.h b/yaml-cpp/include/yaml-cpp/node/emit.h new file mode 100644 index 0000000..041d6a2 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/emit.h @@ -0,0 +1,33 @@ +#ifndef NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + class Emitter; + + class Node; + +/** + * Emits the node to the given {@link Emitter}. If there is an error in writing, + * {@link Emitter#good} will return false. + */ + YAML_CPP_API Emitter &operator<<(Emitter &out, const Node &node); + +/** Emits the node to the given output stream. */ + YAML_CPP_API std::ostream &operator<<(std::ostream &out, const Node &node); + +/** Converts the node to a YAML string. */ + YAML_CPP_API std::string Dump(const Node &node); +} // namespace YAML + +#endif // NODE_EMIT_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/impl.h b/yaml-cpp/include/yaml-cpp/node/impl.h new file mode 100644 index 0000000..7888947 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/impl.h @@ -0,0 +1,435 @@ +#ifndef NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/node/detail/memory.h" +#include "yaml-cpp/node/detail/node.h" +#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/node/node.h" +#include +#include + +namespace YAML { + inline Node::Node() + : m_isValid(true), m_invalidKey{}, m_pMemory(nullptr), m_pNode(nullptr) {} + + inline Node::Node(NodeType::value type) + : m_isValid(true), + m_invalidKey{}, + m_pMemory(new detail::memory_holder), + m_pNode(&m_pMemory->create_node()) { + m_pNode->set_type(type); + } + + template + inline Node::Node(const T &rhs) + : m_isValid(true), + m_invalidKey{}, + m_pMemory(new detail::memory_holder), + m_pNode(&m_pMemory->create_node()) { + Assign(rhs); + } + + inline Node::Node(const detail::iterator_value &rhs) + : m_isValid(rhs.m_isValid), + m_invalidKey(rhs.m_invalidKey), + m_pMemory(rhs.m_pMemory), + m_pNode(rhs.m_pNode) {} + + inline Node::Node(const Node &rhs) = default; + + inline Node::Node(Zombie) + : m_isValid(false), m_invalidKey{}, m_pMemory{}, m_pNode(nullptr) {} + + inline Node::Node(Zombie, const std::string &key) + : m_isValid(false), m_invalidKey(key), m_pMemory{}, m_pNode(nullptr) {} + + inline Node::Node(detail::node &node, detail::shared_memory_holder pMemory) + : m_isValid(true), m_invalidKey{}, m_pMemory(pMemory), m_pNode(&node) {} + + inline Node::~Node() = default; + + inline void Node::EnsureNodeExists() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + if (!m_pNode) { + m_pMemory.reset(new detail::memory_holder); + m_pNode = &m_pMemory->create_node(); + m_pNode->set_null(); + } + } + + inline bool Node::IsDefined() const { + if (!m_isValid) { + return false; + } + return m_pNode ? m_pNode->is_defined() : true; + } + + inline Mark Node::Mark() const { + if (!m_isValid) { + throw InvalidNode(m_invalidKey); + } + return m_pNode ? m_pNode->mark() : Mark::null_mark(); + } + + inline NodeType::value Node::Type() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->type() : NodeType::Null; + } + +// access + +// template helpers + template + struct as_if { + explicit as_if(const Node &node_) : node(node_) {} + + const Node &node; + + T operator()(const S &fallback) const { + if (!node.m_pNode) + return fallback; + + T t; + if (convert::decode(node, t)) + return t; + return fallback; + } + }; + + template + struct as_if { + explicit as_if(const Node &node_) : node(node_) {} + + const Node &node; + + std::string operator()(const S &fallback) const { + if (node.Type() != NodeType::Scalar) + return fallback; + return node.Scalar(); + } + }; + + template + struct as_if { + explicit as_if(const Node &node_) : node(node_) {} + + const Node &node; + + T operator()() const { + if (!node.m_pNode) + throw TypedBadConversion(node.Mark()); + + T t; + if (convert::decode(node, t)) + return t; + throw TypedBadConversion(node.Mark()); + } + }; + + template<> + struct as_if { + explicit as_if(const Node &node_) : node(node_) {} + + const Node &node; + + std::string operator()() const { + if (node.Type() != NodeType::Scalar) + throw TypedBadConversion(node.Mark()); + return node.Scalar(); + } + }; + +// access functions + template + inline T Node::as() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return as_if(*this)(); + } + + template + inline T Node::as(const S &fallback) const { + if (!m_isValid) + return fallback; + return as_if(*this)(fallback); + } + + inline const std::string &Node::Scalar() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->scalar() : detail::node_data::empty_scalar(); + } + + inline const std::string &Node::Tag() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->tag() : detail::node_data::empty_scalar(); + } + + inline void Node::SetTag(const std::string &tag) { + EnsureNodeExists(); + m_pNode->set_tag(tag); + } + + inline EmitterStyle::value Node::Style() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->style() : EmitterStyle::Default; + } + + inline void Node::SetStyle(EmitterStyle::value style) { + EnsureNodeExists(); + m_pNode->set_style(style); + } + +// assignment + inline bool Node::is(const Node &rhs) const { + if (!m_isValid || !rhs.m_isValid) + throw InvalidNode(m_invalidKey); + if (!m_pNode || !rhs.m_pNode) + return false; + return m_pNode->is(*rhs.m_pNode); + } + + template + inline Node &Node::operator=(const T &rhs) { + Assign(rhs); + return *this; + } + + inline Node &Node::operator=(const Node &rhs) { + if (is(rhs)) + return *this; + AssignNode(rhs); + return *this; + } + + inline void Node::reset(const YAML::Node &rhs) { + if (!m_isValid || !rhs.m_isValid) + throw InvalidNode(m_invalidKey); + m_pMemory = rhs.m_pMemory; + m_pNode = rhs.m_pNode; + } + + template + inline void Node::Assign(const T &rhs) { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + AssignData(convert::encode(rhs)); + } + + template<> + inline void Node::Assign(const std::string &rhs) { + EnsureNodeExists(); + m_pNode->set_scalar(rhs); + } + + inline void Node::Assign(const char *rhs) { + EnsureNodeExists(); + m_pNode->set_scalar(rhs); + } + + inline void Node::Assign(char *rhs) { + EnsureNodeExists(); + m_pNode->set_scalar(rhs); + } + + inline void Node::AssignData(const Node &rhs) { + EnsureNodeExists(); + rhs.EnsureNodeExists(); + + m_pNode->set_data(*rhs.m_pNode); + m_pMemory->merge(*rhs.m_pMemory); + } + + inline void Node::AssignNode(const Node &rhs) { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + rhs.EnsureNodeExists(); + + if (!m_pNode) { + m_pNode = rhs.m_pNode; + m_pMemory = rhs.m_pMemory; + return; + } + + m_pNode->set_ref(*rhs.m_pNode); + m_pMemory->merge(*rhs.m_pMemory); + m_pNode = rhs.m_pNode; + } + +// size/iterator + inline std::size_t Node::size() const { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + return m_pNode ? m_pNode->size() : 0; + } + + inline const_iterator Node::begin() const { + if (!m_isValid) + return const_iterator(); + return m_pNode ? const_iterator(m_pNode->begin(), m_pMemory) + : const_iterator(); + } + + inline iterator Node::begin() { + if (!m_isValid) + return iterator(); + return m_pNode ? iterator(m_pNode->begin(), m_pMemory) : iterator(); + } + + inline const_iterator Node::end() const { + if (!m_isValid) + return const_iterator(); + return m_pNode ? const_iterator(m_pNode->end(), m_pMemory) : const_iterator(); + } + + inline iterator Node::end() { + if (!m_isValid) + return iterator(); + return m_pNode ? iterator(m_pNode->end(), m_pMemory) : iterator(); + } + +// sequence + template + inline void Node::push_back(const T &rhs) { + if (!m_isValid) + throw InvalidNode(m_invalidKey); + push_back(Node(rhs)); + } + + inline void Node::push_back(const Node &rhs) { + EnsureNodeExists(); + rhs.EnsureNodeExists(); + + m_pNode->push_back(*rhs.m_pNode, m_pMemory); + m_pMemory->merge(*rhs.m_pMemory); + } + +// helpers for indexing + namespace detail { + template + struct to_value_t { + explicit to_value_t(const T &t_) : t(t_) {} + + const T &t; + using return_type = const T &; + + const T &operator()() const { return t; } + }; + + template<> + struct to_value_t { + explicit to_value_t(const char *t_) : t(t_) {} + + const char *t; + using return_type = std::string; + + const std::string operator()() const { return t; } + }; + + template<> + struct to_value_t { + explicit to_value_t(char *t_) : t(t_) {} + + const char *t; + using return_type = std::string; + + const std::string operator()() const { return t; } + }; + + template + struct to_value_t { + explicit to_value_t(const char *t_) : t(t_) {} + + const char *t; + using return_type = std::string; + + const std::string operator()() const { return t; } + }; + +// converts C-strings to std::strings so they can be copied + template + inline typename to_value_t::return_type to_value(const T &t) { + return to_value_t(t)(); + } + } // namespace detail + + template + std::string key_to_string(const Key &key) { + return streamable_to_string::value>().impl(key); + } + +// indexing + template + inline const Node Node::operator[](const Key &key) const { + EnsureNodeExists(); + detail::node *value = static_cast(*m_pNode).get( + detail::to_value(key), m_pMemory); + if (!value) { + return Node(ZombieNode, key_to_string(key)); + } + return Node(*value, m_pMemory); + } + + template + inline Node Node::operator[](const Key &key) { + EnsureNodeExists(); + detail::node &value = m_pNode->get(detail::to_value(key), m_pMemory); + return Node(value, m_pMemory); + } + + template + inline bool Node::remove(const Key &key) { + EnsureNodeExists(); + return m_pNode->remove(detail::to_value(key), m_pMemory); + } + + inline const Node Node::operator[](const Node &key) const { + EnsureNodeExists(); + key.EnsureNodeExists(); + m_pMemory->merge(*key.m_pMemory); + detail::node *value = + static_cast(*m_pNode).get(*key.m_pNode, m_pMemory); + if (!value) { + return Node(ZombieNode, key_to_string(key)); + } + return Node(*value, m_pMemory); + } + + inline Node Node::operator[](const Node &key) { + EnsureNodeExists(); + key.EnsureNodeExists(); + m_pMemory->merge(*key.m_pMemory); + detail::node &value = m_pNode->get(*key.m_pNode, m_pMemory); + return Node(value, m_pMemory); + } + + inline bool Node::remove(const Node &key) { + EnsureNodeExists(); + key.EnsureNodeExists(); + return m_pNode->remove(*key.m_pNode, m_pMemory); + } + +// map + template + inline void Node::force_insert(const Key &key, const Value &value) { + EnsureNodeExists(); + m_pNode->force_insert(detail::to_value(key), detail::to_value(value), + m_pMemory); + } + +// free functions + inline bool operator==(const Node &lhs, const Node &rhs) { return lhs.is(rhs); } +} // namespace YAML + +#endif // NODE_IMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/iterator.h b/yaml-cpp/include/yaml-cpp/node/iterator.h new file mode 100644 index 0000000..3d3f7b1 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/iterator.h @@ -0,0 +1,33 @@ +#ifndef VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/detail/iterator_fwd.h" +#include "yaml-cpp/node/detail/iterator.h" +#include +#include +#include + +namespace YAML { + namespace detail { + struct iterator_value : public Node, std::pair { + iterator_value() = default; + + explicit iterator_value(const Node &rhs) + : Node(rhs), + std::pair(Node(Node::ZombieNode), Node(Node::ZombieNode)) {} + + explicit iterator_value(const Node &key, const Node &value) + : Node(Node::ZombieNode), std::pair(key, value) {} + }; + } +} + +#endif // VALUE_ITERATOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/node.h b/yaml-cpp/include/yaml-cpp/node/node.h new file mode 100644 index 0000000..c8eeba9 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/node.h @@ -0,0 +1,192 @@ +#ifndef NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/mark.h" +#include "yaml-cpp/node/detail/iterator_fwd.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/type.h" + +namespace YAML { + namespace detail { + class node; + + class node_data; + + struct iterator_value; + } // namespace detail +} // namespace YAML + +namespace YAML { + class YAML_CPP_API Node { + public: + friend class NodeBuilder; + + friend class NodeEvents; + + friend struct detail::iterator_value; + + friend class detail::node; + + friend class detail::node_data; + + template + friend + class detail::iterator_base; + + template + friend + struct as_if; + + using iterator = YAML::iterator; + using const_iterator = YAML::const_iterator; + + Node(); + + explicit Node(NodeType::value type); + + template + explicit Node(const T &rhs); + + explicit Node(const detail::iterator_value &rhs); + + Node(const Node &rhs); + + ~Node(); + + YAML::Mark Mark() const; + + NodeType::value Type() const; + + bool IsDefined() const; + + bool IsNull() const { return Type() == NodeType::Null; } + + bool IsScalar() const { return Type() == NodeType::Scalar; } + + bool IsSequence() const { return Type() == NodeType::Sequence; } + + bool IsMap() const { return Type() == NodeType::Map; } + + // bool conversions + explicit operator bool() const { return IsDefined(); } + + bool operator!() const { return !IsDefined(); } + + // access + template + T as() const; + + template + T as(const S &fallback) const; + + const std::string &Scalar() const; + + const std::string &Tag() const; + + void SetTag(const std::string &tag); + + // style + // WARNING: This API might change in future releases. + EmitterStyle::value Style() const; + + void SetStyle(EmitterStyle::value style); + + // assignment + bool is(const Node &rhs) const; + + template + Node &operator=(const T &rhs); + + Node &operator=(const Node &rhs); + + void reset(const Node &rhs = Node()); + + // size/iterator + std::size_t size() const; + + const_iterator begin() const; + + iterator begin(); + + const_iterator end() const; + + iterator end(); + + // sequence + template + void push_back(const T &rhs); + + void push_back(const Node &rhs); + + // indexing + template + const Node operator[](const Key &key) const; + + template + Node operator[](const Key &key); + + template + bool remove(const Key &key); + + const Node operator[](const Node &key) const; + + Node operator[](const Node &key); + + bool remove(const Node &key); + + // map + template + void force_insert(const Key &key, const Value &value); + + private: + enum Zombie { + ZombieNode + }; + + explicit Node(Zombie); + + explicit Node(Zombie, const std::string &); + + explicit Node(detail::node &node, detail::shared_memory_holder pMemory); + + void EnsureNodeExists() const; + + template + void Assign(const T &rhs); + + void Assign(const char *rhs); + + void Assign(char *rhs); + + void AssignData(const Node &rhs); + + void AssignNode(const Node &rhs); + + private: + bool m_isValid; + // String representation of invalid key, if the node is invalid. + std::string m_invalidKey; + mutable detail::shared_memory_holder m_pMemory; + mutable detail::node *m_pNode; + }; + + YAML_CPP_API bool operator==(const Node &lhs, const Node &rhs); + + YAML_CPP_API Node Clone(const Node &node); + + template + struct convert; +} + +#endif // NODE_NODE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/parse.h b/yaml-cpp/include/yaml-cpp/node/parse.h new file mode 100644 index 0000000..10ff820 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/parse.h @@ -0,0 +1,78 @@ +#ifndef VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + class Node; + +/** + * Loads the input string as a single YAML document. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API Node Load(const std::string &input); + +/** + * Loads the input string as a single YAML document. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API Node Load(const char *input); + +/** + * Loads the input stream as a single YAML document. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API Node Load(std::istream &input); + +/** + * Loads the input file as a single YAML document. + * + * @throws {@link ParserException} if it is malformed. + * @throws {@link BadFile} if the file cannot be loaded. + */ + YAML_CPP_API Node LoadFile(const std::string &filename); + +/** + * Loads the input string as a list of YAML documents. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API std::vector LoadAll(const std::string &input); + +/** + * Loads the input string as a list of YAML documents. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API std::vector LoadAll(const char *input); + +/** + * Loads the input stream as a list of YAML documents. + * + * @throws {@link ParserException} if it is malformed. + */ + YAML_CPP_API std::vector LoadAll(std::istream &input); + +/** + * Loads the input file as a list of YAML documents. + * + * @throws {@link ParserException} if it is malformed. + * @throws {@link BadFile} if the file cannot be loaded. + */ + YAML_CPP_API std::vector LoadAllFromFile(const std::string &filename); +} // namespace YAML + +#endif // VALUE_PARSE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/ptr.h b/yaml-cpp/include/yaml-cpp/node/ptr.h new file mode 100644 index 0000000..bc77224 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/ptr.h @@ -0,0 +1,33 @@ +#ifndef VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include + +namespace YAML { + namespace detail { + class node; + + class node_ref; + + class node_data; + + class memory; + + class memory_holder; + + using shared_node = std::shared_ptr; + using shared_node_ref = std::shared_ptr; + using shared_node_data = std::shared_ptr; + using shared_memory_holder = std::shared_ptr; + using shared_memory = std::shared_ptr; + } +} + +#endif // VALUE_PTR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/node/type.h b/yaml-cpp/include/yaml-cpp/node/type.h new file mode 100644 index 0000000..a0ea585 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/node/type.h @@ -0,0 +1,18 @@ +#ifndef VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +namespace YAML { + struct NodeType { + enum value { + Undefined, Null, Scalar, Sequence, Map + }; + }; +} + +#endif // VALUE_TYPE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/noexcept.h b/yaml-cpp/include/yaml-cpp/noexcept.h new file mode 100644 index 0000000..3a927f1 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/noexcept.h @@ -0,0 +1,18 @@ +#ifndef NOEXCEPT_H_768872DA_476C_11EA_88B8_90B11C0C0FF8 +#define NOEXCEPT_H_768872DA_476C_11EA_88B8_90B11C0C0FF8 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +// This is here for compatibility with older versions of Visual Studio +// which don't support noexcept. +#if defined(_MSC_VER) && _MSC_VER < 1900 +#define YAML_CPP_NOEXCEPT _NOEXCEPT +#else +#define YAML_CPP_NOEXCEPT noexcept +#endif + +#endif diff --git a/yaml-cpp/include/yaml-cpp/null.h b/yaml-cpp/include/yaml-cpp/null.h new file mode 100644 index 0000000..f8dac79 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/null.h @@ -0,0 +1,29 @@ +#ifndef NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/dll.h" +#include + +namespace YAML { + class Node; + + struct YAML_CPP_API _Null { + }; + + inline bool operator==(const _Null &, const _Null &) { return true; } + + inline bool operator!=(const _Null &, const _Null &) { return false; } + + YAML_CPP_API bool IsNull(const Node &node); // old API only + YAML_CPP_API bool IsNullString(const std::string &str); + + extern YAML_CPP_API _Null Null; +} + +#endif // NULL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/ostream_wrapper.h b/yaml-cpp/include/yaml-cpp/ostream_wrapper.h new file mode 100644 index 0000000..35939b5 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/ostream_wrapper.h @@ -0,0 +1,86 @@ +#ifndef OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + class YAML_CPP_API ostream_wrapper { + public: + ostream_wrapper(); + + explicit ostream_wrapper(std::ostream &stream); + + ostream_wrapper(const ostream_wrapper &) = delete; + + ostream_wrapper(ostream_wrapper &&) = delete; + + ostream_wrapper &operator=(const ostream_wrapper &) = delete; + + ostream_wrapper &operator=(ostream_wrapper &&) = delete; + + ~ostream_wrapper(); + + void write(const std::string &str); + + void write(const char *str, std::size_t size); + + void set_comment() { m_comment = true; } + + const char *str() const { + if (m_pStream) { + return nullptr; + } else { + m_buffer[m_pos] = '\0'; + return &m_buffer[0]; + } + } + + std::size_t row() const { return m_row; } + + std::size_t col() const { return m_col; } + + std::size_t pos() const { return m_pos; } + + bool comment() const { return m_comment; } + + private: + void update_pos(char ch); + + private: + mutable std::vector m_buffer; + std::ostream *const m_pStream; + + std::size_t m_pos; + std::size_t m_row, m_col; + bool m_comment; + }; + + template + inline ostream_wrapper &operator<<(ostream_wrapper &stream, + const char (&str)[N]) { + stream.write(str, N - 1); + return stream; + } + + inline ostream_wrapper &operator<<(ostream_wrapper &stream, + const std::string &str) { + stream.write(str); + return stream; + } + + inline ostream_wrapper &operator<<(ostream_wrapper &stream, char ch) { + stream.write(&ch, 1); + return stream; + } +} // namespace YAML + +#endif // OSTREAM_WRAPPER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/parser.h b/yaml-cpp/include/yaml-cpp/parser.h new file mode 100644 index 0000000..1ce7c02 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/parser.h @@ -0,0 +1,96 @@ +#ifndef PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + class EventHandler; + + class Node; + + class Scanner; + + struct Directives; + struct Token; + +/** + * A parser turns a stream of bytes into one stream of "events" per YAML + * document in the input stream. + */ + class YAML_CPP_API Parser { + public: + /** Constructs an empty parser (with no input. */ + Parser(); + + Parser(const Parser &) = delete; + + Parser(Parser &&) = delete; + + Parser &operator=(const Parser &) = delete; + + Parser &operator=(Parser &&) = delete; + + /** + * Constructs a parser from the given input stream. The input stream must + * live as long as the parser. + */ + explicit Parser(std::istream &in); + + ~Parser(); + + /** Evaluates to true if the parser has some valid input to be read. */ + explicit operator bool() const; + + /** + * Resets the parser with the given input stream. Any existing state is + * erased. + */ + void Load(std::istream &in); + + /** + * Handles the next document by calling events on the {@code eventHandler}. + * + * @throw a ParserException on error. + * @return false if there are no more documents + */ + bool HandleNextDocument(EventHandler &eventHandler); + + void PrintTokens(std::ostream &out); + + private: + /** + * Reads any directives that are next in the queue, setting the internal + * {@code m_pDirectives} state. + */ + void ParseDirectives(); + + void HandleDirective(const Token &token); + + /** + * Handles a "YAML" directive, which should be of the form 'major.minor' (like + * a version number). + */ + void HandleYamlDirective(const Token &token); + + /** + * Handles a "TAG" directive, which should be of the form 'handle prefix', + * where 'handle' is converted to 'prefix' in the file. + */ + void HandleTagDirective(const Token &token); + + private: + std::unique_ptr m_pScanner; + std::unique_ptr m_pDirectives; + }; +} // namespace YAML + +#endif // PARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/stlemitter.h b/yaml-cpp/include/yaml-cpp/stlemitter.h new file mode 100644 index 0000000..c9d8b54 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/stlemitter.h @@ -0,0 +1,51 @@ +#ifndef STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include + +namespace YAML { + template + inline Emitter &EmitSeq(Emitter &emitter, const Seq &seq) { + emitter << BeginSeq; + for (typename Seq::const_iterator it = seq.begin(); it != seq.end(); ++it) + emitter << *it; + emitter << EndSeq; + return emitter; + } + + template + inline Emitter &operator<<(Emitter &emitter, const std::vector &v) { + return EmitSeq(emitter, v); + } + + template + inline Emitter &operator<<(Emitter &emitter, const std::list &v) { + return EmitSeq(emitter, v); + } + + template + inline Emitter &operator<<(Emitter &emitter, const std::set &v) { + return EmitSeq(emitter, v); + } + + template + inline Emitter &operator<<(Emitter &emitter, const std::map &m) { + typedef typename std::map map; + emitter << BeginMap; + for (typename map::const_iterator it = m.begin(); it != m.end(); ++it) + emitter << Key << it->first << Value << it->second; + emitter << EndMap; + return emitter; + } +} + +#endif // STLEMITTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/traits.h b/yaml-cpp/include/yaml-cpp/traits.h new file mode 100644 index 0000000..5a20b70 --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/traits.h @@ -0,0 +1,168 @@ +#ifndef TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include + +namespace YAML { + template + struct is_numeric { + enum { + value = false + }; + }; + + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; +#if defined(_MSC_VER) && (_MSC_VER < 1310) + template <> + struct is_numeric<__int64> { + enum { value = true }; + }; + template <> + struct is_numeric { + enum { value = true }; + }; +#else + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; +#endif + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + template<> + struct is_numeric { + enum { + value = true + }; + }; + + template + struct enable_if_c { + using type = T; + }; + + template + struct enable_if_c { + }; + + template + struct enable_if : public enable_if_c { + }; + + template + struct disable_if_c { + using type = T; + }; + + template + struct disable_if_c { + }; + + template + struct disable_if : public disable_if_c { + }; +} + +template +struct is_streamable { + template + static auto test(int) + -> decltype(std::declval() << std::declval(), std::true_type()); + + template + static auto test(...) -> std::false_type; + + static const bool value = decltype(test(0))::value; +}; + +template +struct streamable_to_string { + static std::string impl(const Key &key) { + std::stringstream ss; + ss << key; + return ss.str(); + } +}; + +template +struct streamable_to_string { + static std::string impl(const Key &) { + return ""; + } +}; + +#endif // TRAITS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/include/yaml-cpp/yaml.h b/yaml-cpp/include/yaml-cpp/yaml.h new file mode 100644 index 0000000..dd5db4e --- /dev/null +++ b/yaml-cpp/include/yaml-cpp/yaml.h @@ -0,0 +1,24 @@ +#ifndef YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/parser.h" +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/stlemitter.h" +#include "yaml-cpp/exceptions.h" + +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/impl.h" +#include "yaml-cpp/node/convert.h" +#include "yaml-cpp/node/iterator.h" +#include "yaml-cpp/node/detail/impl.h" +#include "yaml-cpp/node/parse.h" +#include "yaml-cpp/node/emit.h" + +#endif // YAML_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/original-LICENSE b/yaml-cpp/original-LICENSE new file mode 100644 index 0000000..991fdbb --- /dev/null +++ b/yaml-cpp/original-LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2008-2015 Jesse Beder. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/yaml-cpp/src/binary.cpp b/yaml-cpp/src/binary.cpp new file mode 100644 index 0000000..9516717 --- /dev/null +++ b/yaml-cpp/src/binary.cpp @@ -0,0 +1,100 @@ +#include "yaml-cpp/binary.h" + +#include + +namespace YAML { + static const char encoding[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + std::string EncodeBase64(const unsigned char *data, std::size_t size) { + const char PAD = '='; + + std::string ret; + ret.resize(4 * size / 3 + 3); + char *out = &ret[0]; + + std::size_t chunks = size / 3; + std::size_t remainder = size % 3; + + for (std::size_t i = 0; i < chunks; i++, data += 3) { + *out++ = encoding[data[0] >> 2]; + *out++ = encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + *out++ = encoding[((data[1] & 0xf) << 2) | (data[2] >> 6)]; + *out++ = encoding[data[2] & 0x3f]; + } + + switch (remainder) { + case 0: + break; + case 1: + *out++ = encoding[data[0] >> 2]; + *out++ = encoding[((data[0] & 0x3) << 4)]; + *out++ = PAD; + *out++ = PAD; + break; + case 2: + *out++ = encoding[data[0] >> 2]; + *out++ = encoding[((data[0] & 0x3) << 4) | (data[1] >> 4)]; + *out++ = encoding[((data[1] & 0xf) << 2)]; + *out++ = PAD; + break; + } + + ret.resize(out - &ret[0]); + return ret; + } + + static const unsigned char decoding[] = { + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 62, 255, + 255, 255, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 255, 255, + 255, 0, 255, 255, 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, + 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, + 25, 255, 255, 255, 255, 255, 255, 26, 27, 28, 29, 30, 31, 32, 33, + 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, + 49, 50, 51, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, + 255, + }; + + std::vector DecodeBase64(const std::string &input) { + using ret_type = std::vector; + if (input.empty()) + return ret_type(); + + ret_type ret(3 * input.size() / 4 + 1); + unsigned char *out = &ret[0]; + + unsigned value = 0; + for (std::size_t i = 0, cnt = 0; i < input.size(); i++) { + if (std::isspace(input[i])) { + // skip newlines + continue; + } + unsigned char d = decoding[static_cast(input[i])]; + if (d == 255) + return ret_type(); + + value = (value << 6) | d; + if (cnt % 4 == 3) { + *out++ = value >> 16; + if (i > 0 && input[i - 1] != '=') + *out++ = value >> 8; + if (input[i] != '=') + *out++ = value; + } + ++cnt; + } + + ret.resize(out - &ret[0]); + return ret; + } +} // namespace YAML diff --git a/yaml-cpp/src/collectionstack.h b/yaml-cpp/src/collectionstack.h new file mode 100644 index 0000000..223c242 --- /dev/null +++ b/yaml-cpp/src/collectionstack.h @@ -0,0 +1,45 @@ +#ifndef COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +namespace YAML { + struct CollectionType { + enum value { + NoCollection, BlockMap, BlockSeq, FlowMap, FlowSeq, CompactMap + }; + }; + + class CollectionStack { + public: + CollectionStack() : collectionStack{} {} + + CollectionType::value GetCurCollectionType() const { + if (collectionStack.empty()) + return CollectionType::NoCollection; + return collectionStack.top(); + } + + void PushCollectionType(CollectionType::value type) { + collectionStack.push(type); + } + + void PopCollectionType(CollectionType::value type) { + assert(type == GetCurCollectionType()); + (void) type; + collectionStack.pop(); + } + + private: + std::stack collectionStack; + }; +} // namespace YAML + +#endif // COLLECTIONSTACK_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/contrib/graphbuilder.cpp b/yaml-cpp/src/contrib/graphbuilder.cpp new file mode 100644 index 0000000..20e5405 --- /dev/null +++ b/yaml-cpp/src/contrib/graphbuilder.cpp @@ -0,0 +1,17 @@ +#include "graphbuilderadapter.h" + +#include "yaml-cpp/parser.h" // IWYU pragma: keep + +namespace YAML { + class GraphBuilderInterface; + + void *BuildGraphOfNextDocument(Parser &parser, + GraphBuilderInterface &graphBuilder) { + GraphBuilderAdapter eventHandler(graphBuilder); + if (parser.HandleNextDocument(eventHandler)) { + return eventHandler.RootNode(); + } else { + return nullptr; + } + } +} // namespace YAML diff --git a/yaml-cpp/src/contrib/graphbuilderadapter.cpp b/yaml-cpp/src/contrib/graphbuilderadapter.cpp new file mode 100644 index 0000000..190e631 --- /dev/null +++ b/yaml-cpp/src/contrib/graphbuilderadapter.cpp @@ -0,0 +1,94 @@ +#include "graphbuilderadapter.h" +#include "yaml-cpp/contrib/graphbuilder.h" + +namespace YAML { + struct Mark; + + int GraphBuilderAdapter::ContainerFrame::sequenceMarker; + + void GraphBuilderAdapter::OnNull(const Mark &mark, anchor_t anchor) { + void *pParent = GetCurrentParent(); + void *pNode = m_builder.NewNull(mark, pParent); + RegisterAnchor(anchor, pNode); + + DispositionNode(pNode); + } + + void GraphBuilderAdapter::OnAlias(const Mark &mark, anchor_t anchor) { + void *pReffedNode = m_anchors.Get(anchor); + DispositionNode(m_builder.AnchorReference(mark, pReffedNode)); + } + + void GraphBuilderAdapter::OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value) { + void *pParent = GetCurrentParent(); + void *pNode = m_builder.NewScalar(mark, tag, pParent, value); + RegisterAnchor(anchor, pNode); + + DispositionNode(pNode); + } + + void GraphBuilderAdapter::OnSequenceStart(const Mark &mark, + const std::string &tag, + anchor_t anchor, + EmitterStyle::value /* style */) { + void *pNode = m_builder.NewSequence(mark, tag, GetCurrentParent()); + m_containers.push(ContainerFrame(pNode)); + RegisterAnchor(anchor, pNode); + } + + void GraphBuilderAdapter::OnSequenceEnd() { + void *pSequence = m_containers.top().pContainer; + m_containers.pop(); + + DispositionNode(pSequence); + } + + void GraphBuilderAdapter::OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, + EmitterStyle::value /* style */) { + void *pNode = m_builder.NewMap(mark, tag, GetCurrentParent()); + m_containers.push(ContainerFrame(pNode, m_pKeyNode)); + m_pKeyNode = nullptr; + RegisterAnchor(anchor, pNode); + } + + void GraphBuilderAdapter::OnMapEnd() { + void *pMap = m_containers.top().pContainer; + m_pKeyNode = m_containers.top().pPrevKeyNode; + m_containers.pop(); + DispositionNode(pMap); + } + + void *GraphBuilderAdapter::GetCurrentParent() const { + if (m_containers.empty()) { + return nullptr; + } + return m_containers.top().pContainer; + } + + void GraphBuilderAdapter::RegisterAnchor(anchor_t anchor, void *pNode) { + if (anchor) { + m_anchors.Register(anchor, pNode); + } + } + + void GraphBuilderAdapter::DispositionNode(void *pNode) { + if (m_containers.empty()) { + m_pRootNode = pNode; + return; + } + + void *pContainer = m_containers.top().pContainer; + if (m_containers.top().isMap()) { + if (m_pKeyNode) { + m_builder.AssignInMap(pContainer, m_pKeyNode, pNode); + m_pKeyNode = nullptr; + } else { + m_pKeyNode = pNode; + } + } else { + m_builder.AppendToSequence(pContainer, pNode); + } + } +} // namespace YAML diff --git a/yaml-cpp/src/contrib/graphbuilderadapter.h b/yaml-cpp/src/contrib/graphbuilderadapter.h new file mode 100644 index 0000000..b45dfb0 --- /dev/null +++ b/yaml-cpp/src/contrib/graphbuilderadapter.h @@ -0,0 +1,101 @@ +#ifndef GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include + +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/contrib/anchordict.h" +#include "yaml-cpp/contrib/graphbuilder.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/eventhandler.h" + +namespace YAML { + class GraphBuilderInterface; + + struct Mark; +} // namespace YAML + +namespace YAML { + class GraphBuilderAdapter : public EventHandler { + public: + GraphBuilderAdapter(GraphBuilderInterface &builder) + : m_builder(builder), + m_containers{}, + m_anchors{}, + m_pRootNode(nullptr), + m_pKeyNode(nullptr) {} + + GraphBuilderAdapter(const GraphBuilderAdapter &) = delete; + + GraphBuilderAdapter(GraphBuilderAdapter &&) = delete; + + GraphBuilderAdapter &operator=(const GraphBuilderAdapter &) = delete; + + GraphBuilderAdapter &operator=(GraphBuilderAdapter &&) = delete; + + virtual void OnDocumentStart(const Mark &mark) { (void) mark; } + + virtual void OnDocumentEnd() {} + + virtual void OnNull(const Mark &mark, anchor_t anchor); + + virtual void OnAlias(const Mark &mark, anchor_t anchor); + + virtual void OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value); + + virtual void OnSequenceStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style); + + virtual void OnSequenceEnd(); + + virtual void OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style); + + virtual void OnMapEnd(); + + void *RootNode() const { return m_pRootNode; } + + private: + struct ContainerFrame { + ContainerFrame(void *pSequence) + : pContainer(pSequence), pPrevKeyNode(&sequenceMarker) {} + + ContainerFrame(void *pMap, void *pPreviousKeyNode) + : pContainer(pMap), pPrevKeyNode(pPreviousKeyNode) {} + + void *pContainer; + void *pPrevKeyNode; + + bool isMap() const { return pPrevKeyNode != &sequenceMarker; } + + private: + static int sequenceMarker; + }; + + typedef std::stack ContainerStack; + typedef AnchorDict AnchorMap; + + GraphBuilderInterface &m_builder; + ContainerStack m_containers; + AnchorMap m_anchors; + void *m_pRootNode; + void *m_pKeyNode; + + void *GetCurrentParent() const; + + void RegisterAnchor(anchor_t anchor, void *pNode); + + void DispositionNode(void *pNode); + }; +} // namespace YAML + +#endif // GRAPHBUILDERADAPTER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/contrib/yaml-cpp.natvis b/yaml-cpp/src/contrib/yaml-cpp.natvis new file mode 100644 index 0000000..4ac89bc --- /dev/null +++ b/yaml-cpp/src/contrib/yaml-cpp.natvis @@ -0,0 +1,32 @@ + + + + + {{invalid}} + {{pNode==nullptr}} + {{ {*m_pNode} }} + + m_pNode->m_pRef._Ptr->m_pData._Ptr->m_scalar + m_pNode->m_pRef._Ptr->m_pData._Ptr->m_sequence + m_pNode->m_pRef._Ptr->m_pData._Ptr->m_map + m_pNode->m_pRef._Ptr->m_pData._Ptr + + + + + {{node:pRef==nullptr}} + {{node:pRef->pData==nullptr}} + {{undefined}} + {{{m_pRef._Ptr->m_pData._Ptr->m_scalar}}} + {{ Map {m_pRef._Ptr->m_pData._Ptr->m_map}}} + {{ Seq {m_pRef._Ptr->m_pData._Ptr->m_sequence}}} + {{{m_pRef._Ptr->m_pData._Ptr->m_type}}} + + m_pRef._Ptr->m_pData._Ptr->m_scalar + m_pRef._Ptr->m_pData._Ptr->m_sequence + m_pRef._Ptr->m_pData._Ptr->m_map + m_pRef._Ptr->m_pData._Ptr + + + + diff --git a/yaml-cpp/src/contrib/yaml-cpp.natvis.md b/yaml-cpp/src/contrib/yaml-cpp.natvis.md new file mode 100644 index 0000000..37e98b6 --- /dev/null +++ b/yaml-cpp/src/contrib/yaml-cpp.natvis.md @@ -0,0 +1,12 @@ +# MSVC debugger visualizer for YAML::Node + +## How to use + +Add yaml-cpp.natvis to your Visual C++ project like any other source file. It will be included in the debug information, +and improve debugger display on YAML::Node and contained types. + +## Compatibility and Troubleshooting + +This has been tested for MSVC 2017. It is expected to be compatible with VS 2015 and VS 2019. If you have any problems, +you can open an issue here: https://github.com/peterchen-cp/yaml-cpp-natvis + diff --git a/yaml-cpp/src/convert.cpp b/yaml-cpp/src/convert.cpp new file mode 100644 index 0000000..831fd76 --- /dev/null +++ b/yaml-cpp/src/convert.cpp @@ -0,0 +1,80 @@ +#include + +#include "yaml-cpp/node/convert.h" + +namespace { +// we're not gonna mess with the mess that is all the isupper/etc. functions + bool IsLower(char ch) { return 'a' <= ch && ch <= 'z'; } + + bool IsUpper(char ch) { return 'A' <= ch && ch <= 'Z'; } + + char ToLower(char ch) { return IsUpper(ch) ? ch + 'a' - 'A' : ch; } + + std::string tolower(const std::string &str) { + std::string s(str); + std::transform(s.begin(), s.end(), s.begin(), ToLower); + return s; + } + + template + bool IsEntirely(const std::string &str, T func) { + for (char ch : str) + if (!func(ch)) + return false; + + return true; + } + +// IsFlexibleCase +// . Returns true if 'str' is: +// . UPPERCASE +// . lowercase +// . Capitalized + bool IsFlexibleCase(const std::string &str) { + if (str.empty()) + return true; + + if (IsEntirely(str, IsLower)) + return true; + + bool firstcaps = IsUpper(str[0]); + std::string rest = str.substr(1); + return firstcaps && (IsEntirely(rest, IsLower) || IsEntirely(rest, IsUpper)); + } +} // namespace + +namespace YAML { + bool convert::decode(const Node &node, bool &rhs) { + if (!node.IsScalar()) + return false; + + // we can't use iostream bool extraction operators as they don't + // recognize all possible values in the table below (taken from + // http://yaml.org/type/bool.html) + static const struct { + std::string truename, falsename; + } names[] = { + {"y", "n"}, + {"yes", "no"}, + {"true", "false"}, + {"on", "off"}, + }; + + if (!IsFlexibleCase(node.Scalar())) + return false; + + for (const auto &name : names) { + if (name.truename == tolower(node.Scalar())) { + rhs = true; + return true; + } + + if (name.falsename == tolower(node.Scalar())) { + rhs = false; + return true; + } + } + + return false; + } +} // namespace YAML diff --git a/yaml-cpp/src/depthguard.cpp b/yaml-cpp/src/depthguard.cpp new file mode 100644 index 0000000..569bc88 --- /dev/null +++ b/yaml-cpp/src/depthguard.cpp @@ -0,0 +1,9 @@ +#include "yaml-cpp/depthguard.h" + +namespace YAML { + + DeepRecursion::DeepRecursion(int depth, const Mark &mark_, + const std::string &msg_) + : ParserException(mark_, msg_), m_depth(depth) {} + +} // namespace YAML diff --git a/yaml-cpp/src/directives.cpp b/yaml-cpp/src/directives.cpp new file mode 100644 index 0000000..d8e33a8 --- /dev/null +++ b/yaml-cpp/src/directives.cpp @@ -0,0 +1,17 @@ +#include "directives.h" + +namespace YAML { + Directives::Directives() : version{true, 1, 2}, tags{} {} + + const std::string Directives::TranslateTagHandle( + const std::string &handle) const { + std::map::const_iterator it = tags.find(handle); + if (it == tags.end()) { + if (handle == "!!") + return "tag:yaml.org,2002:"; + return handle; + } + + return it->second; + } +} // namespace YAML diff --git a/yaml-cpp/src/directives.h b/yaml-cpp/src/directives.h new file mode 100644 index 0000000..a834440 --- /dev/null +++ b/yaml-cpp/src/directives.h @@ -0,0 +1,29 @@ +#ifndef DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +namespace YAML { + struct Version { + bool isDefault; + int major, minor; + }; + + struct Directives { + Directives(); + + const std::string TranslateTagHandle(const std::string &handle) const; + + Version version; + std::map tags; + }; +} + +#endif // DIRECTIVES_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/emit.cpp b/yaml-cpp/src/emit.cpp new file mode 100644 index 0000000..d4a5c54 --- /dev/null +++ b/yaml-cpp/src/emit.cpp @@ -0,0 +1,25 @@ +#include "yaml-cpp/node/emit.h" +#include "nodeevents.h" +#include "yaml-cpp/emitfromevents.h" +#include "yaml-cpp/emitter.h" + +namespace YAML { + Emitter &operator<<(Emitter &out, const Node &node) { + EmitFromEvents emitFromEvents(out); + NodeEvents events(node); + events.Emit(emitFromEvents); + return out; + } + + std::ostream &operator<<(std::ostream &out, const Node &node) { + Emitter emitter(out); + emitter << node; + return out; + } + + std::string Dump(const Node &node) { + Emitter emitter; + emitter << node; + return emitter.c_str(); + } +} // namespace YAML diff --git a/yaml-cpp/src/emitfromevents.cpp b/yaml-cpp/src/emitfromevents.cpp new file mode 100644 index 0000000..edeb2f7 --- /dev/null +++ b/yaml-cpp/src/emitfromevents.cpp @@ -0,0 +1,120 @@ +#include +#include + +#include "yaml-cpp/emitfromevents.h" +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/emittermanip.h" +#include "yaml-cpp/null.h" + +namespace YAML { + struct Mark; +} // namespace YAML + +namespace { + std::string ToString(YAML::anchor_t anchor) { + std::stringstream stream; + stream << anchor; + return stream.str(); + } +} // namespace + +namespace YAML { + EmitFromEvents::EmitFromEvents(Emitter &emitter) + : m_emitter(emitter), m_stateStack{} {} + + void EmitFromEvents::OnDocumentStart(const Mark &) {} + + void EmitFromEvents::OnDocumentEnd() {} + + void EmitFromEvents::OnNull(const Mark &, anchor_t anchor) { + BeginNode(); + EmitProps("", anchor); + m_emitter << Null; + } + + void EmitFromEvents::OnAlias(const Mark &, anchor_t anchor) { + BeginNode(); + m_emitter << Alias(ToString(anchor)); + } + + void EmitFromEvents::OnScalar(const Mark &, const std::string &tag, + anchor_t anchor, const std::string &value) { + BeginNode(); + EmitProps(tag, anchor); + m_emitter << value; + } + + void EmitFromEvents::OnSequenceStart(const Mark &, const std::string &tag, + anchor_t anchor, + EmitterStyle::value style) { + BeginNode(); + EmitProps(tag, anchor); + switch (style) { + case EmitterStyle::Block: + m_emitter << Block; + break; + case EmitterStyle::Flow: + m_emitter << Flow; + break; + default: + break; + } + m_emitter << BeginSeq; + m_stateStack.push(State::WaitingForSequenceEntry); + } + + void EmitFromEvents::OnSequenceEnd() { + m_emitter << EndSeq; + assert(m_stateStack.top() == State::WaitingForSequenceEntry); + m_stateStack.pop(); + } + + void EmitFromEvents::OnMapStart(const Mark &, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) { + BeginNode(); + EmitProps(tag, anchor); + switch (style) { + case EmitterStyle::Block: + m_emitter << Block; + break; + case EmitterStyle::Flow: + m_emitter << Flow; + break; + default: + break; + } + m_emitter << BeginMap; + m_stateStack.push(State::WaitingForKey); + } + + void EmitFromEvents::OnMapEnd() { + m_emitter << EndMap; + assert(m_stateStack.top() == State::WaitingForKey); + m_stateStack.pop(); + } + + void EmitFromEvents::BeginNode() { + if (m_stateStack.empty()) + return; + + switch (m_stateStack.top()) { + case State::WaitingForKey: + m_emitter << Key; + m_stateStack.top() = State::WaitingForValue; + break; + case State::WaitingForValue: + m_emitter << Value; + m_stateStack.top() = State::WaitingForKey; + break; + default: + break; + } + } + + void EmitFromEvents::EmitProps(const std::string &tag, anchor_t anchor) { + if (!tag.empty() && tag != "?" && tag != "!") + m_emitter << VerbatimTag(tag); + if (anchor) + m_emitter << Anchor(ToString(anchor)); + } +} // namespace YAML diff --git a/yaml-cpp/src/emitter.cpp b/yaml-cpp/src/emitter.cpp new file mode 100644 index 0000000..ec3fae5 --- /dev/null +++ b/yaml-cpp/src/emitter.cpp @@ -0,0 +1,910 @@ +#include + +#include "emitterutils.h" +#include "indentation.h" // IWYU pragma: keep +#include "yaml-cpp/emitter.h" +#include "yaml-cpp/emitterdef.h" +#include "yaml-cpp/emittermanip.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep + +namespace YAML { + class Binary; + + struct _Null; + + Emitter::Emitter() : m_pState(new EmitterState), m_stream{} {} + + Emitter::Emitter(std::ostream &stream) + : m_pState(new EmitterState), m_stream(stream) {} + + Emitter::~Emitter() = default; + + const char *Emitter::c_str() const { return m_stream.str(); } + + std::size_t Emitter::size() const { return m_stream.pos(); } + +// state checking + bool Emitter::good() const { return m_pState->good(); } + + const std::string Emitter::GetLastError() const { + return m_pState->GetLastError(); + } + +// global setters + bool Emitter::SetOutputCharset(EMITTER_MANIP value) { + return m_pState->SetOutputCharset(value, FmtScope::Global); + } + + bool Emitter::SetStringFormat(EMITTER_MANIP value) { + return m_pState->SetStringFormat(value, FmtScope::Global); + } + + bool Emitter::SetBoolFormat(EMITTER_MANIP value) { + bool ok = false; + if (m_pState->SetBoolFormat(value, FmtScope::Global)) + ok = true; + if (m_pState->SetBoolCaseFormat(value, FmtScope::Global)) + ok = true; + if (m_pState->SetBoolLengthFormat(value, FmtScope::Global)) + ok = true; + return ok; + } + + bool Emitter::SetIntBase(EMITTER_MANIP value) { + return m_pState->SetIntFormat(value, FmtScope::Global); + } + + bool Emitter::SetSeqFormat(EMITTER_MANIP value) { + return m_pState->SetFlowType(GroupType::Seq, value, FmtScope::Global); + } + + bool Emitter::SetMapFormat(EMITTER_MANIP value) { + bool ok = false; + if (m_pState->SetFlowType(GroupType::Map, value, FmtScope::Global)) + ok = true; + if (m_pState->SetMapKeyFormat(value, FmtScope::Global)) + ok = true; + return ok; + } + + bool Emitter::SetIndent(std::size_t n) { + return m_pState->SetIndent(n, FmtScope::Global); + } + + bool Emitter::SetPreCommentIndent(std::size_t n) { + return m_pState->SetPreCommentIndent(n, FmtScope::Global); + } + + bool Emitter::SetPostCommentIndent(std::size_t n) { + return m_pState->SetPostCommentIndent(n, FmtScope::Global); + } + + bool Emitter::SetFloatPrecision(std::size_t n) { + return m_pState->SetFloatPrecision(n, FmtScope::Global); + } + + bool Emitter::SetDoublePrecision(std::size_t n) { + return m_pState->SetDoublePrecision(n, FmtScope::Global); + } + +// SetLocalValue +// . Either start/end a group, or set a modifier locally + Emitter &Emitter::SetLocalValue(EMITTER_MANIP value) { + if (!good()) + return *this; + + switch (value) { + case BeginDoc: + EmitBeginDoc(); + break; + case EndDoc: + EmitEndDoc(); + break; + case BeginSeq: + EmitBeginSeq(); + break; + case EndSeq: + EmitEndSeq(); + break; + case BeginMap: + EmitBeginMap(); + break; + case EndMap: + EmitEndMap(); + break; + case Key: + case Value: + // deprecated (these can be deduced by the parity of nodes in a map) + break; + case TagByKind: + EmitKindTag(); + break; + case Newline: + EmitNewline(); + break; + default: + m_pState->SetLocalValue(value); + break; + } + return *this; + } + + Emitter &Emitter::SetLocalIndent(const _Indent &indent) { + m_pState->SetIndent(indent.value, FmtScope::Local); + return *this; + } + + Emitter &Emitter::SetLocalPrecision(const _Precision &precision) { + if (precision.floatPrecision >= 0) + m_pState->SetFloatPrecision(precision.floatPrecision, FmtScope::Local); + if (precision.doublePrecision >= 0) + m_pState->SetDoublePrecision(precision.doublePrecision, FmtScope::Local); + return *this; + } + +// EmitBeginDoc + void Emitter::EmitBeginDoc() { + if (!good()) + return; + + if (m_pState->CurGroupType() != GroupType::NoType) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if (m_pState->HasAnchor() || m_pState->HasTag()) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if (m_stream.col() > 0) + m_stream << "\n"; + m_stream << "---\n"; + + m_pState->StartedDoc(); + } + +// EmitEndDoc + void Emitter::EmitEndDoc() { + if (!good()) + return; + + if (m_pState->CurGroupType() != GroupType::NoType) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if (m_pState->HasAnchor() || m_pState->HasTag()) { + m_pState->SetError("Unexpected begin document"); + return; + } + + if (m_stream.col() > 0) + m_stream << "\n"; + m_stream << "...\n"; + } + +// EmitBeginSeq + void Emitter::EmitBeginSeq() { + if (!good()) + return; + + PrepareNode(m_pState->NextGroupType(GroupType::Seq)); + + m_pState->StartedGroup(GroupType::Seq); + } + +// EmitEndSeq + void Emitter::EmitEndSeq() { + if (!good()) + return; + + if (m_pState->CurGroupChildCount() == 0) + m_pState->ForceFlow(); + + if (m_pState->CurGroupFlowType() == FlowType::Flow) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(m_pState->CurIndent()); + if (m_pState->CurGroupChildCount() == 0) + m_stream << "["; + m_stream << "]"; + } + + m_pState->EndedGroup(GroupType::Seq); + } + +// EmitBeginMap + void Emitter::EmitBeginMap() { + if (!good()) + return; + + PrepareNode(m_pState->NextGroupType(GroupType::Map)); + + m_pState->StartedGroup(GroupType::Map); + } + +// EmitEndMap + void Emitter::EmitEndMap() { + if (!good()) + return; + + if (m_pState->CurGroupChildCount() == 0) + m_pState->ForceFlow(); + + if (m_pState->CurGroupFlowType() == FlowType::Flow) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(m_pState->CurIndent()); + if (m_pState->CurGroupChildCount() == 0) + m_stream << "{"; + m_stream << "}"; + } + + m_pState->EndedGroup(GroupType::Map); + } + +// EmitNewline + void Emitter::EmitNewline() { + if (!good()) + return; + + PrepareNode(EmitterNodeType::NoType); + m_stream << "\n"; + m_pState->SetNonContent(); + } + + bool Emitter::CanEmitNewline() const { return true; } + +// Put the stream in a state so we can simply write the next node +// E.g., if we're in a sequence, write the "- " + void Emitter::PrepareNode(EmitterNodeType::value child) { + switch (m_pState->CurGroupNodeType()) { + case EmitterNodeType::NoType: + PrepareTopNode(child); + break; + case EmitterNodeType::FlowSeq: + FlowSeqPrepareNode(child); + break; + case EmitterNodeType::BlockSeq: + BlockSeqPrepareNode(child); + break; + case EmitterNodeType::FlowMap: + FlowMapPrepareNode(child); + break; + case EmitterNodeType::BlockMap: + BlockMapPrepareNode(child); + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + assert(false); + break; + } + } + + void Emitter::PrepareTopNode(EmitterNodeType::value child) { + if (child == EmitterNodeType::NoType) + return; + + if (m_pState->CurGroupChildCount() > 0 && m_stream.col() > 0) + EmitBeginDoc(); + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + // TODO: if we were writing null, and + // we wanted it blank, we wouldn't want a space + SpaceOrIndentTo(m_pState->HasBegunContent(), 0); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + if (m_pState->HasBegunNode()) + m_stream << "\n"; + break; + } + } + + void Emitter::FlowSeqPrepareNode(EmitterNodeType::value child) { + const std::size_t lastIndent = m_pState->LastIndent(); + + if (!m_pState->HasBegunNode()) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(lastIndent); + if (m_pState->CurGroupChildCount() == 0) + m_stream << "["; + else + m_stream << ","; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo( + m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, + lastIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + assert(false); + break; + } + } + + void Emitter::BlockSeqPrepareNode(EmitterNodeType::value child) { + const std::size_t curIndent = m_pState->CurIndent(); + const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent(); + + if (child == EmitterNodeType::NoType) + return; + + if (!m_pState->HasBegunContent()) { + if (m_pState->CurGroupChildCount() > 0 || m_stream.comment()) { + m_stream << "\n"; + } + m_stream << IndentTo(curIndent); + m_stream << "-"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo(m_pState->HasBegunContent(), nextIndent); + break; + case EmitterNodeType::BlockSeq: + m_stream << "\n"; + break; + case EmitterNodeType::BlockMap: + if (m_pState->HasBegunContent() || m_stream.comment()) + m_stream << "\n"; + break; + } + } + + void Emitter::FlowMapPrepareNode(EmitterNodeType::value child) { + if (m_pState->CurGroupChildCount() % 2 == 0) { + if (m_pState->GetMapKeyFormat() == LongKey) + m_pState->SetLongKey(); + + if (m_pState->CurGroupLongKey()) + FlowMapPrepareLongKey(child); + else + FlowMapPrepareSimpleKey(child); + } else { + if (m_pState->CurGroupLongKey()) + FlowMapPrepareLongKeyValue(child); + else + FlowMapPrepareSimpleKeyValue(child); + } + } + + void Emitter::FlowMapPrepareLongKey(EmitterNodeType::value child) { + const std::size_t lastIndent = m_pState->LastIndent(); + + if (!m_pState->HasBegunNode()) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(lastIndent); + if (m_pState->CurGroupChildCount() == 0) + m_stream << "{ ?"; + else + m_stream << ", ?"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo( + m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, + lastIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + assert(false); + break; + } + } + + void Emitter::FlowMapPrepareLongKeyValue(EmitterNodeType::value child) { + const std::size_t lastIndent = m_pState->LastIndent(); + + if (!m_pState->HasBegunNode()) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(lastIndent); + m_stream << ":"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo( + m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, + lastIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + assert(false); + break; + } + } + + void Emitter::FlowMapPrepareSimpleKey(EmitterNodeType::value child) { + const std::size_t lastIndent = m_pState->LastIndent(); + + if (!m_pState->HasBegunNode()) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(lastIndent); + if (m_pState->CurGroupChildCount() == 0) + m_stream << "{"; + else + m_stream << ","; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo( + m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, + lastIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + assert(false); + break; + } + } + + void Emitter::FlowMapPrepareSimpleKeyValue(EmitterNodeType::value child) { + const std::size_t lastIndent = m_pState->LastIndent(); + + if (!m_pState->HasBegunNode()) { + if (m_stream.comment()) + m_stream << "\n"; + m_stream << IndentTo(lastIndent); + m_stream << ":"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo( + m_pState->HasBegunContent() || m_pState->CurGroupChildCount() > 0, + lastIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + assert(false); + break; + } + } + + void Emitter::BlockMapPrepareNode(EmitterNodeType::value child) { + if (m_pState->CurGroupChildCount() % 2 == 0) { + if (m_pState->GetMapKeyFormat() == LongKey) + m_pState->SetLongKey(); + if (child == EmitterNodeType::BlockSeq || + child == EmitterNodeType::BlockMap) + m_pState->SetLongKey(); + + if (m_pState->CurGroupLongKey()) + BlockMapPrepareLongKey(child); + else + BlockMapPrepareSimpleKey(child); + } else { + if (m_pState->CurGroupLongKey()) + BlockMapPrepareLongKeyValue(child); + else + BlockMapPrepareSimpleKeyValue(child); + } + } + + void Emitter::BlockMapPrepareLongKey(EmitterNodeType::value child) { + const std::size_t curIndent = m_pState->CurIndent(); + const std::size_t childCount = m_pState->CurGroupChildCount(); + + if (child == EmitterNodeType::NoType) + return; + + if (!m_pState->HasBegunContent()) { + if (childCount > 0) { + m_stream << "\n"; + } + if (m_stream.comment()) { + m_stream << "\n"; + } + m_stream << IndentTo(curIndent); + m_stream << "?"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo(true, curIndent + 1); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + break; + } + } + + void Emitter::BlockMapPrepareLongKeyValue(EmitterNodeType::value child) { + const std::size_t curIndent = m_pState->CurIndent(); + + if (child == EmitterNodeType::NoType) + return; + + if (!m_pState->HasBegunContent()) { + m_stream << "\n"; + m_stream << IndentTo(curIndent); + m_stream << ":"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + SpaceOrIndentTo(true, curIndent + 1); + break; + } + } + + void Emitter::BlockMapPrepareSimpleKey(EmitterNodeType::value child) { + const std::size_t curIndent = m_pState->CurIndent(); + const std::size_t childCount = m_pState->CurGroupChildCount(); + + if (child == EmitterNodeType::NoType) + return; + + if (!m_pState->HasBegunNode()) { + if (childCount > 0) { + m_stream << "\n"; + } + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo(m_pState->HasBegunContent(), curIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + break; + } + } + + void Emitter::BlockMapPrepareSimpleKeyValue(EmitterNodeType::value child) { + const std::size_t curIndent = m_pState->CurIndent(); + const std::size_t nextIndent = curIndent + m_pState->CurGroupIndent(); + + if (!m_pState->HasBegunNode()) { + m_stream << ":"; + } + + switch (child) { + case EmitterNodeType::NoType: + break; + case EmitterNodeType::Property: + case EmitterNodeType::Scalar: + case EmitterNodeType::FlowSeq: + case EmitterNodeType::FlowMap: + SpaceOrIndentTo(true, nextIndent); + break; + case EmitterNodeType::BlockSeq: + case EmitterNodeType::BlockMap: + m_stream << "\n"; + break; + } + } + +// SpaceOrIndentTo +// . Prepares for some more content by proper spacing + void Emitter::SpaceOrIndentTo(bool requireSpace, std::size_t indent) { + if (m_stream.comment()) + m_stream << "\n"; + if (m_stream.col() > 0 && requireSpace) + m_stream << " "; + m_stream << IndentTo(indent); + } + + void Emitter::PrepareIntegralStream(std::stringstream &stream) const { + + switch (m_pState->GetIntFormat()) { + case Dec: + stream << std::dec; + break; + case Hex: + stream << "0x"; + stream << std::hex; + break; + case Oct: + stream << "0"; + stream << std::oct; + break; + default: + assert(false); + } + } + + void Emitter::StartedScalar() { m_pState->StartedScalar(); } + +// ******************************************************************************************* +// overloads of Write + + Emitter &Emitter::Write(const std::string &str) { + if (!good()) + return *this; + + const bool escapeNonAscii = m_pState->GetOutputCharset() == EscapeNonAscii; + const StringFormat::value strFormat = + Utils::ComputeStringFormat(str, m_pState->GetStringFormat(), + m_pState->CurGroupFlowType(), escapeNonAscii); + + if (strFormat == StringFormat::Literal) + m_pState->SetMapKeyFormat(YAML::LongKey, FmtScope::Local); + + PrepareNode(EmitterNodeType::Scalar); + + switch (strFormat) { + case StringFormat::Plain: + m_stream << str; + break; + case StringFormat::SingleQuoted: + Utils::WriteSingleQuotedString(m_stream, str); + break; + case StringFormat::DoubleQuoted: + Utils::WriteDoubleQuotedString(m_stream, str, escapeNonAscii); + break; + case StringFormat::Literal: + Utils::WriteLiteralString(m_stream, str, + m_pState->CurIndent() + m_pState->GetIndent()); + break; + } + + StartedScalar(); + + return *this; + } + + std::size_t Emitter::GetFloatPrecision() const { + return m_pState->GetFloatPrecision(); + } + + std::size_t Emitter::GetDoublePrecision() const { + return m_pState->GetDoublePrecision(); + } + + const char *Emitter::ComputeFullBoolName(bool b) const { + const EMITTER_MANIP mainFmt = (m_pState->GetBoolLengthFormat() == ShortBool + ? YesNoBool + : m_pState->GetBoolFormat()); + const EMITTER_MANIP caseFmt = m_pState->GetBoolCaseFormat(); + switch (mainFmt) { + case YesNoBool: + switch (caseFmt) { + case UpperCase: + return b ? "YES" : "NO"; + case CamelCase: + return b ? "Yes" : "No"; + case LowerCase: + return b ? "yes" : "no"; + default: + break; + } + break; + case OnOffBool: + switch (caseFmt) { + case UpperCase: + return b ? "ON" : "OFF"; + case CamelCase: + return b ? "On" : "Off"; + case LowerCase: + return b ? "on" : "off"; + default: + break; + } + break; + case TrueFalseBool: + switch (caseFmt) { + case UpperCase: + return b ? "TRUE" : "FALSE"; + case CamelCase: + return b ? "True" : "False"; + case LowerCase: + return b ? "true" : "false"; + default: + break; + } + break; + default: + break; + } + return b ? "y" : "n"; // should never get here, but it can't hurt to give + // these answers + } + + Emitter &Emitter::Write(bool b) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + + const char *name = ComputeFullBoolName(b); + if (m_pState->GetBoolLengthFormat() == ShortBool) + m_stream << name[0]; + else + m_stream << name; + + StartedScalar(); + + return *this; + } + + Emitter &Emitter::Write(char ch) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + Utils::WriteChar(m_stream, ch); + StartedScalar(); + + return *this; + } + + Emitter &Emitter::Write(const _Alias &alias) { + if (!good()) + return *this; + + if (m_pState->HasAnchor() || m_pState->HasTag()) { + m_pState->SetError(ErrorMsg::INVALID_ALIAS); + return *this; + } + + PrepareNode(EmitterNodeType::Scalar); + + if (!Utils::WriteAlias(m_stream, alias.content)) { + m_pState->SetError(ErrorMsg::INVALID_ALIAS); + return *this; + } + + StartedScalar(); + + return *this; + } + + Emitter &Emitter::Write(const _Anchor &anchor) { + if (!good()) + return *this; + + if (m_pState->HasAnchor()) { + m_pState->SetError(ErrorMsg::INVALID_ANCHOR); + return *this; + } + + PrepareNode(EmitterNodeType::Property); + + if (!Utils::WriteAnchor(m_stream, anchor.content)) { + m_pState->SetError(ErrorMsg::INVALID_ANCHOR); + return *this; + } + + m_pState->SetAnchor(); + + return *this; + } + + Emitter &Emitter::Write(const _Tag &tag) { + if (!good()) + return *this; + + if (m_pState->HasTag()) { + m_pState->SetError(ErrorMsg::INVALID_TAG); + return *this; + } + + PrepareNode(EmitterNodeType::Property); + + bool success = false; + if (tag.type == _Tag::Type::Verbatim) + success = Utils::WriteTag(m_stream, tag.content, true); + else if (tag.type == _Tag::Type::PrimaryHandle) + success = Utils::WriteTag(m_stream, tag.content, false); + else + success = Utils::WriteTagWithPrefix(m_stream, tag.prefix, tag.content); + + if (!success) { + m_pState->SetError(ErrorMsg::INVALID_TAG); + return *this; + } + + m_pState->SetTag(); + + return *this; + } + + void Emitter::EmitKindTag() { Write(LocalTag("")); } + + Emitter &Emitter::Write(const _Comment &comment) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::NoType); + + if (m_stream.col() > 0) + m_stream << Indentation(m_pState->GetPreCommentIndent()); + Utils::WriteComment(m_stream, comment.content, + m_pState->GetPostCommentIndent()); + + m_pState->SetNonContent(); + + return *this; + } + + Emitter &Emitter::Write(const _Null & /*null*/) { + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + + m_stream << "~"; + + StartedScalar(); + + return *this; + } + + Emitter &Emitter::Write(const Binary &binary) { + Write(SecondaryTag("binary")); + + if (!good()) + return *this; + + PrepareNode(EmitterNodeType::Scalar); + Utils::WriteBinary(m_stream, binary); + StartedScalar(); + + return *this; + } +} // namespace YAML diff --git a/yaml-cpp/src/emitterstate.cpp b/yaml-cpp/src/emitterstate.cpp new file mode 100644 index 0000000..97f37ee --- /dev/null +++ b/yaml-cpp/src/emitterstate.cpp @@ -0,0 +1,369 @@ +#include + +#include "emitterstate.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep + +namespace YAML { + EmitterState::EmitterState() + : m_isGood(true), + m_lastError{}, + // default global manipulators + m_charset(EmitNonAscii), + m_strFmt(Auto), + m_boolFmt(TrueFalseBool), + m_boolLengthFmt(LongBool), + m_boolCaseFmt(LowerCase), + m_intFmt(Dec), + m_indent(2), + m_preCommentIndent(2), + m_postCommentIndent(1), + m_seqFmt(Block), + m_mapFmt(Block), + m_mapKeyFmt(Auto), + m_floatPrecision(std::numeric_limits::max_digits10), + m_doublePrecision(std::numeric_limits::max_digits10), + // + m_modifiedSettings{}, + m_globalModifiedSettings{}, + m_groups{}, + m_curIndent(0), + m_hasAnchor(false), + m_hasTag(false), + m_hasNonContent(false), + m_docCount(0) {} + + EmitterState::~EmitterState() = default; + +// SetLocalValue +// . We blindly tries to set all possible formatters to this value +// . Only the ones that make sense will be accepted + void EmitterState::SetLocalValue(EMITTER_MANIP value) { + SetOutputCharset(value, FmtScope::Local); + SetStringFormat(value, FmtScope::Local); + SetBoolFormat(value, FmtScope::Local); + SetBoolCaseFormat(value, FmtScope::Local); + SetBoolLengthFormat(value, FmtScope::Local); + SetIntFormat(value, FmtScope::Local); + SetFlowType(GroupType::Seq, value, FmtScope::Local); + SetFlowType(GroupType::Map, value, FmtScope::Local); + SetMapKeyFormat(value, FmtScope::Local); + } + + void EmitterState::SetAnchor() { m_hasAnchor = true; } + + void EmitterState::SetTag() { m_hasTag = true; } + + void EmitterState::SetNonContent() { m_hasNonContent = true; } + + void EmitterState::SetLongKey() { + assert(!m_groups.empty()); + if (m_groups.empty()) { + return; + } + + assert(m_groups.back()->type == GroupType::Map); + m_groups.back()->longKey = true; + } + + void EmitterState::ForceFlow() { + assert(!m_groups.empty()); + if (m_groups.empty()) { + return; + } + + m_groups.back()->flowType = FlowType::Flow; + } + + void EmitterState::StartedNode() { + if (m_groups.empty()) { + m_docCount++; + } else { + m_groups.back()->childCount++; + if (m_groups.back()->childCount % 2 == 0) { + m_groups.back()->longKey = false; + } + } + + m_hasAnchor = false; + m_hasTag = false; + m_hasNonContent = false; + } + + EmitterNodeType::value EmitterState::NextGroupType( + GroupType::value type) const { + if (type == GroupType::Seq) { + if (GetFlowType(type) == Block) + return EmitterNodeType::BlockSeq; + else + return EmitterNodeType::FlowSeq; + } else { + if (GetFlowType(type) == Block) + return EmitterNodeType::BlockMap; + else + return EmitterNodeType::FlowMap; + } + + // can't happen + assert(false); + return EmitterNodeType::NoType; + } + + void EmitterState::StartedDoc() { + m_hasAnchor = false; + m_hasTag = false; + m_hasNonContent = false; + } + + void EmitterState::EndedDoc() { + m_hasAnchor = false; + m_hasTag = false; + m_hasNonContent = false; + } + + void EmitterState::StartedScalar() { + StartedNode(); + ClearModifiedSettings(); + } + + void EmitterState::StartedGroup(GroupType::value type) { + StartedNode(); + + const std::size_t lastGroupIndent = + (m_groups.empty() ? 0 : m_groups.back()->indent); + m_curIndent += lastGroupIndent; + + // TODO: Create move constructors for settings types to simplify transfer + std::unique_ptr pGroup(new Group(type)); + + // transfer settings (which last until this group is done) + // + // NB: if pGroup->modifiedSettings == m_modifiedSettings, + // m_modifiedSettings is not changed! + pGroup->modifiedSettings = std::move(m_modifiedSettings); + + // set up group + if (GetFlowType(type) == Block) { + pGroup->flowType = FlowType::Block; + } else { + pGroup->flowType = FlowType::Flow; + } + pGroup->indent = GetIndent(); + + m_groups.push_back(std::move(pGroup)); + } + + void EmitterState::EndedGroup(GroupType::value type) { + if (m_groups.empty()) { + if (type == GroupType::Seq) { + return SetError(ErrorMsg::UNEXPECTED_END_SEQ); + } else { + return SetError(ErrorMsg::UNEXPECTED_END_MAP); + } + } + + // get rid of the current group + { + std::unique_ptr pFinishedGroup = std::move(m_groups.back()); + m_groups.pop_back(); + if (pFinishedGroup->type != type) { + return SetError(ErrorMsg::UNMATCHED_GROUP_TAG); + } + } + + // reset old settings + std::size_t lastIndent = (m_groups.empty() ? 0 : m_groups.back()->indent); + assert(m_curIndent >= lastIndent); + m_curIndent -= lastIndent; + + // some global settings that we changed may have been overridden + // by a local setting we just popped, so we need to restore them + m_globalModifiedSettings.restore(); + + ClearModifiedSettings(); + } + + EmitterNodeType::value EmitterState::CurGroupNodeType() const { + if (m_groups.empty()) { + return EmitterNodeType::NoType; + } + + return m_groups.back()->NodeType(); + } + + GroupType::value EmitterState::CurGroupType() const { + return m_groups.empty() ? GroupType::NoType : m_groups.back()->type; + } + + FlowType::value EmitterState::CurGroupFlowType() const { + return m_groups.empty() ? FlowType::NoType : m_groups.back()->flowType; + } + + std::size_t EmitterState::CurGroupIndent() const { + return m_groups.empty() ? 0 : m_groups.back()->indent; + } + + std::size_t EmitterState::CurGroupChildCount() const { + return m_groups.empty() ? m_docCount : m_groups.back()->childCount; + } + + bool EmitterState::CurGroupLongKey() const { + return m_groups.empty() ? false : m_groups.back()->longKey; + } + + std::size_t EmitterState::LastIndent() const { + if (m_groups.size() <= 1) { + return 0; + } + + return m_curIndent - m_groups[m_groups.size() - 2]->indent; + } + + void EmitterState::ClearModifiedSettings() { m_modifiedSettings.clear(); } + + bool EmitterState::SetOutputCharset(EMITTER_MANIP value, + FmtScope::value scope) { + switch (value) { + case EmitNonAscii: + case EscapeNonAscii: + _Set(m_charset, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetStringFormat(EMITTER_MANIP value, FmtScope::value scope) { + switch (value) { + case Auto: + case SingleQuoted: + case DoubleQuoted: + case Literal: + _Set(m_strFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope) { + switch (value) { + case OnOffBool: + case TrueFalseBool: + case YesNoBool: + _Set(m_boolFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolLengthFormat(EMITTER_MANIP value, + FmtScope::value scope) { + switch (value) { + case LongBool: + case ShortBool: + _Set(m_boolLengthFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetBoolCaseFormat(EMITTER_MANIP value, + FmtScope::value scope) { + switch (value) { + case UpperCase: + case LowerCase: + case CamelCase: + _Set(m_boolCaseFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetIntFormat(EMITTER_MANIP value, FmtScope::value scope) { + switch (value) { + case Dec: + case Hex: + case Oct: + _Set(m_intFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetIndent(std::size_t value, FmtScope::value scope) { + if (value <= 1) + return false; + + _Set(m_indent, value, scope); + return true; + } + + bool EmitterState::SetPreCommentIndent(std::size_t value, + FmtScope::value scope) { + if (value == 0) + return false; + + _Set(m_preCommentIndent, value, scope); + return true; + } + + bool EmitterState::SetPostCommentIndent(std::size_t value, + FmtScope::value scope) { + if (value == 0) + return false; + + _Set(m_postCommentIndent, value, scope); + return true; + } + + bool EmitterState::SetFlowType(GroupType::value groupType, EMITTER_MANIP value, + FmtScope::value scope) { + switch (value) { + case Block: + case Flow: + _Set(groupType == GroupType::Seq ? m_seqFmt : m_mapFmt, value, scope); + return true; + default: + return false; + } + } + + EMITTER_MANIP EmitterState::GetFlowType(GroupType::value groupType) const { + // force flow style if we're currently in a flow + if (CurGroupFlowType() == FlowType::Flow) + return Flow; + + // otherwise, go with what's asked of us + return (groupType == GroupType::Seq ? m_seqFmt.get() : m_mapFmt.get()); + } + + bool EmitterState::SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope) { + switch (value) { + case Auto: + case LongKey: + _Set(m_mapKeyFmt, value, scope); + return true; + default: + return false; + } + } + + bool EmitterState::SetFloatPrecision(std::size_t value, FmtScope::value scope) { + if (value > std::numeric_limits::max_digits10) + return false; + _Set(m_floatPrecision, value, scope); + return true; + } + + bool EmitterState::SetDoublePrecision(std::size_t value, + FmtScope::value scope) { + if (value > std::numeric_limits::max_digits10) + return false; + _Set(m_doublePrecision, value, scope); + return true; + } +} // namespace YAML diff --git a/yaml-cpp/src/emitterstate.h b/yaml-cpp/src/emitterstate.h new file mode 100644 index 0000000..4583b35 --- /dev/null +++ b/yaml-cpp/src/emitterstate.h @@ -0,0 +1,251 @@ +#ifndef EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "setting.h" +#include "yaml-cpp/emitterdef.h" +#include "yaml-cpp/emittermanip.h" + +#include +#include +#include +#include +#include + +namespace YAML { + struct FmtScope { + enum value { + Local, Global + }; + }; + struct GroupType { + enum value { + NoType, Seq, Map + }; + }; + struct FlowType { + enum value { + NoType, Flow, Block + }; + }; + + class EmitterState { + public: + EmitterState(); + + ~EmitterState(); + + // basic state checking + bool good() const { return m_isGood; } + + const std::string GetLastError() const { return m_lastError; } + + void SetError(const std::string &error) { + m_isGood = false; + m_lastError = error; + } + + // node handling + void SetAnchor(); + + void SetTag(); + + void SetNonContent(); + + void SetLongKey(); + + void ForceFlow(); + + void StartedDoc(); + + void EndedDoc(); + + void StartedScalar(); + + void StartedGroup(GroupType::value type); + + void EndedGroup(GroupType::value type); + + EmitterNodeType::value NextGroupType(GroupType::value type) const; + + EmitterNodeType::value CurGroupNodeType() const; + + GroupType::value CurGroupType() const; + + FlowType::value CurGroupFlowType() const; + + std::size_t CurGroupIndent() const; + + std::size_t CurGroupChildCount() const; + + bool CurGroupLongKey() const; + + std::size_t LastIndent() const; + + std::size_t CurIndent() const { return m_curIndent; } + + bool HasAnchor() const { return m_hasAnchor; } + + bool HasTag() const { return m_hasTag; } + + bool HasBegunNode() const { + return m_hasAnchor || m_hasTag || m_hasNonContent; + } + + bool HasBegunContent() const { return m_hasAnchor || m_hasTag; } + + void ClearModifiedSettings(); + + // formatters + void SetLocalValue(EMITTER_MANIP value); + + bool SetOutputCharset(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetOutputCharset() const { return m_charset.get(); } + + bool SetStringFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetStringFormat() const { return m_strFmt.get(); } + + bool SetBoolFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetBoolFormat() const { return m_boolFmt.get(); } + + bool SetBoolLengthFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetBoolLengthFormat() const { return m_boolLengthFmt.get(); } + + bool SetBoolCaseFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetBoolCaseFormat() const { return m_boolCaseFmt.get(); } + + bool SetIntFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetIntFormat() const { return m_intFmt.get(); } + + bool SetIndent(std::size_t value, FmtScope::value scope); + + std::size_t GetIndent() const { return m_indent.get(); } + + bool SetPreCommentIndent(std::size_t value, FmtScope::value scope); + + std::size_t GetPreCommentIndent() const { return m_preCommentIndent.get(); } + + bool SetPostCommentIndent(std::size_t value, FmtScope::value scope); + + std::size_t GetPostCommentIndent() const { return m_postCommentIndent.get(); } + + bool SetFlowType(GroupType::value groupType, EMITTER_MANIP value, + FmtScope::value scope); + + EMITTER_MANIP GetFlowType(GroupType::value groupType) const; + + bool SetMapKeyFormat(EMITTER_MANIP value, FmtScope::value scope); + + EMITTER_MANIP GetMapKeyFormat() const { return m_mapKeyFmt.get(); } + + bool SetFloatPrecision(std::size_t value, FmtScope::value scope); + + std::size_t GetFloatPrecision() const { return m_floatPrecision.get(); } + + bool SetDoublePrecision(std::size_t value, FmtScope::value scope); + + std::size_t GetDoublePrecision() const { return m_doublePrecision.get(); } + + private: + template + void _Set(Setting &fmt, T value, FmtScope::value scope); + + void StartedNode(); + + private: + // basic state ok? + bool m_isGood; + std::string m_lastError; + + // other state + Setting m_charset; + Setting m_strFmt; + Setting m_boolFmt; + Setting m_boolLengthFmt; + Setting m_boolCaseFmt; + Setting m_intFmt; + Setting m_indent; + Setting m_preCommentIndent, m_postCommentIndent; + Setting m_seqFmt; + Setting m_mapFmt; + Setting m_mapKeyFmt; + Setting m_floatPrecision; + Setting m_doublePrecision; + + SettingChanges m_modifiedSettings; + SettingChanges m_globalModifiedSettings; + + struct Group { + explicit Group(GroupType::value type_) + : type(type_), + flowType{}, + indent(0), + childCount(0), + longKey(false), + modifiedSettings{} {} + + GroupType::value type; + FlowType::value flowType; + std::size_t indent; + std::size_t childCount; + bool longKey; + + SettingChanges modifiedSettings; + + EmitterNodeType::value NodeType() const { + if (type == GroupType::Seq) { + if (flowType == FlowType::Flow) + return EmitterNodeType::FlowSeq; + else + return EmitterNodeType::BlockSeq; + } else { + if (flowType == FlowType::Flow) + return EmitterNodeType::FlowMap; + else + return EmitterNodeType::BlockMap; + } + + // can't get here + assert(false); + return EmitterNodeType::NoType; + } + }; + + std::vector> m_groups; + std::size_t m_curIndent; + bool m_hasAnchor; + bool m_hasTag; + bool m_hasNonContent; + std::size_t m_docCount; + }; + + template + void EmitterState::_Set(Setting &fmt, T value, FmtScope::value scope) { + switch (scope) { + case FmtScope::Local: + m_modifiedSettings.push(fmt.set(value)); + break; + case FmtScope::Global: + fmt.set(value); + m_globalModifiedSettings.push( + fmt.set(value)); // this pushes an identity set, so when we restore, + // it restores to the value here, and not the previous one + break; + default: + assert(false); + } + } +} // namespace YAML + +#endif // EMITTERSTATE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/emitterutils.cpp b/yaml-cpp/src/emitterutils.cpp new file mode 100644 index 0000000..6c35734 --- /dev/null +++ b/yaml-cpp/src/emitterutils.cpp @@ -0,0 +1,485 @@ +#include +#include + +#include "emitterutils.h" +#include "exp.h" +#include "indentation.h" +#include "regex_yaml.h" +#include "regeximpl.h" +#include "stringsource.h" +#include "yaml-cpp/binary.h" // IWYU pragma: keep +#include "yaml-cpp/null.h" +#include "yaml-cpp/ostream_wrapper.h" + +namespace YAML { + namespace Utils { + namespace { + enum { + REPLACEMENT_CHARACTER = 0xFFFD + }; + + bool IsAnchorChar(int ch) { // test for ns-anchor-char + switch (ch) { + case ',': + case '[': + case ']': + case '{': + case '}': // c-flow-indicator + case ' ': + case '\t': // s-white + case 0xFEFF: // c-byte-order-mark + case 0xA: + case 0xD: // b-char + return false; + case 0x85: + return true; + } + + if (ch < 0x20) { + return false; + } + + if (ch < 0x7E) { + return true; + } + + if (ch < 0xA0) { + return false; + } + if (ch >= 0xD800 && ch <= 0xDFFF) { + return false; + } + if ((ch & 0xFFFE) == 0xFFFE) { + return false; + } + if ((ch >= 0xFDD0) && (ch <= 0xFDEF)) { + return false; + } + if (ch > 0x10FFFF) { + return false; + } + + return true; + } + + int Utf8BytesIndicated(char ch) { + int byteVal = static_cast(ch); + switch (byteVal >> 4) { + case 0: + case 1: + case 2: + case 3: + case 4: + case 5: + case 6: + case 7: + return 1; + case 12: + case 13: + return 2; + case 14: + return 3; + case 15: + return 4; + default: + return -1; + } + } + + bool IsTrailingByte(char ch) { return (ch & 0xC0) == 0x80; } + + bool GetNextCodePointAndAdvance(int &codePoint, + std::string::const_iterator &first, + std::string::const_iterator last) { + if (first == last) + return false; + + int nBytes = Utf8BytesIndicated(*first); + if (nBytes < 1) { + // Bad lead byte + ++first; + codePoint = REPLACEMENT_CHARACTER; + return true; + } + + if (nBytes == 1) { + codePoint = *first++; + return true; + } + + // Gather bits from trailing bytes + codePoint = static_cast(*first) & ~(0xFF << (7 - nBytes)); + ++first; + --nBytes; + for (; nBytes > 0; ++first, --nBytes) { + if ((first == last) || !IsTrailingByte(*first)) { + codePoint = REPLACEMENT_CHARACTER; + break; + } + codePoint <<= 6; + codePoint |= *first & 0x3F; + } + + // Check for illegal code points + if (codePoint > 0x10FFFF) + codePoint = REPLACEMENT_CHARACTER; + else if (codePoint >= 0xD800 && codePoint <= 0xDFFF) + codePoint = REPLACEMENT_CHARACTER; + else if ((codePoint & 0xFFFE) == 0xFFFE) + codePoint = REPLACEMENT_CHARACTER; + else if (codePoint >= 0xFDD0 && codePoint <= 0xFDEF) + codePoint = REPLACEMENT_CHARACTER; + return true; + } + + void WriteCodePoint(ostream_wrapper &out, int codePoint) { + if (codePoint < 0 || codePoint > 0x10FFFF) { + codePoint = REPLACEMENT_CHARACTER; + } + if (codePoint <= 0x7F) { + out << static_cast(codePoint); + } else if (codePoint <= 0x7FF) { + out << static_cast(0xC0 | (codePoint >> 6)) + << static_cast(0x80 | (codePoint & 0x3F)); + } else if (codePoint <= 0xFFFF) { + out << static_cast(0xE0 | (codePoint >> 12)) + << static_cast(0x80 | ((codePoint >> 6) & 0x3F)) + << static_cast(0x80 | (codePoint & 0x3F)); + } else { + out << static_cast(0xF0 | (codePoint >> 18)) + << static_cast(0x80 | ((codePoint >> 12) & 0x3F)) + << static_cast(0x80 | ((codePoint >> 6) & 0x3F)) + << static_cast(0x80 | (codePoint & 0x3F)); + } + } + + bool IsValidPlainScalar(const std::string &str, FlowType::value flowType, + bool allowOnlyAscii) { + // check against null + if (IsNullString(str)) { + return false; + } + + // check the start + const RegEx &start = (flowType == FlowType::Flow ? Exp::PlainScalarInFlow() + : Exp::PlainScalar()); + if (!start.Matches(str)) { + return false; + } + + // and check the end for plain whitespace (which can't be faithfully kept in a + // plain scalar) + if (!str.empty() && *str.rbegin() == ' ') { + return false; + } + + // then check until something is disallowed + static const RegEx &disallowed_flow = + Exp::EndScalarInFlow() | (Exp::BlankOrBreak() + Exp::Comment()) | + Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() | + Exp::Tab(); + static const RegEx &disallowed_block = + Exp::EndScalar() | (Exp::BlankOrBreak() + Exp::Comment()) | + Exp::NotPrintable() | Exp::Utf8_ByteOrderMark() | Exp::Break() | + Exp::Tab(); + const RegEx &disallowed = + flowType == FlowType::Flow ? disallowed_flow : disallowed_block; + + StringCharSource buffer(str.c_str(), str.size()); + while (buffer) { + if (disallowed.Matches(buffer)) { + return false; + } + if (allowOnlyAscii && (0x80 <= static_cast(buffer[0]))) { + return false; + } + ++buffer; + } + + return true; + } + + bool IsValidSingleQuotedScalar(const std::string &str, bool escapeNonAscii) { + // TODO: check for non-printable characters? + for (char ch : str) { + if (escapeNonAscii && (0x80 <= static_cast(ch))) { + return false; + } + if (ch == '\n') { + return false; + } + } + return true; + } + + bool IsValidLiteralScalar(const std::string &str, FlowType::value flowType, + bool escapeNonAscii) { + if (flowType == FlowType::Flow) { + return false; + } + + // TODO: check for non-printable characters? + for (char ch : str) { + if (escapeNonAscii && (0x80 <= static_cast(ch))) { + return false; + } + } + return true; + } + + void WriteDoubleQuoteEscapeSequence(ostream_wrapper &out, int codePoint) { + static const char hexDigits[] = "0123456789abcdef"; + + out << "\\"; + int digits = 8; + if (codePoint < 0xFF) { + out << "x"; + digits = 2; + } else if (codePoint < 0xFFFF) { + out << "u"; + digits = 4; + } else { + out << "U"; + digits = 8; + } + + // Write digits into the escape sequence + for (; digits > 0; --digits) + out << hexDigits[(codePoint >> (4 * (digits - 1))) & 0xF]; + } + + bool WriteAliasName(ostream_wrapper &out, const std::string &str) { + int codePoint; + for (std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end());) { + if (!IsAnchorChar(codePoint)) { + return false; + } + + WriteCodePoint(out, codePoint); + } + return true; + } + } // namespace + + StringFormat::value ComputeStringFormat(const std::string &str, + EMITTER_MANIP strFormat, + FlowType::value flowType, + bool escapeNonAscii) { + switch (strFormat) { + case Auto: + if (IsValidPlainScalar(str, flowType, escapeNonAscii)) { + return StringFormat::Plain; + } + return StringFormat::DoubleQuoted; + case SingleQuoted: + if (IsValidSingleQuotedScalar(str, escapeNonAscii)) { + return StringFormat::SingleQuoted; + } + return StringFormat::DoubleQuoted; + case DoubleQuoted: + return StringFormat::DoubleQuoted; + case Literal: + if (IsValidLiteralScalar(str, flowType, escapeNonAscii)) { + return StringFormat::Literal; + } + return StringFormat::DoubleQuoted; + default: + break; + } + + return StringFormat::DoubleQuoted; + } + + bool WriteSingleQuotedString(ostream_wrapper &out, const std::string &str) { + out << "'"; + int codePoint; + for (std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end());) { + if (codePoint == '\n') { + return false; // We can't handle a new line and the attendant indentation + // yet + } + + if (codePoint == '\'') { + out << "''"; + } else { + WriteCodePoint(out, codePoint); + } + } + out << "'"; + return true; + } + + bool WriteDoubleQuotedString(ostream_wrapper &out, const std::string &str, + bool escapeNonAscii) { + out << "\""; + int codePoint; + for (std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end());) { + switch (codePoint) { + case '\"': + out << "\\\""; + break; + case '\\': + out << "\\\\"; + break; + case '\n': + out << "\\n"; + break; + case '\t': + out << "\\t"; + break; + case '\r': + out << "\\r"; + break; + case '\b': + out << "\\b"; + break; + default: + if (codePoint < 0x20 || + (codePoint >= 0x80 && + codePoint <= 0xA0)) { // Control characters and non-breaking space + WriteDoubleQuoteEscapeSequence(out, codePoint); + } else if (codePoint == 0xFEFF) { // Byte order marks (ZWNS) should be + // escaped (YAML 1.2, sec. 5.2) + WriteDoubleQuoteEscapeSequence(out, codePoint); + } else if (escapeNonAscii && codePoint > 0x7E) { + WriteDoubleQuoteEscapeSequence(out, codePoint); + } else { + WriteCodePoint(out, codePoint); + } + } + } + out << "\""; + return true; + } + + bool WriteLiteralString(ostream_wrapper &out, const std::string &str, + std::size_t indent) { + out << "|\n"; + out << IndentTo(indent); + int codePoint; + for (std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end());) { + if (codePoint == '\n') { + out << "\n" << IndentTo(indent); + } else { + WriteCodePoint(out, codePoint); + } + } + return true; + } + + bool WriteChar(ostream_wrapper &out, char ch) { + if (('a' <= ch && ch <= 'z') || ('A' <= ch && ch <= 'Z')) { + out << ch; + } else if (ch == '\"') { + out << "\"\\\"\""; + } else if (ch == '\t') { + out << "\"\\t\""; + } else if (ch == '\n') { + out << "\"\\n\""; + } else if (ch == '\b') { + out << "\"\\b\""; + } else if (ch == '\\') { + out << "\"\\\\\""; + } else if (0x20 <= ch && ch <= 0x7e) { + out << "\"" << ch << "\""; + } else { + out << "\""; + WriteDoubleQuoteEscapeSequence(out, ch); + out << "\""; + } + return true; + } + + bool WriteComment(ostream_wrapper &out, const std::string &str, + std::size_t postCommentIndent) { + const std::size_t curIndent = out.col(); + out << "#" << Indentation(postCommentIndent); + out.set_comment(); + int codePoint; + for (std::string::const_iterator i = str.begin(); + GetNextCodePointAndAdvance(codePoint, i, str.end());) { + if (codePoint == '\n') { + out << "\n" + << IndentTo(curIndent) << "#" << Indentation(postCommentIndent); + out.set_comment(); + } else { + WriteCodePoint(out, codePoint); + } + } + return true; + } + + bool WriteAlias(ostream_wrapper &out, const std::string &str) { + out << "*"; + return WriteAliasName(out, str); + } + + bool WriteAnchor(ostream_wrapper &out, const std::string &str) { + out << "&"; + return WriteAliasName(out, str); + } + + bool WriteTag(ostream_wrapper &out, const std::string &str, bool verbatim) { + out << (verbatim ? "!<" : "!"); + StringCharSource buffer(str.c_str(), str.size()); + const RegEx &reValid = verbatim ? Exp::URI() : Exp::Tag(); + while (buffer) { + int n = reValid.Match(buffer); + if (n <= 0) { + return false; + } + + while (--n >= 0) { + out << buffer[0]; + ++buffer; + } + } + if (verbatim) { + out << ">"; + } + return true; + } + + bool WriteTagWithPrefix(ostream_wrapper &out, const std::string &prefix, + const std::string &tag) { + out << "!"; + StringCharSource prefixBuffer(prefix.c_str(), prefix.size()); + while (prefixBuffer) { + int n = Exp::URI().Match(prefixBuffer); + if (n <= 0) { + return false; + } + + while (--n >= 0) { + out << prefixBuffer[0]; + ++prefixBuffer; + } + } + + out << "!"; + StringCharSource tagBuffer(tag.c_str(), tag.size()); + while (tagBuffer) { + int n = Exp::Tag().Match(tagBuffer); + if (n <= 0) { + return false; + } + + while (--n >= 0) { + out << tagBuffer[0]; + ++tagBuffer; + } + } + return true; + } + + bool WriteBinary(ostream_wrapper &out, const Binary &binary) { + WriteDoubleQuotedString(out, EncodeBase64(binary.data(), binary.size()), + false); + return true; + } + } // namespace Utils +} // namespace YAML diff --git a/yaml-cpp/src/emitterutils.h b/yaml-cpp/src/emitterutils.h new file mode 100644 index 0000000..57ce54b --- /dev/null +++ b/yaml-cpp/src/emitterutils.h @@ -0,0 +1,61 @@ +#ifndef EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "emitterstate.h" +#include "yaml-cpp/emittermanip.h" +#include "yaml-cpp/ostream_wrapper.h" + +namespace YAML { + class ostream_wrapper; +} // namespace YAML + +namespace YAML { + class Binary; + + struct StringFormat { + enum value { + Plain, SingleQuoted, DoubleQuoted, Literal + }; + }; + + namespace Utils { + StringFormat::value ComputeStringFormat(const std::string &str, + EMITTER_MANIP strFormat, + FlowType::value flowType, + bool escapeNonAscii); + + bool WriteSingleQuotedString(ostream_wrapper &out, const std::string &str); + + bool WriteDoubleQuotedString(ostream_wrapper &out, const std::string &str, + bool escapeNonAscii); + + bool WriteLiteralString(ostream_wrapper &out, const std::string &str, + std::size_t indent); + + bool WriteChar(ostream_wrapper &out, char ch); + + bool WriteComment(ostream_wrapper &out, const std::string &str, + std::size_t postCommentIndent); + + bool WriteAlias(ostream_wrapper &out, const std::string &str); + + bool WriteAnchor(ostream_wrapper &out, const std::string &str); + + bool WriteTag(ostream_wrapper &out, const std::string &str, bool verbatim); + + bool WriteTagWithPrefix(ostream_wrapper &out, const std::string &prefix, + const std::string &tag); + + bool WriteBinary(ostream_wrapper &out, const Binary &binary); + } +} + +#endif // EMITTERUTILS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/exceptions.cpp b/yaml-cpp/src/exceptions.cpp new file mode 100644 index 0000000..c5324b5 --- /dev/null +++ b/yaml-cpp/src/exceptions.cpp @@ -0,0 +1,32 @@ +#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/noexcept.h" + +namespace YAML { + +// These destructors are defined out-of-line so the vtable is only emitted once. + Exception::~Exception() YAML_CPP_NOEXCEPT = default; + + ParserException::~ParserException() YAML_CPP_NOEXCEPT = default; + + RepresentationException::~RepresentationException() YAML_CPP_NOEXCEPT = default; + + InvalidScalar::~InvalidScalar() YAML_CPP_NOEXCEPT = default; + + KeyNotFound::~KeyNotFound() YAML_CPP_NOEXCEPT = default; + + InvalidNode::~InvalidNode() YAML_CPP_NOEXCEPT = default; + + BadConversion::~BadConversion() YAML_CPP_NOEXCEPT = default; + + BadDereference::~BadDereference() YAML_CPP_NOEXCEPT = default; + + BadSubscript::~BadSubscript() YAML_CPP_NOEXCEPT = default; + + BadPushback::~BadPushback() YAML_CPP_NOEXCEPT = default; + + BadInsert::~BadInsert() YAML_CPP_NOEXCEPT = default; + + EmitterException::~EmitterException() YAML_CPP_NOEXCEPT = default; + + BadFile::~BadFile() YAML_CPP_NOEXCEPT = default; +} // namespace YAML diff --git a/yaml-cpp/src/exp.cpp b/yaml-cpp/src/exp.cpp new file mode 100644 index 0000000..17fc790 --- /dev/null +++ b/yaml-cpp/src/exp.cpp @@ -0,0 +1,135 @@ +#include + +#include "exp.h" +#include "stream.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep + +namespace YAML { + struct Mark; +} // namespace YAML + +namespace YAML { + namespace Exp { + unsigned ParseHex(const std::string &str, const Mark &mark) { + unsigned value = 0; + for (char ch : str) { + int digit = 0; + if ('a' <= ch && ch <= 'f') + digit = ch - 'a' + 10; + else if ('A' <= ch && ch <= 'F') + digit = ch - 'A' + 10; + else if ('0' <= ch && ch <= '9') + digit = ch - '0'; + else + throw ParserException(mark, ErrorMsg::INVALID_HEX); + + value = (value << 4) + digit; + } + + return value; + } + + std::string Str(unsigned ch) { return std::string(1, static_cast(ch)); } + +// Escape +// . Translates the next 'codeLength' characters into a hex number and returns +// the result. +// . Throws if it's not actually hex. + std::string Escape(Stream &in, int codeLength) { + // grab string + std::string str; + for (int i = 0; i < codeLength; i++) + str += in.get(); + + // get the value + unsigned value = ParseHex(str, in.mark()); + + // legal unicode? + if ((value >= 0xD800 && value <= 0xDFFF) || value > 0x10FFFF) { + std::stringstream msg; + msg << ErrorMsg::INVALID_UNICODE << value; + throw ParserException(in.mark(), msg.str()); + } + + // now break it up into chars + if (value <= 0x7F) + return Str(value); + else if (value <= 0x7FF) + return Str(0xC0 + (value >> 6)) + Str(0x80 + (value & 0x3F)); + else if (value <= 0xFFFF) + return Str(0xE0 + (value >> 12)) + Str(0x80 + ((value >> 6) & 0x3F)) + + Str(0x80 + (value & 0x3F)); + else + return Str(0xF0 + (value >> 18)) + Str(0x80 + ((value >> 12) & 0x3F)) + + Str(0x80 + ((value >> 6) & 0x3F)) + Str(0x80 + (value & 0x3F)); + } + +// Escape +// . Escapes the sequence starting 'in' (it must begin with a '\' or single +// quote) +// and returns the result. +// . Throws if it's an unknown escape character. + std::string Escape(Stream &in) { + // eat slash + char escape = in.get(); + + // switch on escape character + char ch = in.get(); + + // first do single quote, since it's easier + if (escape == '\'' && ch == '\'') + return "\'"; + + // now do the slash (we're not gonna check if it's a slash - you better pass + // one!) + switch (ch) { + case '0': + return std::string(1, '\x00'); + case 'a': + return "\x07"; + case 'b': + return "\x08"; + case 't': + case '\t': + return "\x09"; + case 'n': + return "\x0A"; + case 'v': + return "\x0B"; + case 'f': + return "\x0C"; + case 'r': + return "\x0D"; + case 'e': + return "\x1B"; + case ' ': + return "\x20"; + case '\"': + return "\""; + case '\'': + return "\'"; + case '\\': + return "\\"; + case '/': + return "/"; + case 'N': + return "\x85"; + case '_': + return "\xA0"; + case 'L': + return "\xE2\x80\xA8"; // LS (#x2028) + case 'P': + return "\xE2\x80\xA9"; // PS (#x2029) + case 'x': + return Escape(in, 2); + case 'u': + return Escape(in, 4); + case 'U': + return Escape(in, 8); + } + + std::stringstream msg; + throw ParserException(in.mark(), std::string(ErrorMsg::INVALID_ESCAPE) + ch); + } + } // namespace Exp +} // namespace YAML diff --git a/yaml-cpp/src/exp.h b/yaml-cpp/src/exp.h new file mode 100644 index 0000000..8492009 --- /dev/null +++ b/yaml-cpp/src/exp.h @@ -0,0 +1,253 @@ +#ifndef EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "regex_yaml.h" +#include "stream.h" + +namespace YAML { +//////////////////////////////////////////////////////////////////////////////// +// Here we store a bunch of expressions for matching different parts of the +// file. + + namespace Exp { +// misc + inline const RegEx &Empty() { + static const RegEx e; + return e; + } + + inline const RegEx &Space() { + static const RegEx e = RegEx(' '); + return e; + } + + inline const RegEx &Tab() { + static const RegEx e = RegEx('\t'); + return e; + } + + inline const RegEx &Blank() { + static const RegEx e = Space() | Tab(); + return e; + } + + inline const RegEx &Break() { + static const RegEx e = RegEx('\n') | RegEx("\r\n"); + return e; + } + + inline const RegEx &BlankOrBreak() { + static const RegEx e = Blank() | Break(); + return e; + } + + inline const RegEx &Digit() { + static const RegEx e = RegEx('0', '9'); + return e; + } + + inline const RegEx &Alpha() { + static const RegEx e = RegEx('a', 'z') | RegEx('A', 'Z'); + return e; + } + + inline const RegEx &AlphaNumeric() { + static const RegEx e = Alpha() | Digit(); + return e; + } + + inline const RegEx &Word() { + static const RegEx e = AlphaNumeric() | RegEx('-'); + return e; + } + + inline const RegEx &Hex() { + static const RegEx e = Digit() | RegEx('A', 'F') | RegEx('a', 'f'); + return e; + } + +// Valid Unicode code points that are not part of c-printable (YAML 1.2, sec. +// 5.1) + inline const RegEx &NotPrintable() { + static const RegEx e = + RegEx(0) | + RegEx("\x01\x02\x03\x04\x05\x06\x07\x08\x0B\x0C\x7F", REGEX_OR) | + RegEx(0x0E, 0x1F) | + (RegEx('\xC2') + (RegEx('\x80', '\x84') | RegEx('\x86', '\x9F'))); + return e; + } + + inline const RegEx &Utf8_ByteOrderMark() { + static const RegEx e = RegEx("\xEF\xBB\xBF"); + return e; + } + +// actual tags + + inline const RegEx &DocStart() { + static const RegEx e = RegEx("---") + (BlankOrBreak() | RegEx()); + return e; + } + + inline const RegEx &DocEnd() { + static const RegEx e = RegEx("...") + (BlankOrBreak() | RegEx()); + return e; + } + + inline const RegEx &DocIndicator() { + static const RegEx e = DocStart() | DocEnd(); + return e; + } + + inline const RegEx &BlockEntry() { + static const RegEx e = RegEx('-') + (BlankOrBreak() | RegEx()); + return e; + } + + inline const RegEx &Key() { + static const RegEx e = RegEx('?') + BlankOrBreak(); + return e; + } + + inline const RegEx &KeyInFlow() { + static const RegEx e = RegEx('?') + BlankOrBreak(); + return e; + } + + inline const RegEx &Value() { + static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx()); + return e; + } + + inline const RegEx &ValueInFlow() { + static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx(",}", REGEX_OR)); + return e; + } + + inline const RegEx &ValueInJSONFlow() { + static const RegEx e = RegEx(':'); + return e; + } + + inline const RegEx Comment() { + static const RegEx e = RegEx('#'); + return e; + } + + inline const RegEx &Anchor() { + static const RegEx e = !(RegEx("[]{},", REGEX_OR) | BlankOrBreak()); + return e; + } + + inline const RegEx &AnchorEnd() { + static const RegEx e = RegEx("?:,]}%@`", REGEX_OR) | BlankOrBreak(); + return e; + } + + inline const RegEx &URI() { + static const RegEx e = Word() | RegEx("#;/?:@&=+$,_.!~*'()[]", REGEX_OR) | + (RegEx('%') + Hex() + Hex()); + return e; + } + + inline const RegEx &Tag() { + static const RegEx e = Word() | RegEx("#;/?:@&=+$_.~*'()", REGEX_OR) | + (RegEx('%') + Hex() + Hex()); + return e; + } + +// Plain scalar rules: +// . Cannot start with a blank. +// . Can never start with any of , [ ] { } # & * ! | > \' \" % @ ` +// . In the block context - ? : must be not be followed with a space. +// . In the flow context ? is illegal and : and - must not be followed with a +// space. + inline const RegEx &PlainScalar() { + static const RegEx e = + !(BlankOrBreak() | RegEx(",[]{}#&*!|>\'\"%@`", REGEX_OR) | + (RegEx("-?:", REGEX_OR) + (BlankOrBreak() | RegEx()))); + return e; + } + + inline const RegEx &PlainScalarInFlow() { + static const RegEx e = + !(BlankOrBreak() | RegEx("?,[]{}#&*!|>\'\"%@`", REGEX_OR) | + (RegEx("-:", REGEX_OR) + Blank())); + return e; + } + + inline const RegEx &EndScalar() { + static const RegEx e = RegEx(':') + (BlankOrBreak() | RegEx()); + return e; + } + + inline const RegEx &EndScalarInFlow() { + static const RegEx e = + (RegEx(':') + (BlankOrBreak() | RegEx() | RegEx(",]}", REGEX_OR))) | + RegEx(",?[]{}", REGEX_OR); + return e; + } + + inline const RegEx &ScanScalarEndInFlow() { + static const RegEx e = (EndScalarInFlow() | (BlankOrBreak() + Comment())); + return e; + } + + inline const RegEx &ScanScalarEnd() { + static const RegEx e = EndScalar() | (BlankOrBreak() + Comment()); + return e; + } + + inline const RegEx &EscSingleQuote() { + static const RegEx e = RegEx("\'\'"); + return e; + } + + inline const RegEx &EscBreak() { + static const RegEx e = RegEx('\\') + Break(); + return e; + } + + inline const RegEx &ChompIndicator() { + static const RegEx e = RegEx("+-", REGEX_OR); + return e; + } + + inline const RegEx &Chomp() { + static const RegEx e = (ChompIndicator() + Digit()) | + (Digit() + ChompIndicator()) | ChompIndicator() | + Digit(); + return e; + } + +// and some functions + std::string Escape(Stream &in); + } // namespace Exp + + namespace Keys { + const char Directive = '%'; + const char FlowSeqStart = '['; + const char FlowSeqEnd = ']'; + const char FlowMapStart = '{'; + const char FlowMapEnd = '}'; + const char FlowEntry = ','; + const char Alias = '*'; + const char Anchor = '&'; + const char Tag = '!'; + const char LiteralScalar = '|'; + const char FoldedScalar = '>'; + const char VerbatimTagStart = '<'; + const char VerbatimTagEnd = '>'; + } // namespace Keys +} // namespace YAML + +#endif // EXP_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/indentation.h b/yaml-cpp/src/indentation.h new file mode 100644 index 0000000..a32caff --- /dev/null +++ b/yaml-cpp/src/indentation.h @@ -0,0 +1,43 @@ +#ifndef INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/ostream_wrapper.h" + +namespace YAML { + struct Indentation { + Indentation(std::size_t n_) : n(n_) {} + + std::size_t n; + }; + + inline ostream_wrapper &operator<<(ostream_wrapper &out, + const Indentation &indent) { + for (std::size_t i = 0; i < indent.n; i++) + out << ' '; + return out; + } + + struct IndentTo { + IndentTo(std::size_t n_) : n(n_) {} + + std::size_t n; + }; + + inline ostream_wrapper &operator<<(ostream_wrapper &out, + const IndentTo &indent) { + while (out.col() < indent.n) + out << ' '; + return out; + } +} + +#endif // INDENTATION_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/memory.cpp b/yaml-cpp/src/memory.cpp new file mode 100644 index 0000000..7064dd4 --- /dev/null +++ b/yaml-cpp/src/memory.cpp @@ -0,0 +1,26 @@ +#include "yaml-cpp/node/detail/memory.h" +#include "yaml-cpp/node/detail/node.h" // IWYU pragma: keep +#include "yaml-cpp/node/ptr.h" + +namespace YAML { + namespace detail { + + void memory_holder::merge(memory_holder &rhs) { + if (m_pMemory == rhs.m_pMemory) + return; + + m_pMemory->merge(*rhs.m_pMemory); + rhs.m_pMemory = m_pMemory; + } + + node &memory::create_node() { + shared_node pNode(new node); + m_nodes.insert(pNode); + return *pNode; + } + + void memory::merge(const memory &rhs) { + m_nodes.insert(rhs.m_nodes.begin(), rhs.m_nodes.end()); + } + } // namespace detail +} // namespace YAML diff --git a/yaml-cpp/src/node.cpp b/yaml-cpp/src/node.cpp new file mode 100644 index 0000000..2cec0f0 --- /dev/null +++ b/yaml-cpp/src/node.cpp @@ -0,0 +1,12 @@ +#include "yaml-cpp/node/node.h" +#include "nodebuilder.h" +#include "nodeevents.h" + +namespace YAML { + Node Clone(const Node &node) { + NodeEvents events(node); + NodeBuilder builder; + events.Emit(builder); + return builder.Root(); + } +} // namespace YAML diff --git a/yaml-cpp/src/node_data.cpp b/yaml-cpp/src/node_data.cpp new file mode 100644 index 0000000..8f80842 --- /dev/null +++ b/yaml-cpp/src/node_data.cpp @@ -0,0 +1,317 @@ +#include +#include +#include + +#include "yaml-cpp/exceptions.h" +#include "yaml-cpp/node/detail/memory.h" +#include "yaml-cpp/node/detail/node.h" // IWYU pragma: keep +#include "yaml-cpp/node/detail/node_data.h" +#include "yaml-cpp/node/detail/node_iterator.h" +#include "yaml-cpp/node/ptr.h" +#include "yaml-cpp/node/type.h" + +namespace YAML { + namespace detail { + std::atomic node::m_amount{0}; + + const std::string &node_data::empty_scalar() { + static const std::string svalue; + return svalue; + } + + node_data::node_data() + : m_isDefined(false), + m_mark(Mark::null_mark()), + m_type(NodeType::Null), + m_tag{}, + m_style(EmitterStyle::Default), + m_scalar{}, + m_sequence{}, + m_seqSize(0), + m_map{}, + m_undefinedPairs{} {} + + void node_data::mark_defined() { + if (m_type == NodeType::Undefined) + m_type = NodeType::Null; + m_isDefined = true; + } + + void node_data::set_mark(const Mark &mark) { m_mark = mark; } + + void node_data::set_type(NodeType::value type) { + if (type == NodeType::Undefined) { + m_type = type; + m_isDefined = false; + return; + } + + m_isDefined = true; + if (type == m_type) + return; + + m_type = type; + + switch (m_type) { + case NodeType::Null: + break; + case NodeType::Scalar: + m_scalar.clear(); + break; + case NodeType::Sequence: + reset_sequence(); + break; + case NodeType::Map: + reset_map(); + break; + case NodeType::Undefined: + assert(false); + break; + } + } + + void node_data::set_tag(const std::string &tag) { m_tag = tag; } + + void node_data::set_style(EmitterStyle::value style) { m_style = style; } + + void node_data::set_null() { + m_isDefined = true; + m_type = NodeType::Null; + } + + void node_data::set_scalar(const std::string &scalar) { + m_isDefined = true; + m_type = NodeType::Scalar; + m_scalar = scalar; + } + +// size/iterator + std::size_t node_data::size() const { + if (!m_isDefined) + return 0; + + switch (m_type) { + case NodeType::Sequence: + compute_seq_size(); + return m_seqSize; + case NodeType::Map: + compute_map_size(); + return m_map.size() - m_undefinedPairs.size(); + default: + return 0; + } + return 0; + } + + void node_data::compute_seq_size() const { + while (m_seqSize < m_sequence.size() && m_sequence[m_seqSize]->is_defined()) + m_seqSize++; + } + + void node_data::compute_map_size() const { + kv_pairs::iterator it = m_undefinedPairs.begin(); + while (it != m_undefinedPairs.end()) { + kv_pairs::iterator jt = std::next(it); + if (it->first->is_defined() && it->second->is_defined()) + m_undefinedPairs.erase(it); + it = jt; + } + } + + const_node_iterator node_data::begin() const { + if (!m_isDefined) + return const_node_iterator(); + + switch (m_type) { + case NodeType::Sequence: + return const_node_iterator(m_sequence.begin()); + case NodeType::Map: + return const_node_iterator(m_map.begin(), m_map.end()); + default: + return const_node_iterator(); + } + } + + node_iterator node_data::begin() { + if (!m_isDefined) + return node_iterator(); + + switch (m_type) { + case NodeType::Sequence: + return node_iterator(m_sequence.begin()); + case NodeType::Map: + return node_iterator(m_map.begin(), m_map.end()); + default: + return node_iterator(); + } + } + + const_node_iterator node_data::end() const { + if (!m_isDefined) + return const_node_iterator(); + + switch (m_type) { + case NodeType::Sequence: + return const_node_iterator(m_sequence.end()); + case NodeType::Map: + return const_node_iterator(m_map.end(), m_map.end()); + default: + return const_node_iterator(); + } + } + + node_iterator node_data::end() { + if (!m_isDefined) + return node_iterator(); + + switch (m_type) { + case NodeType::Sequence: + return node_iterator(m_sequence.end()); + case NodeType::Map: + return node_iterator(m_map.end(), m_map.end()); + default: + return node_iterator(); + } + } + +// sequence + void node_data::push_back(node &node, shared_memory_holder /* pMemory */) { + if (m_type == NodeType::Undefined || m_type == NodeType::Null) { + m_type = NodeType::Sequence; + reset_sequence(); + } + + if (m_type != NodeType::Sequence) + throw BadPushback(); + + m_sequence.push_back(&node); + } + + void node_data::insert(node &key, node &value, shared_memory_holder pMemory) { + switch (m_type) { + case NodeType::Map: + break; + case NodeType::Undefined: + case NodeType::Null: + case NodeType::Sequence: + convert_to_map(pMemory); + break; + case NodeType::Scalar: + throw BadSubscript(m_mark, key); + } + + insert_map_pair(key, value); + } + +// indexing + node *node_data::get(node &key, shared_memory_holder /* pMemory */) const { + if (m_type != NodeType::Map) { + return nullptr; + } + + for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->first->is(key)) + return it->second; + } + + return nullptr; + } + + node &node_data::get(node &key, shared_memory_holder pMemory) { + switch (m_type) { + case NodeType::Map: + break; + case NodeType::Undefined: + case NodeType::Null: + case NodeType::Sequence: + convert_to_map(pMemory); + break; + case NodeType::Scalar: + throw BadSubscript(m_mark, key); + } + + for (node_map::const_iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->first->is(key)) + return *it->second; + } + + node &value = pMemory->create_node(); + insert_map_pair(key, value); + return value; + } + + bool node_data::remove(node &key, shared_memory_holder /* pMemory */) { + if (m_type != NodeType::Map) + return false; + + for (kv_pairs::iterator it = m_undefinedPairs.begin(); + it != m_undefinedPairs.end();) { + kv_pairs::iterator jt = std::next(it); + if (it->first->is(key)) + m_undefinedPairs.erase(it); + it = jt; + } + + for (node_map::iterator it = m_map.begin(); it != m_map.end(); ++it) { + if (it->first->is(key)) { + m_map.erase(it); + return true; + } + } + + return false; + } + + void node_data::reset_sequence() { + m_sequence.clear(); + m_seqSize = 0; + } + + void node_data::reset_map() { + m_map.clear(); + m_undefinedPairs.clear(); + } + + void node_data::insert_map_pair(node &key, node &value) { + m_map.emplace_back(&key, &value); + + if (!key.is_defined() || !value.is_defined()) + m_undefinedPairs.emplace_back(&key, &value); + } + + void node_data::convert_to_map(shared_memory_holder pMemory) { + switch (m_type) { + case NodeType::Undefined: + case NodeType::Null: + reset_map(); + m_type = NodeType::Map; + break; + case NodeType::Sequence: + convert_sequence_to_map(pMemory); + break; + case NodeType::Map: + break; + case NodeType::Scalar: + assert(false); + break; + } + } + + void node_data::convert_sequence_to_map(shared_memory_holder pMemory) { + assert(m_type == NodeType::Sequence); + + reset_map(); + for (std::size_t i = 0; i < m_sequence.size(); i++) { + std::stringstream stream; + stream << i; + + node &key = pMemory->create_node(); + key.set_scalar(stream.str()); + insert_map_pair(key, *m_sequence[i]); + } + + reset_sequence(); + m_type = NodeType::Map; + } + } // namespace detail +} // namespace YAML diff --git a/yaml-cpp/src/nodebuilder.cpp b/yaml-cpp/src/nodebuilder.cpp new file mode 100644 index 0000000..ff0f92c --- /dev/null +++ b/yaml-cpp/src/nodebuilder.cpp @@ -0,0 +1,134 @@ +#include + +#include "nodebuilder.h" +#include "yaml-cpp/node/detail/node.h" +#include "yaml-cpp/node/impl.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/type.h" + +namespace YAML { + struct Mark; + + NodeBuilder::NodeBuilder() + : m_pMemory(new detail::memory_holder), + m_pRoot(nullptr), + m_stack{}, + m_anchors{}, + m_keys{}, + m_mapDepth(0) { + m_anchors.push_back(nullptr); // since the anchors start at 1 + } + + NodeBuilder::~NodeBuilder() = default; + + Node NodeBuilder::Root() { + if (!m_pRoot) + return Node(); + + return Node(*m_pRoot, m_pMemory); + } + + void NodeBuilder::OnDocumentStart(const Mark &) {} + + void NodeBuilder::OnDocumentEnd() {} + + void NodeBuilder::OnNull(const Mark &mark, anchor_t anchor) { + detail::node &node = Push(mark, anchor); + node.set_null(); + Pop(); + } + + void NodeBuilder::OnAlias(const Mark & /* mark */, anchor_t anchor) { + detail::node &node = *m_anchors[anchor]; + Push(node); + Pop(); + } + + void NodeBuilder::OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value) { + detail::node &node = Push(mark, anchor); + node.set_scalar(value); + node.set_tag(tag); + Pop(); + } + + void NodeBuilder::OnSequenceStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) { + detail::node &node = Push(mark, anchor); + node.set_tag(tag); + node.set_type(NodeType::Sequence); + node.set_style(style); + } + + void NodeBuilder::OnSequenceEnd() { Pop(); } + + void NodeBuilder::OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) { + detail::node &node = Push(mark, anchor); + node.set_type(NodeType::Map); + node.set_tag(tag); + node.set_style(style); + m_mapDepth++; + } + + void NodeBuilder::OnMapEnd() { + assert(m_mapDepth > 0); + m_mapDepth--; + Pop(); + } + + detail::node &NodeBuilder::Push(const Mark &mark, anchor_t anchor) { + detail::node &node = m_pMemory->create_node(); + node.set_mark(mark); + RegisterAnchor(anchor, node); + Push(node); + return node; + } + + void NodeBuilder::Push(detail::node &node) { + const bool needsKey = + (!m_stack.empty() && m_stack.back()->type() == NodeType::Map && + m_keys.size() < m_mapDepth); + + m_stack.push_back(&node); + if (needsKey) + m_keys.push_back(PushedKey(&node, false)); + } + + void NodeBuilder::Pop() { + assert(!m_stack.empty()); + if (m_stack.size() == 1) { + m_pRoot = m_stack[0]; + m_stack.pop_back(); + return; + } + + detail::node &node = *m_stack.back(); + m_stack.pop_back(); + + detail::node &collection = *m_stack.back(); + + if (collection.type() == NodeType::Sequence) { + collection.push_back(node, m_pMemory); + } else if (collection.type() == NodeType::Map) { + assert(!m_keys.empty()); + PushedKey &key = m_keys.back(); + if (key.second) { + collection.insert(*key.first, node, m_pMemory); + m_keys.pop_back(); + } else { + key.second = true; + } + } else { + assert(false); + m_stack.clear(); + } + } + + void NodeBuilder::RegisterAnchor(anchor_t anchor, detail::node &node) { + if (anchor) { + assert(anchor == m_anchors.size()); + m_anchors.push_back(&node); + } + } +} // namespace YAML diff --git a/yaml-cpp/src/nodebuilder.h b/yaml-cpp/src/nodebuilder.h new file mode 100644 index 0000000..b85bbb9 --- /dev/null +++ b/yaml-cpp/src/nodebuilder.h @@ -0,0 +1,87 @@ +#ifndef NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/node/ptr.h" + +namespace YAML { + namespace detail { + class node; + } // namespace detail + struct Mark; +} // namespace YAML + +namespace YAML { + class Node; + + class NodeBuilder : public EventHandler { + public: + NodeBuilder(); + + NodeBuilder(const NodeBuilder &) = delete; + + NodeBuilder(NodeBuilder &&) = delete; + + NodeBuilder &operator=(const NodeBuilder &) = delete; + + NodeBuilder &operator=(NodeBuilder &&) = delete; + + ~NodeBuilder() override; + + Node Root(); + + void OnDocumentStart(const Mark &mark) override; + + void OnDocumentEnd() override; + + void OnNull(const Mark &mark, anchor_t anchor) override; + + void OnAlias(const Mark &mark, anchor_t anchor) override; + + void OnScalar(const Mark &mark, const std::string &tag, + anchor_t anchor, const std::string &value) override; + + void OnSequenceStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) override; + + void OnSequenceEnd() override; + + void OnMapStart(const Mark &mark, const std::string &tag, + anchor_t anchor, EmitterStyle::value style) override; + + void OnMapEnd() override; + + private: + detail::node &Push(const Mark &mark, anchor_t anchor); + + void Push(detail::node &node); + + void Pop(); + + void RegisterAnchor(anchor_t anchor, detail::node &node); + + private: + detail::shared_memory_holder m_pMemory; + detail::node *m_pRoot; + + using Nodes = std::vector; + Nodes m_stack; + Nodes m_anchors; + + using PushedKey = std::pair; + std::vector m_keys; + std::size_t m_mapDepth; + }; +} // namespace YAML + +#endif // NODE_NODEBUILDER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/nodeevents.cpp b/yaml-cpp/src/nodeevents.cpp new file mode 100644 index 0000000..150ab52 --- /dev/null +++ b/yaml-cpp/src/nodeevents.cpp @@ -0,0 +1,101 @@ +#include "nodeevents.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/mark.h" +#include "yaml-cpp/node/detail/node.h" +#include "yaml-cpp/node/detail/node_iterator.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/node/type.h" + +namespace YAML { + void NodeEvents::AliasManager::RegisterReference(const detail::node &node) { + m_anchorByIdentity.insert(std::make_pair(node.ref(), _CreateNewAnchor())); + } + + anchor_t NodeEvents::AliasManager::LookupAnchor( + const detail::node &node) const { + AnchorByIdentity::const_iterator it = m_anchorByIdentity.find(node.ref()); + if (it == m_anchorByIdentity.end()) + return 0; + return it->second; + } + + NodeEvents::NodeEvents(const Node &node) + : m_pMemory(node.m_pMemory), m_root(node.m_pNode), m_refCount{} { + if (m_root) + Setup(*m_root); + } + + void NodeEvents::Setup(const detail::node &node) { + int &refCount = m_refCount[node.ref()]; + refCount++; + if (refCount > 1) + return; + + if (node.type() == NodeType::Sequence) { + for (detail::const_node_iterator it = node.begin(); it != node.end(); ++it) + Setup(**it); + } else if (node.type() == NodeType::Map) { + for (detail::const_node_iterator it = node.begin(); it != node.end(); + ++it) { + Setup(*it->first); + Setup(*it->second); + } + } + } + + void NodeEvents::Emit(EventHandler &handler) { + AliasManager am; + + handler.OnDocumentStart(Mark()); + if (m_root) + Emit(*m_root, handler, am); + handler.OnDocumentEnd(); + } + + void NodeEvents::Emit(const detail::node &node, EventHandler &handler, + AliasManager &am) const { + anchor_t anchor = NullAnchor; + if (IsAliased(node)) { + anchor = am.LookupAnchor(node); + if (anchor) { + handler.OnAlias(Mark(), anchor); + return; + } + + am.RegisterReference(node); + anchor = am.LookupAnchor(node); + } + + switch (node.type()) { + case NodeType::Undefined: + break; + case NodeType::Null: + handler.OnNull(Mark(), anchor); + break; + case NodeType::Scalar: + handler.OnScalar(Mark(), node.tag(), anchor, node.scalar()); + break; + case NodeType::Sequence: + handler.OnSequenceStart(Mark(), node.tag(), anchor, node.style()); + for (detail::const_node_iterator it = node.begin(); it != node.end(); + ++it) + Emit(**it, handler, am); + handler.OnSequenceEnd(); + break; + case NodeType::Map: + handler.OnMapStart(Mark(), node.tag(), anchor, node.style()); + for (detail::const_node_iterator it = node.begin(); it != node.end(); + ++it) { + Emit(*it->first, handler, am); + Emit(*it->second, handler, am); + } + handler.OnMapEnd(); + break; + } + } + + bool NodeEvents::IsAliased(const detail::node &node) const { + RefCount::const_iterator it = m_refCount.find(node.ref()); + return it != m_refCount.end() && it->second > 1; + } +} // namespace YAML diff --git a/yaml-cpp/src/nodeevents.h b/yaml-cpp/src/nodeevents.h new file mode 100644 index 0000000..c5744a8 --- /dev/null +++ b/yaml-cpp/src/nodeevents.h @@ -0,0 +1,76 @@ +#ifndef NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/anchor.h" +#include "yaml-cpp/node/ptr.h" + +namespace YAML { + namespace detail { + class node; + } // namespace detail +} // namespace YAML + +namespace YAML { + class EventHandler; + + class Node; + + class NodeEvents { + public: + explicit NodeEvents(const Node &node); + + NodeEvents(const NodeEvents &) = delete; + + NodeEvents(NodeEvents &&) = delete; + + NodeEvents &operator=(const NodeEvents &) = delete; + + NodeEvents &operator=(NodeEvents &&) = delete; + + void Emit(EventHandler &handler); + + private: + class AliasManager { + public: + AliasManager() : m_anchorByIdentity{}, m_curAnchor(0) {} + + void RegisterReference(const detail::node &node); + + anchor_t LookupAnchor(const detail::node &node) const; + + private: + anchor_t _CreateNewAnchor() { return ++m_curAnchor; } + + private: + using AnchorByIdentity = std::map; + AnchorByIdentity m_anchorByIdentity; + + anchor_t m_curAnchor; + }; + + void Setup(const detail::node &node); + + void Emit(const detail::node &node, EventHandler &handler, + AliasManager &am) const; + + bool IsAliased(const detail::node &node) const; + + private: + detail::shared_memory_holder m_pMemory; + detail::node *m_root; + + using RefCount = std::map; + RefCount m_refCount; + }; +} // namespace YAML + +#endif // NODE_NODEEVENTS_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/null.cpp b/yaml-cpp/src/null.cpp new file mode 100644 index 0000000..4828bfd --- /dev/null +++ b/yaml-cpp/src/null.cpp @@ -0,0 +1,10 @@ +#include "yaml-cpp/null.h" + +namespace YAML { + _Null Null; + + bool IsNullString(const std::string &str) { + return str.empty() || str == "~" || str == "null" || str == "Null" || + str == "NULL"; + } +} // namespace YAML diff --git a/yaml-cpp/src/ostream_wrapper.cpp b/yaml-cpp/src/ostream_wrapper.cpp new file mode 100644 index 0000000..9883820 --- /dev/null +++ b/yaml-cpp/src/ostream_wrapper.cpp @@ -0,0 +1,62 @@ +#include "yaml-cpp/ostream_wrapper.h" + +#include +#include +#include + +namespace YAML { + ostream_wrapper::ostream_wrapper() + : m_buffer(1, '\0'), + m_pStream(nullptr), + m_pos(0), + m_row(0), + m_col(0), + m_comment(false) {} + + ostream_wrapper::ostream_wrapper(std::ostream &stream) + : m_buffer{}, + m_pStream(&stream), + m_pos(0), + m_row(0), + m_col(0), + m_comment(false) {} + + ostream_wrapper::~ostream_wrapper() = default; + + void ostream_wrapper::write(const std::string &str) { + if (m_pStream) { + m_pStream->write(str.c_str(), str.size()); + } else { + m_buffer.resize(std::max(m_buffer.size(), m_pos + str.size() + 1)); + std::copy(str.begin(), str.end(), m_buffer.begin() + m_pos); + } + + for (char ch : str) { + update_pos(ch); + } + } + + void ostream_wrapper::write(const char *str, std::size_t size) { + if (m_pStream) { + m_pStream->write(str, size); + } else { + m_buffer.resize(std::max(m_buffer.size(), m_pos + size + 1)); + std::copy(str, str + size, m_buffer.begin() + m_pos); + } + + for (std::size_t i = 0; i < size; i++) { + update_pos(str[i]); + } + } + + void ostream_wrapper::update_pos(char ch) { + m_pos++; + m_col++; + + if (ch == '\n') { + m_row++; + m_col = 0; + m_comment = false; + } + } +} // namespace YAML diff --git a/yaml-cpp/src/parse.cpp b/yaml-cpp/src/parse.cpp new file mode 100644 index 0000000..25da943 --- /dev/null +++ b/yaml-cpp/src/parse.cpp @@ -0,0 +1,72 @@ +#include "yaml-cpp/node/parse.h" + +#include +#include + +#include "nodebuilder.h" +#include "yaml-cpp/node/impl.h" +#include "yaml-cpp/node/node.h" +#include "yaml-cpp/parser.h" + +namespace YAML { + Node Load(const std::string &input) { + std::stringstream stream(input); + return Load(stream); + } + + Node Load(const char *input) { + std::stringstream stream(input); + return Load(stream); + } + + Node Load(std::istream &input) { + Parser parser(input); + NodeBuilder builder; + if (!parser.HandleNextDocument(builder)) { + return Node(); + } + + return builder.Root(); + } + + Node LoadFile(const std::string &filename) { + std::ifstream fin(filename); + if (!fin) { + throw BadFile(filename); + } + return Load(fin); + } + + std::vector LoadAll(const std::string &input) { + std::stringstream stream(input); + return LoadAll(stream); + } + + std::vector LoadAll(const char *input) { + std::stringstream stream(input); + return LoadAll(stream); + } + + std::vector LoadAll(std::istream &input) { + std::vector docs; + + Parser parser(input); + while (1) { + NodeBuilder builder; + if (!parser.HandleNextDocument(builder)) { + break; + } + docs.push_back(builder.Root()); + } + + return docs; + } + + std::vector LoadAllFromFile(const std::string &filename) { + std::ifstream fin(filename); + if (!fin) { + throw BadFile(filename); + } + return LoadAll(fin); + } +} // namespace YAML diff --git a/yaml-cpp/src/parser.cpp b/yaml-cpp/src/parser.cpp new file mode 100644 index 0000000..1024c44 --- /dev/null +++ b/yaml-cpp/src/parser.cpp @@ -0,0 +1,119 @@ +#include +#include + +#include "directives.h" // IWYU pragma: keep +#include "scanner.h" // IWYU pragma: keep +#include "singledocparser.h" +#include "token.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep +#include "yaml-cpp/parser.h" + +namespace YAML { + class EventHandler; + + Parser::Parser() : m_pScanner{}, m_pDirectives{} {} + + Parser::Parser(std::istream &in) : Parser() { Load(in); } + + Parser::~Parser() = default; + + Parser::operator bool() const { return m_pScanner && !m_pScanner->empty(); } + + void Parser::Load(std::istream &in) { + m_pScanner.reset(new Scanner(in)); + m_pDirectives.reset(new Directives); + } + + bool Parser::HandleNextDocument(EventHandler &eventHandler) { + if (!m_pScanner) + return false; + + ParseDirectives(); + if (m_pScanner->empty()) { + return false; + } + + SingleDocParser sdp(*m_pScanner, *m_pDirectives); + sdp.HandleDocument(eventHandler); + return true; + } + + void Parser::ParseDirectives() { + bool readDirective = false; + + while (!m_pScanner->empty()) { + Token &token = m_pScanner->peek(); + if (token.type != Token::DIRECTIVE) { + break; + } + + // we keep the directives from the last document if none are specified; + // but if any directives are specific, then we reset them + if (!readDirective) { + m_pDirectives.reset(new Directives); + } + + readDirective = true; + HandleDirective(token); + m_pScanner->pop(); + } + } + + void Parser::HandleDirective(const Token &token) { + if (token.value == "YAML") { + HandleYamlDirective(token); + } else if (token.value == "TAG") { + HandleTagDirective(token); + } + } + + void Parser::HandleYamlDirective(const Token &token) { + if (token.params.size() != 1) { + throw ParserException(token.mark, ErrorMsg::YAML_DIRECTIVE_ARGS); + } + + if (!m_pDirectives->version.isDefault) { + throw ParserException(token.mark, ErrorMsg::REPEATED_YAML_DIRECTIVE); + } + + std::stringstream str(token.params[0]); + str >> m_pDirectives->version.major; + str.get(); + str >> m_pDirectives->version.minor; + if (!str || str.peek() != EOF) { + throw ParserException( + token.mark, std::string(ErrorMsg::YAML_VERSION) + token.params[0]); + } + + if (m_pDirectives->version.major > 1) { + throw ParserException(token.mark, ErrorMsg::YAML_MAJOR_VERSION); + } + + m_pDirectives->version.isDefault = false; + // TODO: warning on major == 1, minor > 2? + } + + void Parser::HandleTagDirective(const Token &token) { + if (token.params.size() != 2) + throw ParserException(token.mark, ErrorMsg::TAG_DIRECTIVE_ARGS); + + const std::string &handle = token.params[0]; + const std::string &prefix = token.params[1]; + if (m_pDirectives->tags.find(handle) != m_pDirectives->tags.end()) { + throw ParserException(token.mark, ErrorMsg::REPEATED_TAG_DIRECTIVE); + } + + m_pDirectives->tags[handle] = prefix; + } + + void Parser::PrintTokens(std::ostream &out) { + if (!m_pScanner) { + return; + } + + while (!m_pScanner->empty()) { + out << m_pScanner->peek() << "\n"; + m_pScanner->pop(); + } + } +} // namespace YAML diff --git a/yaml-cpp/src/ptr_vector.h b/yaml-cpp/src/ptr_vector.h new file mode 100644 index 0000000..1d5bfd6 --- /dev/null +++ b/yaml-cpp/src/ptr_vector.h @@ -0,0 +1,52 @@ +#ifndef PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include + +namespace YAML { + +// TODO: This class is no longer needed + template + class ptr_vector { + public: + ptr_vector() : m_data{} {} + + ptr_vector(const ptr_vector &) = delete; + + ptr_vector(ptr_vector &&) = default; + + ptr_vector &operator=(const ptr_vector &) = delete; + + ptr_vector &operator=(ptr_vector &&) = default; + + void clear() { m_data.clear(); } + + std::size_t size() const { return m_data.size(); } + + bool empty() const { return m_data.empty(); } + + void push_back(std::unique_ptr &&t) { m_data.push_back(std::move(t)); } + + T &operator[](std::size_t i) { return *m_data[i]; } + + const T &operator[](std::size_t i) const { return *m_data[i]; } + + T &back() { return *(m_data.back().get()); } + + const T &back() const { return *(m_data.back().get()); } + + private: + std::vector> m_data; + }; +} // namespace YAML + +#endif // PTR_VECTOR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/regex_yaml.cpp b/yaml-cpp/src/regex_yaml.cpp new file mode 100644 index 0000000..7a6f790 --- /dev/null +++ b/yaml-cpp/src/regex_yaml.cpp @@ -0,0 +1,44 @@ +#include "regex_yaml.h" + +namespace YAML { +// constructors + + RegEx::RegEx(REGEX_OP op) : m_op(op), m_a(0), m_z(0), m_params{} {} + + RegEx::RegEx() : RegEx(REGEX_EMPTY) {} + + RegEx::RegEx(char ch) : m_op(REGEX_MATCH), m_a(ch), m_z(0), m_params{} {} + + RegEx::RegEx(char a, char z) : m_op(REGEX_RANGE), m_a(a), m_z(z), m_params{} {} + + RegEx::RegEx(const std::string &str, REGEX_OP op) + : m_op(op), m_a(0), m_z(0), m_params(str.begin(), str.end()) {} + +// combination constructors + RegEx operator!(const RegEx &ex) { + RegEx ret(REGEX_NOT); + ret.m_params.push_back(ex); + return ret; + } + + RegEx operator|(const RegEx &ex1, const RegEx &ex2) { + RegEx ret(REGEX_OR); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + + RegEx operator&(const RegEx &ex1, const RegEx &ex2) { + RegEx ret(REGEX_AND); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } + + RegEx operator+(const RegEx &ex1, const RegEx &ex2) { + RegEx ret(REGEX_SEQ); + ret.m_params.push_back(ex1); + ret.m_params.push_back(ex2); + return ret; + } +} // namespace YAML diff --git a/yaml-cpp/src/regex_yaml.h b/yaml-cpp/src/regex_yaml.h new file mode 100644 index 0000000..4bf165d --- /dev/null +++ b/yaml-cpp/src/regex_yaml.h @@ -0,0 +1,107 @@ +#ifndef REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include + +#include "yaml-cpp/dll.h" + +namespace YAML { + class Stream; + + enum REGEX_OP { + REGEX_EMPTY, + REGEX_MATCH, + REGEX_RANGE, + REGEX_OR, + REGEX_AND, + REGEX_NOT, + REGEX_SEQ + }; + +// simplified regular expressions +// . Only straightforward matches (no repeated characters) +// . Only matches from start of string + class YAML_CPP_API RegEx { + public: + RegEx(); + + explicit RegEx(char ch); + + RegEx(char a, char z); + + RegEx(const std::string &str, REGEX_OP op = REGEX_SEQ); + + ~RegEx() = default; + + friend YAML_CPP_API RegEx operator!(const RegEx &ex); + + friend YAML_CPP_API RegEx operator|(const RegEx &ex1, const RegEx &ex2); + + friend YAML_CPP_API RegEx operator&(const RegEx &ex1, const RegEx &ex2); + + friend YAML_CPP_API RegEx operator+(const RegEx &ex1, const RegEx &ex2); + + bool Matches(char ch) const; + + bool Matches(const std::string &str) const; + + bool Matches(const Stream &in) const; + + template + bool Matches(const Source &source) const; + + int Match(const std::string &str) const; + + int Match(const Stream &in) const; + + template + int Match(const Source &source) const; + + private: + explicit RegEx(REGEX_OP op); + + template + bool IsValidSource(const Source &source) const; + + template + int MatchUnchecked(const Source &source) const; + + template + int MatchOpEmpty(const Source &source) const; + + template + int MatchOpMatch(const Source &source) const; + + template + int MatchOpRange(const Source &source) const; + + template + int MatchOpOr(const Source &source) const; + + template + int MatchOpAnd(const Source &source) const; + + template + int MatchOpNot(const Source &source) const; + + template + int MatchOpSeq(const Source &source) const; + + private: + REGEX_OP m_op; + char m_a{}; + char m_z{}; + std::vector m_params; + }; +} // namespace YAML + +#include "regeximpl.h" + +#endif // REGEX_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/regeximpl.h b/yaml-cpp/src/regeximpl.h new file mode 100644 index 0000000..074f73d --- /dev/null +++ b/yaml-cpp/src/regeximpl.h @@ -0,0 +1,185 @@ +#ifndef REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "stream.h" +#include "streamcharsource.h" +#include "stringsource.h" + +namespace YAML { +// query matches + inline bool RegEx::Matches(char ch) const { + std::string str; + str += ch; + return Matches(str); + } + + inline bool RegEx::Matches(const std::string &str) const { + return Match(str) >= 0; + } + + inline bool RegEx::Matches(const Stream &in) const { return Match(in) >= 0; } + + template + inline bool RegEx::Matches(const Source &source) const { + return Match(source) >= 0; + } + +// Match +// . Matches the given string against this regular expression. +// . Returns the number of characters matched. +// . Returns -1 if no characters were matched (the reason for +// not returning zero is that we may have an empty regex +// which is ALWAYS successful at matching zero characters). +// . REMEMBER that we only match from the start of the buffer! + inline int RegEx::Match(const std::string &str) const { + StringCharSource source(str.c_str(), str.size()); + return Match(source); + } + + inline int RegEx::Match(const Stream &in) const { + StreamCharSource source(in); + return Match(source); + } + + template + inline bool RegEx::IsValidSource(const Source &source) const { + return source; + } + + template<> + inline bool RegEx::IsValidSource( + const StringCharSource &source) const { + switch (m_op) { + case REGEX_MATCH: + case REGEX_RANGE: + return source; + default: + return true; + } + } + + template + inline int RegEx::Match(const Source &source) const { + return IsValidSource(source) ? MatchUnchecked(source) : -1; + } + + template + inline int RegEx::MatchUnchecked(const Source &source) const { + switch (m_op) { + case REGEX_EMPTY: + return MatchOpEmpty(source); + case REGEX_MATCH: + return MatchOpMatch(source); + case REGEX_RANGE: + return MatchOpRange(source); + case REGEX_OR: + return MatchOpOr(source); + case REGEX_AND: + return MatchOpAnd(source); + case REGEX_NOT: + return MatchOpNot(source); + case REGEX_SEQ: + return MatchOpSeq(source); + } + + return -1; + } + +////////////////////////////////////////////////////////////////////////////// +// Operators +// Note: the convention MatchOp* is that we can assume +// IsSourceValid(source). +// So we do all our checks *before* we call these functions + +// EmptyOperator + template + inline int RegEx::MatchOpEmpty(const Source &source) const { + return source[0] == Stream::eof() ? 0 : -1; + } + + template<> + inline int RegEx::MatchOpEmpty( + const StringCharSource &source) const { + return !source ? 0 : -1; // the empty regex only is successful on the empty + // string + } + +// MatchOperator + template + inline int RegEx::MatchOpMatch(const Source &source) const { + if (source[0] != m_a) + return -1; + return 1; + } + +// RangeOperator + template + inline int RegEx::MatchOpRange(const Source &source) const { + if (m_a > source[0] || m_z < source[0]) + return -1; + return 1; + } + +// OrOperator + template + inline int RegEx::MatchOpOr(const Source &source) const { + for (const RegEx ¶m : m_params) { + int n = param.MatchUnchecked(source); + if (n >= 0) + return n; + } + return -1; + } + +// AndOperator +// Note: 'AND' is a little funny, since we may be required to match things +// of different lengths. If we find a match, we return the length of +// the FIRST entry on the list. + template + inline int RegEx::MatchOpAnd(const Source &source) const { + int first = -1; + for (std::size_t i = 0; i < m_params.size(); i++) { + int n = m_params[i].MatchUnchecked(source); + if (n == -1) + return -1; + if (i == 0) + first = n; + } + return first; + } + +// NotOperator + template + inline int RegEx::MatchOpNot(const Source &source) const { + if (m_params.empty()) + return -1; + if (m_params[0].MatchUnchecked(source) >= 0) + return -1; + return 1; + } + +// SeqOperator + template + inline int RegEx::MatchOpSeq(const Source &source) const { + int offset = 0; + for (const RegEx ¶m : m_params) { + int n = param.Match(source + offset); // note Match, not + // MatchUnchecked because we + // need to check validity after + // the offset + if (n == -1) + return -1; + offset += n; + } + + return offset; + } +} // namespace YAML + +#endif // REGEXIMPL_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/scanner.cpp b/yaml-cpp/src/scanner.cpp new file mode 100644 index 0000000..da8e648 --- /dev/null +++ b/yaml-cpp/src/scanner.cpp @@ -0,0 +1,391 @@ +#include +#include + +#include "exp.h" +#include "scanner.h" +#include "token.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep + +namespace YAML { + Scanner::Scanner(std::istream &in) + : INPUT(in), + m_tokens{}, + m_startedStream(false), + m_endedStream(false), + m_simpleKeyAllowed(false), + m_canBeJSONFlow(false), + m_simpleKeys{}, + m_indents{}, + m_indentRefs{}, + m_flows{} {} + + Scanner::~Scanner() = default; + + bool Scanner::empty() { + EnsureTokensInQueue(); + return m_tokens.empty(); + } + + void Scanner::pop() { + EnsureTokensInQueue(); + if (!m_tokens.empty()) + m_tokens.pop(); + } + + Token &Scanner::peek() { + EnsureTokensInQueue(); + assert(!m_tokens.empty()); // should we be asserting here? I mean, we really + // just be checking + // if it's empty before peeking. + +#if 0 + static Token *pLast = 0; + if(pLast != &m_tokens.front()) + std::cerr << "peek: " << m_tokens.front() << "\n"; + pLast = &m_tokens.front(); +#endif + + return m_tokens.front(); + } + + Mark Scanner::mark() const { return INPUT.mark(); } + + void Scanner::EnsureTokensInQueue() { + while (1) { + if (!m_tokens.empty()) { + Token &token = m_tokens.front(); + + // if this guy's valid, then we're done + if (token.status == Token::VALID) { + return; + } + + // here's where we clean up the impossible tokens + if (token.status == Token::INVALID) { + m_tokens.pop(); + continue; + } + + // note: what's left are the unverified tokens + } + + // no token? maybe we've actually finished + if (m_endedStream) { + return; + } + + // no? then scan... + ScanNextToken(); + } + } + + void Scanner::ScanNextToken() { + if (m_endedStream) { + return; + } + + if (!m_startedStream) { + return StartStream(); + } + + // get rid of whitespace, etc. (in between tokens it should be irrelevent) + ScanToNextToken(); + + // maybe need to end some blocks + PopIndentToHere(); + + // ***** + // And now branch based on the next few characters! + // ***** + + // end of stream + if (!INPUT) { + return EndStream(); + } + + if (INPUT.column() == 0 && INPUT.peek() == Keys::Directive) { + return ScanDirective(); + } + + // document token + if (INPUT.column() == 0 && Exp::DocStart().Matches(INPUT)) { + return ScanDocStart(); + } + + if (INPUT.column() == 0 && Exp::DocEnd().Matches(INPUT)) { + return ScanDocEnd(); + } + + // flow start/end/entry + if (INPUT.peek() == Keys::FlowSeqStart || + INPUT.peek() == Keys::FlowMapStart) { + return ScanFlowStart(); + } + + if (INPUT.peek() == Keys::FlowSeqEnd || INPUT.peek() == Keys::FlowMapEnd) { + return ScanFlowEnd(); + } + + if (INPUT.peek() == Keys::FlowEntry) { + return ScanFlowEntry(); + } + + // block/map stuff + if (Exp::BlockEntry().Matches(INPUT)) { + return ScanBlockEntry(); + } + + if ((InBlockContext() ? Exp::Key() : Exp::KeyInFlow()).Matches(INPUT)) { + return ScanKey(); + } + + if (GetValueRegex().Matches(INPUT)) { + return ScanValue(); + } + + // alias/anchor + if (INPUT.peek() == Keys::Alias || INPUT.peek() == Keys::Anchor) { + return ScanAnchorOrAlias(); + } + + // tag + if (INPUT.peek() == Keys::Tag) { + return ScanTag(); + } + + // special scalars + if (InBlockContext() && (INPUT.peek() == Keys::LiteralScalar || + INPUT.peek() == Keys::FoldedScalar)) { + return ScanBlockScalar(); + } + + if (INPUT.peek() == '\'' || INPUT.peek() == '\"') { + return ScanQuotedScalar(); + } + + // plain scalars + if ((InBlockContext() ? Exp::PlainScalar() : Exp::PlainScalarInFlow()) + .Matches(INPUT)) { + return ScanPlainScalar(); + } + + // don't know what it is! + throw ParserException(INPUT.mark(), ErrorMsg::UNKNOWN_TOKEN); + } + + void Scanner::ScanToNextToken() { + while (1) { + // first eat whitespace + while (INPUT && IsWhitespaceToBeEaten(INPUT.peek())) { + if (InBlockContext() && Exp::Tab().Matches(INPUT)) { + m_simpleKeyAllowed = false; + } + INPUT.eat(1); + } + + // then eat a comment + if (Exp::Comment().Matches(INPUT)) { + // eat until line break + while (INPUT && !Exp::Break().Matches(INPUT)) { + INPUT.eat(1); + } + } + + // if it's NOT a line break, then we're done! + if (!Exp::Break().Matches(INPUT)) { + break; + } + + // otherwise, let's eat the line break and keep going + int n = Exp::Break().Match(INPUT); + INPUT.eat(n); + + // oh yeah, and let's get rid of that simple key + InvalidateSimpleKey(); + + // new line - we may be able to accept a simple key now + if (InBlockContext()) { + m_simpleKeyAllowed = true; + } + } + } + +/////////////////////////////////////////////////////////////////////// +// Misc. helpers + +// IsWhitespaceToBeEaten +// . We can eat whitespace if it's a space or tab +// . Note: originally tabs in block context couldn't be eaten +// "where a simple key could be allowed +// (i.e., not at the beginning of a line, or following '-', '?', or +// ':')" +// I think this is wrong, since tabs can be non-content whitespace; it's just +// that they can't contribute to indentation, so once you've seen a tab in a +// line, you can't start a simple key + bool Scanner::IsWhitespaceToBeEaten(char ch) { + if (ch == ' ') { + return true; + } + + if (ch == '\t') { + return true; + } + + return false; + } + + const RegEx &Scanner::GetValueRegex() const { + if (InBlockContext()) { + return Exp::Value(); + } + + return m_canBeJSONFlow ? Exp::ValueInJSONFlow() : Exp::ValueInFlow(); + } + + void Scanner::StartStream() { + m_startedStream = true; + m_simpleKeyAllowed = true; + std::unique_ptr pIndent( + new IndentMarker(-1, IndentMarker::NONE)); + m_indentRefs.push_back(std::move(pIndent)); + m_indents.push(&m_indentRefs.back()); + } + + void Scanner::EndStream() { + // force newline + if (INPUT.column() > 0) { + INPUT.ResetColumn(); + } + + PopAllIndents(); + PopAllSimpleKeys(); + + m_simpleKeyAllowed = false; + m_endedStream = true; + } + + Token *Scanner::PushToken(Token::TYPE type) { + m_tokens.push(Token(type, INPUT.mark())); + return &m_tokens.back(); + } + + Token::TYPE Scanner::GetStartTokenFor(IndentMarker::INDENT_TYPE type) const { + switch (type) { + case IndentMarker::SEQ: + return Token::BLOCK_SEQ_START; + case IndentMarker::MAP: + return Token::BLOCK_MAP_START; + case IndentMarker::NONE: + assert(false); + break; + } + assert(false); + throw std::runtime_error("yaml-cpp: internal error, invalid indent type"); + } + + Scanner::IndentMarker *Scanner::PushIndentTo(int column, + IndentMarker::INDENT_TYPE type) { + // are we in flow? + if (InFlowContext()) { + return nullptr; + } + + std::unique_ptr pIndent(new IndentMarker(column, type)); + IndentMarker &indent = *pIndent; + const IndentMarker &lastIndent = *m_indents.top(); + + // is this actually an indentation? + if (indent.column < lastIndent.column) { + return nullptr; + } + if (indent.column == lastIndent.column && + !(indent.type == IndentMarker::SEQ && + lastIndent.type == IndentMarker::MAP)) { + return nullptr; + } + + // push a start token + indent.pStartToken = PushToken(GetStartTokenFor(type)); + + // and then the indent + m_indents.push(&indent); + m_indentRefs.push_back(std::move(pIndent)); + return &m_indentRefs.back(); + } + + void Scanner::PopIndentToHere() { + // are we in flow? + if (InFlowContext()) { + return; + } + + // now pop away + while (!m_indents.empty()) { + const IndentMarker &indent = *m_indents.top(); + if (indent.column < INPUT.column()) { + break; + } + if (indent.column == INPUT.column() && + !(indent.type == IndentMarker::SEQ && + !Exp::BlockEntry().Matches(INPUT))) { + break; + } + + PopIndent(); + } + + while (!m_indents.empty() && + m_indents.top()->status == IndentMarker::INVALID) { + PopIndent(); + } + } + + void Scanner::PopAllIndents() { + // are we in flow? + if (InFlowContext()) { + return; + } + + // now pop away + while (!m_indents.empty()) { + const IndentMarker &indent = *m_indents.top(); + if (indent.type == IndentMarker::NONE) { + break; + } + + PopIndent(); + } + } + + void Scanner::PopIndent() { + const IndentMarker &indent = *m_indents.top(); + m_indents.pop(); + + if (indent.status != IndentMarker::VALID) { + InvalidateSimpleKey(); + return; + } + + if (indent.type == IndentMarker::SEQ) { + m_tokens.push(Token(Token::BLOCK_SEQ_END, INPUT.mark())); + } else if (indent.type == IndentMarker::MAP) { + m_tokens.push(Token(Token::BLOCK_MAP_END, INPUT.mark())); + } + } + + int Scanner::GetTopIndent() const { + if (m_indents.empty()) { + return 0; + } + return m_indents.top()->column; + } + + void Scanner::ThrowParserException(const std::string &msg) const { + Mark mark = Mark::null_mark(); + if (!m_tokens.empty()) { + const Token &token = m_tokens.front(); + mark = token.mark; + } + throw ParserException(mark, msg); + } +} // namespace YAML diff --git a/yaml-cpp/src/scanner.h b/yaml-cpp/src/scanner.h new file mode 100644 index 0000000..e832b80 --- /dev/null +++ b/yaml-cpp/src/scanner.h @@ -0,0 +1,224 @@ +#ifndef SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include +#include +#include +#include +#include + +#include "ptr_vector.h" +#include "stream.h" +#include "token.h" +#include "yaml-cpp/mark.h" + +namespace YAML { + class Node; + + class RegEx; + +/** + * A scanner transforms a stream of characters into a stream of tokens. + */ + class Scanner { + public: + explicit Scanner(std::istream &in); + + ~Scanner(); + + /** Returns true if there are no more tokens to be read. */ + bool empty(); + + /** Removes the next token in the queue. */ + void pop(); + + /** Returns, but does not remove, the next token in the queue. */ + Token &peek(); + + /** Returns the current mark in the input stream. */ + Mark mark() const; + + private: + struct IndentMarker { + enum INDENT_TYPE { + MAP, SEQ, NONE + }; + enum STATUS { + VALID, INVALID, UNKNOWN + }; + + IndentMarker(int column_, INDENT_TYPE type_) + : column(column_), type(type_), status(VALID), pStartToken(nullptr) {} + + int column; + INDENT_TYPE type; + STATUS status; + Token *pStartToken; + }; + + enum FLOW_MARKER { + FLOW_MAP, FLOW_SEQ + }; + + private: + // scanning + + /** + * Scans until there's a valid token at the front of the queue, or the queue + * is empty. The state can be checked by {@link #empty}, and the next token + * retrieved by {@link #peek}. + */ + void EnsureTokensInQueue(); + + /** + * The main scanning function; this method branches out to scan whatever the + * next token should be. + */ + void ScanNextToken(); + + /** Eats the input stream until it reaches the next token-like thing. */ + void ScanToNextToken(); + + /** Sets the initial conditions for starting a stream. */ + void StartStream(); + + /** Closes out the stream, finish up, etc. */ + void EndStream(); + + Token *PushToken(Token::TYPE type); + + bool InFlowContext() const { return !m_flows.empty(); } + + bool InBlockContext() const { return m_flows.empty(); } + + std::size_t GetFlowLevel() const { return m_flows.size(); } + + Token::TYPE GetStartTokenFor(IndentMarker::INDENT_TYPE type) const; + + /** + * Pushes an indentation onto the stack, and enqueues the proper token + * (sequence start or mapping start). + * + * @return the indent marker it generates (if any). + */ + IndentMarker *PushIndentTo(int column, IndentMarker::INDENT_TYPE type); + + /** + * Pops indentations off the stack until it reaches the current indentation + * level, and enqueues the proper token each time. Then pops all invalid + * indentations off. + */ + void PopIndentToHere(); + + /** + * Pops all indentations (except for the base empty one) off the stack, and + * enqueues the proper token each time. + */ + void PopAllIndents(); + + /** Pops a single indent, pushing the proper token. */ + void PopIndent(); + + int GetTopIndent() const; + + // checking input + bool CanInsertPotentialSimpleKey() const; + + bool ExistsActiveSimpleKey() const; + + void InsertPotentialSimpleKey(); + + void InvalidateSimpleKey(); + + bool VerifySimpleKey(); + + void PopAllSimpleKeys(); + + /** + * Throws a ParserException with the current token location (if available), + * and does not parse any more tokens. + */ + void ThrowParserException(const std::string &msg) const; + + bool IsWhitespaceToBeEaten(char ch); + + /** + * Returns the appropriate regex to check if the next token is a value token. + */ + const RegEx &GetValueRegex() const; + + struct SimpleKey { + SimpleKey(const Mark &mark_, std::size_t flowLevel_); + + void Validate(); + + void Invalidate(); + + Mark mark; + std::size_t flowLevel; + IndentMarker *pIndent; + Token *pMapStart, *pKey; + }; + + // and the tokens + void ScanDirective(); + + void ScanDocStart(); + + void ScanDocEnd(); + + void ScanBlockSeqStart(); + + void ScanBlockMapSTart(); + + void ScanBlockEnd(); + + void ScanBlockEntry(); + + void ScanFlowStart(); + + void ScanFlowEnd(); + + void ScanFlowEntry(); + + void ScanKey(); + + void ScanValue(); + + void ScanAnchorOrAlias(); + + void ScanTag(); + + void ScanPlainScalar(); + + void ScanQuotedScalar(); + + void ScanBlockScalar(); + + private: + // the stream + Stream INPUT; + + // the output (tokens) + std::queue m_tokens; + + // state info + bool m_startedStream, m_endedStream; + bool m_simpleKeyAllowed; + bool m_canBeJSONFlow; + std::stack m_simpleKeys; + std::stack m_indents; + ptr_vector m_indentRefs; // for "garbage collection" + std::stack m_flows; + }; +} + +#endif // SCANNER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/scanscalar.cpp b/yaml-cpp/src/scanscalar.cpp new file mode 100644 index 0000000..528479c --- /dev/null +++ b/yaml-cpp/src/scanscalar.cpp @@ -0,0 +1,252 @@ +#include "scanscalar.h" + +#include + +#include "exp.h" +#include "regeximpl.h" +#include "stream.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep + +namespace YAML { +// ScanScalar +// . This is where the scalar magic happens. +// +// . We do the scanning in three phases: +// 1. Scan until newline +// 2. Eat newline +// 3. Scan leading blanks. +// +// . Depending on the parameters given, we store or stop +// and different places in the above flow. + std::string ScanScalar(Stream &INPUT, ScanScalarParams ¶ms) { + bool foundNonEmptyLine = false; + bool pastOpeningBreak = (params.fold == FOLD_FLOW); + bool emptyLine = false, moreIndented = false; + int foldedNewlineCount = 0; + bool foldedNewlineStartedMoreIndented = false; + std::size_t lastEscapedChar = std::string::npos; + std::string scalar; + params.leadingSpaces = false; + + if (!params.end) { + params.end = &Exp::Empty(); + } + + while (INPUT) { + // ******************************** + // Phase #1: scan until line ending + + std::size_t lastNonWhitespaceChar = scalar.size(); + bool escapedNewline = false; + while (!params.end->Matches(INPUT) && !Exp::Break().Matches(INPUT)) { + if (!INPUT) { + break; + } + + // document indicator? + if (INPUT.column() == 0 && Exp::DocIndicator().Matches(INPUT)) { + if (params.onDocIndicator == BREAK) { + break; + } else if (params.onDocIndicator == THROW) { + throw ParserException(INPUT.mark(), ErrorMsg::DOC_IN_SCALAR); + } + } + + foundNonEmptyLine = true; + pastOpeningBreak = true; + + // escaped newline? (only if we're escaping on slash) + if (params.escape == '\\' && Exp::EscBreak().Matches(INPUT)) { + // eat escape character and get out (but preserve trailing whitespace!) + INPUT.get(); + lastNonWhitespaceChar = scalar.size(); + lastEscapedChar = scalar.size(); + escapedNewline = true; + break; + } + + // escape this? + if (INPUT.peek() == params.escape) { + scalar += Exp::Escape(INPUT); + lastNonWhitespaceChar = scalar.size(); + lastEscapedChar = scalar.size(); + continue; + } + + // otherwise, just add the damn character + char ch = INPUT.get(); + scalar += ch; + if (ch != ' ' && ch != '\t') { + lastNonWhitespaceChar = scalar.size(); + } + } + + // eof? if we're looking to eat something, then we throw + if (!INPUT) { + if (params.eatEnd) { + throw ParserException(INPUT.mark(), ErrorMsg::EOF_IN_SCALAR); + } + break; + } + + // doc indicator? + if (params.onDocIndicator == BREAK && INPUT.column() == 0 && + Exp::DocIndicator().Matches(INPUT)) { + break; + } + + // are we done via character match? + int n = params.end->Match(INPUT); + if (n >= 0) { + if (params.eatEnd) { + INPUT.eat(n); + } + break; + } + + // do we remove trailing whitespace? + if (params.fold == FOLD_FLOW) + scalar.erase(lastNonWhitespaceChar); + + // ******************************** + // Phase #2: eat line ending + n = Exp::Break().Match(INPUT); + INPUT.eat(n); + + // ******************************** + // Phase #3: scan initial spaces + + // first the required indentation + while (INPUT.peek() == ' ' && + (INPUT.column() < params.indent || + (params.detectIndent && !foundNonEmptyLine)) && + !params.end->Matches(INPUT)) { + INPUT.eat(1); + } + + // update indent if we're auto-detecting + if (params.detectIndent && !foundNonEmptyLine) { + params.indent = std::max(params.indent, INPUT.column()); + } + + // and then the rest of the whitespace + while (Exp::Blank().Matches(INPUT)) { + // we check for tabs that masquerade as indentation + if (INPUT.peek() == '\t' && INPUT.column() < params.indent && + params.onTabInIndentation == THROW) { + throw ParserException(INPUT.mark(), ErrorMsg::TAB_IN_INDENTATION); + } + + if (!params.eatLeadingWhitespace) { + break; + } + + if (params.end->Matches(INPUT)) { + break; + } + + INPUT.eat(1); + } + + // was this an empty line? + bool nextEmptyLine = Exp::Break().Matches(INPUT); + bool nextMoreIndented = Exp::Blank().Matches(INPUT); + if (params.fold == FOLD_BLOCK && foldedNewlineCount == 0 && nextEmptyLine) + foldedNewlineStartedMoreIndented = moreIndented; + + // for block scalars, we always start with a newline, so we should ignore it + // (not fold or keep) + if (pastOpeningBreak) { + switch (params.fold) { + case DONT_FOLD: + scalar += "\n"; + break; + case FOLD_BLOCK: + if (!emptyLine && !nextEmptyLine && !moreIndented && + !nextMoreIndented && INPUT.column() >= params.indent) { + scalar += " "; + } else if (nextEmptyLine) { + foldedNewlineCount++; + } else { + scalar += "\n"; + } + + if (!nextEmptyLine && foldedNewlineCount > 0) { + scalar += std::string(foldedNewlineCount - 1, '\n'); + if (foldedNewlineStartedMoreIndented || + nextMoreIndented | !foundNonEmptyLine) { + scalar += "\n"; + } + foldedNewlineCount = 0; + } + break; + case FOLD_FLOW: + if (nextEmptyLine) { + scalar += "\n"; + } else if (!emptyLine && !escapedNewline) { + scalar += " "; + } + break; + } + } + + emptyLine = nextEmptyLine; + moreIndented = nextMoreIndented; + pastOpeningBreak = true; + + // are we done via indentation? + if (!emptyLine && INPUT.column() < params.indent) { + params.leadingSpaces = true; + break; + } + } + + // post-processing + if (params.trimTrailingSpaces) { + std::size_t pos = scalar.find_last_not_of(' '); + if (lastEscapedChar != std::string::npos) { + if (pos < lastEscapedChar || pos == std::string::npos) { + pos = lastEscapedChar; + } + } + if (pos < scalar.size()) { + scalar.erase(pos + 1); + } + } + + switch (params.chomp) { + case CLIP: { + std::size_t pos = scalar.find_last_not_of('\n'); + if (lastEscapedChar != std::string::npos) { + if (pos < lastEscapedChar || pos == std::string::npos) { + pos = lastEscapedChar; + } + } + if (pos == std::string::npos) { + scalar.erase(); + } else if (pos + 1 < scalar.size()) { + scalar.erase(pos + 2); + } + } + break; + case STRIP: { + std::size_t pos = scalar.find_last_not_of('\n'); + if (lastEscapedChar != std::string::npos) { + if (pos < lastEscapedChar || pos == std::string::npos) { + pos = lastEscapedChar; + } + } + if (pos == std::string::npos) { + scalar.erase(); + } else if (pos < scalar.size()) { + scalar.erase(pos + 1); + } + } + break; + default: + break; + } + + return scalar; + } +} // namespace YAML diff --git a/yaml-cpp/src/scanscalar.h b/yaml-cpp/src/scanscalar.h new file mode 100644 index 0000000..edf3fbf --- /dev/null +++ b/yaml-cpp/src/scanscalar.h @@ -0,0 +1,69 @@ +#ifndef SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +#include "regex_yaml.h" +#include "stream.h" + +namespace YAML { + enum CHOMP { + STRIP = -1, CLIP, KEEP + }; + enum ACTION { + NONE, BREAK, THROW + }; + enum FOLD { + DONT_FOLD, FOLD_BLOCK, FOLD_FLOW + }; + + struct ScanScalarParams { + ScanScalarParams() + : end(nullptr), + eatEnd(false), + indent(0), + detectIndent(false), + eatLeadingWhitespace(0), + escape(0), + fold(DONT_FOLD), + trimTrailingSpaces(0), + chomp(CLIP), + onDocIndicator(NONE), + onTabInIndentation(NONE), + leadingSpaces(false) {} + + // input: + const RegEx *end; // what condition ends this scalar? + // unowned. + bool eatEnd; // should we eat that condition when we see it? + int indent; // what level of indentation should be eaten and ignored? + bool detectIndent; // should we try to autodetect the indent? + bool eatLeadingWhitespace; // should we continue eating this delicious + // indentation after 'indent' spaces? + char escape; // what character do we escape on (i.e., slash or single quote) + // (0 for none) + FOLD fold; // how do we fold line ends? + bool trimTrailingSpaces; // do we remove all trailing spaces (at the very + // end) + CHOMP chomp; // do we strip, clip, or keep trailing newlines (at the very + // end) + // Note: strip means kill all, clip means keep at most one, keep means keep + // all + ACTION onDocIndicator; // what do we do if we see a document indicator? + ACTION onTabInIndentation; // what do we do if we see a tab where we should + // be seeing indentation spaces + + // output: + bool leadingSpaces; + }; + + std::string ScanScalar(Stream &INPUT, ScanScalarParams &info); +} + +#endif // SCANSCALAR_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/scantag.cpp b/yaml-cpp/src/scantag.cpp new file mode 100644 index 0000000..4df27ff --- /dev/null +++ b/yaml-cpp/src/scantag.cpp @@ -0,0 +1,81 @@ +#include "exp.h" +#include "regex_yaml.h" +#include "regeximpl.h" +#include "stream.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep +#include "yaml-cpp/mark.h" + +namespace YAML { + const std::string ScanVerbatimTag(Stream &INPUT) { + std::string tag; + + // eat the start character + INPUT.get(); + + while (INPUT) { + if (INPUT.peek() == Keys::VerbatimTagEnd) { + // eat the end character + INPUT.get(); + return tag; + } + + int n = Exp::URI().Match(INPUT); + if (n <= 0) + break; + + tag += INPUT.get(n); + } + + throw ParserException(INPUT.mark(), ErrorMsg::END_OF_VERBATIM_TAG); + } + + const std::string ScanTagHandle(Stream &INPUT, bool &canBeHandle) { + std::string tag; + canBeHandle = true; + Mark firstNonWordChar; + + while (INPUT) { + if (INPUT.peek() == Keys::Tag) { + if (!canBeHandle) + throw ParserException(firstNonWordChar, ErrorMsg::CHAR_IN_TAG_HANDLE); + break; + } + + int n = 0; + if (canBeHandle) { + n = Exp::Word().Match(INPUT); + if (n <= 0) { + canBeHandle = false; + firstNonWordChar = INPUT.mark(); + } + } + + if (!canBeHandle) + n = Exp::Tag().Match(INPUT); + + if (n <= 0) + break; + + tag += INPUT.get(n); + } + + return tag; + } + + const std::string ScanTagSuffix(Stream &INPUT) { + std::string tag; + + while (INPUT) { + int n = Exp::Tag().Match(INPUT); + if (n <= 0) + break; + + tag += INPUT.get(n); + } + + if (tag.empty()) + throw ParserException(INPUT.mark(), ErrorMsg::TAG_WITH_NO_SUFFIX); + + return tag; + } +} // namespace YAML diff --git a/yaml-cpp/src/scantag.h b/yaml-cpp/src/scantag.h new file mode 100644 index 0000000..6944a95 --- /dev/null +++ b/yaml-cpp/src/scantag.h @@ -0,0 +1,21 @@ +#ifndef SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include "stream.h" + +namespace YAML { + const std::string ScanVerbatimTag(Stream &INPUT); + + const std::string ScanTagHandle(Stream &INPUT, bool &canBeHandle); + + const std::string ScanTagSuffix(Stream &INPUT); +} + +#endif // SCANTAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/scantoken.cpp b/yaml-cpp/src/scantoken.cpp new file mode 100644 index 0000000..b6779eb --- /dev/null +++ b/yaml-cpp/src/scantoken.cpp @@ -0,0 +1,437 @@ +#include + +#include "exp.h" +#include "regex_yaml.h" +#include "regeximpl.h" +#include "scanner.h" +#include "scanscalar.h" +#include "scantag.h" // IWYU pragma: keep +#include "tag.h" // IWYU pragma: keep +#include "token.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep +#include "yaml-cpp/mark.h" + +namespace YAML { +/////////////////////////////////////////////////////////////////////// +// Specialization for scanning specific tokens + +// Directive +// . Note: no semantic checking is done here (that's for the parser to do) + void Scanner::ScanDirective() { + std::string name; + std::vector params; + + // pop indents and simple keys + PopAllIndents(); + PopAllSimpleKeys(); + + m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; + + // store pos and eat indicator + Token token(Token::DIRECTIVE, INPUT.mark()); + INPUT.eat(1); + + // read name + while (INPUT && !Exp::BlankOrBreak().Matches(INPUT)) + token.value += INPUT.get(); + + // read parameters + while (1) { + // first get rid of whitespace + while (Exp::Blank().Matches(INPUT)) + INPUT.eat(1); + + // break on newline or comment + if (!INPUT || Exp::Break().Matches(INPUT) || Exp::Comment().Matches(INPUT)) + break; + + // now read parameter + std::string param; + while (INPUT && !Exp::BlankOrBreak().Matches(INPUT)) + param += INPUT.get(); + + token.params.push_back(param); + } + + m_tokens.push(token); + } + +// DocStart + void Scanner::ScanDocStart() { + PopAllIndents(); + PopAllSimpleKeys(); + m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(3); + m_tokens.push(Token(Token::DOC_START, mark)); + } + +// DocEnd + void Scanner::ScanDocEnd() { + PopAllIndents(); + PopAllSimpleKeys(); + m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(3); + m_tokens.push(Token(Token::DOC_END, mark)); + } + +// FlowStart + void Scanner::ScanFlowStart() { + // flows can be simple keys + InsertPotentialSimpleKey(); + m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; + + // eat + Mark mark = INPUT.mark(); + char ch = INPUT.get(); + FLOW_MARKER flowType = (ch == Keys::FlowSeqStart ? FLOW_SEQ : FLOW_MAP); + m_flows.push(flowType); + Token::TYPE type = + (flowType == FLOW_SEQ ? Token::FLOW_SEQ_START : Token::FLOW_MAP_START); + m_tokens.push(Token(type, mark)); + } + +// FlowEnd + void Scanner::ScanFlowEnd() { + if (InBlockContext()) + throw ParserException(INPUT.mark(), ErrorMsg::FLOW_END); + + // we might have a solo entry in the flow context + if (InFlowContext()) { + if (m_flows.top() == FLOW_MAP && VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + else if (m_flows.top() == FLOW_SEQ) + InvalidateSimpleKey(); + } + + m_simpleKeyAllowed = false; + m_canBeJSONFlow = true; + + // eat + Mark mark = INPUT.mark(); + char ch = INPUT.get(); + + // check that it matches the start + FLOW_MARKER flowType = (ch == Keys::FlowSeqEnd ? FLOW_SEQ : FLOW_MAP); + if (m_flows.top() != flowType) + throw ParserException(mark, ErrorMsg::FLOW_END); + m_flows.pop(); + + Token::TYPE type = (flowType ? Token::FLOW_SEQ_END : Token::FLOW_MAP_END); + m_tokens.push(Token(type, mark)); + } + +// FlowEntry + void Scanner::ScanFlowEntry() { + // we might have a solo entry in the flow context + if (InFlowContext()) { + if (m_flows.top() == FLOW_MAP && VerifySimpleKey()) + m_tokens.push(Token(Token::VALUE, INPUT.mark())); + else if (m_flows.top() == FLOW_SEQ) + InvalidateSimpleKey(); + } + + m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(1); + m_tokens.push(Token(Token::FLOW_ENTRY, mark)); + } + +// BlockEntry + void Scanner::ScanBlockEntry() { + // we better be in the block context! + if (InFlowContext()) + throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); + + // can we put it here? + if (!m_simpleKeyAllowed) + throw ParserException(INPUT.mark(), ErrorMsg::BLOCK_ENTRY); + + PushIndentTo(INPUT.column(), IndentMarker::SEQ); + m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(1); + m_tokens.push(Token(Token::BLOCK_ENTRY, mark)); + } + +// Key + void Scanner::ScanKey() { + // handle keys diffently in the block context (and manage indents) + if (InBlockContext()) { + if (!m_simpleKeyAllowed) + throw ParserException(INPUT.mark(), ErrorMsg::MAP_KEY); + + PushIndentTo(INPUT.column(), IndentMarker::MAP); + } + + // can only put a simple key here if we're in block context + m_simpleKeyAllowed = InBlockContext(); + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(1); + m_tokens.push(Token(Token::KEY, mark)); + } + +// Value + void Scanner::ScanValue() { + // and check that simple key + bool isSimpleKey = VerifySimpleKey(); + m_canBeJSONFlow = false; + + if (isSimpleKey) { + // can't follow a simple key with another simple key (dunno why, though - it + // seems fine) + m_simpleKeyAllowed = false; + } else { + // handle values diffently in the block context (and manage indents) + if (InBlockContext()) { + if (!m_simpleKeyAllowed) + throw ParserException(INPUT.mark(), ErrorMsg::MAP_VALUE); + + PushIndentTo(INPUT.column(), IndentMarker::MAP); + } + + // can only put a simple key here if we're in block context + m_simpleKeyAllowed = InBlockContext(); + } + + // eat + Mark mark = INPUT.mark(); + INPUT.eat(1); + m_tokens.push(Token(Token::VALUE, mark)); + } + +// AnchorOrAlias + void Scanner::ScanAnchorOrAlias() { + bool alias; + std::string name; + + // insert a potential simple key + InsertPotentialSimpleKey(); + m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; + + // eat the indicator + Mark mark = INPUT.mark(); + char indicator = INPUT.get(); + alias = (indicator == Keys::Alias); + + // now eat the content + while (INPUT && Exp::Anchor().Matches(INPUT)) + name += INPUT.get(); + + // we need to have read SOMETHING! + if (name.empty()) + throw ParserException(INPUT.mark(), alias ? ErrorMsg::ALIAS_NOT_FOUND + : ErrorMsg::ANCHOR_NOT_FOUND); + + // and needs to end correctly + if (INPUT && !Exp::AnchorEnd().Matches(INPUT)) + throw ParserException(INPUT.mark(), alias ? ErrorMsg::CHAR_IN_ALIAS + : ErrorMsg::CHAR_IN_ANCHOR); + + // and we're done + Token token(alias ? Token::ALIAS : Token::ANCHOR, mark); + token.value = name; + m_tokens.push(token); + } + +// Tag + void Scanner::ScanTag() { + // insert a potential simple key + InsertPotentialSimpleKey(); + m_simpleKeyAllowed = false; + m_canBeJSONFlow = false; + + Token token(Token::TAG, INPUT.mark()); + + // eat the indicator + INPUT.get(); + + if (INPUT && INPUT.peek() == Keys::VerbatimTagStart) { + std::string tag = ScanVerbatimTag(INPUT); + + token.value = tag; + token.data = Tag::VERBATIM; + } else { + bool canBeHandle; + token.value = ScanTagHandle(INPUT, canBeHandle); + if (!canBeHandle && token.value.empty()) + token.data = Tag::NON_SPECIFIC; + else if (token.value.empty()) + token.data = Tag::SECONDARY_HANDLE; + else + token.data = Tag::PRIMARY_HANDLE; + + // is there a suffix? + if (canBeHandle && INPUT.peek() == Keys::Tag) { + // eat the indicator + INPUT.get(); + token.params.push_back(ScanTagSuffix(INPUT)); + token.data = Tag::NAMED_HANDLE; + } + } + + m_tokens.push(token); + } + +// PlainScalar + void Scanner::ScanPlainScalar() { + std::string scalar; + + // set up the scanning parameters + ScanScalarParams params; + params.end = + (InFlowContext() ? &Exp::ScanScalarEndInFlow() : &Exp::ScanScalarEnd()); + params.eatEnd = false; + params.indent = (InFlowContext() ? 0 : GetTopIndent() + 1); + params.fold = FOLD_FLOW; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = true; + params.chomp = STRIP; + params.onDocIndicator = BREAK; + params.onTabInIndentation = THROW; + + // insert a potential simple key + InsertPotentialSimpleKey(); + + Mark mark = INPUT.mark(); + scalar = ScanScalar(INPUT, params); + + // can have a simple key only if we ended the scalar by starting a new line + m_simpleKeyAllowed = params.leadingSpaces; + m_canBeJSONFlow = false; + + // finally, check and see if we ended on an illegal character + // if(Exp::IllegalCharInScalar.Matches(INPUT)) + // throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_SCALAR); + + Token token(Token::PLAIN_SCALAR, mark); + token.value = scalar; + m_tokens.push(token); + } + +// QuotedScalar + void Scanner::ScanQuotedScalar() { + std::string scalar; + + // peek at single or double quote (don't eat because we need to preserve (for + // the time being) the input position) + char quote = INPUT.peek(); + bool single = (quote == '\''); + + // setup the scanning parameters + ScanScalarParams params; + RegEx end = (single ? RegEx(quote) & !Exp::EscSingleQuote() : RegEx(quote)); + params.end = &end; + params.eatEnd = true; + params.escape = (single ? '\'' : '\\'); + params.indent = 0; + params.fold = FOLD_FLOW; + params.eatLeadingWhitespace = true; + params.trimTrailingSpaces = false; + params.chomp = CLIP; + params.onDocIndicator = THROW; + + // insert a potential simple key + InsertPotentialSimpleKey(); + + Mark mark = INPUT.mark(); + + // now eat that opening quote + INPUT.get(); + + // and scan + scalar = ScanScalar(INPUT, params); + m_simpleKeyAllowed = false; + m_canBeJSONFlow = true; + + Token token(Token::NON_PLAIN_SCALAR, mark); + token.value = scalar; + m_tokens.push(token); + } + +// BlockScalarToken +// . These need a little extra processing beforehand. +// . We need to scan the line where the indicator is (this doesn't count as part +// of the scalar), +// and then we need to figure out what level of indentation we'll be using. + void Scanner::ScanBlockScalar() { + std::string scalar; + + ScanScalarParams params; + params.indent = 1; + params.detectIndent = true; + + // eat block indicator ('|' or '>') + Mark mark = INPUT.mark(); + char indicator = INPUT.get(); + params.fold = (indicator == Keys::FoldedScalar ? FOLD_BLOCK : DONT_FOLD); + + // eat chomping/indentation indicators + params.chomp = CLIP; + int n = Exp::Chomp().Match(INPUT); + for (int i = 0; i < n; i++) { + char ch = INPUT.get(); + if (ch == '+') + params.chomp = KEEP; + else if (ch == '-') + params.chomp = STRIP; + else if (Exp::Digit().Matches(ch)) { + if (ch == '0') + throw ParserException(INPUT.mark(), ErrorMsg::ZERO_INDENT_IN_BLOCK); + + params.indent = ch - '0'; + params.detectIndent = false; + } + } + + // now eat whitespace + while (Exp::Blank().Matches(INPUT)) + INPUT.eat(1); + + // and comments to the end of the line + if (Exp::Comment().Matches(INPUT)) + while (INPUT && !Exp::Break().Matches(INPUT)) + INPUT.eat(1); + + // if it's not a line break, then we ran into a bad character inline + if (INPUT && !Exp::Break().Matches(INPUT)) + throw ParserException(INPUT.mark(), ErrorMsg::CHAR_IN_BLOCK); + + // set the initial indentation + if (GetTopIndent() >= 0) + params.indent += GetTopIndent(); + + params.eatLeadingWhitespace = false; + params.trimTrailingSpaces = false; + params.onTabInIndentation = THROW; + + scalar = ScanScalar(INPUT, params); + + // simple keys always ok after block scalars (since we're gonna start a new + // line anyways) + m_simpleKeyAllowed = true; + m_canBeJSONFlow = false; + + Token token(Token::NON_PLAIN_SCALAR, mark); + token.value = scalar; + m_tokens.push(token); + } +} // namespace YAML diff --git a/yaml-cpp/src/setting.h b/yaml-cpp/src/setting.h new file mode 100644 index 0000000..795d6ac --- /dev/null +++ b/yaml-cpp/src/setting.h @@ -0,0 +1,114 @@ +#ifndef SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/noexcept.h" +#include +#include +#include + +namespace YAML { + + class SettingChangeBase { + public: + virtual ~SettingChangeBase() = default; + + virtual void pop() = 0; + }; + + template + class Setting { + public: + Setting() : m_value() {} + + Setting(const T &value) : m_value() { set(value); } + + const T get() const { return m_value; } + + std::unique_ptr set(const T &value); + + void restore(const Setting &oldSetting) { m_value = oldSetting.get(); } + + private: + T m_value; + }; + + template + class SettingChange : public SettingChangeBase { + public: + SettingChange(Setting *pSetting) + : m_pCurSetting(pSetting), + m_oldSetting(*pSetting) // copy old setting to save its state + {} + + SettingChange(const SettingChange &) = delete; + + SettingChange(SettingChange &&) = delete; + + SettingChange &operator=(const SettingChange &) = delete; + + SettingChange &operator=(SettingChange &&) = delete; + + void pop() override { m_pCurSetting->restore(m_oldSetting); } + + private: + Setting *m_pCurSetting; + Setting m_oldSetting; + }; + + template + inline std::unique_ptr Setting::set(const T &value) { + std::unique_ptr pChange(new SettingChange(this)); + m_value = value; + return pChange; + } + + class SettingChanges { + public: + SettingChanges() : m_settingChanges{} {} + + SettingChanges(const SettingChanges &) = delete; + + SettingChanges(SettingChanges &&) YAML_CPP_NOEXCEPT = default; + + SettingChanges &operator=(const SettingChanges &) = delete; + + SettingChanges &operator=(SettingChanges &&rhs) YAML_CPP_NOEXCEPT { + if (this == &rhs) + return *this; + + clear(); + std::swap(m_settingChanges, rhs.m_settingChanges); + + return *this; + } + + ~SettingChanges() { clear(); } + + void clear() YAML_CPP_NOEXCEPT { + restore(); + m_settingChanges.clear(); + } + + void restore() YAML_CPP_NOEXCEPT { + for (setting_changes::const_iterator it = m_settingChanges.begin(); + it != m_settingChanges.end(); ++it) + (*it)->pop(); + } + + void push(std::unique_ptr pSettingChange) { + m_settingChanges.push_back(std::move(pSettingChange)); + } + + private: + using setting_changes = std::vector>; + setting_changes m_settingChanges; + }; +} // namespace YAML + +#endif // SETTING_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/simplekey.cpp b/yaml-cpp/src/simplekey.cpp new file mode 100644 index 0000000..9f320f9 --- /dev/null +++ b/yaml-cpp/src/simplekey.cpp @@ -0,0 +1,132 @@ +#include "scanner.h" +#include "token.h" + +namespace YAML { + struct Mark; + + Scanner::SimpleKey::SimpleKey(const Mark &mark_, std::size_t flowLevel_) + : mark(mark_), + flowLevel(flowLevel_), + pIndent(nullptr), + pMapStart(nullptr), + pKey(nullptr) {} + + void Scanner::SimpleKey::Validate() { + // Note: pIndent will *not* be garbage here; + // we "garbage collect" them so we can + // always refer to them + if (pIndent) + pIndent->status = IndentMarker::VALID; + if (pMapStart) + pMapStart->status = Token::VALID; + if (pKey) + pKey->status = Token::VALID; + } + + void Scanner::SimpleKey::Invalidate() { + if (pIndent) + pIndent->status = IndentMarker::INVALID; + if (pMapStart) + pMapStart->status = Token::INVALID; + if (pKey) + pKey->status = Token::INVALID; + } + +// CanInsertPotentialSimpleKey + bool Scanner::CanInsertPotentialSimpleKey() const { + if (!m_simpleKeyAllowed) + return false; + + return !ExistsActiveSimpleKey(); + } + +// ExistsActiveSimpleKey +// . Returns true if there's a potential simple key at our flow level +// (there's allowed at most one per flow level, i.e., at the start of the flow +// start token) + bool Scanner::ExistsActiveSimpleKey() const { + if (m_simpleKeys.empty()) + return false; + + const SimpleKey &key = m_simpleKeys.top(); + return key.flowLevel == GetFlowLevel(); + } + +// InsertPotentialSimpleKey +// . If we can, add a potential simple key to the queue, +// and save it on a stack. + void Scanner::InsertPotentialSimpleKey() { + if (!CanInsertPotentialSimpleKey()) + return; + + SimpleKey key(INPUT.mark(), GetFlowLevel()); + + // first add a map start, if necessary + if (InBlockContext()) { + key.pIndent = PushIndentTo(INPUT.column(), IndentMarker::MAP); + if (key.pIndent) { + key.pIndent->status = IndentMarker::UNKNOWN; + key.pMapStart = key.pIndent->pStartToken; + key.pMapStart->status = Token::UNVERIFIED; + } + } + + // then add the (now unverified) key + m_tokens.push(Token(Token::KEY, INPUT.mark())); + key.pKey = &m_tokens.back(); + key.pKey->status = Token::UNVERIFIED; + + m_simpleKeys.push(key); + } + +// InvalidateSimpleKey +// . Automatically invalidate the simple key in our flow level + void Scanner::InvalidateSimpleKey() { + if (m_simpleKeys.empty()) + return; + + // grab top key + SimpleKey &key = m_simpleKeys.top(); + if (key.flowLevel != GetFlowLevel()) + return; + + key.Invalidate(); + m_simpleKeys.pop(); + } + +// VerifySimpleKey +// . Determines whether the latest simple key to be added is valid, +// and if so, makes it valid. + bool Scanner::VerifySimpleKey() { + if (m_simpleKeys.empty()) + return false; + + // grab top key + SimpleKey key = m_simpleKeys.top(); + + // only validate if we're in the correct flow level + if (key.flowLevel != GetFlowLevel()) + return false; + + m_simpleKeys.pop(); + + bool isValid = true; + + // needs to be less than 1024 characters and inline + if (INPUT.line() != key.mark.line || INPUT.pos() - key.mark.pos > 1024) + isValid = false; + + // invalidate key + if (isValid) + key.Validate(); + else + key.Invalidate(); + + return isValid; + } + + void Scanner::PopAllSimpleKeys() { + while (!m_simpleKeys.empty()) + m_simpleKeys.pop(); + } +} // namespace YAML diff --git a/yaml-cpp/src/singledocparser.cpp b/yaml-cpp/src/singledocparser.cpp new file mode 100644 index 0000000..c990732 --- /dev/null +++ b/yaml-cpp/src/singledocparser.cpp @@ -0,0 +1,431 @@ +#include +#include +#include + +#include "collectionstack.h" // IWYU pragma: keep +#include "scanner.h" +#include "singledocparser.h" +#include "tag.h" +#include "token.h" +#include "yaml-cpp/depthguard.h" +#include "yaml-cpp/emitterstyle.h" +#include "yaml-cpp/eventhandler.h" +#include "yaml-cpp/exceptions.h" // IWYU pragma: keep +#include "yaml-cpp/mark.h" +#include "yaml-cpp/null.h" + +namespace YAML { + SingleDocParser::SingleDocParser(Scanner &scanner, const Directives &directives) + : m_scanner(scanner), + m_directives(directives), + m_pCollectionStack(new CollectionStack), + m_anchors{}, + m_curAnchor(0) {} + + SingleDocParser::~SingleDocParser() = default; + +// HandleDocument +// . Handles the next document +// . Throws a ParserException on error. + void SingleDocParser::HandleDocument(EventHandler &eventHandler) { + assert(!m_scanner.empty()); // guaranteed that there are tokens + assert(!m_curAnchor); + + eventHandler.OnDocumentStart(m_scanner.peek().mark); + + // eat doc start + if (m_scanner.peek().type == Token::DOC_START) + m_scanner.pop(); + + // recurse! + HandleNode(eventHandler); + + eventHandler.OnDocumentEnd(); + + // and finally eat any doc ends we see + while (!m_scanner.empty() && m_scanner.peek().type == Token::DOC_END) + m_scanner.pop(); + } + + void SingleDocParser::HandleNode(EventHandler &eventHandler) { + DepthGuard<2000> depthguard(depth, m_scanner.mark(), ErrorMsg::BAD_FILE); + + // an empty node *is* a possibility + if (m_scanner.empty()) { + eventHandler.OnNull(m_scanner.mark(), NullAnchor); + return; + } + + // save location + Mark mark = m_scanner.peek().mark; + + // special case: a value node by itself must be a map, with no header + if (m_scanner.peek().type == Token::VALUE) { + eventHandler.OnMapStart(mark, "?", NullAnchor, EmitterStyle::Default); + HandleMap(eventHandler); + eventHandler.OnMapEnd(); + return; + } + + // special case: an alias node + if (m_scanner.peek().type == Token::ALIAS) { + eventHandler.OnAlias(mark, LookupAnchor(mark, m_scanner.peek().value)); + m_scanner.pop(); + return; + } + + std::string tag; + std::string anchor_name; + anchor_t anchor; + ParseProperties(tag, anchor, anchor_name); + + if (!anchor_name.empty()) + eventHandler.OnAnchor(mark, anchor_name); + + // after parsing properties, an empty node is again a possibility + if (m_scanner.empty()) { + eventHandler.OnNull(mark, anchor); + return; + } + + const Token &token = m_scanner.peek(); + + if (token.type == Token::PLAIN_SCALAR && IsNullString(token.value)) { + eventHandler.OnNull(mark, anchor); + m_scanner.pop(); + return; + } + + // add non-specific tags + if (tag.empty()) + tag = (token.type == Token::NON_PLAIN_SCALAR ? "!" : "?"); + + // now split based on what kind of node we should be + switch (token.type) { + case Token::PLAIN_SCALAR: + case Token::NON_PLAIN_SCALAR: + eventHandler.OnScalar(mark, tag, anchor, token.value); + m_scanner.pop(); + return; + case Token::FLOW_SEQ_START: + eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Flow); + HandleSequence(eventHandler); + eventHandler.OnSequenceEnd(); + return; + case Token::BLOCK_SEQ_START: + eventHandler.OnSequenceStart(mark, tag, anchor, EmitterStyle::Block); + HandleSequence(eventHandler); + eventHandler.OnSequenceEnd(); + return; + case Token::FLOW_MAP_START: + eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow); + HandleMap(eventHandler); + eventHandler.OnMapEnd(); + return; + case Token::BLOCK_MAP_START: + eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Block); + HandleMap(eventHandler); + eventHandler.OnMapEnd(); + return; + case Token::KEY: + // compact maps can only go in a flow sequence + if (m_pCollectionStack->GetCurCollectionType() == + CollectionType::FlowSeq) { + eventHandler.OnMapStart(mark, tag, anchor, EmitterStyle::Flow); + HandleMap(eventHandler); + eventHandler.OnMapEnd(); + return; + } + break; + default: + break; + } + + if (tag == "?") + eventHandler.OnNull(mark, anchor); + else + eventHandler.OnScalar(mark, tag, anchor, ""); + } + + void SingleDocParser::HandleSequence(EventHandler &eventHandler) { + // split based on start token + switch (m_scanner.peek().type) { + case Token::BLOCK_SEQ_START: + HandleBlockSequence(eventHandler); + break; + case Token::FLOW_SEQ_START: + HandleFlowSequence(eventHandler); + break; + default: + break; + } + } + + void SingleDocParser::HandleBlockSequence(EventHandler &eventHandler) { + // eat start token + m_scanner.pop(); + m_pCollectionStack->PushCollectionType(CollectionType::BlockSeq); + + while (1) { + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ); + + Token token = m_scanner.peek(); + if (token.type != Token::BLOCK_ENTRY && token.type != Token::BLOCK_SEQ_END) + throw ParserException(token.mark, ErrorMsg::END_OF_SEQ); + + m_scanner.pop(); + if (token.type == Token::BLOCK_SEQ_END) + break; + + // check for null + if (!m_scanner.empty()) { + const Token &nextToken = m_scanner.peek(); + if (nextToken.type == Token::BLOCK_ENTRY || + nextToken.type == Token::BLOCK_SEQ_END) { + eventHandler.OnNull(nextToken.mark, NullAnchor); + continue; + } + } + + HandleNode(eventHandler); + } + + m_pCollectionStack->PopCollectionType(CollectionType::BlockSeq); + } + + void SingleDocParser::HandleFlowSequence(EventHandler &eventHandler) { + // eat start token + m_scanner.pop(); + m_pCollectionStack->PushCollectionType(CollectionType::FlowSeq); + + while (1) { + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW); + + // first check for end + if (m_scanner.peek().type == Token::FLOW_SEQ_END) { + m_scanner.pop(); + break; + } + + // then read the node + HandleNode(eventHandler); + + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_SEQ_FLOW); + + // now eat the separator (or could be a sequence end, which we ignore - but + // if it's neither, then it's a bad node) + Token &token = m_scanner.peek(); + if (token.type == Token::FLOW_ENTRY) + m_scanner.pop(); + else if (token.type != Token::FLOW_SEQ_END) + throw ParserException(token.mark, ErrorMsg::END_OF_SEQ_FLOW); + } + + m_pCollectionStack->PopCollectionType(CollectionType::FlowSeq); + } + + void SingleDocParser::HandleMap(EventHandler &eventHandler) { + // split based on start token + switch (m_scanner.peek().type) { + case Token::BLOCK_MAP_START: + HandleBlockMap(eventHandler); + break; + case Token::FLOW_MAP_START: + HandleFlowMap(eventHandler); + break; + case Token::KEY: + HandleCompactMap(eventHandler); + break; + case Token::VALUE: + HandleCompactMapWithNoKey(eventHandler); + break; + default: + break; + } + } + + void SingleDocParser::HandleBlockMap(EventHandler &eventHandler) { + // eat start token + m_scanner.pop(); + m_pCollectionStack->PushCollectionType(CollectionType::BlockMap); + + while (1) { + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP); + + Token token = m_scanner.peek(); + if (token.type != Token::KEY && token.type != Token::VALUE && + token.type != Token::BLOCK_MAP_END) + throw ParserException(token.mark, ErrorMsg::END_OF_MAP); + + if (token.type == Token::BLOCK_MAP_END) { + m_scanner.pop(); + break; + } + + // grab key (if non-null) + if (token.type == Token::KEY) { + m_scanner.pop(); + HandleNode(eventHandler); + } else { + eventHandler.OnNull(token.mark, NullAnchor); + } + + // now grab value (optional) + if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) { + m_scanner.pop(); + HandleNode(eventHandler); + } else { + eventHandler.OnNull(token.mark, NullAnchor); + } + } + + m_pCollectionStack->PopCollectionType(CollectionType::BlockMap); + } + + void SingleDocParser::HandleFlowMap(EventHandler &eventHandler) { + // eat start token + m_scanner.pop(); + m_pCollectionStack->PushCollectionType(CollectionType::FlowMap); + + while (1) { + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW); + + Token &token = m_scanner.peek(); + const Mark mark = token.mark; + // first check for end + if (token.type == Token::FLOW_MAP_END) { + m_scanner.pop(); + break; + } + + // grab key (if non-null) + if (token.type == Token::KEY) { + m_scanner.pop(); + HandleNode(eventHandler); + } else { + eventHandler.OnNull(mark, NullAnchor); + } + + // now grab value (optional) + if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) { + m_scanner.pop(); + HandleNode(eventHandler); + } else { + eventHandler.OnNull(mark, NullAnchor); + } + + if (m_scanner.empty()) + throw ParserException(m_scanner.mark(), ErrorMsg::END_OF_MAP_FLOW); + + // now eat the separator (or could be a map end, which we ignore - but if + // it's neither, then it's a bad node) + Token &nextToken = m_scanner.peek(); + if (nextToken.type == Token::FLOW_ENTRY) + m_scanner.pop(); + else if (nextToken.type != Token::FLOW_MAP_END) + throw ParserException(nextToken.mark, ErrorMsg::END_OF_MAP_FLOW); + } + + m_pCollectionStack->PopCollectionType(CollectionType::FlowMap); + } + +// . Single "key: value" pair in a flow sequence + void SingleDocParser::HandleCompactMap(EventHandler &eventHandler) { + m_pCollectionStack->PushCollectionType(CollectionType::CompactMap); + + // grab key + Mark mark = m_scanner.peek().mark; + m_scanner.pop(); + HandleNode(eventHandler); + + // now grab value (optional) + if (!m_scanner.empty() && m_scanner.peek().type == Token::VALUE) { + m_scanner.pop(); + HandleNode(eventHandler); + } else { + eventHandler.OnNull(mark, NullAnchor); + } + + m_pCollectionStack->PopCollectionType(CollectionType::CompactMap); + } + +// . Single ": value" pair in a flow sequence + void SingleDocParser::HandleCompactMapWithNoKey(EventHandler &eventHandler) { + m_pCollectionStack->PushCollectionType(CollectionType::CompactMap); + + // null key + eventHandler.OnNull(m_scanner.peek().mark, NullAnchor); + + // grab value + m_scanner.pop(); + HandleNode(eventHandler); + + m_pCollectionStack->PopCollectionType(CollectionType::CompactMap); + } + +// ParseProperties +// . Grabs any tag or anchor tokens and deals with them. + void SingleDocParser::ParseProperties(std::string &tag, anchor_t &anchor, + std::string &anchor_name) { + tag.clear(); + anchor_name.clear(); + anchor = NullAnchor; + + while (1) { + if (m_scanner.empty()) + return; + + switch (m_scanner.peek().type) { + case Token::TAG: + ParseTag(tag); + break; + case Token::ANCHOR: + ParseAnchor(anchor, anchor_name); + break; + default: + return; + } + } + } + + void SingleDocParser::ParseTag(std::string &tag) { + Token &token = m_scanner.peek(); + if (!tag.empty()) + throw ParserException(token.mark, ErrorMsg::MULTIPLE_TAGS); + + Tag tagInfo(token); + tag = tagInfo.Translate(m_directives); + m_scanner.pop(); + } + + void SingleDocParser::ParseAnchor(anchor_t &anchor, std::string &anchor_name) { + Token &token = m_scanner.peek(); + if (anchor) + throw ParserException(token.mark, ErrorMsg::MULTIPLE_ANCHORS); + + anchor_name = token.value; + anchor = RegisterAnchor(token.value); + m_scanner.pop(); + } + + anchor_t SingleDocParser::RegisterAnchor(const std::string &name) { + if (name.empty()) + return NullAnchor; + + return m_anchors[name] = ++m_curAnchor; + } + + anchor_t SingleDocParser::LookupAnchor(const Mark &mark, + const std::string &name) const { + Anchors::const_iterator it = m_anchors.find(name); + if (it == m_anchors.end()) + throw ParserException(mark, ErrorMsg::UNKNOWN_ANCHOR); + + return it->second; + } +} // namespace YAML diff --git a/yaml-cpp/src/singledocparser.h b/yaml-cpp/src/singledocparser.h new file mode 100644 index 0000000..c951c42 --- /dev/null +++ b/yaml-cpp/src/singledocparser.h @@ -0,0 +1,90 @@ +#ifndef SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include +#include +#include + +#include "yaml-cpp/anchor.h" + +namespace YAML { + class CollectionStack; + + template + class DepthGuard; // depthguard.h + class EventHandler; + + class Node; + + class Scanner; + + struct Directives; + struct Mark; + struct Token; + + class SingleDocParser { + public: + SingleDocParser(Scanner &scanner, const Directives &directives); + + SingleDocParser(const SingleDocParser &) = delete; + + SingleDocParser(SingleDocParser &&) = delete; + + SingleDocParser &operator=(const SingleDocParser &) = delete; + + SingleDocParser &operator=(SingleDocParser &&) = delete; + + ~SingleDocParser(); + + void HandleDocument(EventHandler &eventHandler); + + private: + void HandleNode(EventHandler &eventHandler); + + void HandleSequence(EventHandler &eventHandler); + + void HandleBlockSequence(EventHandler &eventHandler); + + void HandleFlowSequence(EventHandler &eventHandler); + + void HandleMap(EventHandler &eventHandler); + + void HandleBlockMap(EventHandler &eventHandler); + + void HandleFlowMap(EventHandler &eventHandler); + + void HandleCompactMap(EventHandler &eventHandler); + + void HandleCompactMapWithNoKey(EventHandler &eventHandler); + + void ParseProperties(std::string &tag, anchor_t &anchor, + std::string &anchor_name); + + void ParseTag(std::string &tag); + + void ParseAnchor(anchor_t &anchor, std::string &anchor_name); + + anchor_t RegisterAnchor(const std::string &name); + + anchor_t LookupAnchor(const Mark &mark, const std::string &name) const; + + private: + int depth = 0; + Scanner &m_scanner; + const Directives &m_directives; + std::unique_ptr m_pCollectionStack; + + using Anchors = std::map; + Anchors m_anchors; + + anchor_t m_curAnchor; + }; +} // namespace YAML + +#endif // SINGLEDOCPARSER_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/stream.cpp b/yaml-cpp/src/stream.cpp new file mode 100644 index 0000000..47de3ab --- /dev/null +++ b/yaml-cpp/src/stream.cpp @@ -0,0 +1,455 @@ +#include + +#include "stream.h" + +#ifndef YAML_PREFETCH_SIZE +#define YAML_PREFETCH_SIZE 2048 +#endif + +#define S_ARRAY_SIZE(A) (sizeof(A) / sizeof(*(A))) +#define S_ARRAY_END(A) ((A) + S_ARRAY_SIZE(A)) + +#define CP_REPLACEMENT_CHARACTER (0xFFFD) + +namespace YAML { + enum UtfIntroState { + uis_start, + uis_utfbe_b1, + uis_utf32be_b2, + uis_utf32be_bom3, + uis_utf32be, + uis_utf16be, + uis_utf16be_bom1, + uis_utfle_bom1, + uis_utf16le_bom2, + uis_utf32le_bom3, + uis_utf16le, + uis_utf32le, + uis_utf8_imp, + uis_utf16le_imp, + uis_utf32le_imp3, + uis_utf8_bom1, + uis_utf8_bom2, + uis_utf8, + uis_error + }; + + enum UtfIntroCharType { + uict00, + uictBB, + uictBF, + uictEF, + uictFE, + uictFF, + uictAscii, + uictOther, + uictMax + }; + + static bool s_introFinalState[] = { + false, // uis_start + false, // uis_utfbe_b1 + false, // uis_utf32be_b2 + false, // uis_utf32be_bom3 + true, // uis_utf32be + true, // uis_utf16be + false, // uis_utf16be_bom1 + false, // uis_utfle_bom1 + false, // uis_utf16le_bom2 + false, // uis_utf32le_bom3 + true, // uis_utf16le + true, // uis_utf32le + false, // uis_utf8_imp + false, // uis_utf16le_imp + false, // uis_utf32le_imp3 + false, // uis_utf8_bom1 + false, // uis_utf8_bom2 + true, // uis_utf8 + true, // uis_error + }; + + static UtfIntroState s_introTransitions[][uictMax] = { + // uict00, uictBB, uictBF, uictEF, + // uictFE, uictFF, uictAscii, uictOther + {uis_utfbe_b1, uis_utf8, uis_utf8, uis_utf8_bom1, uis_utf16be_bom1, + uis_utfle_bom1, uis_utf8_imp, uis_utf8}, + {uis_utf32be_b2, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, + uis_utf16be, uis_utf8}, + {uis_utf32be, uis_utf8, uis_utf8, uis_utf8, uis_utf32be_bom3, uis_utf8, + uis_utf8, uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf32be, uis_utf8, + uis_utf8}, + {uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, uis_utf32be, + uis_utf32be, uis_utf32be, uis_utf32be}, + {uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, uis_utf16be, + uis_utf16be, uis_utf16be, uis_utf16be}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf16be, uis_utf8, + uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf16le_bom2, uis_utf8, + uis_utf8, uis_utf8}, + {uis_utf32le_bom3, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, + uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, + uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, + uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, uis_utf32le, + uis_utf32le, uis_utf32le, uis_utf32le}, + {uis_utf16le_imp, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, + uis_utf8, uis_utf8}, + {uis_utf32le_imp3, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, + uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf32le, uis_utf16le, uis_utf16le, uis_utf16le, uis_utf16le, + uis_utf16le, uis_utf16le, uis_utf16le}, + {uis_utf8, uis_utf8_bom2, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, + uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, + uis_utf8}, + {uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, uis_utf8, + uis_utf8}, + }; + + static char s_introUngetCount[][uictMax] = { + // uict00, uictBB, uictBF, uictEF, uictFE, uictFF, uictAscii, uictOther + {0, 1, 1, 0, 0, 0, 0, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {3, 3, 3, 3, 0, 3, 3, 3}, + {4, 4, 4, 4, 4, 0, 4, 4}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {2, 2, 2, 2, 2, 0, 2, 2}, + {2, 2, 2, 2, 0, 2, 2, 2}, + {0, 1, 1, 1, 1, 1, 1, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {1, 1, 1, 1, 1, 1, 1, 1}, + {0, 2, 2, 2, 2, 2, 2, 2}, + {0, 3, 3, 3, 3, 3, 3, 3}, + {4, 4, 4, 4, 4, 4, 4, 4}, + {2, 0, 2, 2, 2, 2, 2, 2}, + {3, 3, 0, 3, 3, 3, 3, 3}, + {1, 1, 1, 1, 1, 1, 1, 1}, + }; + + inline UtfIntroCharType IntroCharTypeOf(std::istream::int_type ch) { + if (std::istream::traits_type::eof() == ch) { + return uictOther; + } + + switch (ch) { + case 0: + return uict00; + case 0xBB: + return uictBB; + case 0xBF: + return uictBF; + case 0xEF: + return uictEF; + case 0xFE: + return uictFE; + case 0xFF: + return uictFF; + } + + if ((ch > 0) && (ch < 0xFF)) { + return uictAscii; + } + + return uictOther; + } + + inline char Utf8Adjust(unsigned long ch, unsigned char lead_bits, + unsigned char rshift) { + const unsigned char header = + static_cast(((1 << lead_bits) - 1) << (8 - lead_bits)); + const unsigned char mask = (0xFF >> (lead_bits + 1)); + return static_cast( + static_cast(header | ((ch >> rshift) & mask))); + } + + inline void QueueUnicodeCodepoint(std::deque &q, unsigned long ch) { + // We are not allowed to queue the Stream::eof() codepoint, so + // replace it with CP_REPLACEMENT_CHARACTER + if (static_cast(Stream::eof()) == ch) { + ch = CP_REPLACEMENT_CHARACTER; + } + + if (ch < 0x80) { + q.push_back(Utf8Adjust(ch, 0, 0)); + } else if (ch < 0x800) { + q.push_back(Utf8Adjust(ch, 2, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } else if (ch < 0x10000) { + q.push_back(Utf8Adjust(ch, 3, 12)); + q.push_back(Utf8Adjust(ch, 1, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } else { + q.push_back(Utf8Adjust(ch, 4, 18)); + q.push_back(Utf8Adjust(ch, 1, 12)); + q.push_back(Utf8Adjust(ch, 1, 6)); + q.push_back(Utf8Adjust(ch, 1, 0)); + } + } + + Stream::Stream(std::istream &input) + : m_input(input), + m_mark{}, + m_charSet{}, + m_readahead{}, + m_pPrefetched(new unsigned char[YAML_PREFETCH_SIZE]), + m_nPrefetchedAvailable(0), + m_nPrefetchedUsed(0) { + using char_traits = std::istream::traits_type; + + if (!input) + return; + + // Determine (or guess) the character-set by reading the BOM, if any. See + // the YAML specification for the determination algorithm. + char_traits::int_type intro[4]{}; + int nIntroUsed = 0; + UtfIntroState state = uis_start; + for (; !s_introFinalState[state];) { + std::istream::int_type ch = input.get(); + intro[nIntroUsed++] = ch; + UtfIntroCharType charType = IntroCharTypeOf(ch); + UtfIntroState newState = s_introTransitions[state][charType]; + int nUngets = s_introUngetCount[state][charType]; + if (nUngets > 0) { + input.clear(); + for (; nUngets > 0; --nUngets) { + if (char_traits::eof() != intro[--nIntroUsed]) + input.putback(char_traits::to_char_type(intro[nIntroUsed])); + } + } + state = newState; + } + + switch (state) { + case uis_utf8: + m_charSet = utf8; + break; + case uis_utf16le: + m_charSet = utf16le; + break; + case uis_utf16be: + m_charSet = utf16be; + break; + case uis_utf32le: + m_charSet = utf32le; + break; + case uis_utf32be: + m_charSet = utf32be; + break; + default: + m_charSet = utf8; + break; + } + + ReadAheadTo(0); + } + + Stream::~Stream() { delete[] m_pPrefetched; } + + char Stream::peek() const { + if (m_readahead.empty()) { + return Stream::eof(); + } + + return m_readahead[0]; + } + + Stream::operator bool() const { + return m_input.good() || + (!m_readahead.empty() && m_readahead[0] != Stream::eof()); + } + +// get +// . Extracts a character from the stream and updates our position + char Stream::get() { + char ch = peek(); + AdvanceCurrent(); + m_mark.column++; + + if (ch == '\n') { + m_mark.column = 0; + m_mark.line++; + } + + return ch; + } + +// get +// . Extracts 'n' characters from the stream and updates our position + std::string Stream::get(int n) { + std::string ret; + if (n > 0) { + ret.reserve(static_cast(n)); + for (int i = 0; i < n; i++) + ret += get(); + } + return ret; + } + +// eat +// . Eats 'n' characters and updates our position. + void Stream::eat(int n) { + for (int i = 0; i < n; i++) + get(); + } + + void Stream::AdvanceCurrent() { + if (!m_readahead.empty()) { + m_readahead.pop_front(); + m_mark.pos++; + } + + ReadAheadTo(0); + } + + bool Stream::_ReadAheadTo(size_t i) const { + while (m_input.good() && (m_readahead.size() <= i)) { + switch (m_charSet) { + case utf8: + StreamInUtf8(); + break; + case utf16le: + StreamInUtf16(); + break; + case utf16be: + StreamInUtf16(); + break; + case utf32le: + StreamInUtf32(); + break; + case utf32be: + StreamInUtf32(); + break; + } + } + + // signal end of stream + if (!m_input.good()) + m_readahead.push_back(Stream::eof()); + + return m_readahead.size() > i; + } + + void Stream::StreamInUtf8() const { + unsigned char b = GetNextByte(); + if (m_input.good()) { + m_readahead.push_back(static_cast(b)); + } + } + + void Stream::StreamInUtf16() const { + unsigned long ch = 0; + unsigned char bytes[2]; + int nBigEnd = (m_charSet == utf16be) ? 0 : 1; + + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + if (!m_input.good()) { + return; + } + ch = (static_cast(bytes[nBigEnd]) << 8) | + static_cast(bytes[1 ^ nBigEnd]); + + if (ch >= 0xDC00 && ch < 0xE000) { + // Trailing (low) surrogate...ugh, wrong order + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + return; + } else if (ch >= 0xD800 && ch < 0xDC00) { + // ch is a leading (high) surrogate + + // Four byte UTF-8 code point + + // Read the trailing (low) surrogate + for (;;) { + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + if (!m_input.good()) { + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + return; + } + unsigned long chLow = (static_cast(bytes[nBigEnd]) << 8) | + static_cast(bytes[1 ^ nBigEnd]); + if (chLow < 0xDC00 || chLow >= 0xE000) { + // Trouble...not a low surrogate. Dump a REPLACEMENT CHARACTER into the + // stream. + QueueUnicodeCodepoint(m_readahead, CP_REPLACEMENT_CHARACTER); + + // Deal with the next UTF-16 unit + if (chLow < 0xD800 || chLow >= 0xE000) { + // Easiest case: queue the codepoint and return + QueueUnicodeCodepoint(m_readahead, ch); + return; + } else { + // Start the loop over with the new high surrogate + ch = chLow; + continue; + } + } + + // Select the payload bits from the high surrogate + ch &= 0x3FF; + ch <<= 10; + + // Include bits from low surrogate + ch |= (chLow & 0x3FF); + + // Add the surrogacy offset + ch += 0x10000; + break; + } + } + + QueueUnicodeCodepoint(m_readahead, ch); + } + + inline char *ReadBuffer(unsigned char *pBuffer) { + return reinterpret_cast(pBuffer); + } + + unsigned char Stream::GetNextByte() const { + if (m_nPrefetchedUsed >= m_nPrefetchedAvailable) { + std::streambuf *pBuf = m_input.rdbuf(); + m_nPrefetchedAvailable = static_cast( + pBuf->sgetn(ReadBuffer(m_pPrefetched), YAML_PREFETCH_SIZE)); + m_nPrefetchedUsed = 0; + if (!m_nPrefetchedAvailable) { + m_input.setstate(std::ios_base::eofbit); + } + + if (0 == m_nPrefetchedAvailable) { + return 0; + } + } + + return m_pPrefetched[m_nPrefetchedUsed++]; + } + + void Stream::StreamInUtf32() const { + static int indexes[2][4] = {{3, 2, 1, 0}, + {0, 1, 2, 3}}; + + unsigned long ch = 0; + unsigned char bytes[4]; + int *pIndexes = (m_charSet == utf32be) ? indexes[1] : indexes[0]; + + bytes[0] = GetNextByte(); + bytes[1] = GetNextByte(); + bytes[2] = GetNextByte(); + bytes[3] = GetNextByte(); + if (!m_input.good()) { + return; + } + + for (int i = 0; i < 4; ++i) { + ch <<= 8; + ch |= bytes[pIndexes[i]]; + } + + QueueUnicodeCodepoint(m_readahead, ch); + } +} // namespace YAML diff --git a/yaml-cpp/src/stream.h b/yaml-cpp/src/stream.h new file mode 100644 index 0000000..ca1e5fd --- /dev/null +++ b/yaml-cpp/src/stream.h @@ -0,0 +1,104 @@ +#ifndef STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/mark.h" +#include +#include +#include +#include +#include +#include + +namespace YAML { + + class StreamCharSource; + + class Stream { + public: + friend class StreamCharSource; + + Stream(std::istream &input); + + Stream(const Stream &) = delete; + + Stream(Stream &&) = delete; + + Stream &operator=(const Stream &) = delete; + + Stream &operator=(Stream &&) = delete; + + ~Stream(); + + operator bool() const; + + bool operator!() const { return !static_cast(*this); } + + char peek() const; + + char get(); + + std::string get(int n); + + void eat(int n = 1); + + static char eof() { return 0x04; } + + const Mark mark() const { return m_mark; } + + int pos() const { return m_mark.pos; } + + int line() const { return m_mark.line; } + + int column() const { return m_mark.column; } + + void ResetColumn() { m_mark.column = 0; } + + private: + enum CharacterSet { + utf8, utf16le, utf16be, utf32le, utf32be + }; + + std::istream &m_input; + Mark m_mark; + + CharacterSet m_charSet; + mutable std::deque m_readahead; + unsigned char *const m_pPrefetched; + mutable size_t m_nPrefetchedAvailable; + mutable size_t m_nPrefetchedUsed; + + void AdvanceCurrent(); + + char CharAt(size_t i) const; + + bool ReadAheadTo(size_t i) const; + + bool _ReadAheadTo(size_t i) const; + + void StreamInUtf8() const; + + void StreamInUtf16() const; + + void StreamInUtf32() const; + + unsigned char GetNextByte() const; + }; + +// CharAt +// . Unchecked access + inline char Stream::CharAt(size_t i) const { return m_readahead[i]; } + + inline bool Stream::ReadAheadTo(size_t i) const { + if (m_readahead.size() > i) + return true; + return _ReadAheadTo(i); + } +} // namespace YAML + +#endif // STREAM_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/streamcharsource.h b/yaml-cpp/src/streamcharsource.h new file mode 100644 index 0000000..390240d --- /dev/null +++ b/yaml-cpp/src/streamcharsource.h @@ -0,0 +1,57 @@ +#ifndef STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/noexcept.h" +#include "stream.h" +#include + +namespace YAML { + + class StreamCharSource { + public: + StreamCharSource(const Stream &stream) : m_offset(0), m_stream(stream) {} + + StreamCharSource(const StreamCharSource &source) = default; + + StreamCharSource(StreamCharSource &&) YAML_CPP_NOEXCEPT = default; + + StreamCharSource &operator=(const StreamCharSource &) = delete; + + StreamCharSource &operator=(StreamCharSource &&) = delete; + + ~StreamCharSource() = default; + + operator bool() const; + + char operator[](std::size_t i) const { return m_stream.CharAt(m_offset + i); } + + bool operator!() const { return !static_cast(*this); } + + const StreamCharSource operator+(int i) const; + + private: + std::size_t m_offset; + const Stream &m_stream; + }; + + inline StreamCharSource::operator bool() const { + return m_stream.ReadAheadTo(m_offset); + } + + inline const StreamCharSource StreamCharSource::operator+(int i) const { + StreamCharSource source(*this); + if (static_cast(source.m_offset) + i >= 0) + source.m_offset += static_cast(i); + else + source.m_offset = 0; + return source; + } +} // namespace YAML + +#endif // STREAMCHARSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/stringsource.h b/yaml-cpp/src/stringsource.h new file mode 100644 index 0000000..d21da23 --- /dev/null +++ b/yaml-cpp/src/stringsource.h @@ -0,0 +1,50 @@ +#ifndef STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +namespace YAML { + class StringCharSource { + public: + StringCharSource(const char *str, std::size_t size) + : m_str(str), m_size(size), m_offset(0) {} + + operator bool() const { return m_offset < m_size; } + + char operator[](std::size_t i) const { return m_str[m_offset + i]; } + + bool operator!() const { return !static_cast(*this); } + + const StringCharSource operator+(int i) const { + StringCharSource source(*this); + if (static_cast(source.m_offset) + i >= 0) + source.m_offset += i; + else + source.m_offset = 0; + return source; + } + + StringCharSource &operator++() { + ++m_offset; + return *this; + } + + StringCharSource &operator+=(std::size_t offset) { + m_offset += offset; + return *this; + } + + private: + const char *m_str; + std::size_t m_size; + std::size_t m_offset; + }; +} + +#endif // STRINGSOURCE_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/tag.cpp b/yaml-cpp/src/tag.cpp new file mode 100644 index 0000000..fa500e5 --- /dev/null +++ b/yaml-cpp/src/tag.cpp @@ -0,0 +1,50 @@ +#include +#include + +#include "directives.h" // IWYU pragma: keep +#include "tag.h" +#include "token.h" + +namespace YAML { + Tag::Tag(const Token &token) + : type(static_cast(token.data)), handle{}, value{} { + switch (type) { + case VERBATIM: + value = token.value; + break; + case PRIMARY_HANDLE: + value = token.value; + break; + case SECONDARY_HANDLE: + value = token.value; + break; + case NAMED_HANDLE: + handle = token.value; + value = token.params[0]; + break; + case NON_SPECIFIC: + break; + default: + assert(false); + } + } + + const std::string Tag::Translate(const Directives &directives) { + switch (type) { + case VERBATIM: + return value; + case PRIMARY_HANDLE: + return directives.TranslateTagHandle("!") + value; + case SECONDARY_HANDLE: + return directives.TranslateTagHandle("!!") + value; + case NAMED_HANDLE: + return directives.TranslateTagHandle("!" + handle + "!") + value; + case NON_SPECIFIC: + // TODO: + return "!"; + default: + assert(false); + } + throw std::runtime_error("yaml-cpp: internal error, bad tag type"); + } +} // namespace YAML diff --git a/yaml-cpp/src/tag.h b/yaml-cpp/src/tag.h new file mode 100644 index 0000000..f993a38 --- /dev/null +++ b/yaml-cpp/src/tag.h @@ -0,0 +1,34 @@ +#ifndef TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include + +namespace YAML { + struct Directives; + struct Token; + + struct Tag { + enum TYPE { + VERBATIM, + PRIMARY_HANDLE, + SECONDARY_HANDLE, + NAMED_HANDLE, + NON_SPECIFIC + }; + + Tag(const Token &token); + + const std::string Translate(const Directives &directives); + + TYPE type; + std::string handle, value; + }; +} + +#endif // TAG_H_62B23520_7C8E_11DE_8A39_0800200C9A66 diff --git a/yaml-cpp/src/token.h b/yaml-cpp/src/token.h new file mode 100644 index 0000000..605522f --- /dev/null +++ b/yaml-cpp/src/token.h @@ -0,0 +1,72 @@ +#ifndef TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 +#define TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66 + +#if defined(_MSC_VER) || \ + (defined(__GNUC__) && (__GNUC__ == 3 && __GNUC_MINOR__ >= 4) || \ + (__GNUC__ >= 4)) // GCC supports "pragma once" correctly since 3.4 +#pragma once +#endif + +#include "yaml-cpp/mark.h" +#include +#include +#include + +namespace YAML { + const std::string TokenNames[] = { + "DIRECTIVE", "DOC_START", "DOC_END", "BLOCK_SEQ_START", + "BLOCK_MAP_START", "BLOCK_SEQ_END", "BLOCK_MAP_END", "BLOCK_ENTRY", + "FLOW_SEQ_START", "FLOW_MAP_START", "FLOW_SEQ_END", "FLOW_MAP_END", + "FLOW_MAP_COMPACT", "FLOW_ENTRY", "KEY", "VALUE", + "ANCHOR", "ALIAS", "TAG", "SCALAR"}; + + struct Token { + // enums + enum STATUS { + VALID, INVALID, UNVERIFIED + }; + enum TYPE { + DIRECTIVE, + DOC_START, + DOC_END, + BLOCK_SEQ_START, + BLOCK_MAP_START, + BLOCK_SEQ_END, + BLOCK_MAP_END, + BLOCK_ENTRY, + FLOW_SEQ_START, + FLOW_MAP_START, + FLOW_SEQ_END, + FLOW_MAP_END, + FLOW_MAP_COMPACT, + FLOW_ENTRY, + KEY, + VALUE, + ANCHOR, + ALIAS, + TAG, + PLAIN_SCALAR, + NON_PLAIN_SCALAR + }; + + // data + Token(TYPE type_, const Mark &mark_) + : status(VALID), type(type_), mark(mark_), value{}, params{}, data(0) {} + + friend std::ostream &operator<<(std::ostream &out, const Token &token) { + out << TokenNames[token.type] << std::string(": ") << token.value; + for (const std::string ¶m : token.params) + out << std::string(" ") << param; + return out; + } + + STATUS status; + TYPE type; + Mark mark; + std::string value; + std::vector params; + int data; + }; +} // namespace YAML + +#endif // TOKEN_H_62B23520_7C8E_11DE_8A39_0800200C9A66