diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index 85298bd0f0..0000000000 --- a/.appveyor.yml +++ /dev/null @@ -1,73 +0,0 @@ -skip_branch_with_pr: true - -image: - - Visual Studio 2015 - - Visual Studio 2017 - -build: - verbosity: detailed - -clone_folder: c:\projects\cdt-plusplus - -shallow_clone: true - -configuration: Release - -install: - - mkdir C:\projects\dev - - cd C:\projects\dev - - # Install Ninja - - set NINJA_URL="https://github.com/ninja-build/ninja/releases/download/v1.7.2/ninja-win.zip" - - appveyor DownloadFile %NINJA_URL% -FileName ninja.zip - - 7z x ninja.zip -oC:\projects\dev\ninja > nul - - set PATH=%PATH%;C:\projects\dev\ninja - - ninja --version - # Verify CMake - - cmake --version - # Setup Clang-cl - - set PATH=%PATH%;"C:\Program Files\LLVM\bin" - - clang-cl -v - - set CC=clang-cl - - set CXX=clang-cl - - call "C:\Program Files (x86)\Microsoft Visual Studio 14.0\VC\vcvarsall.bat" x86_amd64 - # Use installed conda - - set PATH=%PATH%;C:\Miniconda-x64\Scripts - - conda update conda -y - #- conda list - - conda create --name py36 python=3.6 -y - - activate py36 - # Install Eigen - - conda install -c conda-forge eigen -y - # Install TBB - - conda install -c conda-forge tbb -y - # Install MPFR - - conda install -c conda-forge mpfr -y - # Install Boost 1.66.0 - - conda install -c conda-forge boost -y - # Install CGAL - - conda install -c conda-forge cgal -y - # Install Curl - - conda install -c conda-forge curl -y - -before_build: - - cd C:\projects\CDT-plusplus - -build_script: - - mkdir build - - cd build - - cmake -G Ninja -DCMAKE_BUILD_TYPE=Release -DTESTS:BOOL=OFF .. -# - cmake --build . - -#on_success: -# - cmake --build . --target test - -notifications: - - - provider: Email - to: - - acgetchell@ucdavis.edu - on_build_status_changed: true - -#on_finish: -# - ps: $blockRdp = $true; iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/appveyor/ci/master/scripts/enable-rdp.ps1')) diff --git a/.clang-format b/.clang-format index 54e4d69dd5..93126d6d79 100644 --- a/.clang-format +++ b/.clang-format @@ -1,83 +1,221 @@ --- -Language: Cpp +Language: Cpp # BasedOnStyle: Google AccessModifierOffset: -1 -AlignAfterOpenBracket: true -AlignConsecutiveAssignments: true -AlignConsecutiveDeclarations: true -AlignEscapedNewlinesLeft: true -AlignOperands: true +AlignAfterOpenBracket: Align +AlignArrayOfStructures: Right +AlignConsecutiveMacros: AcrossEmptyLinesAndComments +AlignConsecutiveAssignments: AcrossEmptyLinesAndComments +AlignConsecutiveBitFields: None +AlignConsecutiveDeclarations: AcrossEmptyLines +AlignEscapedNewlines: Left +AlignOperands: AlignAfterOperator AlignTrailingComments: true +AllowAllArgumentsOnNextLine: true +AllowAllConstructorInitializersOnNextLine: true AllowAllParametersOfDeclarationOnNextLine: true -AllowShortBlocksOnASingleLine: true -AllowShortCaseLabelsOnASingleLine: false -AllowShortIfStatementsOnASingleLine: true -AllowShortLoopsOnASingleLine: true +AllowShortEnumsOnASingleLine: true +AllowShortBlocksOnASingleLine: Always +AllowShortCaseLabelsOnASingleLine: true AllowShortFunctionsOnASingleLine: All +AllowShortLambdasOnASingleLine: All +AllowShortIfStatementsOnASingleLine: AllIfsAndElse +AllowShortLoopsOnASingleLine: true +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None AlwaysBreakBeforeMultilineStrings: true -AlwaysBreakTemplateDeclarations: true -BinPackParameters: true +AlwaysBreakTemplateDeclarations: "Yes" +AttributeMacros: + - __capability BinPackArguments: true +BinPackParameters: true BraceWrapping: - AfterClass: true - AfterControlStatement: true - AfterEnum: true - AfterFunction: true - AfterNamespace: true - AfterStruct: true - AfterUnion: true - BeforeCatch: true - BeforeElse: true - IndentBraces: false - SplitEmptyFunction: false -BreakBeforeBraces: Custom + AfterCaseLabel: true + AfterClass: true + AfterControlStatement: Always + AfterEnum: true + AfterFunction: true + AfterNamespace: true + AfterObjCDeclaration: false + AfterStruct: true + AfterUnion: true + AfterExternBlock: false + BeforeCatch: true + BeforeElse: true + BeforeLambdaBody: false + BeforeWhile: true + IndentBraces: false + SplitEmptyFunction: false + SplitEmptyRecord: false + SplitEmptyNamespace: false BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: true +BreakBeforeBraces: Custom +BreakBeforeInheritanceComma: false +BreakInheritanceList: BeforeComma BreakBeforeTernaryOperators: true BreakConstructorInitializersBeforeComma: true -ColumnLimit: 80 -CommentPragmas: '^ IWYU pragma:' +BreakConstructorInitializers: BeforeComma +BreakAfterJavaFieldAnnotations: false +BreakStringLiterals: false +ColumnLimit: 80 +CommentPragmas: '^ IWYU pragma:' CompactNamespaces: true ConstructorInitializerAllOnOneLineOrOnePerLine: true ConstructorInitializerIndentWidth: 4 ContinuationIndentWidth: 4 Cpp11BracedListStyle: true -DerivePointerAlignment: false -DisableFormat: false +DeriveLineEnding: true +DerivePointerAlignment: true +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: LogicalBlock ExperimentalAutoDetectBinPacking: false FixNamespaceComments: true -ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Regroup +IncludeCategories: + - Regex: '^' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*\.h>' + Priority: 1 + SortPriority: 0 + CaseSensitive: false + - Regex: '^<.*' + Priority: 2 + SortPriority: 0 + CaseSensitive: false + - Regex: '.*' + Priority: 3 + SortPriority: 0 + CaseSensitive: false +IncludeIsMainRegex: '([-_](test|unittest))?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: false IndentCaseLabels: true -IndentFunctionDeclarationAfterType: false -IndentWidth: 2 +IndentCaseBlocks: false +IndentGotoLabels: true +IndentPPDirectives: None +IndentExternBlock: AfterExternBlock +IndentRequiresClause: true +IndentWidth: 2 IndentWrappedFunctionNames: false +InsertBraces: true +InsertTrailingCommas: None +JavaScriptQuotes: Leave +JavaScriptWrapImports: true KeepEmptyLinesAtTheStartOfBlocks: false -Language: Cpp +LambdaBodyIndentation: Signature +MacroBlockBegin: '' +MacroBlockEnd: '' MaxEmptyLinesToKeep: 1 NamespaceIndentation: All +ObjCBinPackProtocolList: Never ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true ObjCSpaceAfterProperty: false -ObjCSpaceBeforeProtocolList: false +ObjCSpaceBeforeProtocolList: true +PenaltyBreakAssignment: 2 PenaltyBreakBeforeFirstCallParameter: 1 PenaltyBreakComment: 300 -PenaltyBreakString: 1000 PenaltyBreakFirstLessLess: 120 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 PenaltyExcessCharacter: 1000000 PenaltyReturnTypeOnItsOwnLine: 200 +PenaltyIndentedWhitespace: 0 PointerAlignment: Left +PPIndentWidth: -1 +QualifierAlignment: Custom +QualifierOrder: + - static + - inline + - type + - const + - constexpr + - volatile + - restrict +RawStringFormats: + - Language: Cpp + Delimiters: + - cc + - CC + - cpp + - Cpp + - CPP + - 'c++' + - 'C++' + CanonicalDelimiter: '' + BasedOnStyle: google + - Language: TextProto + Delimiters: + - pb + - PB + - proto + - PROTO + EnclosingFunctions: + - EqualsProto + - EquivToProto + - PARSE_PARTIAL_TEXT_PROTO + - PARSE_TEST_PROTO + - PARSE_TEXT_PROTO + - ParseTextOrDie + - ParseTextProtoOrDie + - ParseTestProto + - ParsePartialTestProto + CanonicalDelimiter: pb + BasedOnStyle: google +ReferenceAlignment: Pointer ReflowComments: true -SortIncludes: true +ShortNamespaceLines: 1 +SortIncludes: CaseInsensitive +SortJavaStaticImport: Before SortUsingDeclarations: true -SpacesBeforeTrailingComments: 2 -SpacesInParentheses: false -SpacesInSquareBrackets: false -SpacesInAngles: false -SpaceInEmptyParentheses: false -SpacesInCStyleCastParentheses: false SpaceAfterCStyleCast: false -SpacesInContainerLiterals: true +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true SpaceBeforeParens: ControlStatements -Standard: Cpp11 -TabWidth: 8 -UseTab: Never +SpaceAroundPointerQualifiers: Default +SpaceBeforeRangeBasedForLoopColon: true +SpaceInEmptyBlock: false +SpaceInEmptyParentheses: false +SpacesBeforeTrailingComments: 2 +SpacesInAngles: Never +SpacesInConditionalStatement: false +SpacesInContainerLiterals: true +SpacesInCStyleCastParentheses: false +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInParentheses: false +SpacesInSquareBrackets: false +SpaceBeforeSquareBrackets: false +BitFieldColonSpacing: Both +Standard: c++20 +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 8 +UseCRLF: false +UseTab: Never +WhitespaceSensitiveMacros: + - STRINGIZE + - PP_STRINGIZE + - BOOST_PP_STRINGIZE + - NS_SWIFT_NAME + - CF_SWIFT_NAME ... diff --git a/.clang-tidy b/.clang-tidy index 7ef11cccc2..a5faa1d61b 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,117 +1,32 @@ --- -Checks: "clang-diagnostic-*,clang-analyzer-*,-*,cert*,clang*,cppcoreguidelines*,misc-assert*,misc-b*,misc-dangling*,misc-f*,misc-i*,misc-move-const*,misc-n*,misc-r*,misc-s*,misc-t*,misc-u*,misc-v*,modernize*,performance*" -WarningsAsErrors: "" -HeaderFilterRegex: ".*" -AnalyzeTemporaryDtors: false -FormatStyle: none -User: adam -CheckOptions: - - key: cert-dcl59-cpp.HeaderFileExtensions - value: h,hh,hpp,hxx - - key: cert-err09-cpp.CheckThrowTemporaries - value: "1" - - key: cert-err61-cpp.CheckThrowTemporaries - value: "1" - - key: cert-oop11-cpp.IncludeStyle - value: llvm - - key: cppcoreguidelines-no-malloc.Allocations - value: "::malloc;::calloc" - - key: cppcoreguidelines-no-malloc.Deallocations - value: "::free" - - key: cppcoreguidelines-no-malloc.Reallocations - value: "::realloc" - - key: cppcoreguidelines-pro-bounds-constant-array-index.GslHeader - value: "" - - key: cppcoreguidelines-pro-bounds-constant-array-index.IncludeStyle - value: "0" - - key: cppcoreguidelines-pro-type-member-init.IgnoreArrays - value: "0" - - key: cppcoreguidelines-special-member-functions.AllowMissingMoveFunctions - value: "0" - - key: cppcoreguidelines-special-member-functions.AllowSoleDefaultDtor - value: "0" - - key: google-readability-braces-around-statements.ShortStatementLines - value: "1" - - key: google-readability-function-size.StatementThreshold - value: "800" - - key: google-readability-namespace-comments.ShortNamespaceLines - value: "10" - - key: google-readability-namespace-comments.SpacesBeforeComments - value: "2" - - key: misc-assert-side-effect.AssertMacros - value: assert - - key: misc-assert-side-effect.CheckFunctionCalls - value: "0" - - key: misc-dangling-handle.HandleClasses - value: "std::basic_string_view;std::experimental::basic_string_view" - - key: misc-move-constructor-init.IncludeStyle - value: llvm - - key: misc-sizeof-expression.WarnOnSizeOfCompareToConstant - value: "1" - - key: misc-sizeof-expression.WarnOnSizeOfConstant - value: "1" - - key: misc-sizeof-expression.WarnOnSizeOfThis - value: "1" - - key: misc-string-constructor.LargeLengthThreshold - value: "8388608" - - key: misc-string-constructor.WarnOnLargeLength - value: "1" - - key: misc-suspicious-enum-usage.StrictMode - value: "0" - - key: misc-suspicious-missing-comma.MaxConcatenatedTokens - value: "5" - - key: misc-suspicious-missing-comma.RatioThreshold - value: "0.200000" - - key: misc-suspicious-missing-comma.SizeThreshold - value: "5" - - key: misc-suspicious-string-compare.StringCompareLikeFunctions - value: "" - - key: misc-suspicious-string-compare.WarnOnImplicitComparison - value: "1" - - key: misc-suspicious-string-compare.WarnOnLogicalNotComparison - value: "0" - - key: misc-throw-by-value-catch-by-reference.CheckThrowTemporaries - value: "1" - - key: modernize-loop-convert.MaxCopySize - value: "16" - - key: modernize-loop-convert.MinConfidence - value: reasonable - - key: modernize-loop-convert.NamingStyle - value: CamelCase - - key: modernize-pass-by-value.IncludeStyle - value: llvm - - key: modernize-pass-by-value.ValuesOnly - value: "0" - - key: modernize-raw-string-literal.ReplaceShorterLiterals - value: "0" - - key: modernize-replace-auto-ptr.IncludeStyle - value: llvm - - key: modernize-replace-random-shuffle.IncludeStyle - value: llvm - - key: modernize-use-auto.RemoveStars - value: "0" - - key: modernize-use-default-member-init.UseAssignment - value: "0" - - key: modernize-use-emplace.ContainersWithPushBack - value: "::std::vector;::std::list;::std::deque" - - key: modernize-use-emplace.SmartPointers - value: "::std::shared_ptr;::std::unique_ptr;::std::auto_ptr;::std::weak_ptr" - - key: modernize-use-nullptr.NullMacros - value: "NULL" - - key: modernize-use-transparent-functors.SafeMode - value: "0" - - key: modernize-use-using.IgnoreMacros - value: "1" - - key: performance-faster-string-find.StringLikeClasses - value: "std::basic_string" - - key: performance-for-range-copy.WarnOnAllAutoCopies - value: "0" - - key: performance-inefficient-string-concatenation.StrictMode - value: "0" - - key: performance-inefficient-vector-operation.VectorLikeClasses - value: "::std::vector" - - key: performance-type-promotion-in-math-fn.IncludeStyle - value: llvm - - key: performance-unnecessary-value-param.IncludeStyle - value: llvm +Checks: >- + -*, + bugprone-*, + cert-*, + clang-diagnostic-*, + concurrency-*, + cppcoreguidelines-*, + misc-*, + modernize-*, + performance-*, + portability-*, + readability-*, + -bugprone-easily-swappable-parameters, + -bugprone-exception-escape, + -cppcoreguidelines-avoid-c-arrays, + -cppcoreguidelines-avoid-do-while, + -cppcoreguidelines-avoid-magic-numbers, + -cppcoreguidelines-pro-bounds-avoid-unchecked-container-access, + -cppcoreguidelines-pro-bounds-constant-array-index, + -misc-include-cleaner, + -modernize-avoid-c-arrays, + -modernize-use-trailing-return-type, + -performance-enum-size, + -readability-function-cognitive-complexity, + -readability-function-size, + -readability-identifier-length, + -readability-magic-numbers, + -readability-math-missing-parentheses +WarningsAsErrors: '' +HeaderFilterRegex: '^(.*/)?(include|src)/.*' ... diff --git a/.cmake-format.yaml b/.cmake-format.yaml new file mode 100644 index 0000000000..b95861ecef --- /dev/null +++ b/.cmake-format.yaml @@ -0,0 +1,13 @@ +--- +bullet_char: '*' +dangle_parens: false +enum_char: . +line_ending: unix +line_width: 120 +max_pargs_hwrap: 3 +separate_ctrl_name_with_space: false +separate_fn_name_with_space: false +tab_size: 2 + +markup: + enable_markup: false diff --git a/.codecov.yml b/.codecov.yml index 0e39b81113..30006f401f 100644 --- a/.codecov.yml +++ b/.codecov.yml @@ -1,37 +1,32 @@ +--- codecov: - max_report_age: off notify: - require_ci_to_pass: no + require_ci_to_pass: false coverage: precision: 2 round: down - range: "30...100" # Figure out how to exclude or test included subrepos + range: "30...100" status: - project: yes - patch: yes - changes: no - - notify: - gitter: - default: - url: https://webhooks.gitter.im/e/c70e4d2749931f601747 - threshold: 1% + project: + default: + threshold: 3% + patch: false + changes: false parsers: gcov: branch_detection: - conditional: yes - loop: yes - method: no - macro: no + conditional: true + loop: true + method: false + macro: false comment: layout: "reach, diff, flags, files, footer" behavior: default - require_changes: no + require_changes: false ignore: - - "src/date/**/*" - - "src/docopt/**/*" + - "tests/" diff --git a/.coderabbit.yaml b/.coderabbit.yaml new file mode 100644 index 0000000000..500704a603 --- /dev/null +++ b/.coderabbit.yaml @@ -0,0 +1,78 @@ +--- +language: en-US +tone_instructions: >- + Be constructive and professional. Focus on technical accuracy while + maintaining a friendly tone. +early_access: true +enable_free_tier: true +reviews: + profile: assertive + request_changes_workflow: true + high_level_summary: true + high_level_summary_placeholder: '@coderabbitai summary' + auto_title_placeholder: '@coderabbitai' + review_status: true + commit_status: true + poem: true + collapse_walkthrough: false + sequence_diagrams: true + changed_files_summary: true + labeling_instructions: [] + path_filters: [] + path_instructions: + - path: 'src/**/*.cpp' + instructions: 'Focus on performance, memory management, and RAII principles' + - path: 'include/**/*.hpp' + instructions: 'Focus on design patterns, interfaces, and encapsulation' + - path: 'tests/**/*.cpp' + instructions: | + Review the following unit test code written using doctest. Ensure the following: + - Comprehensive test coverage and proper test organization. + - The code adheres to best practices using doctest. + - Descriptive test names are used to clearly convey the intent of each test. + abort_on_close: true + auto_review: + enabled: true + auto_incremental_review: true + ignore_title_keywords: [] + labels: [] + drafts: true + base_branches: [] + tools: + shellcheck: + enabled: true + markdownlint: + enabled: true + github-checks: + enabled: true + timeout_ms: 90000 + gitleaks: + enabled: true + languagetool: + enabled: true + enabled_only: false + level: default + hadolint: + enabled: true + yamllint: + enabled: true + actionlint: + enabled: true + pmd: + enabled: true + semgrep: + enabled: true +chat: + auto_reply: true +knowledge_base: + opt_out: false + learnings: + scope: auto + issues: + scope: auto + jira: + project_keys: [] + linear: + team_keys: [] + pull_requests: + scope: auto diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000000..69b47b5ade --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +*.bat text eol=crlf diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index fae7b9651e..c1b1bb9643 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -1,66 +1,90 @@ -# How to Contribute - -First, thank you! - -Writing esoteric scientific software can be it's own reward, but it's not for the faint of heart. - -If you want a general overview as to why this software package exists, please look at my talk [Causal Dynamical Triangulations with CGAL][slides], or the [Wiki]. - -Second, here are some simple guidelines that will make it easier on me to process and accept your contributions. - -1. Fork the repository. -2. Familiarize yourself with [Catch] and in particular, the [Gherkin] syntax. -3. Write a unit test for your proposed contribution. Unit tests go in the `test` directory and are named \{YourContribution\}Test.cpp, so that they can be automatically built. -All proposed features of your contribution should have a corresponding test in \{YourContribution\}Test.cpp. -Consult the [Catch Test cases and sections] if you are unsure, or consult existing tests for examples. -4. I highly recommend writing your tests first, before your contribution, as this helps to think about how the rest of the program will use your functions and/or classes. -[Test-Driven Development] (and [BDD]) has saved me quite a lot from various mistakes. -5. Project source files go into the `src` directory; header files go into `include`. -This makes integration into tests and the main program easy and modular, and follows convention. -6. Don't forget documentation! It's helpful if you state explicitly what your functions and classes do. -I use [Doxygen] to automatically build documentation, so using `/// @brief` and `/// @param` is helpful and easy. -Consult existing code for examples. -7. Commit your changes with a clear, [well-written commit message]. -*I am guilty of not always writing the clearest commit messages in this project, and will do better. -For the longest time, however, no one but me actually read them. -When I contribute to other projects, I definitely try to have useful, clear commit messages and you should, too.* -8. Run `clang-format` using the project's [.clang-format]. -9. Run `clang-tidy` using the project's [.clang-tidy]. -10. Open a pull request against the develop branch of the main repository (which is the default). -[Travis-CI] will test it against combinations of Linux (Ubuntu 14.04), MacOS, clang, and gcc, so ensure that your code compiles on both platforms with both compilers. -11. All pull requests must pass [Travis-CI] and [AppVeyor] to be accepted. -In particular, look at results from git whitespace checks (`git diff --check HEAD^`), [ClangFormat], [ClangTidy], [Valgrind], [Codecov], and [SonarCloud] . -12. I will get to your change as soon as I can. -Feel free to ping me on [Gitter] with any questions. -You will receive proper credit for your contributions both in the code and any resulting scientific papers using the output of `git log --format='%aN | sort -u`. - -# Style Guide - -This project generally follows [Stroustrup formatting with Allman brackets][1], enforced by [ClangFormat]. -The [C++ Core Guidelines][cpp-core] are checked using [ClangTidy]. -Running [clang-tidy.sh] changes the code (using `-fix`), so compare results and run unit tests before you commit. -Especially since some of ClangTidy's fixes break the codebase (the script runs just the tests that don't). - -Most editors/IDEs have plugins for `clang-format` and `clang-tidy`. - -[Wiki]: https://github.com/acgetchell/CDT-plusplus/wiki -[Test-Driven Development]: http://alexott.net/en/cpp/CppTestingIntro.html -[Doxygen]: http://doxygen.org -[well-written commit message]: https://chris.beams.io/posts/git-commit/ -[Travis-CI]: https://travis-ci.org/acgetchell/CDT-plusplus -[1]: https://isocpp.org/wiki/faq/coding-standards -[2]: http://llvm.org/releases/4.0.0/tools/clang/docs/ClangFormatStyleOptions.html -[ClangFormat]: https://github.com/acgetchell/CDT-plusplus/blob/master/.clang-format -[slides]: http://slides.com/acgetchell/causal-dynamical-triangulations-3 -[Valgrind]: http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun -[cpp-core]: https://github.com/isocpp/CppCoreGuidelines/blob/master/CppCoreGuidelines.md -[clang-tidy.sh]: https://github.com/acgetchell/CDT-plusplus/blob/master/clang-tidy.sh -[AppVeyor]: https://ci.appveyor.com/project/acgetchell/cdt-plusplus -[Catch]: https://github.com/catchorg/Catch2/blob/master/docs/Readme.md -[Gherkin]: https://www.tutorialspoint.com/behavior_driven_development/behavior_driven_development_gherkin.htm -[BDD]: https://en.wikipedia.org/wiki/Behavior-driven_development -[Catch Test cases and sections]: https://github.com/catchorg/Catch2/blob/master/docs/test-cases-and-sections.md -[Codecov]: https://codecov.io/support -[Gitter]: https://gitter.im/acgetchell/CDT-plusplus -[ClangTidy]: http://clang.llvm.org/extra/clang-tidy/index.html -[SonarCloud]: https://sonarcloud.io/dashboard?id=CDT-plusplus%3Adevelop +# Contributing during maintenance mode + +Thank you for helping improve CDT++. + +CDT++ is being prepared for one final C++23 release, v1.0.0, after which this repository will be archived. The project +is maintained as a scientific reference implementation and regression oracle for +[causal-triangulations](https://github.com/acgetchell/causal-triangulations), its supported Rust successor. The +maintenance and archival scope is tracked by +[issue #90](https://github.com/acgetchell/CDT-plusplus/issues/90). + +## Accepted work + +Until archival, contributions should be limited to: + +- correctness fixes, especially for causal invariants, bistellar moves, and scientific results; +- deterministic tests, reproducibility improvements, and cross-implementation validation; +- documentation, build, CI, portability, dependency, and release-readiness fixes; +- work already approved in a project issue or release milestone, including + [Qt restoration #98](https://github.com/acgetchell/CDT-plusplus/issues/98) and + [domain invariant work #101](https://github.com/acgetchell/CDT-plusplus/issues/101); and +- changes required to complete the v1.0.0 release and Zenodo archival handoff. + +New simulation features, 3+1D/4D development, and unrelated C++ expansion are out of scope. Propose ongoing feature +development in the Rust successor instead. If a change is not already tracked, open an issue before investing in a +substantial implementation so its maintenance value and scope can be agreed upon. + +## Contribution workflow + +1. Fork the repository and create a short-lived branch from `main`. + +2. Keep the change focused and preserve scientific behavior unless the purpose of the change is to correct a + documented bug. + +3. Add or update deterministic tests for behavior changes. Tests use [doctest] and live in `tests`; register new test + files in `tests/CMakeLists.txt`. Existing tests use descriptive BDD-style `SCENARIO`, `GIVEN`, `WHEN`, and `THEN` + sections where that structure clarifies behavior. + +4. Update relevant documentation and Doxygen comments when interfaces, supported workflows, or scientific behavior + change. + +5. Run the repository-owned validation commands: + + ```bash + just fix + just check + just ci + ``` + + `just check` is the fast, non-mutating source and tooling gate. `just ci` adds the supported build and 11-test smoke + suite. When changing C++ behavior, also run `just clang-tidy` with the pinned LLVM 22 toolchain and review its + advisory diagnostics. + +6. Run the relevant Linux sanitizer configuration for changes involving memory, lifetime, undefined behavior, or + concurrency: + + ```bash + just sanitize asan + just sanitize lsan + just sanitize tsan + ``` + + MemorySanitizer is experimental because third-party dependencies are not instrumented; run it manually with + `just sanitize msan` when useful. + +7. Open a pull request against `main`, explain the maintenance issue being addressed, and identify any scientific or + reproducibility implications. All required GitHub Actions checks must pass. + +The project [Code of Conduct](CODE_OF_CONDUCT.md) applies to all participation. + +## Style + +The project uses Stroustrup-style formatting with Allman braces, enforced by the repository's `.clang-format` and +LLVM 22. The C++ Core Guidelines inform the `.clang-tidy` policy. Prefer minimal, readable changes over cosmetic +modernization, and do not suppress diagnostics without documenting why the check is inappropriate for this codebase. + +Project source files belong in `src`, public or shared headers in `include`, and tests in `tests`. Use the existing +CMake targets, presets, CTest registrations, Just recipes, and pinned vcpkg manifest rather than introducing parallel +build paths. + +## Release and archival + +The final v1.0.0 release will be tagged from `main` and archived through [Zenodo]. Release metadata and the archival +handoff are tracked by [issue #96](https://github.com/acgetchell/CDT-plusplus/issues/96). After archival, the repository +will be read-only and will no longer accept issues or pull requests. Further development should occur in +[causal-triangulations](https://github.com/acgetchell/causal-triangulations) or in an independent fork. + +Contributors retain credit through the repository history and resulting project citation metadata. + +[doctest]: https://github.com/doctest/doctest +[Zenodo]: https://zenodo.org/ diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md new file mode 100644 index 0000000000..99dc35ad62 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -0,0 +1,42 @@ +--- +name: Bug report +about: Create a report to help us improve +title: '' +labels: '' +assignees: '' + +--- + +## Describe the bug + +A clear and concise description of what the bug is. + +## To reproduce + +Steps to reproduce the behavior: + +1. Go to '...' +2. Click on '....' +3. Scroll down to '....' +4. See error + +Include the exact Just recipe or command, input values, and complete relevant output. + +## Expected behavior + +A clear and concise description of what you expected to happen. + +## Screenshots + +If applicable, add screenshots to help explain your problem. + +## Build environment + +- Compiler and version: [e.g. AppleClang 17.0] +- Operating system: [e.g. macOS 15.5] +- CMake preset: [e.g. reference] +- CDT++ commit: [e.g. output of `git rev-parse --short HEAD`] + +## Additional context + +Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md new file mode 100644 index 0000000000..57adfd5416 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -0,0 +1,25 @@ +--- +name: Feature request +about: Suggest an idea for this project +title: '' +labels: '' +assignees: '' + +--- + +## Problem + +Describe the problem this request would solve. CDT++ is approaching its final archival release; new development may +belong in the supported [causal-triangulations](https://github.com/acgetchell/causal-triangulations) successor. + +## Proposed solution + +Describe the behavior you would like and why it belongs in this C++ reference implementation. + +## Alternatives considered + +Describe any alternative solutions or workarounds you considered. + +## Additional context + +Add any other context or screenshots about the feature request here. diff --git a/.github/actions/setup-just/action.yml b/.github/actions/setup-just/action.yml new file mode 100644 index 0000000000..fb2fc053ed --- /dev/null +++ b/.github/actions/setup-just/action.yml @@ -0,0 +1,41 @@ +--- +name: Set up Just +description: Resolve the pinned Just version from the Justfile and install it. + +outputs: + version: + description: The Just version declared by the repository. + value: ${{ steps.resolve.outputs.version }} + +runs: + using: composite + steps: + - name: Resolve Just version + id: resolve + shell: bash + run: | + set -euo pipefail + shopt -s extglob + version="" + declaration_re='^[[:space:]]*just_version[[:space:]]*:=[[:space:]]*(.*)$' + while IFS= read -r line; do + if [[ "$line" =~ $declaration_re ]]; then + version="${BASH_REMATCH[1]}" + version="${version%%#*}" + version="${version##+([[:space:]])}" + version="${version%%+([[:space:]])}" + version="${version#\"}" + version="${version%\"}" + break + fi + done < Justfile + if [[ ! "$version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Could not resolve a semantic Just version from Justfile." >&2 + exit 1 + fi + echo "version=$version" >> "$GITHUB_OUTPUT" + + - name: Install Just + uses: taiki-e/cache-cargo-install-action@417450f3c33ee20393705369577571770643d4c7 # v3.0.7 + with: + tool: just@${{ steps.resolve.outputs.version }} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..d04ea2695a --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,9 @@ +--- +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + cooldown: + default-days: 7 diff --git a/.github/issue_template.md b/.github/issue_template.md deleted file mode 100644 index 6748cca7c7..0000000000 --- a/.github/issue_template.md +++ /dev/null @@ -1,7 +0,0 @@ -### Expected behavior - - -### Actual behavior - - -### Steps to reproduce the behavior diff --git a/.github/workflows/_sanitizer.yml b/.github/workflows/_sanitizer.yml new file mode 100644 index 0000000000..352b329932 --- /dev/null +++ b/.github/workflows/_sanitizer.yml @@ -0,0 +1,93 @@ +--- +name: Reusable sanitizer build + +"on": + workflow_call: + inputs: + preset: + description: CMake sanitizer preset to run + required: true + type: string + job_name: + description: Display name for the sanitizer job + required: true + type: string + asan_options: + description: AddressSanitizer runtime options + required: false + type: string + default: '' + lsan_options: + description: LeakSanitizer runtime options + required: false + type: string + default: '' + msan_options: + description: MemorySanitizer runtime options + required: false + type: string + default: '' + tsan_options: + description: ThreadSanitizer runtime options + required: false + type: string + default: '' + ubsan_options: + description: UndefinedBehaviorSanitizer runtime options + required: false + type: string + default: '' + +permissions: + contents: read + +jobs: + sanitizer: + name: ${{ inputs.job_name }} + runs-on: ubuntu-latest + timeout-minutes: 45 + env: + ASAN_OPTIONS: ${{ inputs.asan_options }} + LSAN_OPTIONS: ${{ inputs.lsan_options }} + MSAN_OPTIONS: ${{ inputs.msan_options }} + TSAN_OPTIONS: ${{ inputs.tsan_options }} + UBSAN_OPTIONS: ${{ inputs.ubsan_options }} + + steps: + - name: Check out repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + persist-credentials: false + submodules: true + + - name: Install system build dependencies + run: | + sudo apt-get update + sudo apt-get install --yes \ + automake autoconf autoconf-archive build-essential ccache \ + libtool-bin ninja-build texinfo yasm + + - name: Set up Just + uses: ./.github/actions/setup-just + + - name: Resolve LLVM version + id: llvm-version + shell: bash + run: echo "version=$(just --evaluate llvm_version)" >> "$GITHUB_OUTPUT" + + - name: Set up Clang + uses: pkgxdev/setup@4d4ae97af87ccb39ab8be4e073dea697fef2c6f7 # v5.0.0 + with: + +: llvm.org@${{ steps.llvm-version.outputs.version }} + + - name: Report compiler version + run: clang --version + + - name: Restore artifacts or set up vcpkg + uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 + + - name: Build and exercise sanitizer configuration + env: + SANITIZER_PRESET: ${{ inputs.preset }} + run: just sanitize "$SANITIZER_PRESET" diff --git a/.github/workflows/asan.yml b/.github/workflows/asan.yml new file mode 100644 index 0000000000..399c953ed3 --- /dev/null +++ b/.github/workflows/asan.yml @@ -0,0 +1,27 @@ +--- +name: Address Sanitizer + +"on": + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + uses: ./.github/workflows/_sanitizer.yml + with: + preset: asan + job_name: AddressSanitizer + UndefinedBehaviorSanitizer + asan_options: fast_unwind_on_malloc=0:halt_on_error=1:symbolize=1 + ubsan_options: halt_on_error=1:print_stacktrace=1 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..cb83044b2b --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,160 @@ +--- +name: CI + +"on": + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + platform: + name: ${{ matrix.name }} + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: + - name: Ubuntu GCC + os: ubuntu-latest + compiler_package: gnu.org/gcc@16 + cc: gcc + cxx: g++ + - name: Ubuntu Clang + os: ubuntu-latest + compiler_package: llvm.org@22 + cc: clang + cxx: clang++ + - name: macOS AppleClang + os: macos-latest + compiler_package: "" + cc: clang + cxx: clang++ + - name: Windows MSVC + os: windows-latest + compiler_package: "" + cc: "" + cxx: "" + + steps: + - name: Check out repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + persist-credentials: false + submodules: true + + - name: Set up Unix environment with pkgx + if: runner.os != 'Windows' + uses: pkgxdev/setup@4d4ae97af87ccb39ab8be4e073dea697fef2c6f7 # v5.0.0 + + - name: Activate MSVC + if: runner.os == 'Windows' + uses: ilammy/msvc-dev-cmd@0b201ec74fa43914dc39ae48a89fd1d8cb592756 # v1.13.0 + with: + arch: x64 + + - name: Select the Windows vcpkg triplet + if: runner.os == 'Windows' + shell: pwsh + run: Add-Content -Path $env:GITHUB_ENV -Value 'VCPKG_DEFAULT_TRIPLET=x64-windows' + + - name: Restore artifacts or set up vcpkg + uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 + + - name: Build and test Unix + if: runner.os != 'Windows' + env: + CC: ${{ matrix.cc }} + CDT_PKGX_COMPILER_PACKAGE: ${{ matrix.compiler_package }} + CXX: ${{ matrix.cxx }} + run: ./scripts/pkgx-build.sh + + - name: Configure Windows + if: runner.os == 'Windows' + run: cmake --preset reference -S . + + - name: Build Windows + if: runner.os == 'Windows' + run: cmake --build --preset reference --parallel 2 + + - name: Test Windows + if: runner.os == 'Windows' + run: ctest --preset reference-smoke + + quality: + name: Repository quality checks + runs-on: ubuntu-latest + + steps: + - name: Check out repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Set up Just + uses: ./.github/actions/setup-just + + - name: Resolve tool versions + id: tool-versions + shell: bash + run: | + { + echo "llvm=$(just --evaluate llvm_version)" + echo "uv=$(just --evaluate uv_version)" + echo "zizmor=$(just --evaluate zizmor_version)" + } >> "$GITHUB_OUTPUT" + + - name: Set up repository tools with pkgx + uses: pkgxdev/setup@4d4ae97af87ccb39ab8be4e073dea697fef2c6f7 # v5.0.0 + with: + +: llvm.org@${{ steps.tool-versions.outputs.llvm }} + + - name: Set up Python + uses: actions/setup-python@ece7cb06caefa5fff74198d8649806c4678c61a1 # v6.3.0 + with: + python-version-file: .python-version + + - name: Set up uv + uses: astral-sh/setup-uv@11f9893b081a58869d3b5fccaea48c9e9e46f990 # v8.3.2 + with: + version: ${{ steps.tool-versions.outputs.uv }} + + - name: Synchronize Python development dependencies + run: uv sync --locked --group dev + + - name: Install zizmor + uses: taiki-e/cache-cargo-install-action@417450f3c33ee20393705369577571770643d4c7 # v3.0.7 + with: + tool: zizmor@${{ steps.tool-versions.outputs.zizmor }} + + - name: Check repository quality + run: just check + + build: + name: build + if: ${{ always() }} + needs: + - platform + - quality + runs-on: ubuntu-latest + + steps: + - name: Verify platform matrix + env: + PLATFORM_RESULT: ${{ needs.platform.result }} + QUALITY_RESULT: ${{ needs.quality.result }} + run: | + test "${PLATFORM_RESULT}" = success + test "${QUALITY_RESULT}" = success diff --git a/.github/workflows/codecov-upload.yml b/.github/workflows/codecov-upload.yml new file mode 100644 index 0000000000..45d64d8112 --- /dev/null +++ b/.github/workflows/codecov-upload.yml @@ -0,0 +1,69 @@ +--- +name: CodeCov + +"on": + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + codecov: + name: CodeCov + runs-on: ubuntu-latest + permissions: + contents: read + id-token: write # Intentionally required for Codecov's OIDC upload. + + steps: + - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + fetch-depth: 0 + persist-credentials: false + + - name: Setup + run: | + sudo apt update + sudo apt-get install --yes \ + automake autoconf autoconf-archive build-essential ccache \ + libtool-bin ninja-build texinfo yasm + + - name: Setup GCC + uses: pkgxdev/setup@4d4ae97af87ccb39ab8be4e073dea697fef2c6f7 # v5.0.0 + with: + +: gnu.org/gcc@16 + + - run: gcc --version + + - name: Restore artifacts or setup vcpkg + uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 + + - name: Configure + run: >- + cmake -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo + -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_COVERAGE:BOOL=TRUE + -S . -B build + + - name: Build + run: cmake --build build -j 2 + + - name: Test + working-directory: build + run: ctest --no-tests=error --output-on-failure -j 2 + + - name: Submit to codecov.io + uses: codecov/codecov-action@fb8b3582c8e4def4969c97caa2f19720cb33a72f # v7.0.0 + with: + fail_ci_if_error: true + gcov_executable: gcov + gcov_ignore: vcpkg_installed + plugins: gcov + use_oidc: true + verbose: true diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml new file mode 100644 index 0000000000..952bfc5f99 --- /dev/null +++ b/.github/workflows/codeql.yml @@ -0,0 +1,92 @@ +--- +# For most projects, this workflow file will not need changing; you simply need +# to commit it to your repository. +# +# You may wish to alter this file to override the set of languages analyzed, +# or to provide custom queries or build logic. +# +# ******** NOTE ******** +# We have attempted to detect the languages in your repository. Please check +# the `language` matrix defined below to confirm you have the correct set of +# supported CodeQL languages. +# +name: "CodeQL Advanced" + +"on": + push: + branches: ["main", "gh-pages"] + pull_request: + branches: ["main", "gh-pages"] + schedule: + - cron: '29 0 * * 2' + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + analyze: + name: Analyze (${{ matrix.language }}) + # Runner size impacts CodeQL analysis time. To learn more, please see: + # - https://gh.io/recommended-hardware-resources-for-running-codeql + # - https://gh.io/supported-runners-and-hardware-resources + # - https://gh.io/using-larger-runners (GitHub.com only) + # Consider using larger runners or machines with greater resources for + # possible analysis time improvements. + runs-on: ${{ (matrix.language == 'swift' && 'macos-latest') || 'ubuntu-latest' }} + permissions: + # required for all workflows + security-events: write + + # required to fetch internal or private CodeQL packs + packages: read + + # only required for workflows in private repositories + actions: read + contents: read + + strategy: + fail-fast: false + matrix: + include: + - language: actions + build-mode: none + - language: c-cpp + build-mode: manual + - language: python + build-mode: none + steps: + - name: Checkout repository + uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 + with: + persist-credentials: false + + - name: Set up C++ environment with pkgx + if: matrix.language == 'c-cpp' + uses: pkgxdev/setup@4d4ae97af87ccb39ab8be4e073dea697fef2c6f7 # v5.0.0 + + - name: Restore artifacts or set up vcpkg + if: matrix.language == 'c-cpp' + uses: lukka/run-vcpkg@b1a0dd252f06b9e25b3c022a9a03bd7a427fb6a2 # v11.6 + + - name: Initialize CodeQL + uses: github/codeql-action/init@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + languages: ${{ matrix.language }} + build-mode: ${{ matrix.build-mode }} + + - name: Build C/C++ + if: matrix.language == 'c-cpp' + env: + CC: gcc + CDT_PKGX_COMPILER_PACKAGE: gnu.org/gcc@16 + CXX: g++ + run: ./scripts/pkgx-build.sh + + - name: Perform CodeQL Analysis + uses: github/codeql-action/analyze@99df26d4f13ea111d4ec1a7dddef6063f76b97e9 # v4.37.0 + with: + category: "/language:${{ matrix.language }}" diff --git a/.github/workflows/doxygen.yml b/.github/workflows/doxygen.yml new file mode 100644 index 0000000000..9ce0f7eebe --- /dev/null +++ b/.github/workflows/doxygen.yml @@ -0,0 +1,28 @@ +--- +name: Doxygen GitHub Pages Deploy Action + +"on": + push: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + deploy: + runs-on: ubuntu-latest + permissions: + contents: write + steps: + - uses: DenverCoder1/doxygen-github-pages-action@a30f9538f8ef1305aeceb563018f452c7a62d200 # v2.0.0 + with: + github_token: ${{ secrets.GITHUB_TOKEN }} + branch: gh-pages + folder: docs/html + config_file: docs/Doxyfile diff --git a/.github/workflows/lsan.yml b/.github/workflows/lsan.yml new file mode 100644 index 0000000000..0287c86d94 --- /dev/null +++ b/.github/workflows/lsan.yml @@ -0,0 +1,26 @@ +--- +name: Leak Sanitizer + +"on": + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + uses: ./.github/workflows/_sanitizer.yml + with: + preset: lsan + job_name: LeakSanitizer + lsan_options: exitcode=1 diff --git a/.github/workflows/msan.yml b/.github/workflows/msan.yml new file mode 100644 index 0000000000..3c004a524d --- /dev/null +++ b/.github/workflows/msan.yml @@ -0,0 +1,20 @@ +--- +name: Memory Sanitizer (experimental) + +"on": + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + uses: ./.github/workflows/_sanitizer.yml + with: + preset: msan + job_name: MemorySanitizer (experimental) + msan_options: halt_on_error=1:symbolize=1 diff --git a/.github/workflows/tsan.yml b/.github/workflows/tsan.yml new file mode 100644 index 0000000000..34e215c76d --- /dev/null +++ b/.github/workflows/tsan.yml @@ -0,0 +1,26 @@ +--- +name: Thread Sanitizer + +"on": + push: + branches: + - main + pull_request: + branches: + - main + workflow_dispatch: + +permissions: + contents: read + +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + +jobs: + build: + uses: ./.github/workflows/_sanitizer.yml + with: + preset: tsan + job_name: ThreadSanitizer + tsan_options: halt_on_error=1 diff --git a/.gitignore b/.gitignore index 91454927c8..44622bd688 100644 --- a/.gitignore +++ b/.gitignore @@ -19,18 +19,23 @@ .DS_Store *.swp *.lock +!uv.lock profile # Build, Doc, and Testing dirs -build/* +/build* html/ +/cmake-build* cov-int +/out/* +/Testing # Editor files .clang_complete .idea -.vscode/ +.vs* xcode/ +CMakeSettings.json # Program/script executables cdt_tests @@ -42,14 +47,35 @@ errors *.off *.dat slurm-*.out -*.tmp # Instrumentation *.trace build-wrapper-macosx-x86 *.scannerwork bw-output/* +coverage.info # Cruft *.old.* *.bak + +# SourceTrail +*.srctrlbm +*.srctrldb* +*.srctrlprj + +# Pipenv +Pipfile +scanresults/ +venv + +# Python tooling and virtual environments +/.venv/ +**/__pycache__/ +*.py[cod] +/.ruff_cache/ +/.pytest_cache/ + +# vcpkg +vcpkg_installed +/.cache/ diff --git a/.pinact.yaml b/.pinact.yaml new file mode 100644 index 0000000000..a765c9872f --- /dev/null +++ b/.pinact.yaml @@ -0,0 +1,8 @@ +--- +version: 3 +files: + - pattern: .github/workflows/*.yml + - pattern: .github/workflows/*.yaml +separator: " # " +min_age: + value: 7 diff --git a/.python-version b/.python-version new file mode 100644 index 0000000000..e4fba21835 --- /dev/null +++ b/.python-version @@ -0,0 +1 @@ +3.12 diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index cd57fdc783..0000000000 --- a/.travis.yml +++ /dev/null @@ -1,299 +0,0 @@ -language: cpp -sudo: false -dist: trusty -osx_image: xcode9.2 - -addons: - apt: - packages: - - gcc-7 - - g++-7 - - ninja-build - - clang-6.0 - - libmpfr-dev - - libgmp3-dev - - libeigen3-dev - - libtbb-dev - - libcgal-dev - sources: &sources - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 - -env: - global: - - BOOST_VERSION=1.66.0 - matrix: - - TESTS=true - - TESTS=false - -cache: - apt: - ccache: true - directories: - - ${TRAVIS_BUILD_DIR}/boost-${BOOST_VERSION} - -os: - - linux - - osx - -compiler: - - gcc - - clang - -before_install: - # Workaround for https://github.com/travis-ci/travis-ci/issues/6307 - - | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - command curl -sSL https://rvm.io/mpapis.asc | gpg --import -; - rvm get head || true - brew update - fi - -install: - - | - if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then - brew outdated cmake || brew upgrade cmake - brew install gcc - brew link --overwrite gcc - brew install ninja - brew install eigen - brew install tbb - fi - - | - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then - CMAKE_URL="https://cmake.org/files/v3.10/cmake-3.10.3-Linux-x86_64.tar.gz" - mkdir cmake && travis_retry wget --no-check-certificate --quiet -O - ${CMAKE_URL} | tar --strip-components=1 -xz -C cmake - export PATH=${TRAVIS_BUILD_DIR}/cmake/bin:${PATH} - if [[ "${BOOST_VERSION}" != "" ]]; then - BOOST_DIR=${TRAVIS_BUILD_DIR}/boost-${BOOST_VERSION} - BOOST_URL="https://github.com/boostorg/boost/archive/boost-${BOOST_VERSION}.tar.gz" - mkdir -p ${BOOST_DIR} - { travis_retry wget -O - ${BOOST_URL} | tar --strip-components=1 -xz -C ${BOOST_DIR}; } || exit 1 - CMAKE_OPTIONS+=" -DBOOST_ROOT=${BOOST_DIR}" - fi - INCLUDE_DIR="/usr/include/" - fi - - cmake --version - - if [[ "$CXX" = "g++" ]]; then export CXX="g++-7" CC="gcc-7"; fi - - if [[ "$TRAVIS_OS_NAME" == "linux" && "$CXX" == "clang++" ]]; then export - CXX="clang++-6.0" CC="clang-6.0"; fi - - echo $CXX $CC - # Install CGAL from source for Linux - - cd $TRAVIS_BUILD_DIR - - travis_retry curl -L -o CGAL-4.11.1.tar.gz https://github.com/CGAL/cgal/archive/releases/CGAL-4.11.1.tar.gz - - tar zxvf CGAL-4.11.1.tar.gz &> install.log - - cd cgal-releases-CGAL-4.11.1 - - CMAKE_OPTIONS+=" -DCMAKE_BUILD_TYPE=Release -DWITH_Eigen3=ON" - - echo ${CMAKE_OPTIONS} - - cmake ${CMAKE_OPTIONS} -G Ninja . - - cmake --build . - - sudo env "PATH=$PATH" cmake --build . --target install &> install.log - - cd .. - -before_script: - - mkdir build - - cd build - -# Build matrix -# Matrix build combos of {linux,osx} x {gcc,clang} x {TESTS=true, TESTS=false} run script -# Specific includes run their own scripts -matrix: - fast_finish: true - include: - # Git Check - - os: linux - compiler: gcc - env: TESTS=false GITCHECK=true - # Skip unnecessary steps since we aren't compiling - before_install: - install: - before_script: - # Overwrite script on matrix jobs - script: - - | - if [[ -n $(git diff --check HEAD^) ]]; then - echo "You must remove whitespace before submitting a pull request." - echo "" - git diff --check HEAD^ - exit -1 - fi - # Skip after_success - after_success: - # ClangFormat - - os: linux - compiler: clang - env: TESTS=false CLANGFORMAT=true - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 - packages: - - clang-6.0 - - clang-format-6.0 - # Skip unnecessary steps since we aren't compiling - before_install: - install: - before_script: - # Overwrite script on matrix jobs - script: - - | - if [[ -n $(git diff -U0 --no-color HEAD^ | /usr/share/clang/clang-format-6.0/clang-format-diff.py -style file) ]]; then - echo "Run clang-format before submitting a pull request." - echo "" - git diff -U0 --no-color HEAD^ | /usr/share/clang/clang-format-6.0/clang-format-diff.py -style file - exit -1 - fi - # Skip after_success - after_success: - # ClangTidy - - os: linux - compiler: clang - env: TESTS=false CLANGTIDY=true - addons: - apt: - sources: - - ubuntu-toolchain-r-test - - llvm-toolchain-trusty-6.0 - packages: - - clang-6.0 - - clang-tidy-6.0 - # Skip unnecessary steps since we aren't compiling - before_install: - install: - before_script: - # Overwrite script on matrix jobs - script: - - git diff -U0 HEAD^ | /usr/lib/llvm-6.0/share/clang/clang-tidy-diff.py > output.txt - - | - if [[ -n $(grep "warning: " output.txt) ]] || [[ -n $(grep "error: " output.txt) ]]; then - echo "You must pass the clang tidy checks before submitting a pull request" - echo "" - grep --color -E '^|warning: |error: ' output.txt - exit -1; - else - echo -e "\033[1;32m\xE2\x9C\x93 passed:\033[0m $1"; - fi - # Skip after_success - after_success: - # Valgrind - - os: linux - compiler: gcc - env: TESTS=false VALGRIND=true - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-7 - - g++-7 - - ninja-build - - libmpfr-dev - - libgmp3-dev - - libeigen3-dev - - libtbb-dev - - libcgal-dev - - valgrind - script: - - cmake -DCMAKE_CXX_COMPILER=g++-7 -DVALGRIND=ON -DTESTS:BOOL=OFF -DBOOST_ROOT=${BOOST_DIR} -G Ninja .. - - cmake --build . - - ctest -T memcheck - # Codecov - - os: linux - compiler: gcc - env: TESTS=false CODECOV=true - addons: - apt: - sources: - - ubuntu-toolchain-r-test - packages: - - gcc-7 - - g++-7 - - ninja-build - - libmpfr-dev - - libgmp3-dev - - libeigen3-dev - - libtbb-dev - - libcgal-dev - - lcov - script: - - cmake -DTESTS:BOOL=ON -DENABLE_COVERAGE=ON -DCMAKE_CXX_COMPILER="g++-7" -DBOOST_ROOT=${BOOST_DIR} -G Ninja .. - - cmake --build . - after_success: - - cd ${TRAVIS_BUILD_DIR}/build - - pwd - - ctest - - cd ${TRAVIS_BUILD_DIR} - - lcov --directory . --capture --output-file coverage.info - - lcov --remove coverage.info '/usr/*' --output-file coverage.info - - lcov --list coverage.info - - bash <(curl -s https://codecov.io/bash) || echo "Codecov did not collect coverage reports" - # SonarQube - - os: osx - compiler: clang - env: TESTS=false SONARQUBE=true - addons: - sonarcloud: - organization: "acgetchell-github" - branches: - - develop - - master - # Skip unnecessary steps - before_install: - - git fetch --unshallow - script: - - CMAKE_OPTIONS="-DTESTS:BOOL=ON -DCMAKE_BUILD_TYPE=Debug -DBOOST_ROOT=${BOOST_DIR}" - - build-wrapper-macosx-x86 --out-dir bw_output cmake ${CMAKE_OPTIONS} -G Ninja .. - - sonar-scanner -X -Dproject.settings=../sonar-project.properties - cache: - ccache: true - directories: - - '$HOME/.sonar/cache' - - ${TRAVIS_BUILD_DIR}/boost-${BOOST_VERSION} - after_success: - allow_failures: - - os: linux - compiler: gcc - env: TESTS=false VALGRIND=true - - os: linux - compiler: gcc - env: TESTS=false CODECOV=true - - os: linux - compiler: clang - env: TESTS=false CLANGTIDY=true - - os: osx - compiler: clang - env: TESTS=false SONARQUBE=true - - os: linux - compiler: clang - env: TESTS=true - - os: linux - compiler: clang - env: TESTS=false - -script: - - CMAKE_OPTIONS="-DBOOST_ROOT=${BOOST_DIR} -DBUILD_SHARED_LIBS=ON" - - | - if [[ ${TESTS} == "true" ]]; then - CMAKE_OPTIONS+=" -DCMAKE_BUILD_TYPE=Debug -DTESTS:BOOL=ON" - else - CMAKE_OPTIONS+=" -DCMAKE_BUILD_TYPE=Release -DTESTS:BOOL=OFF" - fi - - echo $CMAKE_OPTIONS - - cmake $CMAKE_OPTIONS -G Ninja .. - - cmake --build . - -after_success: - - cd build - # Integration tests excluding Catch -# - ctest -E CDT-unit-tests - # Catch tests showing only failures - - if [[ ${TESTS} == "true" ]]; then ./test/CDT_test; fi - -notifications: - webhooks: - urls: - - https://webhooks.gitter.im/e/c70e4d2749931f601747 - - https://www.travisbuddy.com - on_success: change - on_failure: always diff --git a/.yamllint.yml b/.yamllint.yml new file mode 100644 index 0000000000..f764383387 --- /dev/null +++ b/.yamllint.yml @@ -0,0 +1,6 @@ +--- +extends: default + +rules: + line-length: + max: 120 diff --git a/CMakeLists.txt b/CMakeLists.txt index 1e6e86b670..b6912a486c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,191 +1,140 @@ -cmake_minimum_required(VERSION 3.8.2) +cmake_minimum_required(VERSION 3.21) -project(CDT-plusplus VERSION 0.1.8 LANGUAGES CXX) +# vcpkg settings must be set before project() +if(DEFINED ENV{VCPKG_ROOT} AND NOT DEFINED CMAKE_TOOLCHAIN_FILE) + set(CMAKE_TOOLCHAIN_FILE + "$ENV{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake" + CACHE STRING "") +endif() + +if(POLICY CMP0167) + cmake_policy(SET CMP0167 NEW) +endif () -if(${CMAKE_SOURCE_DIR} STREQUAL ${CMAKE_BINARY_DIR}) - message(FATAL_ERROR "Do not build in-source. - Please remove CMakeCache.txt and the CMakeFiles/ directory. Then build out-of-source.") +# In Manifest mode CMake invokes vcpkg automatically This makes setup easier, however, in CI or Docker we may want to +# turn this off +option(VCPKG_MANIFEST_MODE "Build vcpkg ports from manifest" ON) +set(_vcpkg_install_options ${VCPKG_INSTALL_OPTIONS}) +list(APPEND _vcpkg_install_options "--no-print-usage") +list(REMOVE_DUPLICATES _vcpkg_install_options) +set(VCPKG_INSTALL_OPTIONS "${_vcpkg_install_options}" CACHE STRING "Additional options passed to vcpkg install" FORCE) +unset(_vcpkg_install_options) + +project( + CDT-plusplus + VERSION 0.1.8 + DESCRIPTION "Fast Causal Dynamical Triangulations in C++" + LANGUAGES CXX) + +# Project settings +include(cmake/StandardProjectSettings.cmake) + +# Prevent in source builds +include(cmake/PreventInSourceBuilds.cmake) + +# Link this 'library' to set the c++ standard / compile-time options requested +add_library(project_options INTERFACE) +target_compile_features(project_options INTERFACE cxx_std_23) + +if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + option(ENABLE_BUILD_WITH_TIME_TRACE "Enable -ftime-trace to generate time tracing .json files on clang" OFF) + if(ENABLE_BUILD_WITH_TIME_TRACE) + target_compile_options(project_options INTERFACE -ftime-trace) + endif() endif() -############################ -## Modules and scripts ## -############################ +# Link this 'library' to use the warnings specified in CompilerWarnings.cmake +add_library(project_warnings INTERFACE) -#Standard CMake modules -include(CTest) -include(CMakeDependentOption) +# enable cache system +include(cmake/Cache.cmake) -#Coverage -if (ENABLE_COVERAGE) - set(CMAKE_BUILD_TYPE Debug) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -ftest-coverage") - set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage") -endif () +# standard compiler warnings +include(cmake/CompilerWarnings.cmake) +set_project_warnings(project_warnings) -#Valgrind -if (VALGRIND) - set(CMAKE_BUILD_TYPE Debug) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -g") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -O0") - set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --leak-check=full") - set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --track-fds=yes") - set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --trace-children=yes") - set(MEMORYCHECK_COMMAND_OPTIONS "${MEMORYCHECK_COMMAND_OPTIONS} --error-exitcode=1") - # Known Valgrind issue - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address") -endif() +# diagnostic compile and link options +include(cmake/Coverage.cmake) +enable_coverage(project_options) -############### -## OPTIONS ## -############### +include(cmake/Sanitizers.cmake) +enable_sanitizers(project_options) -#Turn on / off Catch Tests -option(TESTS ON) -#Turn on / off TBB -set(TBB_ON TRUE) -#Set mimumum Boost -set(BOOST_MIN_VERSION "1.64.0") -#Compile commands for ClangTidy et. al -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +# allow for static analysis options +include(cmake/StaticAnalyzers.cmake) +# Options ## +option(BUILD_SHARED_LIBS "Enable compilation of shared libraries" OFF) +option(ENABLE_TESTING "Enable building of tests" ON) -#Threads -set(CMAKE_THREAD_PREFER_PTHREAD TRUE) +# Modules and scripts ## +include(CTest) +include(CMakeDependentOption) -#Compiler flags -if (CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "-frounding-math") +# Minimum compiler versions required for C++23 support: +# - MSVC 19.34 (Visual Studio 2022 version 17.4) +# - GCC 12.2 +# - AppleClang 15.0 (Xcode 15) +# - Clang 16.0 +if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "19.34") + message(FATAL_ERROR "MSVC 19.34 or higher required for C++23 support") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "12.2") + message(FATAL_ERROR "GCC 12.2 or higher required for C++23 support") +elseif(CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "15.0") + message(FATAL_ERROR "AppleClang 15.0 (Xcode 15) or higher required for C++23 std::expected support") +elseif(CMAKE_CXX_COMPILER_ID MATCHES "Clang" AND CMAKE_CXX_COMPILER_VERSION VERSION_LESS "16.0") + message(FATAL_ERROR "Clang 16.0 or higher required for C++23 support") endif() -#Turn off CGAL Triangulation Assertions and Postconditions -add_definitions(-DCGAL_TRIANGULATION_NO_ASSERTIONS -DCGAL_TRIANGULATION_NO_POSTCONDITIONS) +# Set NOMINMAX to avoid min/max macro errors on Windows in date.h +#if(WIN32) +# # Workaround for https://github.com/CGAL/cgal/issues/4665 and https://github.com/microsoft/vcpkg/issues/23572 +# add_compile_options(/DNOMINMAX) +#endif() -#Disable CLion generation of RelWithDebInfo and MinSizeRel to avoid conflicts -#with CGAL_SetupFlags.cmake -set(CMAKE_CONFIGURATION_TYPES "Release" "Debug" CACHE STRING "" FORCE) +# Project vcpkg dependencies -#Extra warnings -add_compile_options(-Wall -Wno-comment) +# https://github.com/CGAL/cgal +# Do not let CGAL override project compiler/linker flags during package discovery. +set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS + TRUE + CACHE BOOL "Force CGAL to maintain CMAKE flags") +find_package(CGAL CONFIG REQUIRED) -#Easier navigation in an IDE when projects are organized in folders. -set_property(GLOBAL PROPERTY USE_FOLDERS ON) +# https://howardhinnant.github.io/date/date.html +find_package(date CONFIG REQUIRED) -############### -## Project ## -############### +# https://github.com/doctest/doctest +find_package(doctest CONFIG REQUIRED) -set(EXECUTABLE_NAME "CDT") +# https://github.com/fmtlib/fmt +find_package(fmt CONFIG REQUIRED) -#Boost -set(Boost_USE_STATIC_LIBS OFF) -set(Boost_USE_MULTITHREAD ON) -find_package(Boost ${BOOST_MIN_VERSION} REQUIRED) -if (Boost_FOUND) - include_directories(${Boost_INCLUDE_DIR}) -else() -message(FATAL_ERROR "Boost >= ${BOOST_MIN_VERSION} required.\n") -endif () +# https://github.com/microsoft/GSL +find_package(Microsoft.GSL CONFIG REQUIRED) -#CGAL -find_package(CGAL QUIET COMPONENTS Core ) -if(CGAL_FOUND) -#Don't let CGAL override flags - set(CGAL_DONT_OVERRIDE_CMAKE_FLAGS TRUE CACHE BOOL "Force CGAL to maintain CMAKE flags") - include(${CGAL_USE_FILE}) - include(CGAL_CreateSingleSourceCGALProgram) -#TBB - find_package(TBB) - if(TBB_FOUND AND TBB_ON) - include(${TBB_USE_FILE}) - list(APPEND CGAL_3RD_PARTY_LIBRARIES ${TBB_LIBRARIES}) - MESSAGE(${TBB_LIBRARIES}) - endif() -#Eigen - find_package(Eigen3) - if(EIGEN3_FOUND) - include(${EIGEN3_USE_FILE}) - else() - message(FATAL_ERROR "Notice: This program requires the Eigen3 library, and will not be compiled.") - endif() -else() - message(FATAL_ERROR "Notice: This program requires the CGAL library, and will not be compiled.") -endif() +# https://www.pcg-random.org +find_path(PCG_INCLUDE_DIRS "pcg_extras.hpp") + +find_package(Boost CONFIG REQUIRED COMPONENTS compat program_options) +target_link_libraries(project_options INTERFACE Boost::compat) + +# https://github.com/gabime/spdlog +find_package(spdlog CONFIG REQUIRED) + +# https://github.com/intel/tbb +find_package(TBB CONFIG REQUIRED) + +# Header files +include_directories(BEFORE ${PROJECT_SOURCE_DIR}/include) -#Curl -find_package(CURL) -if(CURL_FOUND) - include_directories(${CURL_INCLUDE_DIR}) -else() - message(FATAL_ERROR "Notice: This program requires the Curl library, and will not be compiled.") +# doctest +if(ENABLE_TESTING) + enable_testing() + message(STATUS "Building tests. Look at /tests for unit tests.") + message(STATUS "Look at /tests/logs for spdlog results from unit tests.") + message(NOTICE "These logs can get quite big in DEBUG mode if you run all tests.") + add_subdirectory(tests) endif() -include_directories (BEFORE ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/src/date/include ${CURL_INCLUDE_DIR}) -add_executable(cdt src/cdt.cpp src/docopt/docopt.cpp src/date/src/tz.cpp) -target_link_libraries(cdt PRIVATE ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${CURL_LIBRARIES}) -#Activate C++17 -target_compile_features(cdt PRIVATE cxx_std_17) - -if (UNIX) - add_executable(cdt-gv src/cdt-gv.cpp src/docopt/docopt.cpp) - target_link_libraries(cdt-gv PRIVATE ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES}) - #Activate C++17 - target_compile_features(cdt-gv PRIVATE cxx_std_17) - - - add_executable(cdt-opt src/cdt-opt.cpp ${PROJECT_SOURCE_DIR}/src/date/src/tz.cpp) - target_link_libraries(cdt-opt PRIVATE ${CGAL_LIBRARIES} ${CGAL_3RD_PARTY_LIBRARIES} ${CURL_LIBRARIES}) - #Activate C++17 - target_compile_features(cdt-opt PRIVATE cxx_std_17) - -endif(UNIX) - -############### -## Tests ## -############### - -#Catch -add_subdirectory(test) - -#CTest basic testing - -#Does the usage message work ? -add_test (CDT-Usage cdt) -set_tests_properties (CDT-Usage - PROPERTIES - PASS_REGULAR_EXPRESSION "Usage:./cdt") - -#Dimensions != 4 -add_test (CDT-3Donly cdt --s -n640 -t4 -a0.6 -k1.1 -l0.1 -d4 -p10 -c1) -set_tests_properties (CDT-3Donly - PROPERTIES - PASS_REGULAR_EXPRESSION "Invalid parameter ... Exiting.") - -#Simplices and timeslices >= 2 -add_test(CDT-Simplices cdt --s -n1 -t2 -a0.6 -k1.1 -l0.1 -d3 -p10 -c1) -set_tests_properties(CDT-Simplices - PROPERTIES - PASS_REGULAR_EXPRESSION "Simplices and timeslices should be greater or equal to 2.") -add_test(CDT-Timeslices cdt --s -n2 -t1 -a0.6 -k1.1 -l0.1 -d3 -p10 -c1) -set_tests_properties(CDT-Timeslices - PROPERTIES - PASS_REGULAR_EXPRESSION "Simplices and timeslices should be greater or equal to 2.") - -# 3D Triangle inequality -add_test (CDT-3Dtriangle cdt --s -n640 -t4 -a0.3 -k1.1 -l0.1 -d3 -p10 -c1) -set_tests_properties (CDT-3Dtriangle - PROPERTIES - PASS_REGULAR_EXPRESSION "Triangle inequalities violated ... Exiting.") - -#Minimum run -add_test(CDT-MinimalS3 cdt --s -n2 -t2 -a0.6 -k1.1 -l0.1 -p10 -c1) -set_tests_properties(CDT-MinimalS3 - PROPERTIES - PASS_REGULAR_EXPRESSION "Writing to file S3") -#Run an S3 -add_test(CDT-S3Runs cdt --s -n640 -t4 -a0.6 -k1.1 -l0.1 -p10 -c1) -set_tests_properties(CDT-S3Runs - PROPERTIES - PASS_REGULAR_EXPRESSION "Writing to file S3") +add_subdirectory(src) diff --git a/CMakePresets.json b/CMakePresets.json new file mode 100644 index 0000000000..a7da6bbb15 --- /dev/null +++ b/CMakePresets.json @@ -0,0 +1,123 @@ +{ + "version": 3, + "cmakeMinimumRequired": { + "major": 3, + "minor": 21, + "patch": 0 + }, + "configurePresets": [ + { + "name": "common", + "hidden": true, + "generator": "Ninja", + "binaryDir": "${sourceDir}/build", + "cacheVariables": { + "CMAKE_CXX_EXTENSIONS": false, + "CMAKE_CXX_STANDARD": "23", + "CMAKE_CXX_STANDARD_REQUIRED": true + } + }, + { + "name": "unix-diagnostics", + "hidden": true, + "inherits": "common", + "condition": { + "type": "equals", + "lhs": "${hostSystemName}", + "rhs": "Linux" + }, + "cacheVariables": { + "CMAKE_C_COMPILER": "clang", + "CMAKE_CXX_COMPILER": "clang++", + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "CMAKE_CXX_FLAGS": "-Wall -Wextra -Wpedantic -Wconversion -Wsign-conversion -Wcast-qual -Wformat=2 -Werror=float-equal -Wshadow -Wcast-align -Wunused -Wnull-dereference -Wdouble-promotion -Wimplicit-fallthrough -Wextra-semi -Woverloaded-virtual -Wnon-virtual-dtor -Wold-style-cast", + "ENABLE_CACHE": false, + "ENABLE_TESTING": true + } + }, + { + "name": "reference", + "displayName": "Supported headless reference build", + "description": "Configure the supported C++23 regression-oracle build with tests", + "inherits": "common", + "binaryDir": "${sourceDir}/out/build/reference", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "RelWithDebInfo", + "ENABLE_CACHE": false, + "ENABLE_TESTING": true + } + }, + { + "name": "debug", + "displayName": "Local debug build", + "description": "Configure an optional debug build for interactive diagnostics", + "inherits": "common", + "cacheVariables": { + "CMAKE_BUILD_TYPE": "Debug", + "ENABLE_CACHE": false, + "ENABLE_TESTING": true + } + }, + { + "name": "asan", + "description": "Configure the AddressSanitizer and UndefinedBehaviorSanitizer diagnostics", + "inherits": "unix-diagnostics", + "cacheVariables": { + "ENABLE_SANITIZER_ADDRESS": true, + "ENABLE_SANITIZER_UNDEFINED_BEHAVIOR": true + } + }, + { + "name": "lsan", + "description": "Configure the LeakSanitizer diagnostics", + "inherits": "unix-diagnostics", + "cacheVariables": { + "ENABLE_SANITIZER_LEAK": true + } + }, + { + "name": "msan", + "description": "Configure experimental MemorySanitizer diagnostics; dependencies are not instrumented", + "inherits": "unix-diagnostics", + "cacheVariables": { + "ENABLE_SANITIZER_MEMORY": true + } + }, + { + "name": "tsan", + "description": "Configure the ThreadSanitizer diagnostics", + "inherits": "unix-diagnostics", + "cacheVariables": { + "ENABLE_SANITIZER_THREAD": true + } + } + ], + "buildPresets": [ + { + "name": "reference", + "displayName": "Build the supported headless reference targets", + "configurePreset": "reference" + } + ], + "testPresets": [ + { + "name": "reference-smoke", + "displayName": "Run the supported reference smoke tests", + "description": "Exclude the full and duplicate unit-test registrations", + "configurePreset": "reference", + "output": { + "outputOnFailure": true + }, + "filter": { + "exclude": { + "name": "^(cdt-unit-tests|cdt-utilities-tests)$", + "label": "reference-smoke-exclude" + } + }, + "execution": { + "noTestsAction": "error", + "stopOnFailure": false + } + } + ] +} diff --git a/Justfile b/Justfile new file mode 100644 index 0000000000..489d5f7169 --- /dev/null +++ b/Justfile @@ -0,0 +1,255 @@ +# Justfile for the CDT++ maintenance workflow. +# Usage: just or just --list + +set minimum-version := "1.56.0" + +just_version := "1.56.0" +uv_version := "0.11.29" +pinact_version := "4.1.0" +pinact_module := "github.com/suzuki-shunsuke/pinact/v4/cmd/pinact@v" + pinact_version +llvm_version := "22" +zizmor_version := "1.26.1" +primary_binary := if os_family() == "windows" { "out/build/reference/src/cdt.exe" } else { "out/build/reference/src/cdt" } + +# Build the supported configuration through the repository build script. +[group('workflows')] +build: + {{ if os_family() == "windows" { "scripts\\build.bat" } else { "just _build-unix" } }} + +# Run fast, non-mutating local validation. +[group('workflows')] +check: _justfile-check _format-check _yaml-check _action-lint _zizmor _whitespace-check _cmake-check python-check + @echo "Checks complete." + +# Run the comprehensive pre-commit/pre-push validation gate. +[group('workflows')] +ci: check _pinact-check build + @echo "CI validation complete." + +# Apply safe automatic formatting to C++/Python source and the Justfile. +[group('workflows')] +fix: _format-fix python-fix + just --fmt + @echo "Fixes applied." + +# Run Clang-Tidy with the pinned LLVM toolchain. +[group('workflows')] +clang-tidy: + ./scripts/clang-tidy.sh + +# Build and exercise one supported Linux sanitizer configuration. +[group('workflows')] +sanitize kind: + ./scripts/sanitizer.sh {{ kind }} + +# Run every non-mutating Python source check. +[group('workflows')] +python-check: python-format-check python-lint python-typecheck + @echo "Python source checks complete." + +# Apply Ruff lint fixes and formatting to Python source. +[group('workflows')] +python-fix: _ensure-uv + uv run --locked ruff check src/ --fix + uv run --locked ruff format src/ + +# Check Python formatting with Ruff. +[group('workflows')] +python-format-check: _ensure-uv + uv run --locked ruff format --check src/ + +# Lint Python source with Ruff. +[group('workflows')] +python-lint: _ensure-uv + uv run --locked ruff check src/ + +# Synchronize the lightweight Python development environment from the lockfile. +[group('workflows')] +python-sync: _ensure-uv + uv sync --locked --group dev + +# Synchronize dependencies required by the optional experiment scripts. +[group('workflows')] +python-sync-experiments: _ensure-uv + uv sync --locked --group dev --group experiments + +# Type-check Python support code with ty. +[group('workflows')] +python-typecheck: _ensure-uv + uv run --locked ty check src/ --error all + +# Build as needed and run the primary CDT++ executable. +[group('workflows')] +run *args: build + {{ primary_binary }} {{ args }} + +# Update and repin GitHub Actions, then validate the resulting workflows. +[group('workflows')] +update-actions: + just _pinact run -update + just _yaml-check + just _action-lint + just _zizmor + +[default] +[private] +default: + @just --list + +[private] +_action-lint: + #!/usr/bin/env bash + set -euo pipefail + files=() + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && files+=("$file") + done < <(git ls-files -co --exclude-standard -z -- '.github/workflows/*.yml' '.github/workflows/*.yaml') + if command -v actionlint >/dev/null; then + actionlint "${files[@]}" + elif command -v pkgx >/dev/null; then + pkgx actionlint "${files[@]}" + else + echo "actionlint is required; install it or install pkgx." >&2 + exit 1 + fi + +[private] +_build-unix: + #!/usr/bin/env bash + set -euo pipefail + if command -v pkgx >/dev/null; then + exec ./scripts/pkgx-build.sh + fi + exec ./scripts/build.sh + +[private] +_cmake-check: + #!/usr/bin/env bash + set -euo pipefail + if command -v cmake >/dev/null; then + exec cmake --list-presets=all >/dev/null + fi + if command -v pkgx >/dev/null; then + exec pkgx +cmake.org cmake --list-presets=all >/dev/null + fi + echo "CMake is required; install it or install pkgx." >&2 + exit 1 + +[private] +_ensure-uv: + #!/usr/bin/env bash + set -euo pipefail + command -v uv >/dev/null || { echo "uv {{ uv_version }} is required." >&2; exit 1; } + actual_version="$(uv --version | awk '{print $2}')" + if [[ "$actual_version" != "{{ uv_version }}" ]]; then + echo "uv {{ uv_version }} is required; found $actual_version." >&2 + exit 1 + fi + +[private] +_resolve-clang-format: + #!/usr/bin/env bash + set -euo pipefail + clang_format="$(command -v clang-format-{{ llvm_version }} || command -v clang-format || true)" + if [[ -n "$clang_format" ]] && ! "$clang_format" --version | grep -Eq 'clang-format version {{ llvm_version }}([.]|$)'; then + clang_format="" + fi + if [[ -z "$clang_format" ]] && command -v pkgx >/dev/null; then + exec pkgx +llvm.org@{{ llvm_version }} -- just _resolve-clang-format + fi + [[ -n "$clang_format" ]] || { echo "clang-format {{ llvm_version }} is required; install it or install pkgx." >&2; exit 1; } + printf '%s\n' "$clang_format" + +[private] +_format-check: + #!/usr/bin/env bash + set -euo pipefail + clang_format="$(just _resolve-clang-format)" + files=() + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && files+=("$file") + done < <(git ls-files -co --exclude-standard -z -- '*.c' '*.cc' '*.cpp' '*.h' '*.hpp') + if [[ "${#files[@]}" -gt 0 ]]; then + "$clang_format" --dry-run --Werror "${files[@]}" + fi + +[private] +_format-fix: + #!/usr/bin/env bash + set -euo pipefail + clang_format="$(just _resolve-clang-format)" + files=() + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && files+=("$file") + done < <(git ls-files -co --exclude-standard -z -- '*.c' '*.cc' '*.cpp' '*.h' '*.hpp') + if [[ "${#files[@]}" -gt 0 ]]; then + "$clang_format" -i "${files[@]}" + fi + +[private] +_justfile-check: + just --fmt --check + +[private] +_pinact *args: + #!/usr/bin/env bash + set -euo pipefail + if [[ -z "${PINACT_GITHUB_TOKEN:-}" && -z "${GITHUB_TOKEN:-}" ]] && command -v gh >/dev/null && gh auth token >/dev/null 2>&1; then + export PINACT_GITHUB_TOKEN="$(gh auth token)" + fi + if command -v pinact >/dev/null; then + exec pinact {{ args }} + fi + if command -v pkgx >/dev/null; then + exec pkgx go run "{{ pinact_module }}" {{ args }} + fi + echo "pinact {{ pinact_version }} is required; install it with Homebrew or install pkgx." >&2 + exit 1 + +[private] +_pinact-check: + just _pinact run -fix=false -no-api + +[private] +_whitespace-check: + #!/usr/bin/env bash + set -euo pipefail + set +e + git --no-pager grep -nI -E '[[:blank:]]+$' -- . + status=$? + set -e + if [[ "$status" -eq 0 ]]; then + echo "Trailing whitespace found in tracked files." >&2 + exit 1 + fi + [[ "$status" -eq 1 ]] || exit "$status" + +[private] +_yaml-check: + #!/usr/bin/env bash + set -euo pipefail + files=(.clang-format) + while IFS= read -r -d '' file; do + [[ -f "$file" ]] && files+=("$file") + done < <(git ls-files -co --exclude-standard -z -- '*.yml' '*.yaml') + if command -v yamllint >/dev/null; then + yamllint "${files[@]}" + elif command -v pkgx >/dev/null; then + pkgx yamllint "${files[@]}" + else + echo "yamllint is required; install it or install pkgx." >&2 + exit 1 + fi + +[private] +_zizmor: + #!/usr/bin/env bash + set -euo pipefail + if command -v zizmor >/dev/null; then + zizmor .github + elif command -v pkgx >/dev/null; then + pkgx zizmor .github + else + echo "zizmor is required; install it or install pkgx." >&2 + exit 1 + fi diff --git a/LICENSE.md b/LICENSE.md index 1fdb8bbce2..38591bbdfa 100644 --- a/LICENSE.md +++ b/LICENSE.md @@ -1,4 +1,4 @@ -Copyright (c) 2013-2018, Adam Getchell +Copyright (c) 2013-2026, Adam Getchell All rights reserved. diff --git a/README.md b/README.md index af09f31e7a..5616ababc5 100644 --- a/README.md +++ b/README.md @@ -1,135 +1,289 @@ # CDT-plusplus - [![Build Status](https://travis-ci.org/acgetchell/CDT-plusplus.png?branch=develop)](https://travis-ci.org/acgetchell/CDT-plusplus) - [![Build status](https://ci.appveyor.com/api/projects/status/qjvbk6u86sp6cm59?svg=true)](https://ci.appveyor.com/project/acgetchell/cdt-plusplus) - [![codecov](https://codecov.io/gh/acgetchell/CDT-plusplus/branch/develop/graph/badge.svg)](https://codecov.io/gh/acgetchell/CDT-plusplus) - [![SonarCloud](https://sonarcloud.io/api/project_badges/measure?project=CDT-plusplus%3Adevelop&metric=alert_status)](https://sonarcloud.io/dashboard?id=CDT-plusplus%3Adevelop) - [![Open Issues](https://img.shields.io/github/issues-raw/acgetchell/CDT-plusplus.svg)](https://github.com/acgetchell/CDT-plusplus/issues) - [![Join the chat at https://gitter.im/acgetchell/CDT-plusplus](https://img.shields.io/badge/gitter-join%20chat%20→-brightgreen.svg)](https://gitter.im/acgetchell/CDT-plusplus) - **Quantize spacetime on your laptop.** -For an introduction to [Causal Dynamical Triangulations](https://github.com/acgetchell/CDT-plusplus/wiki), including the foundations and recent results, please see the [wiki](https://github.com/acgetchell/CDT-plusplus/wiki). - -[Causal Dynamical Triangulations][CDT] in C++ using the -[Computational Geometry Algorithms Library][CGAL] and [Eigen]>3.1.0, compiled -with [CMake] using [Clang]/[LLVM]. -Arbitrary-precision numbers and functions by [MPFR] and [GMP]. -Option-types via [Boost] >= 1.64.0. -Uses [Docopt] to provide a beautiful command-line interface, and [Howard Hinnant's date and timezone][date] library for accurate time (both as [subrepos]). -[Catch] is included as a single header in order to build/run unit tests. -[Ninja] is a nice (but optional) replacement for `make`. -Intel's [TBB] provides significantly better performance if present (3x+). -Follows the [CppCore Guidelines][guidelines] as enforced by [ClangTidy], which you can run using the -[clang-tidy.sh] script: - -~~~ -./clang-tidy.sh -~~~ - -(Or use your favorite linter plugin for your editor/IDE.) - -The goals and targets of this project are: - -- [x] Developed with [literate programming] using [Doxygen] +[![CI](https://github.com/acgetchell/CDT-plusplus/actions/workflows/ci.yml/badge.svg)](https://github.com/acgetchell/CDT-plusplus/actions/workflows/ci.yml) +[![codecov](https://codecov.io/gh/acgetchell/CDT-plusplus/branch/main/graph/badge.svg)](https://codecov.io/gh/acgetchell/CDT-plusplus) + +![Small foliated Delaunay triangulation](docs/images/S3-7-27528-I1-R1.png "7 timeslices 27528 simplices") + +## Maintenance status + +CDT++ is being prepared for one final C++23 release, v1.0.0, after which this repository will be archived. It is +maintained as an independent scientific reference and regression oracle for +[causal-triangulations](https://github.com/acgetchell/causal-triangulations), the supported Rust successor. New C++ +work is limited to correctness, reproducibility, cross-implementation validation, the complete supported 2+1D move +set, and the final release contract tracked by [issue #90](https://github.com/acgetchell/CDT-plusplus/issues/90). + +## Table of contents + +- [CDT-plusplus](#cdt-plusplus) + - [Maintenance status](#maintenance-status) + - [Introduction](#introduction) + - [Regression-oracle scope](#regression-oracle-scope) + - [Roadmap](#roadmap) + - [Quickstart](#quickstart) + - [Current reference-suite status](#current-reference-suite-status) + - [Setup](#setup) + - [Prerequisites](#prerequisites) + - [Developer workflow](#developer-workflow) + - [vcpkg maintenance](#vcpkg-maintenance) + - [Build](#build) + - [Project Layout](#project-layout) + - [Run](#run) + - [Usage](#usage) + - [Documentation](#documentation) + - [Testing](#testing) + - [Static Analysis](#static-analysis) + - [Sanitizers](#sanitizers) + - [Optimizing Parameters](#optimizing-parameters) + - [Visualization](#visualization) + - [Contributing](#contributing) + - [Issues](#issues) + +## Introduction + +For an introduction to [Causal Dynamical Triangulations](https://github.com/acgetchell/CDT-plusplus/wiki), +including the foundations and recent results, please see the [wiki](https://github.com/acgetchell/CDT-plusplus/wiki). + +[Causal Dynamical Triangulations][CDT] in [C++] uses the +[Computational Geometry Algorithms Library][CGAL], [Boost], and [TBB]. +Arbitrary-precision numbers and functions are by [MPFR] and [GMP]. +[Melissa E. O'Neill's Permuted Congruential Generators][PCG] library provides high-quality RNGs that pass L'Ecuyer's +[TestU01] statistical tests. +[doctest] provides [BDD]/[TDD]. +[vcpkg] provides library management and building. +[Doxygen] provides automated document generation. +[{fmt}] provides a safe and fast alternative to `iostream`. +[spdlog] provides fast, multithreaded logging. +[CometML] provides experiment tracking for the optional Python workflows. + +### Regression-oracle scope + +The principal reason to preserve this implementation is its causality-filtering Delaunay construction path in +[`include/Foliated_triangulation.hpp`](include/Foliated_triangulation.hpp). `check_timevalues` classifies cells from +stored vertex time labels, `find_bad_vertex` selects a vertex responsible for an acausal local configuration, and +`fix_timevalues` removes offending vertices through CGAL so the cavity is retriangulated until the foliation contract +is satisfied. + +The deterministic doctest scenario **"Detecting and fixing problems with vertices and cells"** in +[`tests/Foliated_triangulation_test.cpp`](tests/Foliated_triangulation_test.cpp) exercises this path with fixed points +and time labels. Its inputs, detected bad vertex, final initialization state, cell counts, and causal classification +are the first comparison fixture for `causal-triangulations`; exact Monte Carlo trajectories are not required to +match. + +After building, run that fixture directly with: + +```bash +./out/build/reference/tests/CDT_unit_tests \ + --test-case='*Detecting and fixing problems with vertices and cells*' +``` + +## Roadmap + +- [x] Cross-platform support on Linux, macOS (x64 & arm64), and Windows +- [x] Cross-compiler support on gcc, clang, and MSVC +- [x] Develop with [literate programming] using [Doxygen] - [x] [Efficient Pure Functional Programming in C++ Using Move Semantics][functional] -- [x] Validation tests using [CTest] -- [x] Behavior-driven development ([BDD]) with [Catch] -- [x] Continuous integration with MacOS and Linux on [Travis-CI] and Windows on [AppVeyor] -- [x] Code coverage measurements with [Codecov] +- [x] Test using [CTest] +- [x] Develop using Behavior-driven development ([BDD]) with [doctest] +- [x] Continuous integration by [GitHub Actions] on the leading edge - [x] 3D Simplex - [x] 3D Spherical triangulation - [x] 2+1 foliation -- [x] Integrate [Docopt] CLI - [x] S3 Bulk action - [x] 3D Ergodic moves -- [x] Multithreading via [TBB] -- [x] Metropolis algorithm -- [ ] Output via [HDF5] -- [ ] 4D Simplex -- [ ] 4D Spherical triangulation -- [ ] 3+1 foliation -- [ ] S4 Bulk action -- [ ] 4D Ergodic moves +- [x] High-quality Random Number Generation with M.E. O'Neill's [PCG] library +- [ ] Restore optional parallel triangulation with [TBB] ([#74](https://github.com/acgetchell/CDT-plusplus/issues/74)) +- [x] Automated code analysis with [CodeQL] +- [x] Build/debug with [Visual Studio 2022] +- [x] Use [{fmt}] library (instead of `iostream`) +- [x] 3D Metropolis algorithm +- [x] Multithreaded logging with [spdlog] +- [ ] Restore optional visualization with [Qt] ([#98](https://github.com/acgetchell/CDT-plusplus/issues/98)) - [ ] Initialize two masses -- [ ] Shortest path algorithm +- [ ] The shortest path algorithm - [ ] Einstein tensor - [ ] Complete test coverage - [ ] Complete documentation - [ ] Quantize Spacetime! -## Prerequisites +## Quickstart -[CDT++] should build on any system (e.g. Linux, MacOS, Windows) with -[CMake], [CGAL], [Boost], [MPFR], [Eigen], and [curl] installed. -[TBB] provides an optional (but significant) speed boost. [Catch] is -optional (but recommended) for running the unit tests, and [Ninja] is an -optional replacement for `make` which provides quick parallel builds of the -unit tests. +From a fresh checkout, the primary supported headless build, dependency bootstrap, and test path is: + +```bash +just build +``` + +The `build` recipe uses the pkgx launcher on Unix when pkgx is available, then delegates to `scripts/build.sh`. Its +first run creates an ignored `.cache/vcpkg` checkout at the exact `builtin-baseline` recorded in `vcpkg.json`, +bootstraps vcpkg, installs the manifest dependencies, builds in `out/build/reference`, and runs the supported CTest +smoke suite. The first dependency build can take several minutes; subsequent runs reuse both vcpkg dependencies and +CMake/Ninja outputs, so an unchanged build is a no-op apart from configuration and tests. + +The optional [pkgx](https://pkgx.sh/) entry point supplies the complete Unix developer-tool environment ephemerally +and invokes the same build contract directly, without requiring Just: + +```bash +./scripts/pkgx-build.sh +``` + +pkgx does not install CGAL or any other project library; those remain owned by the pinned vcpkg manifest. The +underlying `./scripts/build.sh` and `scripts\build.bat` entry points remain available for troubleshooting and native +Windows development. + +### Current reference-suite status + +With the pinned baseline, the reference configuration and build succeed on macOS with AppleClang. `build.sh` runs +eleven supported smoke tests on Unix: nine lightweight CLI integration tests and two focused doctest suites. The known +failing `initialize` scenario is excluded from Windows smoke runs, while the other initialization cases remain enabled. +The complete registered suite additionally runs the full unit-test executable and a focused utilities registration; +the focused registrations remain available for quick iteration and are labeled as full-suite duplicates for sanitizer +runs. + +## Setup + +This project uses [CMake]+[Ninja] to build C++23 sources and [vcpkg] manifest mode to manage C++ libraries. macOS with +AppleClang is the primary v1.0.0 restoration target; the remaining compiler and platform matrix will be recorded as +it is verified. + +### Prerequisites + +The smallest pkgx-assisted host setup is: + +- Xcode Command Line Tools on macOS, or a C++23 compiler and base build environment on Linux +- pkgx +- Just when invoking the recipes directly; `scripts/pkgx-build.sh` does not require it +- Python 3.12 and uv when checking or running the Python support scripts + +The pkgx launcher supplies Git, Bash, CMake, Ninja, Python, M4, Autoconf, Autoconf Archive, Automake, GNU +Libtool, Texinfo, and pkg-config. If pkgx is not installed, provide these tools conventionally through a package +manager such as [Homebrew] or apt: + +- Git +- Bash +- build-essential (Linux only) +- m4 +- automake +- autoconf +- autoconf-archive +- libtool (macOS) or libtool-bin (Linux) +- pkg-config +- texinfo +- ninja (macOS) or ninja-build (Linux) + +The build does not require a pre-existing personal vcpkg checkout, a fork, a submodule, Docker, or a hosted +development environment. + +### Developer workflow + +The repository-root [Justfile](Justfile) provides the same small command vocabulary used by the related projects: + +```bash +just check # Fast, non-mutating local checks +just fix # Format C++/Python source and the Justfile +just clang-tidy # Analyze C++ with LLVM 22 +just sanitize asan # Build and exercise one Linux sanitizer preset +just build # Bootstrap, configure, build, and smoke-test +just run --help # Build as needed and run cdt with forwarded arguments +just ci # Comprehensive pre-commit/pre-push validation +just update-actions # Update and repin Actions with pinact, then validate +just python-sync # Install the locked Ruff and ty development environment +just python-check # Check Python formatting, lint, and types +just python-fix # Apply safe Ruff fixes and formatting +``` + +`check` covers repository-wide C++ formatting, Python formatting/lint/type checks, YAML, GitHub Actions syntax and +security, whitespace, and CMake preset parsing. `ci` adds the pinact policy check and the supported build/test +contract. Install the developer tools with +Homebrew, use equivalent system packages, or let pkgx supply them ephemerally; pkgx remains optional. For example: + +```bash +pkgx +just.systems +git-scm.org +cmake.org +ninja-build.org +python.org +llvm.org@22 \ + +yamllint +actionlint +zizmor just check +``` + +[pinact](https://github.com/suzuki-shunsuke/pinact) uses [`.pinact.yaml`](.pinact.yaml) to retain immutable action +SHAs, readable release comments, and a seven-day release cooldown. `just update-actions` uses an installed pinact or +a pkgx-provided Go fallback, then requires `yamllint`, `actionlint`, and `zizmor` to pass. + +### vcpkg maintenance + +`vcpkg.json` is the dependency source of truth. Its `builtin-baseline` pins the official +[`microsoft/vcpkg`](https://github.com/microsoft/vcpkg) registry commit used locally and in CI. The repository-local +`.cache/vcpkg` checkout is disposable tool/cache infrastructure and must not be edited or committed. + +To update dependencies intentionally, bootstrap the current checkout, run the vcpkg baseline updater, review the +manifest diff, and then rerun the complete build: + +```bash +./scripts/bootstrap-vcpkg.sh +export VCPKG_ROOT="$PWD/.cache/vcpkg" +"$VCPKG_ROOT/vcpkg" x-update-baseline +./scripts/build.sh +``` + +CI uses `lukka/run-vcpkg`, which derives the vcpkg checkout commit from the same manifest baseline and supplies a +binary cache. No separately maintained repository variable is required. -On MacOS, the easiest way to do this is with [Homebrew]: +## Build -~~~ -brew upgrade cmake -brew install ninja -brew upgrade boost -brew install eigen -brew install tbb -brew install cgal --with-eigen3 --with-qt -~~~ +Run `just build` from the repository root. It delegates to `./scripts/build.sh`, which can itself be run from any +working directory for troubleshooting. If `VCPKG_ROOT` already names the clean official checkout at the manifest +baseline, the script respects it; otherwise it uses the pinned disposable checkout described above. The script +invokes the `reference` configure and build presets followed by the `reference-smoke` test preset; products and tests +are isolated under `out/build/reference`. Windows uses the same presets through `scripts\build.bat`, while +`scripts\fast-build.bat` configures the same reference tree and builds only the primary `cdt` target. All entry points +preserve a compatible CMake cache and refresh it only when the selected vcpkg toolchain path changes. -On Ubuntu, you will need an updated versions of [Clang] or [gcc], -[CMake], and [Boost], which is scripted in [.travis.yml]. -With Howard Hinnant's [date] library, you may also need to install -`libcurl-dev`, which is a virtual package with many flavors, OpenSSL being -the most tried and tested. +### Project Layout -## Build +The project is similar to [PitchFork Layout], as follows: -This project uses a separate `build/` directory, which allows you to rebuild the -project without cluttering the source code. Thus, download this source code -(clone this repo from GitHub or grab a [release]) and run the following commands -in the top-level directory: +- .github - GitHub specific settings +- out/build/reference - Ephemeral supported headless build directory +- cmake - Cmake configurations +- docs - Documentation +- external - Includes submodules of external projects (none so far, all using [vcpkg]) +- include - Header files +- scripts - Build, test, and run scripts +- src - Source files +- tests - Unit tests -~~~ -mkdir build && cd build -cmake -DTESTS:BOOL=OFF -DCMAKE_BUILD_TYPE=Release .. -cmake --build . -~~~ +### Run -(Or run [build.sh] if you have [Ninja] installed.) +The supported build produces `cdt` and `initialize` in `out/build/reference/src`. Run the primary `cdt` +executable through Just and pass its arguments after the recipe name: -This should result in the main program executable, `cdt` in the `build/` -directory, along with several others. +```bash +just run --help +``` -* `cdt-gv` converts output files to GeomView format for visualization -* `cdt-opt` is a simplified version with hard-coded inputs, mainly useful for -debugging and scripting +For troubleshooting, the equivalent direct command is `./out/build/reference/src/cdt --help`. -If you build [Catch] unit tests (`-DTESTS:BOOL=ON`), the executable -`/test/CDT_test` will also be present. See [Tests](#Tests) for details. +Use `--no-output` for batch, debugging, or scripted runs that should print results without writing checkpoint or final +triangulation files: -For some versions of Linux, you may have to build [CGAL] from source. -Follow the instructions (or their equivalent) given in the install section -of the [.travis.yml] build file. +```bash +just run -s -n256 -t4 -a0.6 -k1.1 -l0.1 -p10 -c10 --no-output +``` -There are enough unit tests that it's worthwhile doing fast parallel builds. -[Ninja] is just the ticket. It's effectively a drop-in replacement for -`make`, and works nicely because [CMake] generates the build files. -There's quite a difference in speed. CMake also abstracts away the build -tool nicely. Again, see [build.sh] for an example. +- `cdt-viewer` is currently disabled and will be restored as an opt-in v1.0.0 target by + [#98](https://github.com/acgetchell/CDT-plusplus/issues/98) +- `initialize` is used by [CometML] to run [parameter optimization](#optimizing-parameters) ## Usage -CDT-plusplus uses [Docopt] to parse options from the help message, and so +CDT-plusplus uses [program_options] to parse options from the help message, and so understands long or short argument formats, provided the short argument given is an unambiguous match to a longer one. The help message should be instructive: -~~~ -./build/cdt --help +```text +./out/build/reference/src/cdt --help Causal Dynamical Triangulations in C++ using CGAL. -Copyright (c) 2014-2018 Adam Getchell +Copyright (c) 2013-2026 Adam Getchell A program that generates d-dimensional triangulated spacetimes with a defined causal structure and evolves them according @@ -137,149 +291,220 @@ to the Metropolis algorithm. Specify the number of passes to control how much evolution is desired. Each pass attempts a number of ergodic moves equal to the number of simplices in the simulation. -Usage:./cdt (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES [-d DIM] -k K --alpha ALPHA --lambda LAMBDA [-p PASSES] [-c CHECKPOINT] +Usage:./cdt (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES + [-d DIM] + [--init INITIAL RADIUS] + [--foliate FOLIATION SPACING] + [--no-output] + -k K + --alpha ALPHA + --lambda LAMBDA + [-p PASSES] + [-c CHECKPOINT] + +Optional arguments are in square brackets. Examples: ./cdt --spherical -n 32000 -t 11 --alpha 0.6 -k 1.1 --lambda 0.1 --passes 1000 -./cdt --s -n32000 -t11 -a.6 -k1.1 -l.1 -p1000 +./cdt -s -n32000 -t11 -a.6 -k1.1 -l.1 -p1000 Options: - -h --help Show this message - --version Show program version - -n SIMPLICES Approximate number of simplices - -t TIMESLICES Number of timeslices - -d DIM Dimensionality [default: 3] - -a --alpha ALPHA Negative squared geodesic length of 1-d - timelike edges - -k K K = 1/(8*pi*G_newton) - -l --lambda LAMBDA K * Cosmological constant - -p --passes PASSES Number of passes [default: 100] - -c --checkpoint CHECKPOINT Checkpoint every n passes [default: 10] -~~~ + -h [ --help ] Show this message + -v [ --version ] Show program version + -s [ --spherical ] Spherical topology + -e [ --toroidal ] Toroidal topology + -n [ --simplices ] arg Approximate number of simplices + -t [ --timeslices ] arg Number of timeslices + -d [ --dimensions ] arg (=3) Dimensionality + -i [ --init ] arg (=1) Initial radius + -f [ --foliate ] arg (=1) Foliation spacing + --no-output Do not write checkpoint or final triangulation + files + -a [ --alpha ] arg Negative squared geodesic length of 1-d + timelike edges + -k [ --k ] arg K = 1/(8*pi*G_newton) + -l [ --lambda ] arg K * Cosmological constant + -p [ --passes ] arg (=100) Number of passes + -c [ --checkpoint ] arg (=10) Checkpoint every n passes +``` The dimensionality of the spacetime is such that each slice of spacetime is -`d-1`-dimensional, so setting `d=3` generates 2 spacelike dimensions and one -timelike dimension, with a defined global time foliation. Thus a +`d-1`-dimensional, so setting `d=3` generates two spacelike dimensions and one +timelike dimension, with a defined global time foliation. A `d`-dimensional simplex will have some `d-1` sub-simplices that are purely spacelike (all on the same timeslice) as well as some that are timelike (span two timeslices). In [CDT] we actually care more about the timelike -links (in 2+1 spacetime) and the timelike faces (in 3+1 spacetime). +links (in 2+1 spacetime), and the timelike faces (in 3+1 spacetime). ## Documentation -Online documentation may be found at http://www.adamgetchell.org/CDT-plusplus/ +Online documentation is at . If you have [Doxygen] installed you can generate the same information -locally by simply typing at the top level directory -([Doxygen] will recursively search): +locally using the configuration file in `docs/Doxyfile` by simply typing at the top +level directory ([Doxygen] will recursively search): -~~~ -doxygen -~~~ +```bash +doxygen ./docs/Doxyfile +``` -This will generate the `html/` directory which will contain +This will generate a `docs/html/` directory containing documentation generated from CDT++ source files. `USE_MATHJAX` has been enabled -in [Doxyfile] so that the LaTeX formulae can be rendered in the html +in [Doxyfile] so that the LaTeX formulae can be rendered in the HTML documentation using [MathJax]. `HAVE_DOT` is set to **YES** which allows various graphs to be autogenerated by [Doxygen] using [GraphViz]. If you do not have GraphViz installed, set this option to **NO** (along with `UML_LOOK`). -## Tests +## Testing -[Catch] is optional, but strongly recommended if you want to make changes to -or understand the source code in detail. It's easily deployable as a [single -header file][catch-header] obtained from GitHub. Building the [Catch] `CDT_test` -executable is set by the `TESTS` variable in [CMakeLists.txt], or -at the command line (first `cd` into `build`) using: +Run `just build`; it delegates to `./scripts/build.sh`, builds the test target, and executes the eleven supported smoke +tests. These include focused doctest runs for the Boost.Compat `function_ref` migration and the causal-foliation +construction code used as a regression oracle. Run `just ci` for the complete local validation gate. -~~~ -cmake -DTESTS:BOOL=ON -DCMAKE_BUILD_TYPE=Debug .. -~~~ +The doctest executable can also be run directly: -Unit tests using Catch are then run (in the `build/test` directory) via: +```bash +./out/build/reference/tests/CDT_unit_tests +``` -~~~ -./CDT_test -~~~ +To rerun the supported smoke suite without rebuilding: -You can also run both [CTest] and [Catch] via: +```bash +ctest --preset reference-smoke +``` -~~~ -cmake --build . --target test -~~~ +To run every currently registered test, including the full unit-test executable and focused duplicate registrations, +bypass the smoke filter explicitly: + +```bash +ctest --test-dir out/build/reference --output-on-failure +``` In addition to the command line output, you can see detailed results in the -`build/Testing` directory which is generated thereby. +`out/build/reference/Testing` directory generated by CTest. + +### Static Analysis + +Python 3.12 is selected by [`.python-version`](.python-version), uv locks the environment in `uv.lock`, Ruff owns +Python formatting and linting, and ty owns static type checking. Run `just python-sync` once and then use +`just python-check` or `just python-fix`; both commands are also part of the repository-wide validation recipes. + +This project follows the [CppCore Guidelines][guidelines] as enforced by [ClangTidy]. The repository pins LLVM 22; +run Clang-Tidy through its Just recipe: + +```bash +just clang-tidy +``` -## Static Analysis +(Or use your favorite linter plugin for your editor/IDE.) + +### Sanitizers -### Manual +[AddressSanitizer] + [UndefinedBehaviorSanitizer], [LeakSanitizer], [MemorySanitizer], and [ThreadSanitizer] share the +repository-owned Linux driver and CMake presets. Run one locally with `just sanitize asan`, `just sanitize lsan`, +`just sanitize msan`, or `just sanitize tsan`; the GitHub Actions workflows invoke the same commands. MemorySanitizer +remains experimental because third-party dependencies are not instrumented. -The [cppcheck-build.sh] script runs a quick static analysis using -[cppcheck]. +## Optimizing Parameters -[Clang] comes with [scan-build] which can run a much more thorough, -but slower static analysis integrated with [CMake] and [Ninja]. -Simply run the [scan.sh] script. +[CometML] is used to record [Experiments] conducted by `src/optimize-initialize.py`; `src/test.py` is the existing +TensorFlow MNIST experiment. These optional, heavyweight dependencies are kept out of the normal lint environment. +Synchronize them from the same uv lockfile when working on the experiment scripts: -### Continuous Integration +```bash +just python-sync-experiments +uv run --locked --group experiments python src/optimize-initialize.py +``` -One of the [Travis-CI] jobs runs ClangTidy on all changed files. +Set `COMET_API_KEY` before starting an online experiment. The experiment results are then available in Comet. +Migration of these legacy scripts to Python 3.14, PyTorch, and the current Comet API is tracked by +[#104](https://github.com/acgetchell/CDT-plusplus/issues/104). -Another runs [Valgrind]; be sure to look at the results to ensure you're not leaking memory. +## Visualization -More comprehensive static checking is done by [SonarCloud], also worth a look. +The Qt-based `cdt-viewer` target is currently disabled. Its opt-in dependency feature, deterministic smoke fixture, +supported desktop matrix, and v1.0.0 restoration are tracked by +[#98](https://github.com/acgetchell/CDT-plusplus/issues/98); Qt and Eigen are intentionally absent from the default +headless build until that work is complete. ## Contributing -Please see [CONTRIBUTING.md](.github/CONTRIBUTING.md) and our [CODE_OF_CONDUCT.md](.github/CODE_OF_CONDUCT.md). - -[CDT]: http://arxiv.org/abs/hep-th/0105267 -[CGAL]: http://www.cgal.org -[CMake]: http://www.cmake.org -[Clang]: http://clang.llvm.org -[LLVM]: http://llvm.org -[Catch]: https://github.com/catchorg/Catch2/blob/master/docs/Readme.md -[guidelines]: http://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines -[clang-tidy.sh]: https://github.com/acgetchell/CDT-plusplus/blob/master/clang-tidy.sh -[Ctest]: http://cmake.org/Wiki/CMake/Testing_With_CTest -[Travis-CI]: https://travis-ci.com/getting_started +Please see [CONTRIBUTING.md] and our [CODE_OF_CONDUCT.md]. + +Your code should pass Continuous Integration: + +- `just fix` for safe automatic formatting with the repository's [.clang-format] + +- `just clang-tidy` to analyze C++ with the pinned LLVM 22 toolchain + +- `just check` for fast, non-mutating source, YAML, workflow, and CMake validation + +- `just ci` for the supported build and smoke-test contract before pushing + +The slower sanitizer workflows remain available through [GitHub Actions] and repository commands when relevant to a +change: + +- [AddressSanitizer], [UndefinedBehaviorSanitizer], [LeakSanitizer], [MemorySanitizer], and [ThreadSanitizer] + +Valgrind is intentionally unsupported: on x86/AMD64 its floating-point emulation does not honor the directed +rounding required by CGAL's interval predicates. Disabling CGAL's rounding check would make geometric results +untrustworthy, so memory diagnostics use the supported sanitizer workflows instead. + +Optional: + +- [ClangTidy] on all changed files + +## Issues + +- [vcpkg]'s version of [date] has an unfixed bug [#23637] which produces `use-of-uninitialized-value` in [MemorySanitizer]. +- [vcpkg] has issues with `fontconfig:arm64-osx` [#40623]. +- [vcpkg] fails to build [gmp] on Linux (which breaks CI) [#45336] + +[#45336]: https://github.com/microsoft/vcpkg/issues/45336 +[#40623]: https://github.com/microsoft/vcpkg/issues/40623 +[#23637]: https://github.com/microsoft/vcpkg/issues/23637 +[CDT]: https://arxiv.org/abs/hep-th/0105267 +[CGAL]: https://www.cgal.org +[CMake]: https://www.cmake.org +[doctest]: https://github.com/doctest/doctest +[guidelines]: https://isocpp.github.io/CppCoreGuidelines/CppCoreGuidelines +[CTest]: https://gitlab.kitware.com/cmake/community/wikis/doc/ctest/Testing-With-CTest [literate programming]: http://www.literateprogramming.com [Doxygen]: http://www.doxygen.org [Homebrew]: https://brew.sh -[release]: https://github.com/acgetchell/CDT-plusplus/releases [Ninja]: https://ninja-build.org -[Docopt]: https://github.com/docopt/docopt.cpp -[Mathjax]: http://www.mathjax.org -[GraphViz]: http://www.graphviz.org -[Eigen]: http://eigen.tuxfamily.org/index.php?title=Main_Page -[build.sh]: https://github.com/acgetchell/CDT-plusplus/blob/master/build.sh -[CMakeLists.txt]: https://github.com/acgetchell/CDT-plusplus/blob/master/CMakeLists.txt -[MPFR]: http://www.mpfr.org +[program_options]: https://www.boost.org/doc/libs/1_85_0/doc/html/program_options/tutorial.html +[Mathjax]: https://www.mathjax.org +[GraphViz]: https://www.graphviz.org +[MPFR]: https://www.mpfr.org [GMP]: https://gmplib.org -[HDF5]: https://www.hdfgroup.org -[scan-build]: http://clang-analyzer.llvm.org/scan-build.html -[scan.sh]: https://github.com/acgetchell/CDT-plusplus/blob/master/scan.sh -[cppcheck]: http://cppcheck.sourceforge.net -[cppcheck-build.sh]: https://github.com/acgetchell/CDT-plusplus/blob/master/cppcheck-build.sh [functional]: https://blog.knatten.org/2012/11/02/efficient-pure-functional-programming-in-c-using-move-semantics/ [TBB]: https://www.threadingbuildingblocks.org -[CDT++]: https://github.com/acgetchell/CDT-plusplus -[.travis.yml]: https://github.com/acgetchell/CDT-plusplus/blob/master/.travis.yml -[Doxyfile]: https://github.com/acgetchell/CDT-plusplus/blob/master/Doxyfile -[Boost]: http://www.boost.org -[gcc]: https://gcc.gnu.org -[contrib]: https://github.com/acgetchell/CDT-plusplus/blob/master/CONTRIBUTING.md -[ClangTidy]: http://releases.llvm.org/5.0.0/tools/clang/tools/extra/docs/clang-tidy/index.html -[Valgrind]: http://valgrind.org/docs/manual/quick-start.html#quick-start.mcrun -[conduct]: https://github.com/acgetchell/CDT-plusplus/blob/master/CODE_OF_CONDUCT.md +[Doxyfile]: https://github.com/acgetchell/CDT-plusplus/blob/main/docs/Doxyfile +[Boost]: https://www.boost.org +[ClangTidy]: https://clang.llvm.org/extra/clang-tidy/ [date]: https://howardhinnant.github.io/date/date.html -[subrepo]: https://github.com/ingydotnet/git-subrepo -[catch-header]: https://github.com/catchorg/Catch2 -[AppVeyor]: https://www.appveyor.com [BDD]: https://en.wikipedia.org/wiki/Behavior-driven_development -[curl]: https://curl.haxx.se -[.appveyor.yml]: https://github.com/acgetchell/CDT-plusplus/blob/master/.appveyor.yml -[Codecov]: https://codecov.io -[SonarCloud]: https://sonarcloud.io/dashboard?id=CDT-plusplus%3Adevelop +[TDD]: https://en.wikipedia.org/wiki/Test-driven_development +[CometML]: https://www.comet.ml/ +[Experiments]: https://www.comet.ml/acgetchell/cdt-plusplus +[vcpkg]: https://github.com/Microsoft/vcpkg +[C++]: https://isocpp.org/ +[Pitchfork Layout]: https://api.csswg.org/bikeshed/?force=1&url=https://raw.githubusercontent.com/vector-of-bool/pitchfork/develop/data/spec.bs#tld.docs +[PCG]: http://www.pcg-random.org/paper.html +[TestU01]: http://simul.iro.umontreal.ca/testu01/tu01.html +[CONTRIBUTING.md]: https://github.com/acgetchell/CDT-plusplus/blob/main/.github/CONTRIBUTING.md +[CODE_OF_CONDUCT.md]: https://github.com/acgetchell/CDT-plusplus/blob/main/.github/CODE_OF_CONDUCT.md +[GitHub Actions]: https://github.com/features/actions +[CodeQL]: https://codeql.github.com/ +[Visual Studio 2022]: https://visualstudio.microsoft.com/vs/ +[{fmt}]: https://github.com/fmtlib/fmt +[AddressSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizer +[LeakSanitizer]: https://github.com/google/sanitizers/wiki/AddressSanitizerLeakSanitizer +[ThreadSanitizer]: https://github.com/google/sanitizers/wiki/ThreadSanitizerCppManual +[MemorySanitizer]: https://github.com/google/sanitizers/wiki/MemorySanitizer +[UndefinedBehaviorSanitizer]: https://clang.llvm.org/docs/UndefinedBehaviorSanitizer.html +[.clang-format]: https://github.com/acgetchell/CDT-plusplus/blob/main/.clang-format +[spdlog]: https://github.com/gabime/spdlog +[Qt]: https://www.qt.io diff --git a/build.sh b/build.sh deleted file mode 100755 index 35b40bf8ab..0000000000 --- a/build.sh +++ /dev/null @@ -1,5 +0,0 @@ -#! /bin/bash -rm -rf build/ -mkdir build && cd build -cmake -G Ninja -DTESTS:BOOL=ON -DCMAKE_BUILD_TYPE=Debug .. -cmake --build . diff --git a/clang-tidy.sh b/clang-tidy.sh deleted file mode 100755 index 57942bac62..0000000000 --- a/clang-tidy.sh +++ /dev/null @@ -1,8 +0,0 @@ -#!/usr/bin/env bash -# Uses run-clang-tidy.py, so clang-tidy must be in your $PATH for this script to run -rm -rf build/ -mkdir build && cd build -# Export compilation database for run-clang-tidy.py -cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. -# Settings for tests to run in .clang-tidy -`locate run-clang-tidy.py` -fix diff --git a/cmake/.clang-tidy b/cmake/.clang-tidy new file mode 100644 index 0000000000..3b209bfbc3 --- /dev/null +++ b/cmake/.clang-tidy @@ -0,0 +1,2 @@ +# Disable all checks in folder +Checks: '-*' \ No newline at end of file diff --git a/cmake/Cache.cmake b/cmake/Cache.cmake new file mode 100644 index 0000000000..bf8423f051 --- /dev/null +++ b/cmake/Cache.cmake @@ -0,0 +1,29 @@ +option(ENABLE_CACHE "Enable cache if available" ON) +if(NOT ENABLE_CACHE) + return() +endif() + +set(CACHE_OPTION + "ccache" + CACHE STRING "Compiler cache to be used") +set(CACHE_OPTION_VALUES "ccache" "sccache") +set_property(CACHE CACHE_OPTION PROPERTY STRINGS ${CACHE_OPTION_VALUES}) +list( + FIND + CACHE_OPTION_VALUES + ${CACHE_OPTION} + CACHE_OPTION_INDEX) + +if(${CACHE_OPTION_INDEX} EQUAL -1) + message( + STATUS + "Using custom compiler cache system: '${CACHE_OPTION}', explicitly supported entries are ${CACHE_OPTION_VALUES}") +endif() + +find_program(CACHE_BINARY ${CACHE_OPTION}) +if(CACHE_BINARY) + message(STATUS "${CACHE_OPTION} found and enabled") + set(CMAKE_CXX_COMPILER_LAUNCHER ${CACHE_BINARY}) +else() + message(STATUS "${CACHE_OPTION} is enabled but was not found. Not using it") +endif() diff --git a/cmake/CompilerWarnings.cmake b/cmake/CompilerWarnings.cmake new file mode 100644 index 0000000000..59ef0394df --- /dev/null +++ b/cmake/CompilerWarnings.cmake @@ -0,0 +1,82 @@ +# Derived from: +# +# https://github.com/lefticus/cpp_starter_project/blob/master/cmake/CompilerWarnings.cmake + +function(set_project_warnings project_name) + option(WARNINGS_AS_ERRORS "Treat compiler warnings as errors" FALSE) + + set(MSVC_WARNINGS + /W4 # Baseline reasonable warnings + /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss of data + /w14254 # 'operator': conversion from 'type1:field_bits' to 'type2:field_bits', possible loss of data + /w14263 # 'function': member function does not override any base class virtual member function + /w14265 # 'classname': class has virtual functions, but destructor is not virtual instances of this class may not + # be destructed correctly + /w14287 # 'operator': unsigned/negative constant mismatch + /we4289 # nonstandard extension used: 'variable': loop control variable declared in the for-loop is used outside + # the for-loop scope + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend 'operator'? + /w14555 # expression has no effect; expected expression with side- effect + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # Enable warning on thread un-safe static member initialization + /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may cause unexpected runtime behavior. + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + /w14928 # illegal copy-initialization; more than one user-defined conversion has been implicitly applied + /permissive- # standards conformance mode for MSVC compiler. + ) + + set(CLANG_WARNINGS + -Wall + -Wextra # reasonable and standard + -Wshadow # warn the user if a variable declaration shadows one from a parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a non-virtual destructor. This helps + # catch hard to track down memory errors + -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output (ie printf) + -Wsign-conversion # warn on sign conversions + -Wcast-qual # warn on casts which remove qualifiers + -Wimplicit-fallthrough # warn on implicit fallthrough in unreachable code + -Wextra-semi # warn on extra semicolons + ) + + if(WARNINGS_AS_ERRORS) + set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) + set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) + endif() + + set(GCC_WARNINGS + ${CLANG_WARNINGS} + -Wmisleading-indentation # warn if indentation implies blocks where blocks do not exist + -Wduplicated-cond # warn if if / else chain has duplicated conditions + -Wduplicated-branches # warn if if / else branches have duplicated code + -Wlogical-op # warn about logical operations being used where bitwise were probably wanted + #-Wuseless-cast # warn if you perform a cast to the same type + ) + + if(MSVC) + set(PROJECT_WARNINGS ${MSVC_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(PROJECT_WARNINGS ${CLANG_WARNINGS}) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(PROJECT_WARNINGS ${GCC_WARNINGS}) + else() + message(AUTHOR_WARNING "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") + endif() + + target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS}) + +endfunction() diff --git a/cmake/Coverage.cmake b/cmake/Coverage.cmake new file mode 100644 index 0000000000..80d836daba --- /dev/null +++ b/cmake/Coverage.cmake @@ -0,0 +1,15 @@ +option(ENABLE_COVERAGE "Enable GCC/Clang coverage instrumentation" OFF) + +function(enable_coverage target) + if(NOT ENABLE_COVERAGE) + return() + endif() + + if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")) + message(FATAL_ERROR "Coverage instrumentation requires GCC or Clang") + endif() + + target_compile_options(${target} INTERFACE --coverage -O0 -g) + target_link_options(${target} INTERFACE --coverage) + message(STATUS "Coverage instrumentation enabled") +endfunction() diff --git a/cmake/PreventInSourceBuilds.cmake b/cmake/PreventInSourceBuilds.cmake new file mode 100644 index 0000000000..57d9c59156 --- /dev/null +++ b/cmake/PreventInSourceBuilds.cmake @@ -0,0 +1,18 @@ +# +# This function will prevent in-source builds +function(AssureOutOfSourceBuilds) + # make sure the user doesn't play dirty with symlinks + get_filename_component(srcdir "${CMAKE_SOURCE_DIR}" REALPATH) + get_filename_component(bindir "${CMAKE_BINARY_DIR}" REALPATH) + + # disallow in-source builds + if("${srcdir}" STREQUAL "${bindir}") + message("######################################################") + message("Warning: in-source builds are disabled") + message("Please create a separate build directory and run cmake from there") + message("######################################################") + message(FATAL_ERROR "Quitting configuration") + endif() +endfunction() + +assureoutofsourcebuilds() diff --git a/cmake/RunCdtNoOutputTest.cmake b/cmake/RunCdtNoOutputTest.cmake new file mode 100644 index 0000000000..7160bbc690 --- /dev/null +++ b/cmake/RunCdtNoOutputTest.cmake @@ -0,0 +1,41 @@ +if(NOT DEFINED CDT_EXECUTABLE OR NOT EXISTS "${CDT_EXECUTABLE}") + message(FATAL_ERROR "CDT_EXECUTABLE must name the built cdt executable") +endif() + +if(NOT DEFINED TEST_DIRECTORY OR TEST_DIRECTORY STREQUAL "" OR TEST_DIRECTORY STREQUAL "/") + message(FATAL_ERROR "TEST_DIRECTORY must name a dedicated test directory") +endif() + +execute_process( + COMMAND "${CDT_EXECUTABLE}" --help + RESULT_VARIABLE help_result + OUTPUT_VARIABLE help_output + ERROR_VARIABLE help_error) +if(NOT help_result EQUAL 0) + message(FATAL_ERROR "cdt --help failed:\n${help_output}\n${help_error}") +endif() +if(NOT help_output MATCHES "--no-output") + message(FATAL_ERROR "cdt --help does not document --no-output") +endif() + +file(REMOVE_RECURSE "${TEST_DIRECTORY}") +file(MAKE_DIRECTORY "${TEST_DIRECTORY}") + +execute_process( + COMMAND "${CDT_EXECUTABLE}" -s -n64 -t3 -a0.6 -k1.1 -l0.1 -p1 -c1 --no-output + WORKING_DIRECTORY "${TEST_DIRECTORY}" + RESULT_VARIABLE run_result + OUTPUT_VARIABLE run_output + ERROR_VARIABLE run_error) +if(NOT run_result EQUAL 0) + message(FATAL_ERROR "cdt --no-output failed:\n${run_output}\n${run_error}") +endif() +if(run_output MATCHES "Writing to file" OR run_error MATCHES "Writing to file") + message(FATAL_ERROR "cdt --no-output attempted to write a triangulation file") +endif() + +file(GLOB_RECURSE generated_files LIST_DIRECTORIES false "${TEST_DIRECTORY}/*") +if(generated_files) + list(JOIN generated_files "\n " generated_file_list) + message(FATAL_ERROR "cdt --no-output created files:\n ${generated_file_list}") +endif() diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 0000000000..37fb74509d --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,80 @@ +# Derived from: +# https://github.com/cpp-best-practices/cmake_template/blob/main/cmake/Sanitizers.cmake + +option(ENABLE_SANITIZER_ADDRESS "Enable AddressSanitizer" OFF) +option(ENABLE_SANITIZER_LEAK "Enable LeakSanitizer" OFF) +option(ENABLE_SANITIZER_MEMORY "Enable MemorySanitizer" OFF) +option(ENABLE_SANITIZER_THREAD "Enable ThreadSanitizer" OFF) +option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable UndefinedBehaviorSanitizer" OFF) + +function(enable_sanitizers target) + if(NOT + ENABLE_SANITIZER_ADDRESS + AND NOT ENABLE_SANITIZER_LEAK + AND NOT ENABLE_SANITIZER_MEMORY + AND NOT ENABLE_SANITIZER_THREAD + AND NOT ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + return() + endif() + + if(NOT (CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")) + message(FATAL_ERROR "The requested sanitizers require GCC or Clang") + endif() + + set(_sanitizers "") + + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND _sanitizers "address") + message(STATUS "AddressSanitizer enabled") + endif() + + if(ENABLE_SANITIZER_LEAK) + if(APPLE) + message(FATAL_ERROR "Standalone LeakSanitizer is not supported on Apple platforms") + endif() + list(APPEND _sanitizers "leak") + message(STATUS "LeakSanitizer enabled") + endif() + + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND _sanitizers "undefined") + message(STATUS "UndefinedBehaviorSanitizer enabled") + endif() + + if(ENABLE_SANITIZER_THREAD) + if(ENABLE_SANITIZER_ADDRESS OR ENABLE_SANITIZER_LEAK) + message(FATAL_ERROR "ThreadSanitizer cannot be combined with AddressSanitizer or LeakSanitizer") + endif() + list(APPEND _sanitizers "thread") + message(STATUS "ThreadSanitizer enabled") + endif() + + if(ENABLE_SANITIZER_MEMORY) + if(NOT CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + message(FATAL_ERROR "MemorySanitizer requires Clang") + endif() + if(NOT CMAKE_SYSTEM_NAME MATCHES "Linux|FreeBSD|NetBSD") + message(FATAL_ERROR "MemorySanitizer is not supported on ${CMAKE_SYSTEM_NAME}") + endif() + if(ENABLE_SANITIZER_ADDRESS OR ENABLE_SANITIZER_LEAK OR ENABLE_SANITIZER_THREAD) + message( + FATAL_ERROR + "MemorySanitizer cannot be combined with AddressSanitizer, LeakSanitizer, or ThreadSanitizer") + endif() + message( + WARNING + "MemorySanitizer requires an instrumented standard library and instrumented dependencies; otherwise reports are not authoritative" + ) + list(APPEND _sanitizers "memory") + message(STATUS "MemorySanitizer enabled") + endif() + + list(JOIN _sanitizers "," _sanitizer_flags) + target_compile_options( + ${target} + INTERFACE -g + -O1 + -fsanitize=${_sanitizer_flags} + -fno-omit-frame-pointer) + target_link_options(${target} INTERFACE -fsanitize=${_sanitizer_flags}) +endfunction() diff --git a/cmake/StandardProjectSettings.cmake b/cmake/StandardProjectSettings.cmake new file mode 100644 index 0000000000..878b22908e --- /dev/null +++ b/cmake/StandardProjectSettings.cmake @@ -0,0 +1,64 @@ +# Disable CLion generation of MinSizeRel for multi-config generators to avoid +# conflicts with CGAL_SetupFlags.cmake. +if(CMAKE_CONFIGURATION_TYPES) + set(CMAKE_CONFIGURATION_TYPES + "Release" "Debug" "RelWithDebInfo" + CACHE STRING "" FORCE) +elseif(NOT CMAKE_BUILD_TYPE) + # Set a default build type for single-config generators when none was specified. + message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") + set(CMAKE_BUILD_TYPE + RelWithDebInfo + CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui, ccmake + set_property( + CACHE CMAKE_BUILD_TYPE + PROPERTY STRINGS + "Debug" + "Release" + "RelWithDebInfo") +endif() + +# Compile commands for ClangTidy et. al +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Link time optimization +# Turning this on disables debugging +option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF) +if(ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + if(result) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + message(STATUS "IPO enabled.") + else() + message(WARNING "IPO is not supported: ${output}") + endif() +endif() + +# Set minimum Boost version +set(BOOST_MIN_VERSION "1.75.0") + +# Use C++23 +set(CMAKE_CXX_STANDARD 23) +set(CMAKE_CXX_STANDARD_REQUIRED ON) +set(CMAKE_CXX_EXTENSIONS OFF) + +# Turn on / off TBB +set(TBB_ON ON) + +# Threads +set(CMAKE_THREAD_PREFER_PTHREAD TRUE) + +# Turn off CGAL Triangulation Assertions and Postconditions, fix https://gitlab.com/libeigen/eigen/-/issues/1894 +add_definitions(-DCGAL_TRIANGULATION_NO_ASSERTIONS -DCGAL_TRIANGULATION_NO_POSTCONDITIONS -D_HAS_DEPRECATED_RESULT_OF=1 -DEIGEN_HAS_STD_RESULT_OF=0 -DCGAL_USE_GMP=ON -DCGAL_USE_MPFR=ON -DCGAL_DO_NOT_USE_BOOST_MP=ON) + +# Easier navigation in an IDE when projects are organized in folders. +set_property(GLOBAL PROPERTY USE_FOLDERS ON) + +# Deal with UTF-8 encoding +if (MSVC) + add_compile_options(/utf-8) +else() + add_compile_options(-finput-charset=UTF-8) +endif() diff --git a/cmake/StaticAnalyzers.cmake b/cmake/StaticAnalyzers.cmake new file mode 100644 index 0000000000..5e0edf68a6 --- /dev/null +++ b/cmake/StaticAnalyzers.cmake @@ -0,0 +1,22 @@ +option(ENABLE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) +option(ENABLE_INCLUDE_WHAT_YOU_USE "Enable static analysis with include-what-you-use" OFF) + +if(ENABLE_CLANG_TIDY) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} -extra-arg=-Wno-unknown-warning-option) + message(STATUS "Clang-tidy enabled.") + else() + message(SEND_ERROR "clang-tidy requested but executable not found") + endif() +endif() + +if(ENABLE_INCLUDE_WHAT_YOU_USE) + find_program(INCLUDE_WHAT_YOU_USE include-what-you-use) + if(INCLUDE_WHAT_YOU_USE) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE}) + message(STATUS "Include-what-you-use enabled.") + else() + message(SEND_ERROR "include-what-you-use requested but executable not found") + endif() +endif() diff --git a/config/publish-doxygen b/config/publish-doxygen deleted file mode 100755 index de686a0986..0000000000 --- a/config/publish-doxygen +++ /dev/null @@ -1,31 +0,0 @@ -#!/bin/bash -e - -# Settings -REPO_PATH=git@github.com:acgetchell/CDT-plusplus.git -HTML_PATH=html -COMMIT_USER="Documentation Builder" -COMMIT_EMAIL="acgetchell@ucdavis.edu" -CHANGESET=$(git rev-parse --verify HEAD) - -# Get a clean version of the HTML documentation repo. -rm -rf ${HTML_PATH} -mkdir -p ${HTML_PATH} -git clone -b gh-pages "${REPO_PATH}" --single-branch ${HTML_PATH} - -# rm all the files through git to prevent stale files. -cd ${HTML_PATH} -git rm -rf . -cd - - -# Generate the HTML documentation. -doxygen ./config/Doxyfile - -# Create and commit the documentation repo. -cd ${HTML_PATH} -touch .nojekyll -git add . -git config user.name "${COMMIT_USER}" -git config user.email "${COMMIT_EMAIL}" -git commit -m "Automated documentation build for changeset ${CHANGESET}." -git push origin gh-pages -cd - diff --git a/config/travisci_rsa.enc b/config/travisci_rsa.enc deleted file mode 100644 index 6761198fe1..0000000000 Binary files a/config/travisci_rsa.enc and /dev/null differ diff --git a/config/travisci_rsa.pub b/config/travisci_rsa.pub deleted file mode 100644 index e90e3586de..0000000000 --- a/config/travisci_rsa.pub +++ /dev/null @@ -1 +0,0 @@ -ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDgrEwfS94zSjSnRfWn0BOKX4Sm0hpLBVstHqkLt8e/XzZzOd+FTQ+NuK1E11vjpD6SZflm7EXebnXf6Zp1gutXEgMSsQ/Y3IU8mwiEVS23TPB/3bJOS/4NCzCta8AZLuMs4xhN0hLbiRjdetMkl8DgeAaVONueZv4JeGON73u/aeBg2tF66tKu+MnnBDdvcGHLG78GtH7nLLZtlxSY7W/w2ulbeXRB3gMXZMsMU58O/pFC0faudcfHSCRKTge2fkJXjh+ig8F4FW0U1GnnYRaCUxvL7ntca6NVQkq/ih51KTy+Mq+j4eOid0JqgIlJuxTf1iKEDjGWtAWJcTqrotIz acgetchell@ucdavis.edu diff --git a/cppcheck-build.sh b/cppcheck-build.sh deleted file mode 100755 index 3af42dcb47..0000000000 --- a/cppcheck-build.sh +++ /dev/null @@ -1,9 +0,0 @@ -#! /bin/bash -rm -rf build/ -mkdir build -cd build -cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_EXPORT_COMPILE_COMMANDS=ON .. -ninja -cppcheck --project=compile_commands.json --enable=all --force -cd .. - diff --git a/config/Doxyfile b/docs/Doxyfile similarity index 88% rename from config/Doxyfile rename to docs/Doxyfile index 77376d1c33..aac422d285 100644 --- a/config/Doxyfile +++ b/docs/Doxyfile @@ -1,4 +1,4 @@ -# Doxyfile 1.8.9.1 +# Doxyfile 1.8.16 # This file describes the settings to be used by the documentation system # doxygen (www.doxygen.org) for a project. @@ -17,11 +17,11 @@ # Project related configuration options #--------------------------------------------------------------------------- -# This tag specifies the encoding used for all characters in the config file -# that follow. The default is UTF-8 which is also the encoding used for all text -# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv -# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv -# for the list of possible encodings. +# This tag specifies the encoding used for all characters in the configuration +# file that follow. The default is UTF-8 which is also the encoding used for all +# text before the first occurrence of this tag. Doxygen uses libiconv (or the +# iconv built into libc) for the transcoding. See +# https://www.gnu.org/software/libiconv/ for the list of possible encodings. # The default value is: UTF-8. DOXYFILE_ENCODING = UTF-8 @@ -44,7 +44,7 @@ PROJECT_NUMBER = # for a project that appears at the top of each page and should give viewer a # quick idea about the purpose of the project. Keep the description short. -PROJECT_BRIEF = "Causal Dynamical Triangulations in C++ using CGAL" +PROJECT_BRIEF = "Causal Dynamical Triangulations in C++" # With the PROJECT_LOGO tag one can specify a logo or an icon that is included # in the documentation. The maximum height of the logo should not exceed 55 @@ -58,7 +58,7 @@ PROJECT_LOGO = # entered, it will be relative to the location where doxygen was started. If # left blank the current directory will be used. -OUTPUT_DIRECTORY = +OUTPUT_DIRECTORY = docs # If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub- # directories (in 2 levels) under the output directory of each output format and @@ -93,6 +93,14 @@ ALLOW_UNICODE_NAMES = NO OUTPUT_LANGUAGE = English +# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all +# documentation generated by doxygen is written. Doxygen will use this +# information to generate all generated output in the proper direction. +# Possible values are: None, LTR, RTL and Context. +# The default value is: None. + +OUTPUT_TEXT_DIRECTION = None + # If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member # descriptions after the members that are listed in the file and class # documentation (similar to Javadoc). Set to NO to disable this. @@ -118,7 +126,17 @@ REPEAT_BRIEF = YES # the entity):The $name class, The $name widget, The $name file, is, provides, # specifies, contains, represents, a, an and the. -ABBREVIATE_BRIEF = +ABBREVIATE_BRIEF = "The $name class" \ + "The $name widget" \ + "The $name file" \ + is \ + provides \ + specifies \ + contains \ + represents \ + a \ + an \ + the # If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then # doxygen will generate a detailed section even if there is only a brief @@ -133,7 +151,7 @@ ALWAYS_DETAILED_SEC = NO # operators of the base classes will not be shown. # The default value is: NO. -INLINE_INHERITED_MEMB = NO +INLINE_INHERITED_MEMB = YES # If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path # before files name in the file list and in the header files. If set to NO the @@ -179,6 +197,16 @@ SHORT_NAMES = NO JAVADOC_AUTOBRIEF = NO +# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line +# such as +# /*************** +# as being the beginning of a Javadoc-style comment "banner". If set to NO, the +# Javadoc-style will behave just like regular comments and it will not be +# interpreted by doxygen. +# The default value is: NO. + +JAVADOC_BANNER = NO + # If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first # line (until the first dot) of a Qt-style comment as the brief description. If # set to NO, the Qt-style will behave just like regular Qt-style comments (thus @@ -226,9 +254,14 @@ TAB_SIZE = 4 # will allow you to put the command \sideeffect (or @sideeffect) in the # documentation, which will result in a user-defined paragraph with heading # "Side Effects:". You can put \n's in the value part of an alias to insert -# newlines. +# newlines (in the resulting output). You can put ^^ in the value part of an +# alias to insert a newline as if a physical newline was in the original file. +# When you need a literal { or } or , in the value part of an alias you have to +# escape them by means of a backslash (\), this can lead to conflicts with the +# commands \{ and \} for these it is advised to use the version @{ and @} or use +# a double escape (\\{ and \\}) -ALIASES = "done=\xrefitem done \"Implemented To-do's\"\"Implemented To-do's\" " +ALIASES = # This tag can be used to specify a number of word-keyword mappings (TCL only). # A mapping has the form "name=value". For example adding "class=itcl::class" @@ -264,17 +297,26 @@ OPTIMIZE_FOR_FORTRAN = NO OPTIMIZE_OUTPUT_VHDL = NO +# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice +# sources only. Doxygen will then generate output that is more tailored for that +# language. For instance, namespaces will be presented as modules, types will be +# separated into more groups, etc. +# The default value is: NO. + +OPTIMIZE_OUTPUT_SLICE = NO + # Doxygen selects the parser to use depending on the extension of the files it # parses. With this tag you can assign which parser to use for a given # extension. Doxygen has a built-in mapping, but you can override or extend it # using this tag. The format is ext=language, where ext is a file extension, and # language is one of the parsers supported by doxygen: IDL, Java, Javascript, -# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran: -# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran: -# Fortran. In the later case the parser tries to guess whether the code is fixed -# or free formatted code, this is the default for Fortran type files), VHDL. For -# instance to make doxygen treat .inc files as Fortran files (default is PHP), -# and .f files as C (default is Fortran), use: inc=Fortran f=C. +# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice, +# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran: +# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser +# tries to guess whether the code is fixed or free formatted code, this is the +# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat +# .inc files as Fortran files (default is PHP), and .f files as C (default is +# Fortran), use: inc=Fortran f=C. # # Note: For files without extension you can use no_extension as a placeholder. # @@ -285,7 +327,7 @@ EXTENSION_MAPPING = # If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments # according to the Markdown format, which allows for more readable -# documentation. See http://daringfireball.net/projects/markdown/ for details. +# documentation. See https://daringfireball.net/projects/markdown/ for details. # The output of markdown processing is further processed by doxygen, so you can # mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in # case of backward compatibilities issues. @@ -293,6 +335,15 @@ EXTENSION_MAPPING = MARKDOWN_SUPPORT = YES +# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up +# to that level are automatically included in the table of contents, even if +# they do not have an id attribute. +# Note: This feature currently applies only to Markdown headings. +# Minimum value: 0, maximum value: 99, default value: 5. +# This tag requires that the tag MARKDOWN_SUPPORT is set to YES. + +TOC_INCLUDE_HEADINGS = 5 + # When enabled doxygen tries to link words that correspond to documented # classes, or namespaces to their corresponding documentation. Such a link can # be prevented in individual cases by putting a % sign in front of the word or @@ -318,7 +369,7 @@ BUILTIN_STL_SUPPORT = YES CPP_CLI_SUPPORT = NO # Set the SIP_SUPPORT tag to YES if your project consists of sip (see: -# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen +# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen # will parse them like normal C++ but will assume all classes use public instead # of private inheritance when no explicit protection keyword is present. # The default value is: NO. @@ -343,6 +394,13 @@ IDL_PROPERTY_SUPPORT = YES DISTRIBUTE_GROUP_DOC = NO +# If one adds a struct or class to a group and this option is enabled, then also +# any nested class or struct is added to the same group. By default this option +# is disabled and one has to add nested compounds explicitly via \ingroup. +# The default value is: NO. + +GROUP_NESTED_COMPOUNDS = NO + # Set the SUBGROUPING tag to YES to allow class member groups of the same type # (for instance a group of public functions) to be put as a subgroup of that # type (e.g. under the Public Functions section). Set it to NO to prevent @@ -361,7 +419,7 @@ SUBGROUPING = YES # SEPARATE_MEMBER_PAGES. # The default value is: NO. -INLINE_GROUPED_CLASSES = NO +INLINE_GROUPED_CLASSES = YES # When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions # with only public data fields or simple typedef fields will be shown inline in @@ -417,6 +475,12 @@ EXTRACT_ALL = NO EXTRACT_PRIVATE = YES +# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual +# methods of a class will be included in the documentation. +# The default value is: NO. + +EXTRACT_PRIV_VIRTUAL = YES + # If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal # scope will be included in the documentation. # The default value is: NO. @@ -495,7 +559,7 @@ INTERNAL_DOCS = NO # names in lower-case letters. If set to YES, upper-case letters are also # allowed. This is useful if you have classes or files whose names only differ # in case and if your file system supports case sensitive file names. Windows -# and Mac users are advised to set this option to NO. +# (including Cygwin) ands Mac users are advised to set this option to NO. # The default value is: system dependent. CASE_SENSE_NAMES = NO @@ -682,7 +746,7 @@ LAYOUT_FILE = # The CITE_BIB_FILES tag can be used to specify one or more bib files containing # the reference definitions. This must be a list of .bib files. The .bib # extension is automatically appended if omitted. This requires the bibtex tool -# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info. +# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info. # For LaTeX the style of the bibliography can be controlled using # LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the # search path. See also \cite for info how to create references. @@ -727,11 +791,18 @@ WARN_IF_DOC_ERROR = YES # This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that # are documented, but have no documentation for their parameters or return # value. If set to NO, doxygen will only warn about wrong or incomplete -# parameter documentation, but not about the absence of documentation. +# parameter documentation, but not about the absence of documentation. If +# EXTRACT_ALL is set to YES then this flag will automatically be disabled. # The default value is: NO. WARN_NO_PARAMDOC = NO +# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when +# a warning is encountered. +# The default value is: NO. + +WARN_AS_ERROR = NO + # The WARN_FORMAT tag determines the format of the warning messages that doxygen # can produce. The string should contain the $file, $line, and $text tags, which # will be replaced by the file and line number from which the warning originated @@ -755,7 +826,7 @@ WARN_LOGFILE = # The INPUT tag is used to specify the files and/or directories that contain # documented source files. You may enter file names like myfile.cpp or # directories like /usr/src/myproject. Separate the files or directories with -# spaces. +# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING # Note: If this tag is empty the current directory is searched. INPUT = @@ -763,7 +834,7 @@ INPUT = # This tag can be used to specify the character encoding of the source files # that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses # libiconv (or the iconv built into libc) for the transcoding. See the libiconv -# documentation (see: http://www.gnu.org/software/libiconv) for the list of +# documentation (see: https://www.gnu.org/software/libiconv/) for the list of # possible encodings. # The default value is: UTF-8. @@ -771,14 +842,63 @@ INPUT_ENCODING = UTF-8 # If the value of the INPUT tag contains directories, you can use the # FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and -# *.h) to filter out the source-files in the directories. If left blank the -# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii, -# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp, -# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown, -# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, -# *.qsf, *.as and *.js. - -FILE_PATTERNS = +# *.h) to filter out the source-files in the directories. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# read by doxygen. +# +# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp, +# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, +# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, +# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08, +# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice. + +FILE_PATTERNS = *.c \ + *.cc \ + *.cxx \ + *.cpp \ + *.c++ \ + *.java \ + *.ii \ + *.ixx \ + *.ipp \ + *.i++ \ + *.inl \ + *.idl \ + *.ddl \ + *.odl \ + *.h \ + *.hh \ + *.hxx \ + *.hpp \ + *.h++ \ + *.cs \ + *.d \ + *.php \ + *.php4 \ + *.php5 \ + *.phtml \ + *.inc \ + *.m \ + *.markdown \ + *.md \ + *.mm \ + *.dox \ + *.py \ + *.pyw \ + *.f90 \ + *.f95 \ + *.f03 \ + *.f08 \ + *.f \ + *.for \ + *.tcl \ + *.vhd \ + *.vhdl \ + *.ucf \ + *.qsf \ + *.ice # The RECURSIVE tag can be used to specify whether or not subdirectories should # be searched for input files as well. @@ -793,8 +913,12 @@ RECURSIVE = YES # Note that relative paths are relative to the directory from which doxygen is # run. -EXCLUDE = googletest \ - docopt +EXCLUDE = build \ + cmake-build-debug \ + cmake-build-release \ + cmake-build-relwithdebinfo \ + external \ + scripts # The EXCLUDE_SYMLINKS tag can be used to select whether or not files or # directories that are symbolic links (a Unix file system feature) are excluded @@ -810,8 +934,7 @@ EXCLUDE_SYMLINKS = NO # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories for example use the pattern */test/* -EXCLUDE_PATTERNS = */build/* \ - cpplint.py +EXCLUDE_PATTERNS = # The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names # (namespaces, classes, functions, etc.) that should be excluded from the @@ -822,7 +945,7 @@ EXCLUDE_PATTERNS = */build/* \ # Note that the wildcards are matched against the file with absolute path, so to # exclude all test directories use the pattern */test/* -EXCLUDE_SYMBOLS = */docopt/* +EXCLUDE_SYMBOLS = # The EXAMPLE_PATH tag can be used to specify one or more files or directories # that contain example code fragments that are included (see the \include @@ -835,7 +958,7 @@ EXAMPLE_PATH = # *.h) to filter out the source-files in the directories. If left blank all # files are included. -EXAMPLE_PATTERNS = +EXAMPLE_PATTERNS = * # If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be # searched for input files to be used with the \include or \dontinclude commands @@ -848,7 +971,7 @@ EXAMPLE_RECURSIVE = NO # that contain images that are to be included in the documentation (see the # \image command). -IMAGE_PATH = images +IMAGE_PATH = docs/images # The INPUT_FILTER tag can be used to specify a program that doxygen should # invoke to filter for each input file. Doxygen will invoke the filter program @@ -864,6 +987,10 @@ IMAGE_PATH = images # Note that the filter must not add or remove lines; it is applied before the # code is scanned, but not when the output code is generated. If lines are added # or removed, the anchors will not be placed correctly. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. INPUT_FILTER = @@ -873,6 +1000,10 @@ INPUT_FILTER = # (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how # filters are used. If the FILTER_PATTERNS tag is empty or if none of the # patterns match the file name, INPUT_FILTER is applied. +# +# Note that for custom extensions or not directly supported extensions you also +# need to set EXTENSION_MAPPING for the extension otherwise the files are not +# properly processed by doxygen. FILTER_PATTERNS = @@ -925,16 +1056,16 @@ INLINE_SOURCES = NO STRIP_CODE_COMMENTS = YES # If the REFERENCED_BY_RELATION tag is set to YES then for each documented -# function all documented functions referencing it will be listed. +# entity all documented functions referencing it will be listed. # The default value is: NO. -REFERENCED_BY_RELATION = NO +REFERENCED_BY_RELATION = YES # If the REFERENCES_RELATION tag is set to YES then for each documented function # all documented entities called/used by that function will be listed. # The default value is: NO. -REFERENCES_RELATION = NO +REFERENCES_RELATION = YES # If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set # to YES then the hyperlinks from functions in REFERENCES_RELATION and @@ -957,12 +1088,12 @@ SOURCE_TOOLTIPS = YES # If the USE_HTAGS tag is set to YES then the references to source code will # point to the HTML generated by the htags(1) tool instead of doxygen built-in # source browser. The htags tool is part of GNU's global source tagging system -# (see http://www.gnu.org/software/global/global.html). You will need version +# (see https://www.gnu.org/software/global/global.html). You will need version # 4.8.6 or higher. # # To use it do the following: # - Install the latest version of global -# - Enable SOURCE_BROWSER and USE_HTAGS in the config file +# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file # - Make sure the INPUT points to the root of the source tree # - Run doxygen as normal # @@ -984,25 +1115,6 @@ USE_HTAGS = NO VERBATIM_HEADERS = YES -# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the -# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the -# cost of reduced performance. This can be particularly helpful with template -# rich C++ code for which doxygen's built-in parser lacks the necessary type -# information. -# Note: The availability of this option depends on whether or not doxygen was -# compiled with the --with-libclang option. -# The default value is: NO. - -CLANG_ASSISTED_PARSING = YES - -# If clang assisted parsing is enabled you can provide the compiler with command -# line options that you would normally use when invoking the compiler. Note that -# the include paths will already be set by doxygen for the files and directories -# specified with INPUT and INCLUDE_PATH. -# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES. - -CLANG_OPTIONS = - #--------------------------------------------------------------------------- # Configuration options related to the alphabetical class index #--------------------------------------------------------------------------- @@ -1121,7 +1233,7 @@ HTML_EXTRA_FILES = # The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen # will adjust the colors in the style sheet and background images according to # this color. Hue is specified as an angle on a colorwheel, see -# http://en.wikipedia.org/wiki/Hue for more information. For instance the value +# https://en.wikipedia.org/wiki/Hue for more information. For instance the value # 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300 # purple, and 360 is red again. # Minimum value: 0, maximum value: 359, default value: 220. @@ -1150,19 +1262,31 @@ HTML_COLORSTYLE_GAMMA = 80 # If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML # page will contain the date and time when the page was generated. Setting this -# to NO can help when comparing the output of multiple runs. -# The default value is: YES. +# to YES can help to show when doxygen was last run and thus if the +# documentation is up to date. +# The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. HTML_TIMESTAMP = YES +# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML +# documentation will contain a main index with vertical navigation menus that +# are dynamically created via Javascript. If disabled, the navigation index will +# consists of multiple levels of tabs that are statically embedded in every HTML +# page. Disable this option to support browsers that do not have Javascript, +# like the Qt help browser. +# The default value is: YES. +# This tag requires that the tag GENERATE_HTML is set to YES. + +HTML_DYNAMIC_MENUS = YES + # If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML # documentation will contain sections that can be hidden and shown after the # page has loaded. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. -HTML_DYNAMIC_SECTIONS = NO +HTML_DYNAMIC_SECTIONS = YES # With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries # shown in the various tree structured indices initially; the user can expand @@ -1179,13 +1303,13 @@ HTML_INDEX_NUM_ENTRIES = 100 # If the GENERATE_DOCSET tag is set to YES, additional index files will be # generated that can be used as input for Apple's Xcode 3 integrated development -# environment (see: http://developer.apple.com/tools/xcode/), introduced with -# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a +# environment (see: https://developer.apple.com/xcode/), introduced with OSX +# 10.5 (Leopard). To create a documentation set, doxygen will generate a # Makefile in the HTML output directory. Running make will produce the docset in # that directory and running make install will install the docset in # ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at -# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html -# for more information. +# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy +# genXcode/_index.html for more information. # The default value is: NO. # This tag requires that the tag GENERATE_HTML is set to YES. @@ -1213,7 +1337,7 @@ DOCSET_BUNDLE_ID = org.adamgetchell.cdtplusplus # The default value is: org.doxygen.Publisher. # This tag requires that the tag GENERATE_DOCSET is set to YES. -DOCSET_PUBLISHER_ID = org.adamgetchell.cdtplusplus.documentation +DOCSET_PUBLISHER_ID = org.adamgetchell.cdt-plusplus.documentation # The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher. # The default value is: Publisher. @@ -1224,7 +1348,7 @@ DOCSET_PUBLISHER_NAME = adamgetchell.org # If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three # additional HTML index files: index.hhp, index.hhc, and index.hhk. The # index.hhp is a project file that can be read by Microsoft's HTML Help Workshop -# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on +# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on # Windows. # # The HTML Help Workshop contains a compiler that can convert all HTML output @@ -1300,7 +1424,7 @@ QCH_FILE = # The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help # Project output. For more information please see Qt Help Project / Namespace -# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace). +# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace). # The default value is: org.doxygen.Project. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1308,7 +1432,7 @@ QHP_NAMESPACE = org.doxygen.Project # The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt # Help Project output. For more information please see Qt Help Project / Virtual -# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual- +# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual- # folders). # The default value is: doc. # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1317,7 +1441,7 @@ QHP_VIRTUAL_FOLDER = doc # If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom # filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1325,7 +1449,7 @@ QHP_CUST_FILTER_NAME = # The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the # custom filter to add. For more information please see Qt Help Project / Custom -# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom- +# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom- # filters). # This tag requires that the tag GENERATE_QHP is set to YES. @@ -1333,7 +1457,7 @@ QHP_CUST_FILTER_ATTRS = # The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this # project's filter section matches. Qt Help Project / Filter Attributes (see: -# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes). +# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes). # This tag requires that the tag GENERATE_QHP is set to YES. QHP_SECT_FILTER_ATTRS = @@ -1426,7 +1550,7 @@ EXT_LINKS_IN_WINDOW = NO FORMULA_FONTSIZE = 10 -# Use the FORMULA_TRANPARENT tag to determine whether or not the images +# Use the FORMULA_TRANSPARENT tag to determine whether or not the images # generated for formulas are transparent PNGs. Transparent PNGs are not # supported properly for IE 6.0, but are supported on all modern browsers. # @@ -1438,7 +1562,7 @@ FORMULA_FONTSIZE = 10 FORMULA_TRANSPARENT = YES # Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see -# http://www.mathjax.org) which uses client side Javascript for the rendering +# https://www.mathjax.org) which uses client side Javascript for the rendering # instead of using pre-rendered bitmaps. Use this if you do not have LaTeX # installed or if you want to formulas look prettier in the HTML output. When # enabled you may also need to install MathJax separately and configure the path @@ -1465,11 +1589,11 @@ MATHJAX_FORMAT = HTML-CSS # MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax # Content Delivery Network so you can quickly see the result without installing # MathJax. However, it is strongly recommended to install a local copy of -# MathJax from http://www.mathjax.org before deployment. -# The default value is: http://cdn.mathjax.org/mathjax/latest. +# MathJax from https://www.mathjax.org before deployment. +# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/. # This tag requires that the tag USE_MATHJAX is set to YES. -MATHJAX_RELPATH = https://cdn.mathjax.org/mathjax/latest +MATHJAX_RELPATH = https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/ # The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax # extension names that should be enabled during MathJax rendering. For example @@ -1527,7 +1651,7 @@ SERVER_BASED_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). +# Xapian (see: https://xapian.org/). # # See the section "External Indexing and Searching" for details. # The default value is: NO. @@ -1540,7 +1664,7 @@ EXTERNAL_SEARCH = NO # # Doxygen ships with an example indexer (doxyindexer) and search engine # (doxysearch.cgi) which are based on the open source search engine library -# Xapian (see: http://xapian.org/). See the section "External Indexing and +# Xapian (see: https://xapian.org/). See the section "External Indexing and # Searching" for details. # This tag requires that the tag SEARCHENGINE is set to YES. @@ -1592,21 +1716,35 @@ LATEX_OUTPUT = latex # The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be # invoked. # -# Note that when enabling USE_PDFLATEX this option is only used for generating -# bitmaps for formulas in the HTML output, but not in the Makefile that is -# written to the output directory. -# The default file is: latex. +# Note that when not enabling USE_PDFLATEX the default is latex when enabling +# USE_PDFLATEX the default is pdflatex and when in the later case latex is +# chosen this is overwritten by pdflatex. For specific output languages the +# default can have been set differently, this depends on the implementation of +# the output language. # This tag requires that the tag GENERATE_LATEX is set to YES. -LATEX_CMD_NAME = latex +LATEX_CMD_NAME = # The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate # index for LaTeX. +# Note: This tag is used in the Makefile / make.bat. +# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file +# (.tex). # The default file is: makeindex. # This tag requires that the tag GENERATE_LATEX is set to YES. MAKEINDEX_CMD_NAME = makeindex +# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to +# generate index for LaTeX. In case there is no backslash (\) as first character +# it will be automatically added in the LaTeX code. +# Note: This tag is used in the generated output file (.tex). +# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat. +# The default value is: makeindex. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_MAKEINDEX_CMD = makeindex + # If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX # documents. This may be useful for small projects and may help to save some # trees in general. @@ -1625,9 +1763,12 @@ COMPACT_LATEX = NO PAPER_TYPE = letter # The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names -# that should be included in the LaTeX output. To get the times font for -# instance you can specify -# EXTRA_PACKAGES=times +# that should be included in the LaTeX output. The package can be specified just +# by its name or with the correct syntax as to be used with the LaTeX +# \usepackage command. To get the times font for instance you can specify : +# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times} +# To use the option intlimits with the amsmath package you can specify: +# EXTRA_PACKAGES=[intlimits]{amsmath} # If left blank no extra packages will be included. # This tag requires that the tag GENERATE_LATEX is set to YES. @@ -1724,12 +1865,28 @@ LATEX_SOURCE_CODE = YES # The LATEX_BIB_STYLE tag can be used to specify the style to use for the # bibliography, e.g. plainnat, or ieeetr. See -# http://en.wikipedia.org/wiki/BibTeX and \cite for more info. +# https://en.wikipedia.org/wiki/BibTeX and \cite for more info. # The default value is: plain. # This tag requires that the tag GENERATE_LATEX is set to YES. LATEX_BIB_STYLE = ieeetr +# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated +# page will contain the date and time when the page was generated. Setting this +# to NO can help when comparing the output of multiple runs. +# The default value is: NO. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_TIMESTAMP = NO + +# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute) +# path from which the emoji images will be read. If a relative path is entered, +# it will be relative to the LATEX_OUTPUT directory. If left blank the +# LATEX_OUTPUT directory will be used. +# This tag requires that the tag GENERATE_LATEX is set to YES. + +LATEX_EMOJI_DIRECTORY = + #--------------------------------------------------------------------------- # Configuration options related to the RTF output #--------------------------------------------------------------------------- @@ -1769,9 +1926,9 @@ COMPACT_RTF = NO RTF_HYPERLINKS = NO -# Load stylesheet definitions from file. Syntax is similar to doxygen's config -# file, i.e. a series of assignments. You only have to provide replacements, -# missing definitions are set to their default value. +# Load stylesheet definitions from file. Syntax is similar to doxygen's +# configuration file, i.e. a series of assignments. You only have to provide +# replacements, missing definitions are set to their default value. # # See also section "Doxygen usage" for information on how to generate the # default style sheet that doxygen normally uses. @@ -1780,8 +1937,8 @@ RTF_HYPERLINKS = NO RTF_STYLESHEET_FILE = # Set optional variables used in the generation of an RTF document. Syntax is -# similar to doxygen's config file. A template extensions file can be generated -# using doxygen -e rtf extensionFile. +# similar to doxygen's configuration file. A template extensions file can be +# generated using doxygen -e rtf extensionFile. # This tag requires that the tag GENERATE_RTF is set to YES. RTF_EXTENSIONS_FILE = @@ -1867,6 +2024,13 @@ XML_OUTPUT = xml XML_PROGRAMLISTING = YES +# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include +# namespace members in file scope as well, matching the HTML output. +# The default value is: NO. +# This tag requires that the tag GENERATE_XML is set to YES. + +XML_NS_MEMB_FILE_SCOPE = NO + #--------------------------------------------------------------------------- # Configuration options related to the DOCBOOK output #--------------------------------------------------------------------------- @@ -1899,9 +2063,9 @@ DOCBOOK_PROGRAMLISTING = NO #--------------------------------------------------------------------------- # If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an -# AutoGen Definitions (see http://autogen.sf.net) file that captures the -# structure of the code including all documentation. Note that this feature is -# still experimental and incomplete at the moment. +# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures +# the structure of the code including all documentation. Note that this feature +# is still experimental and incomplete at the moment. # The default value is: NO. GENERATE_AUTOGEN_DEF = NO @@ -2068,12 +2232,6 @@ EXTERNAL_GROUPS = YES EXTERNAL_PAGES = YES -# The PERL_PATH should be the absolute path and name of the perl script -# interpreter (i.e. the result of 'which perl'). -# The default file (with absolute path) is: /usr/bin/perl. - -PERL_PATH = /usr/bin/perl - #--------------------------------------------------------------------------- # Configuration options related to the dot tool #--------------------------------------------------------------------------- @@ -2087,15 +2245,6 @@ PERL_PATH = /usr/bin/perl CLASS_DIAGRAMS = YES -# You can define message sequence charts within doxygen comments using the \msc -# command. Doxygen will then run the mscgen tool (see: -# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the -# documentation. The MSCGEN_PATH tag allows you to specify the directory where -# the mscgen tool resides. If left empty the tool is assumed to be found in the -# default search path. - -MSCGEN_PATH = - # You can include diagrams made with dia in doxygen documentation. Doxygen will # then run dia to produce the diagram and insert it in the documentation. The # DIA_PATH tag allows you to specify the directory where the dia binary resides. @@ -2203,7 +2352,7 @@ UML_LIMIT_NUM_FIELDS = 10 # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -TEMPLATE_RELATIONS = NO +TEMPLATE_RELATIONS = YES # If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to # YES then doxygen will generate a graph for each documented file showing the @@ -2228,7 +2377,8 @@ INCLUDED_BY_GRAPH = YES # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable call graphs for selected -# functions only using the \callgraph command. +# functions only using the \callgraph command. Disabling a call graph can be +# accomplished by means of the command \hidecallgraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2239,7 +2389,8 @@ CALL_GRAPH = NO # # Note that enabling this option will significantly increase the time of a run. # So in most cases it will be better to enable caller graphs for selected -# functions only using the \callergraph command. +# functions only using the \callergraph command. Disabling a caller graph can be +# accomplished by means of the command \hidecallergraph. # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. @@ -2262,15 +2413,19 @@ GRAPHICAL_HIERARCHY = YES DIRECTORY_GRAPH = YES # The DOT_IMAGE_FORMAT tag can be used to set the image format of the images -# generated by dot. +# generated by dot. For an explanation of the image formats see the section +# output formats in the documentation of the dot tool (Graphviz (see: +# http://www.graphviz.org/)). # Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order # to make the SVG files visible in IE 9+ (other browsers do not have this # requirement). -# Possible values are: png, jpg, gif and svg. +# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo, +# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and +# png:gdiplus:gdiplus. # The default value is: png. # This tag requires that the tag HAVE_DOT is set to YES. -DOT_IMAGE_FORMAT = png +DOT_IMAGE_FORMAT = svg # If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to # enable generation of interactive SVG images that allow zooming and panning. @@ -2282,7 +2437,7 @@ DOT_IMAGE_FORMAT = png # The default value is: NO. # This tag requires that the tag HAVE_DOT is set to YES. -INTERACTIVE_SVG = NO +INTERACTIVE_SVG = YES # The DOT_PATH tag can be used to specify the path where the dot tool can be # found. If left blank, it is assumed the dot tool can be found in the path. @@ -2317,6 +2472,11 @@ DIAFILE_DIRS = PLANTUML_JAR_PATH = +# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a +# configuration file for plantuml. + +PLANTUML_CFG_FILE = + # When using plantuml, the specified paths are searched for files specified by # the !include statement in a plantuml block. diff --git a/images/26.eps b/docs/images/26.eps old mode 100644 new mode 100755 similarity index 100% rename from images/26.eps rename to docs/images/26.eps diff --git a/images/26.png b/docs/images/26.png old mode 100644 new mode 100755 similarity index 100% rename from images/26.png rename to docs/images/26.png diff --git a/docs/images/44.png b/docs/images/44.png new file mode 100644 index 0000000000..e6d3adcb8d Binary files /dev/null and b/docs/images/44.png differ diff --git a/docs/images/S3-7-27528-I1-R1.png b/docs/images/S3-7-27528-I1-R1.png new file mode 100644 index 0000000000..a510b34566 Binary files /dev/null and b/docs/images/S3-7-27528-I1-R1.png differ diff --git a/docs/images/t8-v68-s298.png b/docs/images/t8-v68-s298.png new file mode 100755 index 0000000000..d3e04b74b0 Binary files /dev/null and b/docs/images/t8-v68-s298.png differ diff --git a/include/Apply_move.hpp b/include/Apply_move.hpp new file mode 100644 index 0000000000..48cd327580 --- /dev/null +++ b/include/Apply_move.hpp @@ -0,0 +1,52 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2019 Adam Getchell + ******************************************************************************/ + +/// @file Apply_move.hpp +/// @brief Apply Pachner moves to foliated Delaunay triangulations +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_APPLY_MOVE_HPP +#define CDT_PLUSPLUS_APPLY_MOVE_HPP + +#include + +#include +#include +#include +#include +#include + +/** + * \brief An applicative function similar to std::apply on a manifold + * \tparam ManifoldType The type (topology, dimensionality) of manifold + * \tparam ExpectedType The result type of the move on the manifold + * \tparam FunctionType The type of move applied to the manifold + * \param t_manifold The manifold on which to make the Pachner move + * \param t_move The Pachner move + * \return The expected or unexpected result in a std::expected + */ +template , + typename FunctionType = + boost::compat::function_ref> +auto constexpr apply_move(ManifoldType&& t_manifold, FunctionType t_move) + -> decltype(auto) +{ + if (auto result = std::invoke(t_move, std::forward(t_manifold)); + result.has_value()) + { + return result; + } + else // NOLINT + { + // Log errors + spdlog::debug("apply_move called.\n"); + spdlog::debug("{}", result.error()); + return result; + } +} + +#endif // CDT_PLUSPLUS_APPLY_MOVE_HPP diff --git a/include/Ergodic_moves_3.hpp b/include/Ergodic_moves_3.hpp new file mode 100644 index 0000000000..68e4c717ac --- /dev/null +++ b/include/Ergodic_moves_3.hpp @@ -0,0 +1,1012 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2019 Adam Getchell + ******************************************************************************/ + +/// @file Ergodic_moves_3.hpp +/// @brief Pachner moves on 2+1 dimensional foliated Delaunay triangulations +/// @author Adam Getchell +/// @details Pachner moves operate on the level of the Manifold_3. +/// The helper functions for the moves operate on the level of the +/// Delaunay_Triangulation_3. +/// C++23 support is required for std::expected. + +#ifndef CDT_PLUSPLUS_ERGODIC_MOVES_3_HPP +#define CDT_PLUSPLUS_ERGODIC_MOVES_3_HPP + +#include + +#include "Formatters.hpp" +#include "Manifold.hpp" +#include "Move_tracker.hpp" + +namespace ergodic_moves +{ + using Manifold = manifolds::Manifold_3; + using Expected = std::expected; + using Cell_handle = Cell_handle_t<3>; + using Cell_container = std::vector; + using Edge_handle = Edge_handle_t<3>; + using Edge_container = std::vector; + using Vertex_handle = Vertex_handle_t<3>; + using Vertex_container = std::vector; + using Delaunay = Delaunay_t<3>; + + namespace detail + { + /// @brief Check an edge handle without dereferencing its cell handle. + /// @details A tetrahedral cell has four local vertex indices in [0, 4). + [[nodiscard]] inline auto is_well_formed_edge( + Edge_handle const& edge) noexcept -> bool + { + static auto constexpr vertex_count = Int_precision{4}; + auto const valid_index = [](Int_precision const index) { + return index >= 0 && index < vertex_count; + }; + + return edge.first != nullptr && valid_index(edge.second) && + valid_index(edge.third) && edge.second != edge.third; + } + } // namespace detail + + /// @brief Perform a null move + /// + /// @param t_manifold The simplicial manifold + /// @returns The null-moved manifold + [[nodiscard]] inline auto null_move(Manifold const& t_manifold) noexcept + -> Expected + { return t_manifold; } // null_move + + /// @brief Perform a TriangulationDataStructure_3::flip on a facet + /// @param t_manifold The manifold containing the cell to flip + /// @param to_be_moved The cell on which to try the move + /// @returns True if move succeeded + /// @see + /// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#a2ad2941984c1eac5561665700bfd60b4 + [[nodiscard]] inline auto try_23_move(Manifold& t_manifold, + Cell_handle const& to_be_moved) -> bool + { + if (to_be_moved->info() != 22) { return false; } // NOLINT + auto& triangulation = t_manifold.triangulation(); + auto flipped = false; + // Try every facet of the (2,2) cell + for (auto i = 0; i < 4; ++i) + { + auto const neighbor = to_be_moved->neighbor(i); + if (triangulation.is_infinite(neighbor)) { continue; } + + // A causal (2,3) move must replace the facet with a timelike edge. + // CGAL also permits topological flips that create a spacelike edge. + auto const mirror_index = neighbor->index(to_be_moved); + auto const first_time = + static_cast(to_be_moved->vertex(i)->info()); + auto const second_time = + static_cast(neighbor->vertex(mirror_index)->info()); + auto const time_difference = first_time > second_time + ? first_time - second_time + : second_time - first_time; + if (time_difference != 1) { continue; } + + if (triangulation.flip(to_be_moved, i)) + { +#ifndef NDEBUG + spdlog::trace("Facet {} was flippable.\n", i); +#endif + flipped = true; + break; + } +#ifndef NDEBUG + spdlog::trace("Facet {} was not flippable.\n", i); +#endif + } + return flipped; + } // try_23_move + + /// @brief Perform a (2,3) move + /// + /// A (2,3) move "flips" a timelike face into a timelike edge. + /// This adds a (2,2) simplex and a timelike edge. + /// + /// This function calls try_23_move on (2,2) simplices drawn from a + /// randomly shuffled container until it succeeds or runs out of simplices. + /// + /// If successful, the triangulation is no longer Delaunay. + /// + /// @param t_manifold The simplicial manifold + /// @returns The Expected (2,3) moved manifold or an Unexpected + [[nodiscard]] inline auto do_23_move(Manifold& t_manifold) -> Expected + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + + auto two_two = t_manifold.get_triangulation().get_two_two(); + // Shuffle the container to create a random sequence of (2,2) cells + std::ranges::shuffle(two_two, utilities::make_random_generator()); + // Try a (2,3) move on successive cells in the sequence + if (std::ranges::any_of( + two_two, [&](auto& cell) { return try_23_move(t_manifold, cell); })) + { + return t_manifold; + } + // We've run out of (2,2) cells + std::string const msg = "No (2,3) move possible.\n"; + spdlog::warn(msg); + return std::unexpected(msg); + } + + /// @brief Perform a TriangulationDataStructure_3::flip on an edge + /// @param t_manifold The manifold containing the edge to flip + /// @param to_be_moved The edge on which to try the move + /// @returns True if move succeeded + /// @see + /// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#a5837d666e4198f707f862003c1ffa033 + [[nodiscard]] inline auto try_32_move(Manifold& t_manifold, + Edge_handle const& to_be_moved) -> bool + { + return t_manifold.triangulation().flip( + to_be_moved.first, to_be_moved.second, to_be_moved.third); + } // try_32_move + + /// @brief Perform a (3,2) move + /// @details A (3,2) move "flips" a timelike edge into a timelike face. + /// This removes a (2,2) simplex and the timelike edge. + /// This function calls try_32_move on timelike edges drawn from a + /// randomly shuffled container until it succeeds or runs out of edges. + /// If successful, the triangulation is no longer Delaunay. + /// @param t_manifold The simplicial manifold + /// @returns The Expected (3,2) moved manifold or an Unexpected + [[nodiscard]] inline auto do_32_move(Manifold& t_manifold) -> Expected + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + auto timelike_edges = t_manifold.get_timelike_edges(); + // Shuffle the container to create a random sequence of edges + std::ranges::shuffle(timelike_edges, utilities::make_random_generator()); + // Try a (3,2) move on successive timelike edges in the sequence + if (std::ranges::any_of(timelike_edges, [&](auto& edge) { + return try_32_move(t_manifold, edge); + })) + { + return t_manifold; + } + // We've run out of edges to try + std::string const msg = "No (3,2) move possible.\n"; + spdlog::warn(msg); + return std::unexpected(msg); + } // do_32_move() + + /// @brief Find a (2,6) move location + /// @details This function checks to see if a (2,6) move is possible. Starting + /// with a (1,3) simplex, it checks neighbors for a (3,1) simplex. + /// @param t_cell The (1,3) simplex that is checked + /// @returns The integer of the neighboring (3,1) simplex or nullopt + [[nodiscard]] inline auto find_adjacent_31_cell(Cell_handle const& t_cell) + -> std::optional + { + if (t_cell->info() != 13) { return std::nullopt; } // NOLINT + for (auto i = 0; i < 4; ++i) + { +#ifndef NDEBUG + spdlog::trace("Neighbor {} is of type {}\n", i, + t_cell->neighbor(i)->info()); +#endif + if (foliated_triangulations::expected_cell_type<3>(t_cell->neighbor(i)) == + Cell_type::THREE_ONE) + { + return std::make_optional(i); + } + } + return std::nullopt; + } // find_26_move() + + /// @brief Perform a (2,6) move + /// @details A (2,6) move inserts a vertex into the spacelike face between a + /// (1,3) simplex on the bottom connected to a (3,1) simplex on top. + /// This adds 2 (1,3) simplices and 2 (3,1) simplices. + /// It adds 2 spacelike faces and 6 timelike faces. + /// It also adds 2 timelike edges and 3 spacelike edges, as well as the + /// vertex. + /// This function calls find_adjacent_31_cell on (1,3) simplices drawn from a + /// randomly shuffled container until it succeeds or runs out of simplices. + /// If successful, the triangulation is no longer Delaunay. + /// @image html 26.png + /// @image latex 26.eps width=7cm + /// @param t_manifold The simplicial manifold + /// @returns The Expected (2,6) moved manifold or an Unexpected + [[nodiscard]] inline auto do_26_move(Manifold& t_manifold) -> Expected + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + static auto constexpr INCIDENT_CELLS_FOR_6_2_MOVE = 6; + auto one_three = t_manifold.get_triangulation().get_one_three(); + // Shuffle the container to pick a random sequence of (1,3) cells to try + std::ranges::shuffle(one_three, utilities::make_random_generator()); + for (auto const& bottom : one_three) + { + if (auto neighboring_31_index = find_adjacent_31_cell(bottom); + neighboring_31_index) + { +#ifndef NDEBUG + spdlog::trace("neighboring_31_index is {}.\n", *neighboring_31_index); +#endif + Cell_handle const top = bottom->neighbor(neighboring_31_index.value()); + // Calculate the common face with respect to the bottom cell + auto common_face_index = std::numeric_limits::max(); + if (!bottom->has_neighbor(top, common_face_index)) + { + std::string const msg = "Bottom cell does not have a neighbor.\n"; +#ifndef NDEBUG + spdlog::trace(msg); +#endif + return std::unexpected(msg); + } + + // Get indices of vertices of common face with respect to bottom cell + // A face is denoted by the index of the opposite vertex + // Thus, the indices of the vertices of the face are all other indices + // except the common_face_index + // CGAL uses bitwise operations like (common_face_index +1) & 3 + // We use % 4 which is equivalent and doesn't trigger clang-tidy + auto const i_1 = (common_face_index + 1) % 4; + auto const i_2 = (common_face_index + 2) % 4; + auto const i_3 = (common_face_index + 3) % 4; + + // Get vertices of common face from indices + auto const v_1 = bottom->vertex(i_1); + auto const v_2 = bottom->vertex(i_2); + auto const v_3 = bottom->vertex(i_3); + + // Timeslice of vertices should be same + if (v_1->info() != v_2->info() || v_2->info() != v_3->info()) + { + std::string const msg = "Vertices have different timeslices.\n"; +#ifndef NDEBUG + spdlog::trace(msg); +#endif + return std::unexpected(msg); + } + + // Do the (2,6) move + // Insert new vertex + Vertex_handle const v_center = + t_manifold.triangulation().delaunay().tds().insert_in_facet( + bottom, *neighboring_31_index); + + // Checks + Cell_container incident_cells; + t_manifold.triangulation().delaunay().tds().incident_cells( + v_center, std::back_inserter(incident_cells)); + // the (2,6) center vertex should be bounded by 6 simplices + if (incident_cells.size() != INCIDENT_CELLS_FOR_6_2_MOVE) + { + std::string const msg = + "Center vertex is not bounded by 6 simplices.\n"; +#ifndef NDEBUG + spdlog::trace(msg); +#endif + return std::unexpected(msg); + } + + // Each incident cell should be combinatorially and geometrically valid + if (auto check_cells = + std::ranges::all_of(incident_cells, + [&t_manifold](auto const& cell) { + return t_manifold.get_triangulation() + .get_delaunay() + .tds() + .is_cell(cell); + }); + !check_cells) + { + std::string const msg = "A cell is invalid.\n"; +#ifndef NDEBUG + spdlog::trace(msg); +#endif + return std::unexpected(msg); + } + + // Now assign a geometric point to the center vertex + auto center_point = + CGAL::centroid(v_1->point(), v_2->point(), v_3->point()); +#ifndef NDEBUG + spdlog::trace("Center point is: ({}).\n", + utilities::point_to_str(center_point)); +#endif + v_center->set_point(center_point); + + // Assign a timevalue to the new vertex + auto timevalue = v_1->info(); + v_center->info() = timevalue; + +#ifndef NDEBUG + if (t_manifold.is_vertex(v_center)) + { + spdlog::trace("It's a vertex in the TDS.\n"); + } + else + { + spdlog::trace("It's not a vertex in the TDS.\n"); + } + spdlog::trace("Spacelike face timevalue is {}.\n", timevalue); + spdlog::trace("Inserted vertex ({}) with timevalue {}.\n", + utilities::point_to_str(v_center->point()), + v_center->info()); +#endif + + // Final checks + // is_valid() checks for combinatorial and geometric validity + if (!t_manifold.get_delaunay().tds().is_valid(v_center, true, 1)) + { + std::string const msg = "v_center is invalid.\n"; +#ifndef NDEBUG + spdlog::trace(msg); +#endif + return std::unexpected(msg); + } + + return t_manifold; + } + // Try next cell +#ifndef NDEBUG + spdlog::debug("Cell not insertable.\n"); +#endif + } + // We've run out of (1,3) simplices to try + std::string const msg = "No (2,6) move possible.\n"; + spdlog::warn(msg); + return std::unexpected(msg); + } // do_26_move() + + /// @brief Find a (6,2) move location + /// @details This function checks to see if a (6,2) move is possible. Starting + /// with a vertex, it checks all incident cells. There must be 6 + /// incident cells; 3 should be (3,1) simplices, 3 should be (1,3) simplices, + /// and there should be no (2,2) simplices. + /// @param manifold The simplicial manifold + /// @param candidate The vertex to check + /// @returns True if (6,2) move is possible + [[nodiscard]] inline auto is_62_movable(Manifold const& manifold, + Vertex_handle const& candidate) + -> bool + { + if (manifold.dimensionality() != 3) + { +#ifndef NDEBUG + spdlog::trace("Manifold is not 3-dimensional.\n"); +#endif + return false; + } + + if (!manifold.is_vertex(candidate)) + { +#ifndef NDEBUG + spdlog::trace("Candidate is not a vertex.\n"); +#endif + return false; + } + + // We must have 5 incident edges to have 6 incident cells + if (auto incident_edges = manifold.degree(candidate); + incident_edges != 5) // NOLINT + { +#ifndef NDEBUG + spdlog::trace("Vertex has {} incident edges.\n", incident_edges); +#endif + return false; + } + + // Obtain all incident cells + auto const incident_cells = manifold.incident_cells(candidate); + + // We must have 6 cells incident to the vertex to make a (6,2) move + if (incident_cells.size() != 6) // NOLINT + { +#ifndef NDEBUG + spdlog::trace("Vertex has {} incident cells.\n", incident_cells.size()); +#endif + return false; + } + + // Check that none of the incident cells are infinite + for (auto const& cell : incident_cells) + { + if (manifold.get_triangulation().is_infinite(cell)) + { +#ifndef NDEBUG + spdlog::trace("Cell is infinite.\n"); +#endif + return false; + } + } + + // Run until all vertices are fixed + while (foliated_triangulations::fix_vertices<3>( + manifold.get_delaunay(), manifold.initial_radius(), + manifold.foliation_spacing())) + { + spdlog::warn("Fixing vertices found by is_62_movable().\n"); + } + + // Run until all cells fixed or 50 passes + // for (auto passes = 1; passes < foliated_triangulations::MAX_FIX_PASSES + // + 1; + // ++passes) + // { + // if (!foliated_triangulations::fix_cells<3>(manifold.get_delaunay())) + // { + // break; + // } + // spdlog::warn("Fixing cells found by is_62_movable() pass {}.\n", + // passes); + // } + + auto const incident_31 = foliated_triangulations::filter_cells<3>( + incident_cells, Cell_type::THREE_ONE); + auto const incident_22 = foliated_triangulations::filter_cells<3>( + incident_cells, Cell_type::TWO_TWO); + auto const incident_13 = foliated_triangulations::filter_cells<3>( + incident_cells, Cell_type::ONE_THREE); + + // All cells should be classified + if (incident_13.size() + incident_22.size() + incident_31.size() != + 6) // NOLINT + { + spdlog::warn("Some incident cells on this vertex need to be fixed.\n"); + } + +#ifndef NDEBUG + spdlog::trace( + "Vertex has {} incident cells with {} incident (3,1) simplices and {} " + "incident (2,2) simplices and {} incident (1,3) simplices.\n", + incident_cells.size(), incident_31.size(), incident_22.size(), + incident_13.size()); + foliated_triangulations::debug_print_cells<3>(std::span{incident_cells}); +#endif + return incident_31.size() == 3 && incident_22.empty() && + incident_13.size() == 3; + + } // find_62_moves() + + /// @brief Apply the combinatorial (6,2) retriangulation on a private copy. + /// @details A (3,2) flip of either timelike edge incident to the removable + /// vertex leaves that vertex with degree four. Removing it from its maximal + /// simplex then replaces the original six cells with the required two cells. + /// Keeping both operations in a private copy makes rejection failure-atomic. + /// @param source_triangulation The triangulation containing the candidate + /// @param source_candidate The degree-five vertex to remove + /// @returns The moved triangulation, or nullopt when the topology is not + /// flippable or the result violates a triangulation or causal-cell invariant + [[nodiscard]] inline auto try_62_move(Delaunay const& source_triangulation, + Vertex_handle const source_candidate) + -> std::optional + { + if (!source_triangulation.tds().is_vertex(source_candidate) || + source_triangulation.is_infinite(source_candidate)) + { + return std::nullopt; + } + + auto const candidate_point = source_candidate->point(); + Delaunay triangulation{source_triangulation}; + auto const copied_candidate = + foliated_triangulations::find_vertex<3>(triangulation, candidate_point); + if (!copied_candidate) { return std::nullopt; } + + auto const candidate = *copied_candidate; + auto& tds = triangulation.tds(); + auto const old_cells = triangulation.number_of_finite_cells(); + auto const old_vertices = triangulation.number_of_vertices(); + + Edge_container incident_edges; + triangulation.finite_incident_edges(candidate, + std::back_inserter(incident_edges)); + std::ranges::shuffle(incident_edges, utilities::make_random_generator()); + + auto const is_timelike = [](Edge_handle const& edge) { + auto const first_time = edge.first->vertex(edge.second)->info(); + auto const second_time = edge.first->vertex(edge.third)->info(); + return first_time != second_time; + }; + auto const flipped = std::ranges::any_of( + incident_edges, + [&](auto const& edge) { return is_timelike(edge) && tds.flip(edge); }); + if (!flipped || tds.degree(candidate) != 4 || !tds.is_valid()) + { + return std::nullopt; + } + + tds.remove_from_maximal_dimension_simplex(candidate); + if (!tds.is_valid() || + triangulation.number_of_finite_cells() + 4 != old_cells || + triangulation.number_of_vertices() + 1 != old_vertices) + { + return std::nullopt; + } + + for (auto const cell : triangulation.finite_cell_handles()) + { + auto const type = foliated_triangulations::expected_cell_type<3>(cell); + if (type == Cell_type::ACAUSAL || type == Cell_type::UNCLASSIFIED) + { + return std::nullopt; + } + cell->info() = static_cast(type); + } + + return triangulation; + } // try_62_move() + + /// @brief Perform a (6,2) move + /// @details This function performs a (6,2) move on the given manifold. + /// A (6,2) move removes a vertex which has 3 incident (3,1) simplices + /// and 3 (1,3) simplices for a total of 6 incident simplices exactly. + /// This converts the 3 (1,3) simplices into a single (1,3) simplex on + /// the bottom and the 3 (3,1) simplices into a single (3,1) simplex on + /// top. It thus removes 2 (1,3) simplices, 2 (3,1) simplices, 2 spacelike + /// faces, 6 timelike faces, 3 spacelike edges, 2 timelike edges, and a + /// single vertex. + /// + /// This function calls is_62_movable() on a randomly shuffled container + /// of vertices until it succeeds or runs out of vertices. + /// + /// If successful, the triangulation remains Delaunay. (Other moves may + /// change this, however.) + /// + /// @param t_manifold The simplicial manifold + /// @returns The Expected (6,2) moved manifold or Unexpected + [[nodiscard]] inline auto do_62_move(Manifold& t_manifold) -> Expected + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + auto vertices = t_manifold.get_vertices(); + // Shuffle the container to create a random sequence of vertices + std::ranges::shuffle(vertices, utilities::make_random_generator()); + // Try a (6,2) move on successive vertices in the sequence + for (auto const& vertex : vertices) + { + if (!is_62_movable(t_manifold, vertex)) { continue; } + if (auto moved = try_62_move(t_manifold.get_delaunay(), vertex)) + { + t_manifold.triangulation().delaunay().swap(*moved); + return t_manifold; + } + } + // We've run out of vertices to try + std::string const msg = "No (6,2) move possible.\n"; + spdlog::warn(msg); + return std::unexpected(msg); + } // do_62_move() + + /// @brief Find all cells incident to the edge + /// @param triangulation The Delaunay triangulation + /// @param edge The edge + /// @returns A container of cells incident to the edge or nullopt + /// @see + /// https://github.com/CGAL/cgal/blob/8430d04539179f25fb8e716f99e19d28589beeda/TDS_3/include/CGAL/Triangulation_data_structure_3.h#L2094 + [[nodiscard]] inline auto incident_cells_from_edge( + Delaunay_t<3> const& triangulation, Edge_handle const& edge) + -> std::optional + { + if (!detail::is_well_formed_edge(edge) || + !triangulation.tds().is_edge(edge.first, edge.second, edge.third)) + { + return std::nullopt; + } + // Create the circulator of cells around the edge, starting with the cell + // containing the edge + auto circulator = triangulation.incident_cells(edge, edge.first); + Cell_container incident_cells; + // Add cells to the container until we get back to the first one in the + // circulator + do + { // NOLINT(cppcoreguidelines-avoid-do-while) + // Ignore cells containing the infinite vertex + if (triangulation.is_infinite(circulator)) { continue; } + incident_cells.emplace_back(circulator); + } + while (++circulator != edge.first); +#ifndef NDEBUG + spdlog::trace("Found {} incident cells on edge.\n", incident_cells.size()); +#endif + return incident_cells; + } // incident_cells_from_edge() + + /// @brief Find a bistellar flip location + /// @details This function checks to see if a bistellar flip is possible. + /// Starting with an edge, it checks all incident cells. There must be 4 + /// incident cells; 2 should be (3,1) simplices, 2 should be (1,3) simplices, + /// and there should be no (2,2) simplices. + /// @param triangulation The simplicial manifold + /// @param t_edge_candidate The edge to check + /// @returns A container of incident cells if there are exactly 4 or nullopt + [[nodiscard]] inline auto find_bistellar_flip_location( + Delaunay const& triangulation, Edge_handle const& t_edge_candidate) + -> std::optional + { + if (auto incident_cells = + incident_cells_from_edge(triangulation, t_edge_candidate); + incident_cells.has_value() && incident_cells->size() == 4) + { + auto const cell_type_count = [&](Cell_type const type) { + return std::ranges::count_if(*incident_cells, [&](auto const cell) { + return cell->info() == static_cast(type); + }); + }; + if (cell_type_count(Cell_type::THREE_ONE) == 2 && + cell_type_count(Cell_type::ONE_THREE) == 2) + { + return incident_cells.value(); + } + } + return std::nullopt; + } // find_bistellar_flip_location() + + /// @brief Return a container of cells incident to an edge. + /// @param triangulation The triangulation with the cells. + /// @param edge The edge to find the incident cells of. + /// @returns A container of cells incident to the edge or nullopt + [[nodiscard]] inline auto get_incident_cells(Delaunay const& triangulation, + Edge_handle const edge) + -> std::optional + { + return incident_cells_from_edge(triangulation, edge); + } // get_incident_cells() + + /// @brief Perform a bistellar flip on triangulation via the given edge + /// @details Pass by value to avoid modifying the original triangulation + /// in the event that the flip is unsuccessful. + /// @param source_triangulation The triangulation to flip + /// @param source_edge The edge to pivot on + /// @param source_top Top vertex of the cells being flipped + /// @param source_bottom Bottom vertex of the cells being flipped + /// @returns A flipped triangulation or nullopt + [[nodiscard]] inline auto bistellar_flip(Delaunay const& source_triangulation, + Edge_handle const source_edge, + Vertex_handle const source_top, + Vertex_handle const source_bottom) + -> std::optional + { + if (!detail::is_well_formed_edge(source_edge) || source_top == nullptr || + source_bottom == nullptr || + !source_triangulation.tds().is_edge( + source_edge.first, source_edge.second, source_edge.third) || + !source_triangulation.tds().is_vertex(source_top) || + !source_triangulation.tds().is_vertex(source_bottom) || + source_triangulation.is_infinite(source_top) || + source_triangulation.is_infinite(source_bottom)) + { + return std::nullopt; + } + + // CGAL copy construction duplicates its vertices and cells, invalidating + // all handles from the source triangulation. Capture stable point values, + // then resolve the corresponding handles in the private copy before + // attempting the mutation. + auto const pivot_from_1_point = + source_edge.first->vertex(source_edge.second)->point(); + auto const pivot_from_2_point = + source_edge.first->vertex(source_edge.third)->point(); + auto const top_point = source_top->point(); + auto const bottom_point = source_bottom->point(); + + Delaunay triangulation{source_triangulation}; + auto const pivot_from_1_handle = foliated_triangulations::find_vertex<3>( + triangulation, pivot_from_1_point); + auto const pivot_from_2_handle = foliated_triangulations::find_vertex<3>( + triangulation, pivot_from_2_point); + auto const top_handle = + foliated_triangulations::find_vertex<3>(triangulation, top_point); + auto const bottom_handle = + foliated_triangulations::find_vertex<3>(triangulation, bottom_point); + if (!pivot_from_1_handle || !pivot_from_2_handle || !top_handle || + !bottom_handle) + { + return std::nullopt; + } + + auto const pivot_from_1 = *pivot_from_1_handle; + auto const pivot_from_2 = *pivot_from_2_handle; + auto const top = *top_handle; + auto const bottom = *bottom_handle; + + Cell_handle copied_edge_cell = nullptr; + int copied_edge_first_index{}; + int copied_edge_second_index{}; + if (!triangulation.is_edge(pivot_from_1, pivot_from_2, copied_edge_cell, + copied_edge_first_index, + copied_edge_second_index)) + { + return std::nullopt; + } + Edge_handle const edge{copied_edge_cell, copied_edge_first_index, + copied_edge_second_index}; + + auto const incident_cells = get_incident_cells(triangulation, edge); + if (!incident_cells || incident_cells->size() != 4 || top == bottom || + top == pivot_from_1 || top == pivot_from_2 || bottom == pivot_from_1 || + bottom == pivot_from_2 || + std::ranges::any_of(*incident_cells, [&](auto const& cell) { + return triangulation.is_infinite(cell) || !cell->is_valid(); + })) + { + return std::nullopt; + } + + auto const incident_count = [&](Vertex_handle const vertex) { + return std::ranges::count_if( + *incident_cells, + [&](Cell_handle const cell) { return cell->has_vertex(vertex); }); + }; + if (incident_count(top) != 2 || incident_count(bottom) != 2) + { + return std::nullopt; + } + + // A 3D 4-to-4 bistellar move is the composition of CGAL's checked TDS + // 2-to-3 facet flip and checked 3-to-2 edge flip. The TDS operations are + // intentional: either geometrically checked Triangulation_3 facet flip + // can reject the transient, degenerate intermediate even when the final + // 4-to-4 configuration is valid. Flipping a facet that contains the old + // edge and either boundary vertex creates the new diagonal; the old edge + // then has degree three and can be removed by the second flip. + Cell_handle boundary_facet_cell = nullptr; + int pivot_from_1_index{}; + int pivot_from_2_index{}; + int boundary_index{}; + if (!triangulation.is_facet(pivot_from_1, pivot_from_2, bottom, + boundary_facet_cell, pivot_from_1_index, + pivot_from_2_index, boundary_index)) + { + return std::nullopt; + } + auto constexpr cell_index_sum = 0 + 1 + 2 + 3; + auto const boundary_facet_index = cell_index_sum - pivot_from_1_index - + pivot_from_2_index - boundary_index; + if (!triangulation.tds().flip( + Delaunay::Facet{boundary_facet_cell, boundary_facet_index})) + { + return std::nullopt; + } + + Cell_handle old_edge_cell = nullptr; + int old_edge_first_index{}; + int old_edge_second_index{}; + if (!triangulation.is_edge(pivot_from_1, pivot_from_2, old_edge_cell, + old_edge_first_index, old_edge_second_index) || + !triangulation.tds().flip(Delaunay::Edge{ + old_edge_cell, old_edge_first_index, old_edge_second_index})) + { + return std::nullopt; + } + + if (!triangulation.tds().is_valid()) { return std::nullopt; } + + for (auto const cell : triangulation.finite_cell_handles()) + { + cell->info() = static_cast( + foliated_triangulations::expected_cell_type<3>(cell)); + } + + return triangulation; + } // bistellar_flip() + + /// @return The center edge of a 4-cell complex + [[nodiscard]] inline auto find_pivot_edge(Delaunay const& triangulation, + Edge_container const& edges) + -> std::optional + { + for (auto const& edge : edges) + { + if (auto incident_cells = incident_cells_from_edge(triangulation, edge)) + { +#ifndef NDEBUG + fmt::print("Edge has {} incident finite cells\n", + incident_cells->size()); +#endif + if (incident_cells->size() == 4) { return edge; } + } + } + return std::nullopt; + } // find_pivot_edge() + + /// @brief Return a container of all vertices in a container of cells. + /// @param cells The cells to find the vertices of. + /// @return A container of vertices in the cells + [[nodiscard]] inline auto get_vertices(Cell_container const& cells) + { + std::unordered_set vertices; + auto get_vertices = [&vertices](auto const& cell) { + for (int i = 0; i < 4; ++i) { vertices.emplace(cell->vertex(i)); } + }; + std::ranges::for_each(cells, get_vertices); + Vertex_container result(vertices.begin(), vertices.end()); + return result; + } // get_vertices() + + /// @brief Perform a (4,4) move + /// @details This is a bistellar flip pivoting the internal spacelike edge + /// between the two spacelike faces. + /// A (4,4) move flips an edge which has exactly 4 incident cells. + /// In CDT specifically, the edge is spacelike and the 4 incident cells + /// are a pair of (1,3) simplices and a pair of (3,1) simplices. It thus + /// re-labels each of the 4 cells in the complex, but doesn't actually + /// change the number of cells, vertices, or edges. This move has the + /// effect of mixing up the simplices, thus possibly creating different + /// potential moves in different locations. + /// + /// This function calls is_44_movable() on a randomly shuffled container + /// of edges until it succeeds or runs out of edges. + /// + /// If successful, the triangulation remains combinatorially valid. A CDT + /// move is not required to preserve the Euclidean Delaunay property of the + /// coordinates used to represent the abstract triangulation. + /// + /// @param t_manifold The simplicial manifold + /// @return The Expected (4,4) moved manifold or Unexpected + [[nodiscard]] inline auto do_44_move(Manifold const& t_manifold) -> Expected + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + auto spacelike_edges = t_manifold.get_spacelike_edges(); + // Shuffle the container to pick a random sequence of edges to try + std::ranges::shuffle(spacelike_edges, utilities::make_random_generator()); + for (auto const& edge : spacelike_edges) + { + // Obtain all incident cells + if (auto const incident_cells = find_bistellar_flip_location( + t_manifold.get_triangulation().get_delaunay(), edge); + incident_cells) + { +#ifndef NDEBUG + for (auto const& cell : *incident_cells) + { + spdlog::trace("Incident cell is of type {}.\n", cell->info()); + } +#endif + + // Get edge vertices + auto const& v1 = edge.first->vertex(edge.second); + auto const& v2 = edge.first->vertex(edge.third); + + // Find top and bottom vertices + Vertex_handle top = nullptr; + Vertex_handle bottom = nullptr; + + // Analyze cells to find the top and bottom vertices + for (auto const& cell : *incident_cells) + { + for (int i = 0; i < 4; ++i) + { + auto vertex = cell->vertex(i); + if (vertex != v1 && vertex != v2) + { + // Use timevalue to determine if it's a top or bottom vertex + if (top == nullptr || vertex->info() > top->info()) + { + top = vertex; + } + if (bottom == nullptr || vertex->info() < bottom->info()) + { + bottom = vertex; + } + } + } + } + + // Try the bistellar flip + if (auto flipped_triangulation = + bistellar_flip(t_manifold.get_triangulation().get_delaunay(), + edge, top, bottom); + flipped_triangulation.has_value()) + { + // Create a new foliated triangulation with the flipped Delaunay + // triangulation + auto new_triangulation = + foliated_triangulations::FoliatedTriangulation<3>( + flipped_triangulation.value(), t_manifold.initial_radius(), + t_manifold.foliation_spacing()); + + // Create a new manifold with the updated triangulation + auto new_manifold = Manifold(new_triangulation); + + return new_manifold; + } + + // If we get here, the flip failed but we found potential cells + // Log the reason and continue trying other edges +#ifndef NDEBUG + spdlog::debug("Bistellar flip failed."); +#endif + } + // Try next edge + } + // We've run out of edges to try + std::string const msg = "No (4,4) move possible.\n"; + spdlog::warn(msg); + return std::unexpected(msg); + } // do_44_move() + + /// @brief Check move correctness + /// @param t_before The manifold before the move + /// @param t_after The manifold after the move + /// @param t_move The type of move + /// @return True if the move correctly changed the triangulation + [[nodiscard]] inline auto check_move(Manifold const& t_before, + Manifold const& t_after, + move_tracker::move_type const& t_move) + -> bool + { + switch (t_move) + { + case move_tracker::move_type::FOUR_FOUR: + return t_after.is_valid() && t_after.N3() == t_before.N3() && + t_after.N3_31() == t_before.N3_31() && + t_after.N3_22() == t_before.N3_22() && + t_after.N3_13() == t_before.N3_13() && + t_after.N2() == t_before.N2() && t_after.N1() == t_before.N1() && + t_after.N1_TL() == t_before.N1_TL() && + t_after.N1_SL() == t_before.N1_SL() && + t_after.N0() == t_before.N0() && + t_after.max_time() == t_before.max_time() && + t_after.min_time() == t_before.min_time(); + case move_tracker::move_type::TWO_THREE: + return t_after.is_valid() && t_after.N3() == t_before.N3() + 1 && + t_after.N3_31() == t_before.N3_31() && + t_after.N3_22() == t_before.N3_22() + 1 && + t_after.N3_13() == t_before.N3_13() && + t_after.N2() == t_before.N2() + 2 && + t_after.N1() == t_before.N1() + 1 && + t_after.N1_TL() == t_before.N1_TL() + 1 && + t_after.N1_SL() == t_before.N1_SL() && + t_after.N0() == t_before.N0() && + t_after.max_time() == t_before.max_time() && + t_after.min_time() == t_before.min_time(); + case move_tracker::move_type::THREE_TWO: + return t_after.is_valid() && t_after.N3() == t_before.N3() - 1 && + t_after.N3_31() == t_before.N3_31() && + t_after.N3_22() == t_before.N3_22() - 1 && + t_after.N3_13() == t_before.N3_13() && + t_after.N2() == t_before.N2() - 2 && + t_after.N1() == t_before.N1() - 1 && + t_after.N1_TL() == t_before.N1_TL() - 1 && + t_after.N1_SL() == t_before.N1_SL() && + t_after.N0() == t_before.N0() && + t_after.max_time() == t_before.max_time() && + t_after.min_time() == t_before.min_time(); + case move_tracker::move_type::TWO_SIX: + return t_after.is_valid() && t_after.N3() == t_before.N3() + 4 && + t_after.N3_31() == t_before.N3_31() + 2 && + t_after.N3_22() == t_before.N3_22() && + t_after.N3_13() == t_before.N3_13() + 2 && + t_after.N2() == t_before.N2() + 8 && // NOLINT + t_after.N1() == t_before.N1() + 5 && // NOLINT + t_after.N1_TL() == t_before.N1_TL() + 2 && + t_after.N1_SL() == t_before.N1_SL() + 3 && + t_after.N0() == t_before.N0() + 1 && + t_after.max_time() == t_before.max_time() && + t_after.min_time() == t_before.min_time(); + case move_tracker::move_type::SIX_TWO: + return t_after.is_valid() && t_after.N3() == t_before.N3() - 4 && + t_after.N3_31() == t_before.N3_31() - 2 && + t_after.N3_22() == t_before.N3_22() && + t_after.N3_13() == t_before.N3_13() - 2 && + t_after.N2() == t_before.N2() - 8 && // NOLINT + t_after.N1() == t_before.N1() - 5 && // NOLINT + t_after.N1_TL() == t_before.N1_TL() - 2 && + t_after.N1_SL() == t_before.N1_SL() - 3 && + t_after.N0() == t_before.N0() - 1 && + t_after.max_time() == t_before.max_time() && + t_after.min_time() == t_before.min_time(); + default: return false; + } + } // check_move() + +} // namespace ergodic_moves + +#endif // CDT_PLUSPLUS_ERGODIC_MOVES_3_HPP diff --git a/include/Foliated_triangulation.hpp b/include/Foliated_triangulation.hpp new file mode 100644 index 0000000000..a835c85fe6 --- /dev/null +++ b/include/Foliated_triangulation.hpp @@ -0,0 +1,1535 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2018 Adam Getchell + ******************************************************************************/ + +/// @file Foliated_triangulation.hpp +/// @brief Create foliated spherical triangulations +/// @author Adam Getchell +/// @details Extends CGAL's Delaunay_triangulation_3 and Triangulation_3 classes +/// to create foliated spherical triangulations of a given dimension. +/// +/// The dimensionality, number of desired simplices, and number of desired +/// timeslices is given. Successive spheres are created with increasing radii, +/// parameterized by INITIAL_RADIUS and RADIAL_FACTOR. Each vertex at a given +/// radius is assigned a timeslice so that the entire triangulation will have a +/// defined foliation of time. +/// @see +/// https://doc.cgal.org/latest/Triangulation_3/index.html#Chapter_3D_Triangulations + +#ifndef CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP +#define CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP + +#include "Triangulation_traits.hpp" +#include "Utilities.hpp" + +template +using Delaunay_t = typename TriangulationTraits::Delaunay; + +template +using Point_t = typename TriangulationTraits::Point; + +template +using Causal_vertices_t = + std::vector, Int_precision>>; + +template +using Cell_handle_t = typename TriangulationTraits::Cell_handle; + +template +using Face_handle_t = typename TriangulationTraits::Face_handle; + +template +using Facet_t = typename TriangulationTraits::Facet; + +template +using Edge_handle_t = typename TriangulationTraits::Edge_handle; + +template +using Vertex_handle_t = typename TriangulationTraits::Vertex_handle; + +template +using Spherical_points_generator_t = + typename TriangulationTraits::Spherical_points_generator; + +/// @concept ContainerType +/// @brief This is std::movable from +/// @details Right now the real restriction on Containers is that elements must +/// be swappable in order for std::shuffle to work. +template +concept ContainerType = std::movable; + +/// (n,m) is number of vertices on (lower, higher) timeslice +enum class Cell_type +{ + // 3D simplices + THREE_ONE = 31, // (3,1) + TWO_TWO = 22, // (2,2) + ONE_THREE = 13, // (1,3) + ACAUSAL = 99, // The vertex timevalues differ by > 1 or are all equal + UNCLASSIFIED = 0 // An error happened classifying cell +}; + +namespace foliated_triangulations +{ + static int constexpr MAX_FIX_PASSES = 50; + + /// @brief Create causal vertices from vertices and timevalues + /// @tparam dimension Dimensionality of the manifold + /// @param vertices The vertices of the manifold + /// @param timevalues The timevalue of each vertex + /// @return A container of vertices that have an associated timevalue + template + auto make_causal_vertices(std::span const> vertices, + std::span timevalues) + -> Causal_vertices_t + { + if (vertices.size() != timevalues.size()) + { + throw std::length_error("Vertices and timevalues must be the same size."); + } + Causal_vertices_t causal_vertices; + causal_vertices.reserve(vertices.size()); + std::ranges::transform(vertices, timevalues, + std::back_inserter(causal_vertices), + [](Point_t point, size_t time) { + return std::make_pair(point, time); + }); + return causal_vertices; + } + + /// @brief Returns a container of all the finite edges in the triangulation + /// @details Regardless of the dimensionality of the triangulation, the edges + /// are 1-d simplices connecting 0-d vertices. + /// @tparam dimension The dimensionality of the triangulation + /// @param delaunay The triangulation + /// @returns Container of all the finite edges in the triangulation + template + [[nodiscard]] auto collect_edges(Delaunay_t const& delaunay) + { + assert(delaunay.is_valid()); + std::vector> init_edges; + init_edges.reserve(delaunay.number_of_finite_edges()); + for (auto eit = delaunay.finite_edges_begin(); + eit != delaunay.finite_edges_end(); ++eit) + { + Cell_handle_t<3> const cell = eit->first; + Edge_handle_t<3> thisEdge{cell, cell->index(cell->vertex(eit->second)), + cell->index(cell->vertex(eit->third))}; + // Each edge is valid in the triangulation + assert(delaunay.tds().is_valid(thisEdge.first, thisEdge.second, + thisEdge.third)); + init_edges.emplace_back(thisEdge); + } + assert(init_edges.size() == delaunay.number_of_finite_edges()); + return init_edges; + } // collect_edges + + /// @brief Returns the vertex containing the given point + /// @tparam dimension The dimensionality of the triangulation + /// @param delaunay The triangulation + /// @param point The point to find the vertex for + /// @returns The vertex containing the given point + /// @see + /// https://doc.cgal.org/latest/Triangulation_3/classCGAL_1_1Triangulation__3.html#a5b45572c663e5d2c10f26e7be421e140 + template + [[nodiscard]] auto find_vertex(Delaunay_t const& delaunay, + Point_t const& point) + -> std::optional> + { + if (Vertex_handle_t vertex{nullptr}; + delaunay.is_vertex(point, vertex)) + { + return vertex; + } + return std::nullopt; + } // find_vertex + + /// @brief Returns the cell containing the vertices + /// @tparam dimension The dimensionality of the triangulation + /// @param delaunay The triangulation + /// @param vh1 The first vertex + /// @param vh2 The second vertex + /// @param vh3 The third vertex + /// @param vh4 The fourth vertex + /// @returns The cell containing the vertices + /// @see + /// https://doc.cgal.org/latest/Triangulation_3/classCGAL_1_1Triangulation__3.html#a8766c9a0c2a84203be31537e5e015646 + template + [[nodiscard]] auto find_cell(Delaunay_t const& delaunay, + Vertex_handle_t const& vh1, + Vertex_handle_t const& vh2, + Vertex_handle_t const& vh3, + Vertex_handle_t const& vh4) + -> std::optional> + { + if (Cell_handle_t cell{nullptr}; + delaunay.is_cell(vh1, vh2, vh3, vh4, cell)) + { + return cell; + } + return std::nullopt; + } // find_cell + + /// @tparam dimension The dimensionality of the simplices + /// @returns True if timevalue of lhs is less than rhs + template + auto constexpr compare_v_info = [](Vertex_handle_t const& lhs, + Vertex_handle_t const& rhs) { + return lhs->info() < rhs->info(); + }; + + /// @tparam dimension The dimensionality of the simplices + /// @param t_vertices The container of vertices + /// @returns The maximum timevalue in the container + template + [[nodiscard]] auto find_max_timevalue(Container&& t_vertices) -> Int_precision + { + auto vertices = std::forward(t_vertices); + assert(!vertices.empty()); + auto max_element = std::max_element(vertices.begin(), vertices.end(), + compare_v_info); + auto result_index = std::distance(vertices.begin(), max_element); + // std::distance may be negative if random-access iterators are used and + // first is reachable from last + assert(result_index >= 0); + auto const index = static_cast(std::abs(result_index)); + return vertices[index]->info(); + } // find_max_timevalue + + /// @tparam dimension The dimensionality of the simplices + /// @param t_vertices The container of vertices + /// @returns The minimum timevalue in the container + template + [[nodiscard]] auto find_min_timevalue(Container&& t_vertices) -> Int_precision + { + auto vertices = std::forward(t_vertices); + assert(!vertices.empty()); + auto min_element = std::min_element(vertices.begin(), vertices.end(), + compare_v_info); + auto result_index = std::distance(vertices.begin(), min_element); + assert(result_index >= 0); + auto const index = static_cast(std::abs(result_index)); + return vertices[index]->info(); + } // find_min_timevalue + + /// @brief Predicate to classify edge as timelike or spacelike + /// @tparam dimension The dimensionality of the simplices + /// @param t_edge The Edge_handle to classify + /// @returns True if timelike and false if spacelike + template + [[nodiscard]] auto classify_edge(Edge_handle_t const& t_edge) + -> bool + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + auto const& cell = t_edge.first; + auto time1 = cell->vertex(t_edge.second)->info(); + auto time2 = cell->vertex(t_edge.third)->info(); + +#ifndef NDEBUG + spdlog::trace("Edge: Vertex(1) timevalue: {} Vertex(2) timevalue: {}\n", + time1, time2); +#endif + + return time1 != time2; + } // classify_edge + + /// @tparam dimension The dimensionality of the simplices + /// @param t_edges The container of edges to filter + /// @param t_is_Timelike_pred The predicate to filter by + /// @returns A container of is_Timelike edges + template + [[nodiscard]] auto filter_edges( + std::vector> const& t_edges, + bool t_is_Timelike_pred) -> std::vector> + { + std::vector> filtered_edges; + // Short-circuit if no edges + if (t_edges.empty()) { return filtered_edges; } + std::copy_if(t_edges.begin(), t_edges.end(), + std::back_inserter(filtered_edges), [&](auto const& edge) { + return t_is_Timelike_pred == classify_edge(edge); + }); + return filtered_edges; + } // filter_edges + + /// @tparam dimension The dimensionality of the simplices + /// @param t_cells The container of simplices + /// @param t_cell_type The type of simplex to filter by + /// @returns A container of simplices filtered by type + template + [[nodiscard]] auto filter_cells( + std::vector> const& t_cells, + Cell_type const& t_cell_type) -> std::vector> + { + std::vector> filtered_cells; + // Short-circuit if no cells + if (t_cells.empty()) { return filtered_cells; } + std::copy_if(t_cells.begin(), t_cells.end(), + std::back_inserter(filtered_cells), + [&t_cell_type](auto const& cell) { + return cell->info() == static_cast(t_cell_type); + }); + return filtered_cells; + } // filter_cells + + /// @brief Calculate the squared radius from the origin + /// @tparam dimension The dimensionality of the simplices + /// @param t_vertex The vertex to check + /// @returns The squared radial distance of the vertex from the origin + template + [[nodiscard]] auto squared_radius(Vertex_handle_t const& t_vertex) + -> double + { + typename TriangulationTraits::squared_distance const r_2; + return r_2(t_vertex->point(), TriangulationTraits::ORIGIN_POINT); + } // squared_radius + + /// @brief Find the expected timevalue for a vertex + /// @details The formula for the expected timevalue is: + /// + /// \f[t=\frac{R-I+S}{S}\f] + /// + /// Where R is radius, I is INITIAL_RADIUS, and S is RADIAL_SEPARATION + /// + /// @tparam dimension Dimensionality of the vertex + /// @param t_vertex The vertex + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @returns The effective radius of the vertex + template + [[nodiscard]] auto expected_timevalue( + Vertex_handle_t const& t_vertex, double t_initial_radius, + double t_foliation_spacing) -> Int_precision + { + auto const radius = std::sqrt(squared_radius(t_vertex)); + return static_cast( + std::lround((radius - t_initial_radius + t_foliation_spacing) / + t_foliation_spacing)); + } // expected_timevalue + + /// @brief Checks if vertex timevalue is correct + /// @tparam dimension Dimensionality of the vertex + /// @param t_vertex The vertex + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @returns True if the timevalue of the vertex matches its effective radius + template + [[nodiscard]] auto is_vertex_timevalue_correct( + Vertex_handle_t const& t_vertex, double const t_initial_radius, + double const t_foliation_spacing) -> bool + { + auto const timevalue = expected_timevalue( + t_vertex, t_initial_radius, t_foliation_spacing); +#ifndef NDEBUG + spdlog::trace("Vertex({}) timevalue {} has expected timevalue == {}\n", + utilities::point_to_str(t_vertex->point()), t_vertex->info(), + timevalue); +#endif + return timevalue == t_vertex->info(); + } // is_vertex_timevalue_correct + + /// @brief Obtain all finite vertices in the Delaunay triangulation + /// @tparam dimension Dimensionality of the Delaunay triangulation + /// @param t_triangulation The Delaunay triangulation + /// @returns A container of finite vertices + template + [[nodiscard]] auto collect_vertices( + Delaunay_t const& t_triangulation) + { + std::vector> vertices; + for (auto vit = t_triangulation.finite_vertices_begin(); + vit != t_triangulation.finite_vertices_end(); ++vit) + { + // Each vertex is valid + assert(t_triangulation.tds().is_vertex(vit)); + vertices.emplace_back(vit); + } + return vertices; + } // collect_vertices + + /// @brief Check if vertices have the correct timevalues + /// @tparam dimension Dimensionality of the vertices and Delaunay + /// triangulation + /// @param t_triangulation The Delaunay triangulation + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @returns True if all vertices have correct timevalues + template + [[nodiscard]] auto check_vertices( + Delaunay_t const& t_triangulation, double t_initial_radius, + double t_foliation_spacing) + { + auto checked_vertices = collect_vertices(t_triangulation); + return std::all_of(checked_vertices.begin(), checked_vertices.end(), + [&](auto const& vertex) { + return is_vertex_timevalue_correct( + vertex, t_initial_radius, t_foliation_spacing); + }); + } // check_vertices + + /// @brief Obtain all finite cells in the Delaunay triangulation + /// @tparam dimension Dimensionality of the Delaunay triangulation + /// @param t_triangulation The triangulation + /// @returns A container of finite cells + template + [[nodiscard]] auto collect_cells(Delaunay_t const& t_triangulation) + -> std::vector> + { + std::vector> cells; + for (auto cit = t_triangulation.finite_cells_begin(); + cit != t_triangulation.finite_cells_end(); ++cit) + { + // Each cell is valid + assert(t_triangulation.tds().is_cell(cit)); + cells.emplace_back(cit); + } + return cells; + } // collect_cells + + /// @brief Extracts vertices from cells + /// @param t_cells The cells from which to extract vertices + /// @returns All of the vertices contained in the cells + template + [[nodiscard]] auto get_vertices_from_cells( + std::vector> const& t_cells) + { + std::unordered_set> cell_vertices; + auto get_vertices = [&cell_vertices](auto const& t_cell) { + for (int i = 0; i < dimension + 1; ++i) + { + cell_vertices.emplace(t_cell->vertex(i)); + } + }; + std::for_each(t_cells.begin(), t_cells.end(), get_vertices); + std::vector> result(cell_vertices.begin(), + cell_vertices.end()); + return result; + } // get_vertices_from_cells + + /// @brief Obtain vertices with incorrect timevalues + /// @tparam dimension Dimensionality of vertices and cells + /// @param t_cells Container of cells to check + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @return A container of vertices with incorrect timevalues + template + [[nodiscard]] auto find_incorrect_vertices( + std::vector> const& t_cells, + double t_initial_radius, double t_foliation_spacing) + { + auto checked_vertices = get_vertices_from_cells(t_cells); + std::vector> incorrect_vertices; + + std::copy_if(checked_vertices.begin(), checked_vertices.end(), + std::back_inserter(incorrect_vertices), + [&](auto const& vertex) { + return !is_vertex_timevalue_correct( + vertex, t_initial_radius, t_foliation_spacing); + }); + return incorrect_vertices; + } // find_incorrect_vertices + + /// @brief Obtain vertices with incorrect timevalues + /// @tparam dimension Dimensionality of the vertices and Delaunay + /// triangulation + /// @param t_triangulation The Delaunay triangulation + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @return A container of vertices with incorrect timevalues + template + [[nodiscard]] auto find_incorrect_vertices( + Delaunay_t const& t_triangulation, double t_initial_radius, + double t_foliation_spacing) + { + auto cells_to_check = collect_cells(t_triangulation); + return find_incorrect_vertices(cells_to_check, t_initial_radius, + t_foliation_spacing); + } // find_incorrect_vertices + + /// @brief Fix vertices with incorrect timevalues + /// @details Changes vertex->info() to the correct timevalue using + /// foliated_triangulations::expected_timevalue + /// @tparam dimension Dimensionality of vertices and cells + /// @param t_cells Container of cells to check + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing + /// @return True if any vertex->info() was fixed + template + [[nodiscard]] auto fix_vertices( + std::vector> const& t_cells, + double t_initial_radius, double t_foliation_spacing) + { + auto incorrect_vertices = find_incorrect_vertices( + t_cells, t_initial_radius, t_foliation_spacing); + std::for_each(incorrect_vertices.begin(), incorrect_vertices.end(), + [&](auto const& vertex) { + vertex->info() = expected_timevalue( + vertex, t_initial_radius, t_foliation_spacing); + }); + return !incorrect_vertices.empty(); + } // fix_vertices + + /// @brief Fix vertices with incorrect timevalues + /// @details Changes vertex->info() to the correct timevalue + /// @tparam dimension Dimensionality of the vertices and Delaunay + /// triangulation + /// @param t_triangulation The triangulation + /// @param t_initial_radius The initial radius of the radial foliation + /// @param t_foliation_spacing The spacing between successive leaves + /// @return True if any vertex->info() was fixed + template + [[nodiscard]] auto fix_vertices(Delaunay_t const& t_triangulation, + double const t_initial_radius, + double const t_foliation_spacing) -> bool + { + return fix_vertices(collect_cells(t_triangulation), + t_initial_radius, t_foliation_spacing); + } // fix_vertices + + /// @brief Classifies cells by their timevalues + /// @tparam dimension The dimensionality of the simplices + /// @param t_cell The simplex to check + /// @return The type of the simplex + template + [[nodiscard]] auto expected_cell_type(Cell_handle_t const& t_cell) + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + std::array(dimension) + 1> + vertex_timevalues{}; + // There are d+1 vertices in a d-dimensional simplex + for (auto i = 0; i < dimension + 1; ++i) + { + // Obtain timevalue of vertex + vertex_timevalues.at(static_cast(i)) = + t_cell->vertex(i)->info(); + } + auto const maxtime_ref = + std::max_element(vertex_timevalues.begin(), vertex_timevalues.end()); + auto const mintime_ref = + std::min_element(vertex_timevalues.begin(), vertex_timevalues.end()); + auto maxtime = *maxtime_ref; + auto mintime = *mintime_ref; + // A properly foliated simplex should have a timevalue difference of 1 + if (maxtime - mintime != 1 || maxtime == mintime) + { +#ifndef NDEBUG + spdlog::trace("This simplex is acausal:\n"); + spdlog::trace("Max timevalue is {} and min timevalue is {}.\n", maxtime, + mintime); + spdlog::trace("--\n"); +#endif + return Cell_type::ACAUSAL; + } + std::multiset const timevalues{vertex_timevalues.begin(), + vertex_timevalues.end()}; + auto max_vertices = timevalues.count(maxtime); + auto min_vertices = timevalues.count(mintime); + + // 3D simplices + if (max_vertices == 3 && min_vertices == 1) { return Cell_type::ONE_THREE; } + if (max_vertices == 2 && min_vertices == 2) { return Cell_type::TWO_TWO; } + if (max_vertices == 1 && min_vertices == 3) { return Cell_type::THREE_ONE; } + + // If we got here, there's some kind of error +#ifndef NDEBUG + spdlog::trace("This simplex has an error:\n"); + spdlog::trace("Max timevalue is {} and min timevalue is {}.\n", maxtime, + mintime); + spdlog::trace( + "There are {} vertices with the max timevalue and {} vertices with " + "the min timevalue.\n", + max_vertices, min_vertices); + spdlog::trace("--\n"); +#endif + return Cell_type::UNCLASSIFIED; + } // expected_cell_type + + /// @brief Checks if a cell is classified correctly + /// @tparam dimension The dimensionality of the simplices + /// @param t_cell The simplex to check + /// @return True if the cell_info matches expected cell_info + template + [[nodiscard]] auto is_cell_type_correct( + Cell_handle_t const& t_cell) -> bool + { + auto cell_type = expected_cell_type(t_cell); + return cell_type != Cell_type::ACAUSAL && + cell_type != Cell_type::UNCLASSIFIED && + cell_type == static_cast(t_cell->info()); + } // is_cell_type_correct + + /// @brief Check all finite cells in the Delaunay triangulation + /// @tparam dimension Dimensionality of the Delaunay triangulation + /// @param t_triangulation The Delaunay triangulation + /// @return True if there are no finite cells, or all finite cells are + /// correctly classified + template + [[nodiscard]] auto check_cells(Delaunay_t const& t_triangulation) + -> bool + { + auto checked_cells = collect_cells(t_triangulation); + return checked_cells.empty() || + std::all_of(checked_cells.begin(), checked_cells.end(), + [&](auto const& cell) { + return is_cell_type_correct(cell); + }); + } // check_cells + + /// @brief Check all finite cells in the Delaunay triangulation + /// @tparam dimension Dimensionality of the Delaunay triangulation + /// @param t_triangulation The Delaunay triangulation + /// @return A container of cells that are not classified correctly + template + [[nodiscard]] auto find_incorrect_cells( + Delaunay_t const& t_triangulation) + { + auto checked_cells = collect_cells(t_triangulation); + + std::vector> incorrect_cells; + std::copy_if(checked_cells.begin(), checked_cells.end(), + std::back_inserter(incorrect_cells), [&](auto const& cell) { + return !is_cell_type_correct(cell); + }); + return incorrect_cells; + } // find_incorrect_cells + + /// @brief Fix simplices with the wrong type + /// @tparam dimension The dimensionality of the simplices + /// @param t_triangulation The Delaunay triangulation + /// @return True if cells->info() was fixed + template + [[nodiscard]] auto fix_cells(Delaunay_t const& t_triangulation) + -> bool + { + auto incorrect_cells = find_incorrect_cells(t_triangulation); + std::for_each( + incorrect_cells.begin(), incorrect_cells.end(), [&](auto const& cell) { + cell->info() = + static_cast(expected_cell_type(cell)); + }); + return !incorrect_cells.empty(); + } // fix_cells + + /// @brief Print a cell in the triangulation + /// @tparam dimension The dimensionality of the triangulation + /// @param cell The cell to print + template + void print_cell(Cell_handle_t cell) + { + fmt::print("Cell info => {}\n", cell->info()); + // There are d+1 vertices in a d-dimensional simplex + for (int j = 0; j < dimension + 1; ++j) + { + fmt::print("Vertex({}) Point: ({}) Timevalue: {}\n", j, + utilities::point_to_str(cell->vertex(j)->point()), + cell->vertex(j)->info()); + } + fmt::print("---\n"); + } // print_cell + + /// @brief Print timevalues of each vertex in the cell and the resulting + /// cell->info() + /// @tparam dimension The dimensionality of the simplices + /// @param t_cells The cells to print + template + void print_cells(Container&& t_cells) + { + for (auto cells = std::forward(t_cells); + auto const& cell : cells) + { + print_cell(cell); + } + } // print_cells + + /// @brief Write to debug log timevalues of each vertex in the cell and the + /// resulting cell->info + /// @tparam dimension The dimensionality of the simplices + /// @tparam Container The type of container + /// @param t_cells The cells to write to debug log + template + void debug_print_cells(Container&& t_cells) + { + for (auto cells = std::forward(t_cells); + auto const& cell : cells) + { + spdlog::debug("Cell info => {}\n", cell->info()); + for (int j = 0; j < dimension + 1; ++j) + { + spdlog::debug("Vertex({}) Point: ({}) Timevalue: {}\n", j, + utilities::point_to_str(cell->vertex(j)->point()), + cell->vertex(j)->info()); + } + spdlog::debug("---\n"); + } + } // debug_print_cells + + /// @brief Print neighboring cells + /// @tparam dimension The dimensionality of the simplices + /// @param cell The cell to print neighbors of + template + void print_neighboring_cells(Cell_handle_t cell) + { + for (int j = 0; j < dimension + 1; ++j) + { + fmt::print("Neighboring cell {}:", j); + print_cell(cell->neighbor(j)); + } + } // print_neighboring_cells + + /// @brief Print edge + /// @details An edge is represented by a cell and two indices which refer + /// to the vertices of the cell connected by the edge. The data is stored + /// in a CGAL::Triple, which is an extension of std::pair. + /// @tparam dimension The dimensionality of the simplices + /// @param t_edge The edge to print + /// @see https://doc.cgal.org/latest/TDS_3/index.html#fig__TDS3figrepres + /// @see https://doc.cgal.org/latest/STL_Extension/classCGAL_1_1Triple.html + template + void print_edge(Edge_handle_t const& t_edge) + { + fmt::print( + "Edge: Vertex({}) Point({}) Timevalue: {} -> Vertex({}) Point({}) " + "Timevalue: {}\n", + t_edge.second, + utilities::point_to_str(t_edge.first->vertex(t_edge.second)->point()), + t_edge.first->vertex(t_edge.second)->info(), t_edge.third, + utilities::point_to_str(t_edge.first->vertex(t_edge.third)->point()), + t_edge.first->vertex(t_edge.third)->info()); + } // print_edge + + /// @brief Collect spacelike facets into a container indexed by time value + /// @details *Warning!* Turning on debugging info will generate gigabytes + /// of logs. + /// @tparam dimension The dimensionality of the simplices + /// @param t_facets A container of facets + /// @return Container with spacelike facets per timeslice + template + [[nodiscard]] auto volume_per_timeslice(Container&& t_facets) + -> std::multimap> + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + std::multimap> space_faces; + for (auto facets = std::forward(t_facets); + auto const& face : facets) + { + Cell_handle_t const cell = face.first; + auto index_of_facet = face.second; +#ifndef NDEBUG + spdlog::trace("Facet index is {}\n", index_of_facet); +#endif + std::set facet_timevalues; + // There are d+1 vertices in a d-dimensional simplex + for (int i = 0; i < dimension + 1; ++i) + { + if (i != index_of_facet) + { +#ifndef NDEBUG + spdlog::trace("Vertex[{}] has timevalue {}\n", i, + cell->vertex(i)->info()); +#endif + facet_timevalues.insert(cell->vertex(i)->info()); + } + } + // If we have a 1-element set then all timevalues on that facet are + // equal + if (facet_timevalues.size() == 1) + { +#ifndef NDEBUG + spdlog::trace("Facet is spacelike on timevalue {}.\n", + *facet_timevalues.begin()); +#endif + space_faces.insert({*facet_timevalues.begin(), face}); + } + else + { +#ifndef NDEBUG + spdlog::trace("Facet is timelike.\n"); +#endif + } + } + return space_faces; + } // volume_per_timeslice + + /// @brief Check cells for correct foliation + /// @details The timevalues of the vertices of a cell differ by at most one + /// and cannot all be the same. The first case would correspond to the + /// cell (simplex) spanning more than one timeslice; the second would + /// correspond to the cell being purely spacelike. Both of these cases are + /// causally inconsistent. + /// Note that this takes a Delaunay triangulation as input, as it is + /// expected to be called while the Foliated triangulation is still being + /// constructed. + /// Note also that to guard against numeric errors causing invalid cells, + /// fix_vertices() should be called before this function. + /// @tparam dimension The dimensionality of the cells and triangulation + /// @param t_triangulation The Delaunay triangulation + /// @return An optional container of invalid cells + template + [[nodiscard]] auto check_timevalues( + Delaunay_t const& t_triangulation) + -> std::optional>> + { + auto const& cells = collect_cells(t_triangulation); + std::vector> invalid_cells; + std::copy_if( + cells.begin(), cells.end(), std::back_inserter(invalid_cells), + [](auto const& cell) { + return expected_cell_type(cell) == Cell_type::ACAUSAL || + expected_cell_type(cell) == Cell_type::UNCLASSIFIED; + }); + auto result = invalid_cells.empty() ? std::nullopt + : std::make_optional(invalid_cells); + return result; + } // check_timevalues + + /// @brief Find the vertex that is causing a cell's foliation to be invalid + /// @tparam dimension Dimensionality of the cell + /// @param cell The cell to check + /// @return The offending vertex + template + [[nodiscard]] auto find_bad_vertex(Cell_handle_t const& cell) + -> Vertex_handle_t + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); + spdlog::debug("===Invalid Cell===\n"); + std::vector> bad_cell{cell}; + debug_print_cells(std::span{bad_cell}); +#endif + std::multimap> vertices; + for (int i = 0; i < dimension + 1; ++i) + { + vertices.emplace( + std::make_pair(cell->vertex(i)->info(), cell->vertex(i))); + } + // Now it's sorted in the multimap + auto const minvalue = vertices.cbegin()->first; + auto const maxvalue = vertices.crbegin()->first; + auto const minvalue_count = vertices.count(minvalue); + auto const maxvalue_count = vertices.count(maxvalue); + // Return the vertex with the highest value if there are equal or more + // vertices with lower values. Note that we preferentially return higher + // timeslice vertices because there are typically more cells at higher + // timeslices (see expected_points_per_timeslice()) + return minvalue_count >= maxvalue_count ? vertices.rbegin()->second + : vertices.begin()->second; + } // find_bad_vertex + + /// @brief Fix the vertices of a cell to be consistent with the foliation + /// + /// @tparam dimension Dimensionality of the triangulation + /// @param t_triangulation The Delaunay triangulation + /// @return True if incorrectly foliated simplices were fixed + template + [[nodiscard]] auto fix_timevalues(Delaunay_t& t_triangulation) + -> bool + { + // Obtain a container of cells that are incorrectly foliated + if (auto invalid_cells = check_timevalues(t_triangulation); + invalid_cells) + { + std::set> vertices_to_remove; + // Transform the invalid cells into a set of vertices to remove + // Reduction to unique vertices happens via the set container + std::transform( + invalid_cells->begin(), invalid_cells->end(), + std::inserter(vertices_to_remove, vertices_to_remove.begin()), + find_bad_vertex); + // Remove the vertices +#ifndef NDEBUG + spdlog::warn("There are {} invalid vertices.\n", + vertices_to_remove.size()); +#endif + t_triangulation.remove(vertices_to_remove.begin(), + vertices_to_remove.end()); + assert(t_triangulation.tds().is_valid()); + assert(t_triangulation.is_valid()); + return true; + } + return false; + } // fix_timevalues + + /// @brief Make foliated ball + /// @details Makes a solid ball of successive layers of spheres at + /// a given radius. + /// @tparam dimension The dimensionality of the simplices + /// @param t_simplices The desired number of simplices in the triangulation + /// @param t_timeslices The desired number of timeslices in the + /// triangulation + /// @param initial_radius The radius of the first time slice + /// @param foliation_spacing The distance between successive time slices + /// @return A container of (vertex, timevalue) pairs + template + [[nodiscard]] auto make_foliated_ball( + Int_precision const t_simplices, Int_precision const t_timeslices, + double const initial_radius = INITIAL_RADIUS, + double const foliation_spacing = FOLIATION_SPACING) + { + Causal_vertices_t causal_vertices; + causal_vertices.reserve(static_cast(t_simplices)); + auto const points_per_timeslice = utilities::expected_points_per_timeslice( + dimension, t_simplices, t_timeslices); + assert(points_per_timeslice >= 2); + + for (gsl::index i = 0; i < t_timeslices; ++i) + { + auto const radius = + initial_radius + static_cast(i) * foliation_spacing; + Spherical_points_generator_t gen{radius}; + // Generate random points at the radius + for (gsl::index j = 0; + j < static_cast(points_per_timeslice * radius); ++j) + { + causal_vertices.emplace_back(*gen++, i + 1); + } // j + } // i + return causal_vertices; + } // make_foliated_ball + + /// @brief Make a Delaunay triangulation + /// @tparam dimension Dimensionality of the Delaunay triangulation + /// @param t_simplices Number of desired simplices + /// @param t_timeslices Number of desired timeslices + /// @param initial_radius Radius of first timeslice + /// @param foliation_spacing Radial separation between timeslices + /// @return A Delaunay triangulation with a timevalue for each vertex + template + [[nodiscard]] auto make_triangulation( + Int_precision const t_simplices, Int_precision t_timeslices, + double const initial_radius = INITIAL_RADIUS, + double const foliation_spacing = FOLIATION_SPACING) + -> Delaunay_t + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + fmt::print("\nGenerating universe ...\n"); +#ifdef CGAL_LINKED_WITH_TBB + // Construct the locking data-structure + // using the bounding-box of the points + auto bounding_box_size = static_cast(t_timeslices + 1); + typename Delaunay_t::Lock_data_structure locking_ds{ + CGAL::Bbox_3{-bounding_box_size, -bounding_box_size, -bounding_box_size, + bounding_box_size, bounding_box_size, bounding_box_size}, + 50 + }; + Delaunay_t triangulation = + Delaunay_t{TriangulationTraits<3>::Kernel{}, &locking_ds}; +#else + Delaunay_t triangulation = Delaunay_t{}; +#endif + + // Make initial triangulation + auto causal_vertices = make_foliated_ball( + t_simplices, t_timeslices, initial_radius, foliation_spacing); + triangulation.insert(causal_vertices.begin(), causal_vertices.end()); + + // Fix vertices + for (auto passes = 1; passes < MAX_FIX_PASSES + 1; ++passes) + { + if (!fix_vertices(triangulation, initial_radius, + foliation_spacing)) + { + break; + } +#ifndef NDEBUG + spdlog::warn("Deleting incorrect vertices pass #{}\n", passes); +#endif + } + + // Fix timeslices + for (auto passes = 1; passes < MAX_FIX_PASSES + 1; ++passes) + { + if (!fix_timevalues(triangulation)) { break; } +#ifndef NDEBUG + spdlog::warn("Fixing timeslices pass #{}\n", passes); +#endif + } + + // Fix cells + for (auto i = 1; i < MAX_FIX_PASSES + 1; ++i) + { + if (!fix_cells(triangulation)) { break; } +#ifndef NDEBUG + spdlog::warn("Fixing incorrect cells pass #{}\n", i); +#endif + } + + utilities::print_delaunay(triangulation); + assert(!check_timevalues(triangulation)); + return triangulation; + } // make_triangulation + + /// FoliatedTriangulation class template + /// @tparam dimension Dimensionality of triangulation + template + class FoliatedTriangulation; + + /// @brief 3D Foliated triangulation + /// @details This class is a wrapper around a Delaunay triangulation. + /// The Delaunay triangulation is augmented with a timevalue for each + /// vertex and a simplex type for each cell. + /// The FoliatedTriangulation class invariant is that the Delaunay + /// triangulation has validly foliated vertices and cells, and has further + /// containers for the various sub-simplicial complexes of the triangulation. + template <> + class [[nodiscard("This contains data!")]] FoliatedTriangulation<3> // NOLINT + { + using Delaunay = Delaunay_t<3>; + using Cell_handle = Cell_handle_t<3>; + using Cell_container = std::vector; + using Face_container = std::vector>; + using Edge_container = std::vector>; + using Vertex_handle = Vertex_handle_t<3>; + using Vertex_container = std::vector; + using Volume_by_timeslice = std::multimap>; + + /// Data members initialized in order of declaration (Working Draft, + /// Standard for C++ Programming Language, 11.9.3 section 13.3) + Delaunay m_triangulation{Delaunay{}}; + double m_initial_radius{INITIAL_RADIUS}; + double m_foliation_spacing{FOLIATION_SPACING}; + Vertex_container m_vertices; + Cell_container m_cells; + Cell_container m_three_one; + Cell_container m_two_two; + Cell_container m_one_three; + Face_container m_faces; + Volume_by_timeslice m_spacelike_facets; + Edge_container m_edges; + Edge_container m_timelike_edges; + Edge_container m_spacelike_edges; + Int_precision m_max_timevalue{0}; + Int_precision m_min_timevalue{0}; + + public: + /// @brief Default dtor + ~FoliatedTriangulation() = default; + + /// @brief Default ctor + FoliatedTriangulation() = default; + + /// @brief Copy Constructor + FoliatedTriangulation(FoliatedTriangulation const& other) noexcept + : FoliatedTriangulation( + static_cast(other.get_delaunay()), + other.m_initial_radius, other.m_foliation_spacing) + {} + + /// @brief Copy/Move Assignment operator + auto operator=(FoliatedTriangulation other) noexcept + -> FoliatedTriangulation& + { + swap(other, *this); + return *this; + } + + /// @brief Move ctor + FoliatedTriangulation(FoliatedTriangulation&& other) noexcept + : FoliatedTriangulation{} + { swap(other, *this); } + + /// @brief Non-member swap function for Foliated Triangulations. + /// @details Note that this function calls swap() from CGAL's + /// Triangulation_3 base class, which assumes that the first triangulation + /// is discarded after it is swapped into the second one. + /// @param swap_from The value to be swapped from. Assumed to be discarded. + /// @param swap_into The value to be swapped into. + friend void swap(FoliatedTriangulation& swap_from, + FoliatedTriangulation& swap_into) noexcept + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + // Uses the triangulation swap method in CGAL + // This assumes that the first triangulation is not used afterward! + // See + // https://doc.cgal.org/latest/Triangulation_3/classCGAL_1_1Triangulation__3.html#a767066a964b4d7b14376e5f5d1a04b34 + swap_into.m_triangulation.swap(swap_from.m_triangulation); + using std::swap; + swap(swap_from.m_initial_radius, swap_into.m_initial_radius); + swap(swap_from.m_foliation_spacing, swap_into.m_foliation_spacing); + swap(swap_from.m_vertices, swap_into.m_vertices); + swap(swap_from.m_cells, swap_into.m_cells); + swap(swap_from.m_three_one, swap_into.m_three_one); + swap(swap_from.m_two_two, swap_into.m_two_two); + swap(swap_from.m_one_three, swap_into.m_one_three); + swap(swap_from.m_faces, swap_into.m_faces); + swap(swap_from.m_spacelike_facets, swap_into.m_spacelike_facets); + swap(swap_from.m_edges, swap_into.m_edges); + swap(swap_from.m_timelike_edges, swap_into.m_timelike_edges); + swap(swap_from.m_spacelike_edges, swap_into.m_spacelike_edges); + swap(swap_from.m_max_timevalue, swap_into.m_max_timevalue); + swap(swap_from.m_min_timevalue, swap_into.m_min_timevalue); + + } // swap + + /// @brief Constructor using delaunay triangulation + /// Pass-by-value-then-move. + /// Delaunay is the ctor for the Delaunay triangulation. + /// @param triangulation Delaunay triangulation + /// @param initial_radius Radius of first timeslice + /// @param foliation_spacing Radial separation between timeslices + explicit FoliatedTriangulation( + Delaunay triangulation, double const initial_radius = INITIAL_RADIUS, + double const foliation_spacing = FOLIATION_SPACING) + : m_triangulation{std::move(triangulation)} + , m_initial_radius{initial_radius} + , m_foliation_spacing{foliation_spacing} + , m_vertices{classify_vertices(collect_vertices<3>(m_triangulation))} + , m_cells{classify_cells(collect_cells<3>(m_triangulation))} + , m_three_one{filter_cells<3>(m_cells, Cell_type::THREE_ONE)} + , m_two_two{filter_cells<3>(m_cells, Cell_type::TWO_TWO)} + , m_one_three{filter_cells<3>(m_cells, Cell_type::ONE_THREE)} + , m_faces{collect_faces()} + , m_spacelike_facets{volume_per_timeslice<3>(std::span{m_faces})} + , m_edges{collect_edges()} + , m_timelike_edges{filter_edges<3>(m_edges, true)} + , m_spacelike_edges{filter_edges<3>(m_edges, false)} + , m_max_timevalue{find_max_timevalue<3>(std::span{m_vertices})} + , m_min_timevalue{find_min_timevalue<3>(std::span{m_vertices})} + {} + + /// @brief Constructor with parameters + /// @param t_simplices Number of desired simplices + /// @param t_timeslices Number of desired timeslices + /// @param t_initial_radius Radius of first timeslice + /// @param t_foliation_spacing Radial separation between timeslices + FoliatedTriangulation(Int_precision const t_simplices, + Int_precision const t_timeslices, + double const t_initial_radius = INITIAL_RADIUS, + double const t_foliation_spacing = FOLIATION_SPACING) + : FoliatedTriangulation{ + make_triangulation<3>(t_simplices, t_timeslices, t_initial_radius, + t_foliation_spacing), + t_initial_radius, t_foliation_spacing} + {} + + /// @brief Constructor from Causal_vertices + /// @param causal_vertices Causal_vertices to place into the + /// FoliatedTriangulation + /// @param t_initial_radius Radius of first timeslice + /// @param t_foliation_spacing Radial separation between timeslices + explicit FoliatedTriangulation( + Causal_vertices_t<3> const& causal_vertices, + double const t_initial_radius = INITIAL_RADIUS, + double const t_foliation_spacing = FOLIATION_SPACING) + : FoliatedTriangulation{ + Delaunay{causal_vertices.begin(), causal_vertices.end()}, + t_initial_radius, t_foliation_spacing + } + {} + + /// @brief Verifies the triangulation is properly foliated + /// + /// Can not be called until after Foliated_triangulation has been + /// constructed (i.e. not in make_triangulation) + /// + /// @return True if foliated correctly + [[nodiscard]] auto is_foliated() const -> bool + { + return !static_cast(check_timevalues<3>(this->get_delaunay())); + } // is_foliated + + /// @return True if the triangulation is Delaunay + [[nodiscard]] auto is_delaunay() const -> bool + { return get_delaunay().is_valid(); } // is_delaunay + + /// @return True if the triangulation data structure is valid + [[nodiscard]] auto is_tds_valid() const -> bool + { return get_delaunay().tds().is_valid(); } // is_tds_valid + + /// @return True if the Foliated Triangulation class invariants hold + [[nodiscard]] auto is_correct() const -> bool + { + return is_foliated() && is_tds_valid() && check_all_cells(); + } // is_correct + + /// @return True if the Foliated Triangulation has been initialized + /// correctly + [[nodiscard]] auto is_initialized() const -> bool + { return is_correct() && is_delaunay(); } // is_initialized + + /// @return True if fixes were done on the Delaunay triangulation + [[nodiscard]] auto is_fixed() -> bool + { + auto const fixed_vertices = foliated_triangulations::fix_vertices<3>( + m_triangulation, m_initial_radius, m_foliation_spacing); + auto const fixed_cells = + foliated_triangulations::fix_cells<3>(m_triangulation); + auto const fixed_timeslices = + foliated_triangulations::fix_timevalues<3>(m_triangulation); + return fixed_vertices || fixed_cells || fixed_timeslices; + } // is_fixed + + /// @return A mutable reference to the Delaunay triangulation + [[nodiscard]] auto delaunay() -> Delaunay& { return m_triangulation; } + + /// @return A read-only reference to the Delaunay triangulation + [[nodiscard]] auto get_delaunay() const -> Delaunay const& + { return m_triangulation; } // get_delaunay + + /// @return Number of 3D simplices in triangulation data structure + [[nodiscard]] auto number_of_finite_cells() const + { + return m_triangulation.number_of_finite_cells(); + } // number_of_finite_cells + + /// @return Number of 2D faces in triangulation data structure + [[nodiscard]] auto number_of_finite_facets() const + { + return m_triangulation.number_of_finite_facets(); + } // number_of_finite_facets + + /// @return Number of 1D edges in triangulation data structure + [[nodiscard]] auto number_of_finite_edges() const + { + return m_triangulation.number_of_finite_edges(); + } // number_of_finite_edges + + /// @return Number of vertices in triangulation data structure + [[nodiscard]] auto number_of_vertices() const + { return m_triangulation.number_of_vertices(); } // number_of_vertices + + /// @return If a cell or vertex contains or is the infinite vertex + /// Forward parameters (see F.19 of C++ Core Guidelines) + template + [[nodiscard]] auto is_infinite(VertexHandle&& t_vertex) const + { + return m_triangulation.is_infinite(std::forward(t_vertex)); + } // is_infinite + + /// @brief Call one of the TSD3.flip functions + /// + /// See + /// https://doc.cgal.org/latest/Triangulation_3/classCGAL_1_1Triangulation__3.html#a883fed00b53cae9e85feb20230f54dd9 + /// + /// @tparam Ts Variadic template of types of the arguments + /// @param args Parameter pack of arguments to TDS3.flip + /// @return True if the flip occurred + template + [[nodiscard]] auto flip(Ts&&... args) + { return m_triangulation.flip(std::forward(args)...); } // flip + + /// @return Returns the infinite vertex in the triangulation + [[maybe_unused]] [[nodiscard]] auto infinite_vertex() const + { return m_triangulation.infinite_vertex(); } // infinite_vertex + + /// @return Dimensionality of triangulation data structure (int) + [[nodiscard]] auto dimension() const { return m_triangulation.dimension(); } + + /// @return Container of spacelike facets indexed by time value + [[nodiscard]] auto N2_SL() const + -> std::multimap::Facet> const& + { return m_spacelike_facets; } // N2_SL + + /// @return Number of timelike edges + [[nodiscard]] auto N1_TL() const + { return static_cast(m_timelike_edges.size()); } // N1_TL + + /// @return Number of spacelike edges + [[nodiscard]] auto N1_SL() const + { return static_cast(m_spacelike_edges.size()); } // N1_SL + + /// @return Container of timelike edges + [[nodiscard]] auto get_timelike_edges() const noexcept + -> Edge_container const& + { return m_timelike_edges; } // get_timelike_edges + + /// @return Container of spacelike edges + [[nodiscard]] auto get_spacelike_edges() const -> Edge_container const& + { return m_spacelike_edges; } // get_spacelike_edges + + /// @return Container of vertices + [[nodiscard]] auto get_vertices() const noexcept -> Vertex_container const& + { return m_vertices; } // get_vertices + + /// @return A span of vertices + [[nodiscard]] auto get_vertices_span() const noexcept + -> std::span + { return std::span{m_vertices}; } // get_vertices_span + + /// @return Maximum time value in triangulation + [[nodiscard]] auto max_time() const { return m_max_timevalue; } + + /// @return Minimum time value in triangulation + [[nodiscard]] auto min_time() const { return m_min_timevalue; } + + /// @return The initial radius for timeslice = 1 + [[nodiscard]] auto initial_radius() const { return m_initial_radius; } + + /// @return The spacing between timeslices + [[nodiscard]] auto foliation_spacing() const { return m_foliation_spacing; } + + /// @brief Perfect forwarding to TriangulationDataStructure_3::degree + /// @return The number of incident edges to a vertex + /// @see + /// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#a51fce32aa7abf3d757bcabcebd22f2fe + template + [[nodiscard]] auto degree(VertexHandle&& t_vertex) const + { + return m_triangulation.degree(std::forward(t_vertex)); + } // degree + + /// @brief Perfect forwarding to + /// TriangulationDataStructure_3::incident_cells + /// @details If there are n incident edges there are 2(n-2) incident cells + /// @tparam VertexHandle Template parameter used to forward + /// @param t_vh Vertex + /// @return A container of incident cells + /// @see + /// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#a93f8ab30228b2a515a5c9cdacd9d4d36 + template + [[nodiscard]] auto incident_cells(VertexHandle&& t_vh) const noexcept + -> decltype(auto) + { + Cell_container inc_cells; + get_delaunay().tds().incident_cells(std::forward(t_vh), + std::back_inserter(inc_cells)); + return inc_cells; + } // incident_cells + + /// @brief Perfect forwarding to + /// TriangulationDataStructure_3::incident_cells + /// @tparam Ts Variadic template used to forward + /// @param args Parameter pack of arguments to call incident_cells() + /// @return A Cell_circulator + /// @see + /// https://doc.cgal.org/latest/TDS_3/classTriangulationDataStructure__3.html#a93f8ab30228b2a515a5c9cdacd9d4d36 + template + [[nodiscard]] auto incident_cells(Ts&&... args) const noexcept + -> decltype(auto) + { + return get_delaunay().tds().incident_cells(std::forward(args)...); + } // incident_cells + + /// @brief Check the radius of a vertex from the origin with its timevalue + /// @param t_vertex The vertex to check + /// @return True if the effective radial distance squared matches timevalue + /// squared + [[nodiscard]] auto does_vertex_radius_match_timevalue( + Vertex_handle_t<3> const t_vertex) const -> bool + { + auto const actual_radius_squared = squared_radius<3>(t_vertex); + auto const radius = expected_radius(t_vertex); + auto const expected_radius_squared = std::pow(radius, 2); + return actual_radius_squared > + expected_radius_squared * (1 - TOLERANCE) && + actual_radius_squared < expected_radius_squared * (1 + TOLERANCE); + } // does_vertex_radius_match_timevalue + + /// @brief Calculates the expected radial distance of a vertex + /// @details The formula for the radius is: + /// + /// \f[R=I+S(t-1)\f] + /// + /// Where I is INITIAL_RADIUS, S is RADIAL_SEPARATION, and t is timevalue + /// + /// @param t_vertex The vertex to check + /// @return The expected radial distance of the vertex with that timevalue + [[nodiscard]] auto expected_radius(Vertex_handle_t<3> const& t_vertex) const + -> double + { + auto const timevalue = t_vertex->info(); + return m_initial_radius + m_foliation_spacing * (timevalue - 1); + } // expected_radial_distance + + /// @brief Calculate the expected timevalue for a vertex + /// @param t_vertex The vertex to check + /// @return The expected timevalue of the vertex + [[nodiscard]] auto expected_timevalue( + Vertex_handle_t<3> const& t_vertex) const -> int + { + return foliated_triangulations::expected_timevalue<3>( + t_vertex, m_initial_radius, m_foliation_spacing); + } // expected_timevalue + + /// @return True if all vertices have correct timevalues + [[nodiscard]] auto check_all_vertices() const -> bool + { + return foliated_triangulations::check_vertices<3>( + m_triangulation, m_initial_radius, m_foliation_spacing); + } // check_all_vertices + + /// @return A container of incorrect vertices + [[nodiscard]] auto find_incorrect_vertices() const + { + return foliated_triangulations::find_incorrect_vertices<3>( + m_triangulation, m_initial_radius, m_foliation_spacing); + } // find_incorrect_vertices + + /// @brief Fix vertices with wrong timevalues after foliation + [[nodiscard]] auto fix_vertices() const -> bool + { + return foliated_triangulations::fix_vertices<3>( + m_triangulation, m_initial_radius, m_foliation_spacing); + } // fix_vertices + + /// @brief Print values of a vertex + void print_vertices() const + { + for (auto const& vertex : m_vertices) + { + fmt::print("Vertex Point: ({}) Timevalue: {} Expected Timevalue: {}\n", + utilities::point_to_str(vertex->point()), vertex->info(), + expected_timevalue(vertex)); + } + } // print_vertices + + /// @brief Print timevalues of each vertex in the edge and classify as + /// timelike or spacelike + void print_edges() const + { + for (auto const& edge : m_edges) + { + if (classify_edge<3>(edge)) { fmt::print("==> timelike\n"); } + else + { + fmt::print("==> spacelike\n"); + } + } + } // print_edges + + /// @brief Print the number of spacelike faces per timeslice + void print_volume_per_timeslice() const + { + for (auto j = min_time(); j <= max_time(); ++j) + { + fmt::print("Timeslice {} has {} spacelike faces.\n", j, + m_spacelike_facets.count(j)); + } + } // print_volume_per_timeslice + + /// @return Container of cells + [[nodiscard]] auto get_cells() const -> Cell_container const& + { + assert(m_cells.size() == number_of_finite_cells()); + return m_cells; + } // get_cells + + /// @return Container of (3,1) cells + [[nodiscard]] auto get_three_one() const noexcept + -> std::span + { return std::span{m_three_one}; } // get_three_one + + /// @return Container of (2,2) cells + [[nodiscard]] auto get_two_two() const noexcept -> Cell_container const& + { return m_two_two; } // get_two_two + + /// @return Container of (1,3) cells + [[nodiscard]] auto get_one_three() const noexcept -> Cell_container const& + { return m_one_three; } // get_one_three + + /// @brief Check that all cells are correctly classified + /// @details A default triangulation will have no cells, and for this case + /// the triangulation is correctly classified. A triangulation with cells + /// will have them checked via check_cells. + /// @return True if there are no cells or all cells are validly classified + [[nodiscard]] auto check_all_cells() const -> bool + { + return foliated_triangulations::check_cells<3>(get_delaunay()); + } // check_all_cells + + /// @brief Fix all cells in the triangulation + auto fix_cells() const -> bool + { + return foliated_triangulations::fix_cells<3>(get_delaunay()); + } // fix_cells + + /// @brief Print timevalues of each vertex in the cell and the resulting + /// cell->info() + void print_cells() const + { foliated_triangulations::print_cells<3>(m_cells); } + + /// @brief Print triangulation statistics + void print() const + { + fmt::print( + "Triangulation has {} vertices and {} edges and {} faces and {} " + "simplices.\n", + this->number_of_vertices(), this->number_of_finite_edges(), + this->number_of_finite_facets(), this->number_of_finite_cells()); + } + + private: + [[nodiscard]] auto classify_vertices(Vertex_container const& vertices) const + -> Vertex_container + { + assert(vertices.size() == number_of_vertices()); + for (auto const& vertex : vertices) + { + vertex->info() = expected_timevalue(vertex); + } + return vertices; + } // classify_vertices + + /// @brief Classify cells + /// @param cells The container of simplices to classify + /// @return A container of simplices with Cell_type written to cell->info() + [[nodiscard]] auto classify_cells(Cell_container const& cells) const + -> Cell_container + { + assert(cells.size() == number_of_finite_cells()); + for (auto const& cell : cells) + { + cell->info() = static_cast(expected_cell_type<3>(cell)); + } + return cells; + } // classify_cells + + /// @return Container of all the finite facets in the triangulation + [[nodiscard]] auto collect_faces() const -> Face_container + { + // Somewhere in bistellar_flip_really a vertex is rendered invalid + assert(is_tds_valid()); + Face_container init_faces; + init_faces.reserve(get_delaunay().number_of_finite_facets()); + for (auto fit = get_delaunay().finite_facets_begin(); + fit != get_delaunay().finite_facets_end(); ++fit) + { + Cell_handle_t<3> const cell = fit->first; + // Each face is valid in the triangulation + assert(get_delaunay().tds().is_facet(cell, fit->second)); + Face_handle_t<3> const thisFacet{std::make_pair(cell, fit->second)}; + init_faces.emplace_back(thisFacet); + } + assert(init_faces.size() == get_delaunay().number_of_finite_facets()); + return init_faces; + } // collect_faces + + /// @return Container of all the finite edges in the triangulation + [[nodiscard]] auto collect_edges() const -> Edge_container + { + assert(is_tds_valid()); + Edge_container init_edges; + init_edges.reserve(number_of_finite_edges()); + for (auto eit = get_delaunay().finite_edges_begin(); + eit != get_delaunay().finite_edges_end(); ++eit) + { + Cell_handle_t<3> const cell = eit->first; + Edge_handle_t<3> const thisEdge{cell, + cell->index(cell->vertex(eit->second)), + cell->index(cell->vertex(eit->third))}; + // Each edge is valid in the triangulation + assert(get_delaunay().tds().is_valid(thisEdge.first, thisEdge.second, + thisEdge.third)); + init_edges.emplace_back(thisEdge); + } + assert(init_edges.size() == number_of_finite_edges()); + return init_edges; + } // collect_edges + }; + + using FoliatedTriangulation_3 = FoliatedTriangulation<3>; + +} // namespace foliated_triangulations + +#endif // CDT_PLUSPLUS_FOLIATEDTRIANGULATION_HPP diff --git a/include/Formatters.hpp b/include/Formatters.hpp new file mode 100644 index 0000000000..ac34fcbb0f --- /dev/null +++ b/include/Formatters.hpp @@ -0,0 +1,41 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2025 Adam Getchell + ******************************************************************************/ + +/// @file Formatters.hpp +/// @brief Formatter specializations for various types +/// @author Adam Getchell +/// @details Formatter specializations for types used in the project + +#ifndef CDT_PLUSPLUS_FORMATTERS_HPP +#define CDT_PLUSPLUS_FORMATTERS_HPP + +#include +#include + +#include + +#include "Triangulation_traits.hpp" + +// Formatter specialization for CGAL::Point_3 +template +struct fmt::formatter> +{ + // Format specification handling - keeping it simple for now + auto constexpr parse(format_parse_context& ctx) -> decltype(ctx.begin()) + { return ctx.begin(); } + + // Format the point as a string with coordinates + template + auto format(CGAL::Point_3 const& point, FormatContext& ctx) const + -> decltype(ctx.out()) + { + std::stringstream ss; + ss << point; + return fmt::format_to(ctx.out(), "{}", ss.str()); + } +}; + +#endif // CDT_PLUSPLUS_FORMATTERS_HPP diff --git a/include/Function_ref.hpp b/include/Function_ref.hpp deleted file mode 100644 index fbdf3c5913..0000000000 --- a/include/Function_ref.hpp +++ /dev/null @@ -1,95 +0,0 @@ -//============================================================================== -// LLVM Release License -//============================================================================== -// University of Illinois/NCSA -// Open Source License -// -// Copyright (c) 2003-2016 University of Illinois at Urbana-Champaign. -// All rights reserved. -// -// Developed by: -// -// LLVM Team -// -// University of Illinois at Urbana-Champaign -// -// http://llvm.org -// -// Permission is hereby granted, free of charge, to any person obtaining a copy -// of this software and associated documentation files (the "Software"), to -// deal with 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: -// -//* Redistributions of source code must retain the above copyright notice, -// this list of conditions and the following disclaimers. -// -//* Redistributions in binary form must reproduce the above copyright notice, -// this list of conditions and the following disclaimers in the -// documentation and/or other materials provided with the distribution. -// -//* Neither the names of the LLVM Team, University of Illinois at -// Urbana-Champaign, nor the names of its contributors may be used to -// endorse or promote products derived from this Software without specific -// prior written permission. -// -// 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 -// CONTRIBUTORS 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 -// WITH THE SOFTWARE. - -/// An efficient, type-erasing, non-owning reference to a callable. This is -/// intended for use as the type of a function parameter that is not used -/// after the function in question returns. -/// -/// This class does not own the callable, so it is not in general safe to store -/// a function_ref. - -/// @file Function_ref.hpp from llvm/ADT/STLExtras.h -/// @brief Efficient, type-erasing, non-owning function reference -/// @author https://llvm.org - -#ifndef SRC_FUNCTION_REF_HPP_ -#define SRC_FUNCTION_REF_HPP_ - -#include -#include -#include -template -class function_ref; - -template -class function_ref -{ - Ret (*callback)(intptr_t callable, Params... params); - intptr_t callable; - - template - static Ret callback_fn(intptr_t callable, Params... params) - { - return (*reinterpret_cast(callable))( - std::forward(params)...); - } - - public: - template - explicit function_ref( - Callable&& callable, - typename std::enable_if< - !std::is_same::type, - function_ref>::value>::type* = nullptr) - : callback(callback_fn::type>) - , callable(reinterpret_cast(&callable)) - {} - - Ret operator()(Params... params) const - { - return callback(callable, std::forward(params)...); - } -}; - -#endif // SRC_FUNCTION_REF_HPP_ diff --git a/include/Geometry.hpp b/include/Geometry.hpp new file mode 100644 index 0000000000..774ccb689c --- /dev/null +++ b/include/Geometry.hpp @@ -0,0 +1,106 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2018 Adam Getchell + ******************************************************************************/ + +/// @file Geometry.hpp +/// @brief Geometric scalars of the Manifold used to calculate the Regge action +/// @details This is a data structure to hold the geometric information of the +/// Manifold for quick access in calculation of the Regge action. There are +/// no class invariants, so it is a simple struct. +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_GEOMETRY_HPP +#define CDT_PLUSPLUS_GEOMETRY_HPP + +#include "Foliated_triangulation.hpp" + +/// Geometry class template +/// @tparam dimension Dimensionality of geometry +template +struct Geometry; + +/// 3D Geometry +template <> +struct [[nodiscard("This contains data!")]] Geometry<3> +{ + /// @brief Number of 3D simplices + Int_precision N3{0}; // NOLINT + + /// @brief Number of (3,1) simplices + Int_precision N3_31{0}; // NOLINT + + /// @brief Number of (1,3) simplices + Int_precision N3_13{0}; // NOLINT + + /// @brief Number of (3,1) + (1,3) simplices + Int_precision N3_31_13{0}; // NOLINT + + /// @brief Number of (2,2) simplices + Int_precision N3_22{0}; // NOLINT + + /// @brief Number of 2D faces + Int_precision N2{0}; // NOLINT + + /// @brief Number of 1D edges + Int_precision N1{0}; // NOLINT + + /// @brief Number of timelike edges + Int_precision N1_TL{0}; // NOLINT + + /// @brief Number of spacelike edges + Int_precision N1_SL{0}; // NOLINT + + /// @brief Number of vertices + Int_precision N0{0}; // NOLINT + + /// @brief Default ctor + Geometry() = default; + + /// @brief Constructor with triangulation + /// @param triangulation Triangulation for which Geometry is being + /// calculated + explicit Geometry( + foliated_triangulations::FoliatedTriangulation_3 const& triangulation) + + : N3{static_cast(triangulation.number_of_finite_cells())} + , N3_31{static_cast(triangulation.get_three_one().size())} + , N3_13{static_cast(triangulation.get_one_three().size())} + , N3_31_13{N3_31 + N3_13} + , N3_22{static_cast(triangulation.get_two_two().size())} + , N2{static_cast(triangulation.number_of_finite_facets())} + , N1{static_cast(triangulation.number_of_finite_edges())} + , N1_TL{triangulation.N1_TL()} + , N1_SL{triangulation.N1_SL()} + , N0{static_cast(triangulation.number_of_vertices())} + + {} + + /// @brief Non-member swap function for Geometry + /// @details Used for no-except updates of geometry data structures. + /// Usually called from a Manifold swap. + /// @param swap_from The value to be swapped from. Assumed to be discarded. + /// @param swap_into The value to be swapped into. + friend void swap(Geometry& swap_from, Geometry& swap_into) noexcept + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + using std::swap; + swap(swap_from.N3, swap_into.N3); + swap(swap_from.N3_31, swap_into.N3_31); + swap(swap_from.N3_13, swap_into.N3_13); + swap(swap_from.N3_31_13, swap_into.N3_31_13); + swap(swap_from.N3_22, swap_into.N3_22); + swap(swap_from.N2, swap_into.N2); + swap(swap_from.N1, swap_into.N1); + swap(swap_from.N1_TL, swap_into.N1_TL); + swap(swap_from.N1_SL, swap_into.N1_SL); + swap(swap_from.N0, swap_into.N0); + } // swap +}; // struct Geometry<3> + +using Geometry_3 = Geometry<3>; + +#endif // CDT_PLUSPLUS_GEOMETRY_HPP diff --git a/include/Manifold.hpp b/include/Manifold.hpp new file mode 100644 index 0000000000..ba1cfc3fcf --- /dev/null +++ b/include/Manifold.hpp @@ -0,0 +1,428 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2018 Adam Getchell + ******************************************************************************/ + +/// @file Manifold.hpp +/// @brief Data structures for manifolds +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_MANIFOLD_HPP +#define CDT_PLUSPLUS_MANIFOLD_HPP + +#include +#include + +#include "Geometry.hpp" + +namespace manifolds +{ + /// @brief Create Causal vertices + /// @tparam dimension Dimensionality of vertices + /// @param vertices A container of vertices + /// @param timevalues A container of matching timevalues + /// @return A container of Causal_vertices + template + auto make_causal_vertices(std::span const> vertices, + std::span const timevalues) + -> Causal_vertices_t + { + return foliated_triangulations::make_causal_vertices(vertices, + timevalues); + } + + /// Manifold class template + /// @tparam dimension Dimensionality of manifold + template + class Manifold; + + /// 3D Manifold + template <> + class [[nodiscard("This contains data!")]] Manifold<3> + { + using Triangulation = foliated_triangulations::FoliatedTriangulation_3; + using Geometry = Geometry_3; + + /// @brief The data structure of geometric and combinatorial relationships + Triangulation m_triangulation; + + /// @brief The data structure of scalar values for computations + Geometry m_geometry; + + public: + /// @brief Dimensionality of the manifold + /// @details Used to determine the manifold dimension at compile-time + static int constexpr dimension = 3; + + /// @brief Topology of the manifold + static topology_type constexpr topology = topology_type::SPHERICAL; + + /// @brief Default dtor + ~Manifold() = default; + + /// @brief Default ctor + Manifold() = default; + + /// @brief Default copy ctor + Manifold(Manifold const& other) = default; + + /// @brief Default copy assignment + auto operator=(Manifold const& other) -> Manifold& = default; + + /// @brief Default move ctor + Manifold(Manifold&& other) = default; + + /// @brief Default move assignment + auto operator=(Manifold&& other) -> Manifold& = default; + + /// @brief Non-member swap function for Manifolds. + /// @details Used for no-except updates of manifolds after moves. + /// @param swap_from The value to be swapped from. Assumed to be discarded. + /// @param swap_into The value to be swapped into. + friend void swap(Manifold& swap_from, Manifold& swap_into) noexcept + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + using std::swap; + swap(swap_from.m_triangulation, swap_into.m_triangulation); + swap(swap_from.m_geometry, swap_into.m_geometry); + } // swap + + /// @brief Construct manifold from a Foliated triangulation + /// @param t_foliated_triangulation Triangulation used to construct manifold + explicit Manifold(Triangulation t_foliated_triangulation) + : m_triangulation{std::move(t_foliated_triangulation)} + , m_geometry{get_triangulation()} + {} + + /// @brief Construct manifold using arguments + /// @param t_desired_simplices Number of desired simplices + /// @param t_desired_timeslices Number of desired timeslices + /// @param t_initial_radius Radius of first timeslice + /// @param t_foliation_spacing Radial separation between timeslices + Manifold(Int_precision const t_desired_simplices, + Int_precision const t_desired_timeslices, + double const t_initial_radius = INITIAL_RADIUS, + double const t_foliation_spacing = FOLIATION_SPACING) + : Manifold{ + Triangulation{t_desired_simplices, t_desired_timeslices, + t_initial_radius, t_foliation_spacing} + } + {} + + /// @brief Construct manifold from Causal_vertices + /// Pass-by-value-then-move. + /// @param causal_vertices Causal_vertices to place into the Manifold + /// @param t_initial_radius Radius of first timeslice + /// @param t_foliation_spacing Radial separation between timeslices + explicit Manifold(Causal_vertices_t<3> const& causal_vertices, + double const t_initial_radius = INITIAL_RADIUS, + double const t_foliation_spacing = FOLIATION_SPACING) + : Manifold{ + Triangulation{causal_vertices, t_initial_radius, + t_foliation_spacing} + } + {} + + /// @brief Update the Manifold data structures + void update() + try + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + update_triangulation(); + update_geometry(); + } + catch (std::system_error const& ex) + { + spdlog::trace("Exception thrown: {}\n", ex.what()); + } // update + + /// @returns A read-only reference to the triangulation + [[nodiscard]] auto get_triangulation() const noexcept + -> Triangulation const& + { return m_triangulation; } // get_triangulation + + /// @returns A read-only reference to the Delaunay triangulation + [[nodiscard]] auto get_delaunay() const noexcept -> Delaunay_t<3> const& + { return get_triangulation().get_delaunay(); } // get_delaunay + + /// @returns A mutable reference to the triangulation + [[nodiscard]] auto triangulation() -> Triangulation& + { return m_triangulation; } // triangulation + + /// @returns A read-only reference to the Geometry + [[nodiscard]] auto get_geometry() const -> Geometry const& + { return m_geometry; } // get_geometry + + /// @brief Forwarding to FoliatedTriangulation_3.is_foliated() + /// @returns True if the Manifold triangulation is foliated + [[nodiscard]] auto is_foliated() const -> bool + { return m_triangulation.is_foliated(); } // is_foliated + + /// @brief Forwarding to FoliatedTriangulation.is_delaunay() + /// @returns True if the Manifold triangulation is Delaunay + [[nodiscard]] auto is_delaunay() const -> bool + { return m_triangulation.is_delaunay(); } // is_delaunay + + /// @brief Forwarding to FoliatedTriangulation.is_tds_valid() + /// @returns True if the TriangulationDataStructure is valid + [[nodiscard]] auto is_valid() const -> bool + { return m_triangulation.is_tds_valid(); } // is_valid + + /// @returns If base data structures are correct + [[nodiscard]] auto is_correct() const -> bool + { return m_triangulation.is_correct(); } // is_correct + + /// @brief Perfect forwarding to FoliatedTriangulation_3.is_vertex() + /// @tparam VertexType The vertex type + /// @param t_vertex_candidate The vertex to check + /// @returns True if the vertex candidate is a vertex + template + [[nodiscard]] auto is_vertex(VertexType&& t_vertex_candidate) const -> bool + { + return m_triangulation.get_delaunay().is_vertex( + std::forward(t_vertex_candidate)); + } // is_vertex + + /// @brief Forwarding to FoliatedTriangulation_3.is_edge() + /// @param t_edge_candidate The edge to test + /// @returns True if the candidate is an edge + [[nodiscard]] auto is_edge( + Edge_handle_t<3> const& t_edge_candidate) const noexcept -> bool + { + return m_triangulation.get_delaunay().tds().is_edge( + t_edge_candidate.first, t_edge_candidate.second, + t_edge_candidate.third); + } // is_edge + + /// @returns Run-time dimensionality of the triangulation data structure + [[nodiscard]] auto dimensionality() const + { return m_triangulation.dimension(); } + + /// @brief Initial radius of the first timeslice + [[nodiscard]] auto initial_radius() const + { return m_triangulation.initial_radius(); } + + /// @brief Radial separation between timeslices + [[nodiscard]] auto foliation_spacing() const + { return m_triangulation.foliation_spacing(); } + + /// @returns Number of 3D simplices in geometry data structure + [[nodiscard]] auto N3() const { return m_geometry.N3; } + + /// @returns Number of (3,1) simplices in geometry data structure + [[nodiscard]] auto N3_31() const { return m_geometry.N3_31; } + + /// @returns Number of (2,2) simplices in geometry data structure + [[nodiscard]] auto N3_22() const { return m_geometry.N3_22; } + + /// @returns Number of (1,3) simplices in geometry data structure + [[nodiscard]] auto N3_13() const { return m_geometry.N3_13; } + + /// @returns Number of (3,1) and (1,3) simplices in geometry data structure + [[nodiscard]] auto N3_31_13() const { return m_geometry.N3_31_13; } + + /// @returns Number of 3D simplices in triangulation data structure + [[nodiscard]] auto simplices() const + { + return static_cast(m_triangulation.get_cells().size()); + } // number_of_simplices + + /// @returns Number of 2D faces in geometry data structure + [[nodiscard]] auto N2() const { return m_geometry.N2; } + + /// @returns An associative container of spacelike faces indexed by + /// timevalue + [[nodiscard]] auto N2_SL() const -> auto const& + { return m_triangulation.N2_SL(); } // N2_SL + + /// @returns Number of 2D faces in triangulation data structure + [[nodiscard]] auto faces() const + { + return static_cast( + m_triangulation.number_of_finite_facets()); + } // faces + + /// @returns Number of 1D edges in geometry data structure + [[nodiscard]] auto N1() const { return m_geometry.N1; } + + /// @returns Number of spacelike edges in triangulation data structure + [[nodiscard]] auto N1_SL() const { return m_triangulation.N1_SL(); } + + /// @returns Number of timelike edges in triangulation data structure + [[nodiscard]] auto N1_TL() const { return m_triangulation.N1_TL(); } + + /// @returns Number of 1D edges in triangulation data structure + [[nodiscard]] auto edges() const + { + return static_cast( + m_triangulation.number_of_finite_edges()); + } // edges + + /// @returns Number of vertices in geometry data structure + [[nodiscard]] auto N0() const { return m_geometry.N0; } + + /// @returns Number of vertices in triangulation data structure + [[nodiscard]] auto vertices() const + { + return static_cast(m_triangulation.number_of_vertices()); + } // vertices + + /// @returns Minimum timeslice value in triangulation data structure + [[nodiscard]] auto min_time() const + { return m_triangulation.min_time(); } // min_time + + /// @returns Maximum timeslice value in triangulation data structure + [[nodiscard]] auto max_time() const + { return m_triangulation.max_time(); } // max_time + + /// @brief Perfect forwarding to FoliatedTriangulation_3.degree() + template + [[nodiscard]] auto degree(VertexHandle&& t_vertex) const -> decltype(auto) + { + return m_triangulation.degree(std::forward(t_vertex)); + } // degree + + /// @brief Perfect forwarding to FoliatedTriangulation_3.incident_cells() + template + [[nodiscard]] auto incident_cells(Ts&&... args) const noexcept + -> decltype(auto) + { + return m_triangulation.incident_cells(std::forward(args)...); + } // incident_cells + + /// @brief Call to triangulation_.get_timelike_edges() + [[nodiscard]] auto get_timelike_edges() const noexcept -> auto const& + { return m_triangulation.get_timelike_edges(); } // get_timelike_edges + + /// @brief Call triangulation.get_spacelike_edges() + [[nodiscard]] auto get_spacelike_edges() const -> auto const& + { return m_triangulation.get_spacelike_edges(); } // get_spacelike_edges + + /// @brief Call FoliatedTriangulation_3.get_vertices() + [[nodiscard]] auto get_vertices() const noexcept -> auto const& + { return m_triangulation.get_vertices(); } // get_vertices + + /// @brief Call FoliatedTriangulation_3.get_vertices_span() + [[nodiscard]] auto get_vertices_span() const noexcept -> auto + { return m_triangulation.get_vertices_span(); } // get_vertices_span + + /// @returns True if all cells in triangulation are classified and match + /// number in geometry + [[nodiscard]] auto check_simplices() const -> bool + { + return this->simplices() == this->N3() && + m_triangulation.check_all_cells(); + } // check_simplices + + /// @brief Print the codimension 1 volume of simplices (faces) per timeslice + void print_volume_per_timeslice() const + { + m_triangulation.print_volume_per_timeslice(); + } // print_volume_per_timeslice + + /// @brief Print values of a vertex->info() + void print_vertices() const { m_triangulation.print_vertices(); } + + /// @brief Print timevalues of each vertex in the cell and the resulting + /// cell->info() + void print_cells() const { m_triangulation.print_cells(); } + + /// @brief Print manifold + void print() const + try + { + fmt::print( + "Manifold has {} vertices and {} edges and {} faces and {} " + "simplices.\n", + this->N0(), this->N1(), this->N2(), this->N3()); + } + catch (...) + { + fmt::print(stderr, "print() went wrong ...\n"); + throw; + } // print + + /// @brief Print details of the manifold + void print_details() const + try + { + fmt::print( + "There are {} (3,1) simplices and {} (2,2) simplices and {} (1,3) " + "simplices.\n", + this->N3_31(), this->N3_22(), this->N3_13()); + fmt::print("There are {} timelike edges and {} spacelike edges.\n", + this->N1_TL(), this->N1_SL()); + } + catch (...) + { + fmt::print(stderr, "print_details() went wrong ...\n"); + throw; + } // print_details + + /// @brief Obtains a vertex handle from a point + /// @param point The point to search for + /// @return The vertex handle to the vertex containing the point + auto get_vertex(Point_t<3> const& point) const -> Vertex_handle_t<3> + { + Vertex_handle_t<3> result; + m_triangulation.get_delaunay().is_vertex(point, result); + return result; + } // get_vertex + + /// @brief Get a cell handle from 4 vertex handles + /// @param vh1 The first vertex handle + /// @param vh2 The second vertex handle + /// @param vh3 The third vertex handle + /// @param vh4 The fourth vertex handle + /// @return The cell handle containing the vertex handles + auto get_cell(Vertex_handle_t<3> const& vh1, Vertex_handle_t<3> const& vh2, + Vertex_handle_t<3> const& vh3, + Vertex_handle_t<3> const& vh4) const -> Cell_handle_t<3> + { + Cell_handle_t<3> result; + m_triangulation.get_delaunay().is_cell(vh1, vh2, vh3, vh4, result); + return result; + } // get_cell_handle + + private: + /// @brief Update the triangulation + void update_triangulation() + try + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + // Constructing a new triangulation updates all data structures + Triangulation local_triangulation(m_triangulation.get_delaunay(), + m_triangulation.initial_radius(), + m_triangulation.foliation_spacing()); + swap(local_triangulation, m_triangulation); + } + catch (std::system_error const& ex) + { + fmt::print("Exception thrown: {}\n", ex.what()); + } // update_triangulation + + /// @brief Update geometry data of the manifold when the triangulation has + /// been changed + void update_geometry() noexcept + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + // constructing a new geometry updates all data structures + Geometry geom(m_triangulation); + swap(geom, m_geometry); + } // update_geometry + }; + + using Manifold_3 = Manifold<3>; + +} // namespace manifolds + +#endif // CDT_PLUSPLUS_MANIFOLD_HPP diff --git a/include/Measurements.hpp b/include/Measurements.hpp deleted file mode 100644 index bae17ba57c..0000000000 --- a/include/Measurements.hpp +++ /dev/null @@ -1,97 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2016-2018 Adam Getchell -/// -/// Interesting measurements on the simulation - -/// @file Measurements.hpp -/// @brief Measurements of the simulation -/// @author Adam Getchell - -#ifndef SRC_MEASUREMENTS_HPP_ -#define SRC_MEASUREMENTS_HPP_ - -/// Toggles detailed per-facet debugging output -#define DETAILED_DEBUGGING -#undef DETAILED_DEBUGGING - -#include -#include -#include -#include -#include - -using Facet = Delaunay::Facet; - -template -auto VolumePerTimeslice(T&& manifold) -> decltype(manifold) -{ -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; -#endif - - // manifold.update(); - print_results(manifold); - - std::multimap spacelike_facets; - Delaunay::Finite_facets_iterator fit; - // Visit every finite facet in the manifold - for (fit = manifold.triangulation->finite_facets_begin(); - fit != manifold.triangulation->finite_facets_end(); ++fit) - { - // Iterate over all vertices in the facet - // First get the cell - auto cell = fit->first; - // Now the index of the facet in the cell - auto index_of_facet = fit->second; -#ifdef DETAILED_DEBUGGING - std::cout << "Facet index is " << index_of_facet << "\n"; -#endif - std::set facet_timevalues; - // The vertices of the facet are the ones that aren't the index - for (auto i = 0; i < 4; ++i) { - if (i != index_of_facet) { -#ifdef DETAILED_DEBUGGING - std::cout << "Vertex[" << i << "] has timevalue " - << cell->vertex(i)->info() << "\n"; -#endif - facet_timevalues.insert(cell->vertex(i)->info()); - } - } - // If we have a 1-element set then all timevalues on that facet are equal - if (facet_timevalues.size() == 1) { -#ifdef DETAILED_DEBUGGING - std::cout << "Timevalue is " << facet_timevalues.front() << "\n"; -#endif - spacelike_facets.insert({*facet_timevalues.begin(), *fit}); - } - } -#ifndef NDEBUG - std::cout << "Number of spacelike faces is " << spacelike_facets.size() - << "\n"; -#endif - - // Determine which timevalues are populated - std::set timevalues; - for (const auto& item : manifold.geometry->vertices) { - timevalues.insert(item->info()); - } - - auto min_timevalue = *timevalues.cbegin(); - auto max_timevalue = *timevalues.crbegin(); - std::cout << "Minimum timevalue is " << min_timevalue << "\n"; - std::cout << "Maximum timevalue is " << max_timevalue << "\n"; - - for (auto j = min_timevalue; j <= max_timevalue; ++j) { - std::cout << "Timeslice " << j << " has " << spacelike_facets.count(j) - << " spacelike faces.\n"; - } - - // Save values in GeomInfo struct - manifold.geometry->timevalues = timevalues; - manifold.geometry->spacelike_facets = spacelike_facets; - - return manifold; -} // VolumePerTimeslice() - -#endif // SRC_MEASUREMENTS_HPP_ diff --git a/include/Metropolis.hpp b/include/Metropolis.hpp index d570f85dd0..805536be95 100644 --- a/include/Metropolis.hpp +++ b/include/Metropolis.hpp @@ -1,369 +1,515 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2015-2017 Adam Getchell -/// -/// Performs the Metropolis-Hastings algorithm on the foliated Delaunay -/// triangulations. -/// For details see: -/// M. Creutz, and B. Freedman. “A Statistical Approach to Quantum Mechanics.” -/// Annals of Physics 132 (1981): 427–62. -/// http://thy.phy.bnl.gov/~creutz/mypubs/pub044.pdf +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL -/// @todo Atomic integral types for safe multithreading -/// @todo Debug occasional infinite loops and segfaults! -/// @todo Implement concurrency -/// @todo Change A1 to count successful moves, total moves gets dragged down by (6,2) attempts + Copyright © 2015 Adam Getchell + ******************************************************************************/ /// @file Metropolis.hpp /// @brief Perform Metropolis-Hastings algorithm on Delaunay Triangulations /// @author Adam Getchell -/// @bug There's a segfault in CalculateA1 on MacOS/gcc. -/// @bug The call operator segfaults in Release mode -/// @bug The number of attempted (6,2) moves makes A1 really low preventing other moves +/// @details Performs the Metropolis-Hastings algorithm on the foliated Delaunay +/// triangulations. For details see: +/// M. Creutz, and B. Freedman. “A Statistical Approach to Quantum Mechanics.” +/// Annals of Physics 132 (1981): 427–62. +/// @see http://thy.phy.bnl.gov/~creutz/mypubs/pub044.pdf +/// @todo Implement concurrency -#ifndef SRC_METROPOLIS_HPP_ -#define SRC_METROPOLIS_HPP_ +#ifndef INCLUDE_METROPOLIS_HPP_ +#define INCLUDE_METROPOLIS_HPP_ -// CDT headers -#include -#include +#include -// C++ headers -#include -#include -#include -#include -#include +// CDT headers +#include "Move_command.hpp" +#include "Move_strategy.hpp" +#include "S3Action.hpp" using Gmpzf = CGAL::Gmpzf; -extern const std::int_fast32_t PRECISION; - -/// @class Metropolis -/// @brief Metropolis-Hastings algorithm function object -/// -/// The Metropolis-Hastings algorithm is a Markov Chain Monte Carlo method. -/// The probability of making an ergodic (Pachner) move is: +/// @brief Metropolis-Hastings algorithm strategy +/// @details The Metropolis-Hastings algorithm is a Markov Chain Monte Carlo +/// method. The probability of making an ergodic (Pachner) move is: /// /// \f[P_{ergodic move}=a_{1}a_{2}\f] /// \f[a_1=\frac{move[i]}{\sum\limits_{i}move[i]}\f] /// \f[a_2=e^{\Delta S}\f] -class Metropolis : public MoveAlgorithm +/// +/// @tparam ManifoldType The type of Manifold on which to apply the algorithm +template + requires(ManifoldType::dimension == 3) +class MoveStrategy { - private: - /// @brief The length of the timelike edges. - long double Alpha_; + using Counter = move_tracker::MoveTracker; + + /// @brief The length of the timelike edges + long double m_Alpha{}; /// @brief \f$K=\frac{1}{8\pi G_{N}}\f$. - long double K_; + long double m_K{}; /// @brief \f$\lambda=\frac{\Lambda}{8\pi G_{N}}\f$ where \f$\Lambda\f$ is - /// the cosmological constant. - long double Lambda_; + /// the cosmological constant + long double m_Lambda{}; + + /// @brief The number of move passes executed by the algorithm + /// @details Each move pass makes a number of attempts equal to the number + /// of simplices in the triangulation. + Int_precision m_passes{1}; + + /// @brief The number of passes before a checkpoint + /// @details Each checkpoint writes a file containing the current + /// triangulation. + Int_precision m_checkpoint{1}; + + /// @brief Whether checkpoint and final triangulation files may be written + bool m_write_files{true}; + + /// @brief The current geometry of the manifold + Geometry m_geometry; + + /// @brief The number of moves the algorithm tried + /// @details This equals accepted moves + rejected moves. + Counter m_proposed_moves; + + /// @brief The number of moves accepted by the algorithm + Counter m_accepted_moves; + + /// @brief The number of moves rejected by the algorithm + Counter m_rejected_moves; + + /// @brief The number of moves that were attempted by a MoveCommand. + /// @details This should equal accepted moves. + Counter m_attempted_moves; + + /// @brief The number of moves that succeeded in the MoveCommand + Counter m_succeeded_moves; + + /// @brief The number of moves that a MoveCommand failed to make due to an + /// error + Counter m_failed_moves; public: + /// @brief Default ctor + MoveStrategy() = default; + /// @brief Metropolis function object constructor - /// - /// Setup of runtime job parameters. - /// + /// @details Setup of runtime job parameters. /// @param Alpha \f$\alpha\f$ is the timelike edge length. /// @param K \f$k=\frac{1}{8\pi G_{Newton}}\f$ /// @param Lambda \f$\lambda=k*\Lambda\f$ where \f$\Lambda\f$ is the /// Cosmological constant. /// @param passes Number of passes of ergodic moves on triangulation. /// @param checkpoint Print/write output for every n=checkpoint passes. - Metropolis(const long double Alpha, const long double K, - const long double Lambda, const std::int_fast32_t passes, - const std::int_fast32_t checkpoint) - : MoveAlgorithm(passes, checkpoint), Alpha_(Alpha), K_(K), Lambda_(Lambda) + /// @param write_files Whether checkpoints may write triangulation files. + [[maybe_unused]] MoveStrategy(long double const Alpha, long double const K, + long double const Lambda, + Int_precision const passes, + Int_precision const checkpoint, + bool const write_files = true) + : m_Alpha(Alpha) + , m_K(K) + , m_Lambda(Lambda) + , m_passes(passes) + , m_checkpoint{checkpoint} + , m_write_files{write_files} { + if (m_passes < 0) + { + throw std::invalid_argument{"Metropolis passes cannot be negative"}; + } + if (m_checkpoint <= 0) + { + throw std::invalid_argument{ + "Metropolis checkpoint interval must be positive"}; + } #ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); #endif } - /// @brief Gets value of **Alpha_**. - /// @return Alpha_ - auto Alpha() const noexcept { return Alpha_; } + /// @returns The length of the timelike edge + [[nodiscard]] auto Alpha() const noexcept { return m_Alpha; } - /// @brief Gets value of **K_**. - /// @return K_ - auto K() const noexcept { return K_; } + /// @returns The normalized Newton's constant + [[nodiscard]] auto K() const noexcept { return m_K; } - /// @brief Gets value of **Lambda_**. - /// @return Lambda_ - auto Lambda() const noexcept { return Lambda_; } + /// @returns The normalized Cosmological constant + [[nodiscard]] auto Lambda() const noexcept { return m_Lambda; } - /// @brief Gets value of **passes_**. - /// @return passes_ - auto Passes() const noexcept { return passes_; } + /// @returns The number of passes to make + [[nodiscard]] auto passes() const noexcept { return m_passes; } - /// @brief Gets value of **checkpoint_**. - /// @return checkpoint_ - auto Checkpoint() const noexcept { return checkpoint_; } + /// @returns The number of passes before writing a checkpoint file + [[nodiscard]] auto checkpoint() const noexcept { return m_checkpoint; } - /// @brief Gets the total number of attempted moves. - /// @return TwoThreeMoves() + ThreeTwoMoves() + TwoSixMoves() + SixTwoMoves() - /// + FourFourMoves() - auto TotalMoves() const noexcept - { - return TwoThreeMoves() + ThreeTwoMoves() + TwoSixMoves() + SixTwoMoves() + - FourFourMoves(); - } + /// @returns Whether the strategy writes checkpoint triangulation files + [[nodiscard]] auto writes_files() const noexcept { return m_write_files; } + + /// @returns The container of trial moves + auto get_proposed() const { return m_proposed_moves; } + + /// @returns The container of accepted moves + auto get_accepted() const { return m_accepted_moves; } + + /// @returns The container of rejected moves + auto get_rejected() const { return m_rejected_moves; } + + /// @returns The container of attempted moves + auto get_attempted() const { return m_attempted_moves; } + + /// @returns The container of successful moves + auto get_succeeded() const { return m_succeeded_moves; } + + /// @returns The container of failed moves + auto get_failed() const { return m_failed_moves; } /// @brief Calculate A1 - /// - /// Calculate the probability of making a move divided by the + /// @details Calculate the probability of making a move divided by the /// probability of its reverse, that is: /// \f[a_1=\frac{move[i]}{\sum\limits_{i}move[i]}\f] /// /// @param move The type of move - /// @return \f$a_1=\frac{move[i]}{\sum\limits_{i}move[i]}\f$ - auto CalculateA1(const move_type move) const noexcept + /// @returns \f$a_1=\frac{move[i]}{\sum\limits_{i}move[i]}\f$ + auto CalculateA1(move_tracker::move_type move) const noexcept { - auto total_moves = this->TotalMoves(); - auto this_move = attempted_moves_[to_integral(move)]; + auto all_moves = m_proposed_moves.total(); + auto this_move = m_proposed_moves[move]; // Set precision for initialization and assignment functions mpfr_set_default_prec(PRECISION); // Initialize for MPFR - mpfr_t r1, r2, a1; - mpfr_inits2(PRECISION, r1, r2, a1, nullptr); + mpfr_t r_1; + mpfr_t r_2; + mpfr_t a_1; + mpfr_inits2(PRECISION, a_1, nullptr); // NOLINT - mpfr_init_set_ui(r1, this_move, MPFR_RNDD); // r1 = this_move - mpfr_init_set_ui(r2, total_moves, MPFR_RNDD); // r2 = total_moves + mpfr_init_set_si(r_1, this_move, MPFR_RNDD); // r_1 = this_move NOLINT + mpfr_init_set_si(r_2, all_moves, MPFR_RNDD); // r_2 = total_moves NOLINT // The result - mpfr_div(a1, r1, r2, MPFR_RNDD); // a1 = r1/r2 - - // std::cout << "A1 is " << mpfr_out_str(stdout, 10, 0, a1, MPFR_RNDD) + mpfr_div(a_1, r_1, r_2, MPFR_RNDD); // a_1 = r_1/r_2 NOLINT // Convert mpfr_t total to Gmpzf result by using Gmpzf(double d) - // Gmpzf result = Gmpzf(mpfr_get_d(a1, MPFR_RNDD)); - // MP_Float result = MP_Float(mpfr_get_ld(a1, MPFR_RNDD)); - auto result = mpfr_get_d(a1, MPFR_RNDD); + auto result = mpfr_get_ld(a_1, MPFR_RNDD); // NOLINT // Free memory - mpfr_clears(r1, r2, a1, nullptr); + mpfr_clears(r_1, r_2, a_1, nullptr); // NOLINT #ifndef NDEBUG - std::cout << "TotalMoves() = " << total_moves << "\n"; - std::cout << "A1 is " << result << "\n"; + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); + spdlog::trace("Total proposed moves = {}\n", all_moves); + spdlog::trace("A1 is {}\n", result); #endif return result; } // CalculateA1() /// @brief Calculate A2 - /// - /// Calculate \f$a_2=e^{\Delta S}\f$ - /// + /// @details Calculate \f$a_2=e^{\Delta S}\f$ /// @param move The type of move - /// @return \f$a_2=e^{-\Delta S}\f$ - auto CalculateA2(const move_type move) const noexcept + /// @returns \f$a_2=e^{-\Delta S}\f$ + auto CalculateA2(move_tracker::move_type const move) const noexcept { auto currentS3Action = - S3_bulk_action(N1_TL_, N3_31_13_, N3_22_, Alpha_, K_, Lambda_); + S3_bulk_action(m_geometry.N1_TL, m_geometry.N3_31_13, m_geometry.N3_22, + m_Alpha, m_K, m_Lambda); auto newS3Action = static_cast(0); - // auto newS3Action = static_cast(0); switch (move) { - case move_type::TWO_THREE: + case move_tracker::move_type::TWO_THREE: // A (2,3) move adds a timelike edge // and a (2,2) simplex - newS3Action = S3_bulk_action(N1_TL_ + 1, N3_31_13_, N3_22_ + 1, Alpha_, - K_, Lambda_); + newS3Action = + S3_bulk_action(m_geometry.N1_TL + 1, m_geometry.N3_31_13, + m_geometry.N3_22 + 1, m_Alpha, m_K, m_Lambda); break; - case move_type::THREE_TWO: + case move_tracker::move_type::THREE_TWO: // A (3,2) move removes a timelike edge // and a (2,2) simplex - newS3Action = S3_bulk_action(N1_TL_ - 1, N3_31_13_, N3_22_ - 1, Alpha_, - K_, Lambda_); + newS3Action = + S3_bulk_action(m_geometry.N1_TL - 1, m_geometry.N3_31_13, + m_geometry.N3_22 - 1, m_Alpha, m_K, m_Lambda); break; - case move_type::TWO_SIX: + case move_tracker::move_type::TWO_SIX: // A (2,6) move adds 2 timelike edges and // 2 (1,3) and 2 (3,1) simplices - newS3Action = S3_bulk_action(N1_TL_ + 2, N3_31_13_ + 4, N3_22_, Alpha_, - K_, Lambda_); + newS3Action = + S3_bulk_action(m_geometry.N1_TL + 2, m_geometry.N3_31_13 + 4, + m_geometry.N3_22, m_Alpha, m_K, m_Lambda); break; - case move_type::SIX_TWO: + case move_tracker::move_type::SIX_TWO: // A (6,2) move removes 2 timelike edges and // 2 (1,3) and 2 (3,1) simplices - newS3Action = S3_bulk_action(N1_TL_ - 2, N3_31_13_, N3_22_ - 4, Alpha_, - K_, Lambda_); + newS3Action = + S3_bulk_action(m_geometry.N1_TL - 2, m_geometry.N3_31_13 - 4, + m_geometry.N3_22, m_Alpha, m_K, m_Lambda); break; - case move_type::FOUR_FOUR: -// A (4,4) move changes nothing with respect to the action, -// and e^0==1 + case move_tracker::move_type::FOUR_FOUR: + // A (4,4) move changes nothing with respect to the action, + // and e^0==1 #ifndef NDEBUG - std::cout << "A2 is 1\n"; + spdlog::trace("A2 is 1\n"); #endif - return static_cast(1); + return static_cast(1); + default: break; } - // auto exponent = newS3Action - currentS3Action; auto exponent = currentS3Action - newS3Action; - auto exponent_double = Gmpzf_to_double(exponent); + auto exponent_double = utilities::Gmpzf_to_double(exponent); // if exponent > 0 then e^exponent >=1 so according to Metropolis // algorithm return A2=1 - if (exponent >= 0) return static_cast(1); + if (exponent >= 0) { return static_cast(1); } // Set precision for initialization and assignment functions mpfr_set_default_prec(PRECISION); // Initialize for MPFR - mpfr_t r1, a2; - mpfr_inits2(PRECISION, r1, a2, nullptr); + mpfr_t r_1; + mpfr_t a_2; + mpfr_inits2(PRECISION, a_2, nullptr); // NOLINT // Set input parameters and constants to mpfr_t equivalents - mpfr_init_set_d(r1, exponent_double, MPFR_RNDD); // r1 = exponent + mpfr_init_set_ld(r_1, exponent_double, // NOLINT + MPFR_RNDD); // r1 = exponent // e^exponent - mpfr_exp(a2, r1, MPFR_RNDD); + mpfr_exp(a_2, r_1, MPFR_RNDD); // NOLINT // Convert mpfr_t total to Gmpzf result by using Gmpzf(double d) - // Gmpzf result = Gmpzf(mpfr_get_d(a2, MPFR_RNDD)); - auto result = mpfr_get_d(a2, MPFR_RNDD); + auto result = mpfr_get_ld(a_2, MPFR_RNDD); // NOLINT // Free memory - mpfr_clears(r1, a2, nullptr); + mpfr_clears(r_1, a_2, nullptr); // NOLINT #ifndef NDEBUG - std::cout << "A2 is " << result << "\n"; + spdlog::trace("A2 is {}\n", result); #endif return result; } // CalculateA2() - /// @brief Attempt a move of the selected type - /// - /// This function implements the core of the Metropolis-Hastings algorithm - /// by generating a random number and comparing with the results of - /// CalculateA1 and CalculateA2. If the move is accepted, this function - /// calls make_move(). If not, it updates **attempted_moves_**. - /// + /// @brief Try a move of the selected type + /// @details This function implements the core of the Metropolis-Hastings + /// algorithm by generating a random number and comparing with the results + /// of CalculateA1 and CalculateA2. /// @param move The type of move - void attempt_move(const move_type move) + /// @returns True if the move is accepted + auto try_move(move_tracker::move_type const move) -> bool { + // Record the proposed move + ++m_proposed_moves[as_integer(move)]; + // Calculate probability - auto a1 = CalculateA1(move); - // Make move if random number < probability - auto a2 = CalculateA2(move); + auto a_1 = CalculateA1(move); - const auto trial_value = generate_probability(); - // Convert to Gmpzf because trial_value will be set to 0 when - // comparing with a1 and a2! - // const auto trial = Gmpzf(static_cast(trial_value)); - const auto trial = static_cast(trial_value); + // Make move if random number < probability + auto a_2 = CalculateA2(move); + if (auto const trial_value = utilities::generate_probability(); + trial_value <= a_1 * a_2) + { #ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; - std::cout << "trial_value = " << trial_value << "\n"; - std::cout << "trial = " << trial << "\n"; + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); + spdlog::trace("Trying move.\n"); + spdlog::trace("Move type = {}\n", as_integer(move)); + spdlog::trace("Trial_value = {}\n", trial_value); + spdlog::trace("A1 = {}\n", a_1); + spdlog::trace("A2 = {}\n", a_2); + spdlog::trace("A1*A2 = {}\n", a_1 * a_2); + spdlog::trace("{}\n", trial_value <= a_1 * a_2 ? "Move accepted." + : "Move rejected."); #endif - - if (trial <= a1 * a2) { - // Move accepted - make_move(move); - } - else - { - // Move rejected - // Increment attempted_moves_ - ++attempted_moves_[to_integral(move)]; + // Accept the move + ++m_accepted_moves[as_integer(move)]; + return true; } + // Reject the move + ++m_rejected_moves[as_integer(move)]; + return false; + + } // try_move() + + /// @brief Initialize the Metropolis algorithm + /// @details This function initializes the Metropolis algorithm by + /// making a move of each type, so that when A1 is calculated + /// we don't have divide by zero + /// @param t_manifold Manifold on which to operate + /// @returns A manifold with a move of each type completed + [[nodiscard]] auto initialize(ManifoldType t_manifold) + -> std::optional> + try + { + MoveCommand command(t_manifold); + fmt::print("Making initial moves ...\n"); + + // Make a move of each type + for (auto move = 0; move < move_tracker::NUMBER_OF_3D_MOVES; ++move) + { #ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; - std::cout << "Attempting move.\n"; - std::cout << "Move type = " << to_integral(move) << "\n"; - std::cout << "Trial = " << trial << "\n"; - std::cout << "A1 = " << a1 << "\n"; - std::cout << "A2 = " << a2 << "\n"; - std::cout << "A1*A2 = " << a1 * a2 << "\n"; - std::cout << ((trial <= a1 * a2) ? "Move accepted." : "Move rejected.") - << "\n"; - print_run(); + spdlog::trace("Making move {} ...\n", move); #endif - } // attempt_move() + command.enqueue(move_tracker::as_move(move)); + ++m_proposed_moves[move]; + ++m_accepted_moves[move]; + } + + // Execute the initial moves + command.execute(); + command.print_successful(); + command.print_errors(); + + // Update attempted, succeeded, and failed moves from MoveCommand + m_attempted_moves += command.get_attempted(); + m_succeeded_moves += command.get_succeeded(); + m_failed_moves += command.get_failed(); + + // Reset the move counters + command.reset_counters(); + + // print initial results + auto initial_results = command.get_results(); + initial_results.print(); + initial_results.print_details(); + + return command; + } + catch (std::system_error const& SystemError) + { + spdlog::debug("Metropolis initialization failed with {} ... exiting.\n", + SystemError.what()); + spdlog::trace("{}\n", SystemError.code().message()); + return std::nullopt; + } /// @brief Call operator - /// - /// This makes the Metropolis class into a function object. Setup of the - /// runtime job parameters is handled by the constructor. This () operator - /// conducts all of the algorithmic work for Metropolis-Hastings on the - /// manifold. - /// - /// @tparam T Type of manifold - /// @param universe Manifold on which to operate - /// @return The **universe** upon which the passes have been completed. - /// \todo: Fix segfaults here - template - auto operator()(T&& universe) -> decltype(universe) + /// @details This makes the Metropolis class into a function object. Setup + /// of the runtime job parameters is handled by the constructor. This () + /// operator conducts all of the algorithmic work for Metropolis-Hastings on + /// the manifold. + /// @param t_manifold Manifold on which to operate + /// @returns The manifold upon which the passes have been completed + auto operator()(ManifoldType const& t_manifold) -> ManifoldType { #ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); #endif - std::cout << "Starting Metropolis-Hastings algorithm ...\n"; - // Populate member data - universe_ = std::move(universe); - N1_TL_ = universe_.geometry->N1_TL(); - N3_31_13_ = universe_.geometry->N3_31_13(); - N3_22_ = universe_.geometry->N3_22(); - - // Populate attempted_moves_ and successful_moves_ - std::cout << "Making initial moves ...\n"; - try - { - // Determine how many actual timeslices there are - universe_ = std::move(VolumePerTimeslice(universe_)); - // Make a successful move of each type - make_move(move_type::TWO_THREE); - make_move(move_type::THREE_TWO); - make_move(move_type::TWO_SIX); - make_move(move_type::SIX_TWO); - print_run(); - } - catch (std::logic_error& LogicError) - { - std::cerr << LogicError.what() << "\n"; - std::cerr << "Metropolis initialization failed ... Exiting.\n"; - } - std::cout << "Making random moves ...\n"; - // Loop through passes_ - for (std::int_fast32_t pass_number = 1; pass_number <= passes_; ++pass_number) { - auto total_simplices_this_pass = CurrentTotalSimplices(); - // Loop through CurrentTotalSimplices - for (std::int_fast32_t move_attempt = 0; - move_attempt < total_simplices_this_pass; ++move_attempt) + fmt::print( + "Starting Metropolis-Hastings algorithm in {}+1 dimensions ...\n", + ManifoldType::dimension - 1); + + m_proposed_moves.reset(); + m_accepted_moves.reset(); + m_rejected_moves.reset(); + m_attempted_moves.reset(); + m_succeeded_moves.reset(); + m_failed_moves.reset(); + + auto initialized = initialize(t_manifold); + auto command = initialized ? std::move(*initialized) + : MoveCommand{t_manifold}; + + fmt::print("Making random moves ...\n"); + + // Loop through m_passes + for (auto pass_number = 1; pass_number <= m_passes; ++pass_number) + { + fmt::print("=== Pass {} ===\n", pass_number); + auto total_simplices_this_pass = command.get_const_results().N3(); + // Attempt a random move per simplex + for (auto move_attempt = 0; move_attempt < total_simplices_this_pass; + ++move_attempt) { // Pick a move to attempt - auto move_choice = generate_random_signed(0, 3); -#ifndef NDEBUG - std::cout << "Move choice = " << move_choice << "\n"; -#endif - // Convert std::int_fast32_t move_choice to move_type enum - auto move = static_cast(move_choice); - attempt_move(move); - } // End loop through CurrentTotalSimplices - - // Do stuff on checkpoint_ - if ((pass_number % checkpoint_) == 0) { - std::cout << "Pass " << pass_number << "\n"; - // write results to a file - write_file(universe_, topology_type::SPHERICAL, 3, - universe_.geometry->number_of_cells(), - universe_.geometry->max_timevalue().get()); + if (auto move = move_tracker::generate_random_move_3(); try_move(move)) + { + command.enqueue(move); + } + } // Ends loop through CurrentTotalSimplices + + // Do the moves + command.execute(); + + // Update attempted and failed moves + this->m_attempted_moves += command.get_attempted(); + this->m_succeeded_moves += command.get_succeeded(); + this->m_failed_moves += command.get_failed(); + command.reset_counters(); + + // Do stuff on checkpoint + if (pass_number % m_checkpoint == 0) + { + fmt::print("=== Pass {} ===\n", pass_number); + print_results(); + if (m_write_files) + { + fmt::print("Writing to file.\n"); + utilities::write_file(command.get_results()); + } } - } // End loop through passes_ + } // Ends loop through m_passes + // output results - std::cout << "Run results: \n"; - print_run(); - return universe_; - } + fmt::print("=== Run results ===\n"); + print_results(); + return command.get_results(); + } // operator() + + /// @brief Display results of run + void print_results() + { + fmt::print("=== Move Results ===\n"); + fmt::print( + "There were {} proposed moves with {} accepted moves and {} rejected " + "moves.\n", + m_proposed_moves.total(), m_accepted_moves.total(), + m_rejected_moves.total()); + fmt::print( + "There were {} attempted moves with {} successful moves and {} " + "failed moves.\n", + m_attempted_moves.total(), m_succeeded_moves.total(), + m_failed_moves.total()); + fmt::print( + "(2,3) moves: {} proposed ({} accepted and {} rejected) with {} " + "attempted ({} successful and {} failed).\n", + m_proposed_moves.two_three_moves(), m_accepted_moves.two_three_moves(), + m_rejected_moves.two_three_moves(), m_attempted_moves.two_three_moves(), + m_succeeded_moves.two_three_moves(), m_failed_moves.two_three_moves()); + + fmt::print( + "(3,2) moves: {} proposed ({} accepted and {} rejected) with {} " + "attempted ({} successful and {} failed).\n", + m_proposed_moves.three_two_moves(), m_accepted_moves.three_two_moves(), + m_rejected_moves.three_two_moves(), m_attempted_moves.three_two_moves(), + m_succeeded_moves.three_two_moves(), m_failed_moves.three_two_moves()); + + fmt::print( + "(2,6) moves: {} proposed ({} accepted and {} rejected) with {} " + "attempted ({} successful and {} failed).\n", + m_proposed_moves.two_six_moves(), m_accepted_moves.two_six_moves(), + m_rejected_moves.two_six_moves(), m_attempted_moves.two_six_moves(), + m_succeeded_moves.two_six_moves(), m_failed_moves.two_six_moves()); + + fmt::print( + "(6,2) moves: {} proposed ({} accepted and {} rejected) with {} " + "attempted ({} successful and {} failed).\n", + m_proposed_moves.six_two_moves(), m_accepted_moves.six_two_moves(), + m_rejected_moves.six_two_moves(), m_attempted_moves.six_two_moves(), + m_succeeded_moves.six_two_moves(), m_failed_moves.six_two_moves()); + + fmt::print( + "(4,4) moves: {} proposed ({} accepted and {} rejected) with {} " + "attempted ({} successful and {} failed).\n", + m_proposed_moves.four_four_moves(), m_accepted_moves.four_four_moves(), + m_rejected_moves.four_four_moves(), m_attempted_moves.four_four_moves(), + m_succeeded_moves.four_four_moves(), m_failed_moves.four_four_moves()); + } // print_results }; // Metropolis -#endif // SRC_METROPOLIS_HPP_ +using Metropolis_3 = + MoveStrategy; + +#endif // INCLUDE_METROPOLIS_HPP_ diff --git a/include/MoveAlgorithm.hpp b/include/MoveAlgorithm.hpp deleted file mode 100644 index 3a64313464..0000000000 --- a/include/MoveAlgorithm.hpp +++ /dev/null @@ -1,253 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2017 Adam Getchell -/// -/// Base class for all move algorithms, e.g. Metropolis, MoveAlways -/// -/// @file MoveAlgorithm.hpp -/// @brief Base class for move algorithms on Delaunay Triangulations -/// @author Adam Getchell - -#ifndef SRC_MOVE_ALGORITHM_HPP_ -#define SRC_MOVE_ALGORITHM_HPP_ - -#include -#include -#include -#include -#include - -/// @brief Convert enum class to its underlying type -/// -/// http://stackoverflow.com/questions/14589417/can-an-enum-class-be-converted-to-the-underlying-type -/// @tparam E Enum class type -/// @param e Enum class -/// @return Integral type of enum member -template -constexpr auto to_integral(E e) -> typename std::underlying_type::type -{ - return static_cast::type>(e); -} - -/// @class MoveAlgorithm -/// @brief Base class for move algorithms -class MoveAlgorithm -{ - protected: - /// @brief 2-argument constructor - /// @param passes Number of passes through simulation, where each pass - /// equals a number of moves equal to the number of simplices - /// @param checkpoint Write/print results every *checkpoint* passes - MoveAlgorithm(const std::int_fast32_t passes, const std::int_fast32_t checkpoint) - : passes_(passes), checkpoint_(checkpoint) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; -#endif - } - - /// @brief A SimplicialManifold. - SimplicialManifold universe_; - - /// @brief The current number of timelike edges - std::int_fast32_t N1_TL_{0}; - - /// @brief The current number of (3,1) and (1,3) simplices - std::int_fast32_t N3_31_13_{0}; - - /// @brief The current number of (2,2) simplices - std::int_fast32_t N3_22_{0}; - - /// @brief Attempted (2,3), (3,2), (2,6), (6,2), and (4,4) moves. - Move_tracker attempted_moves_{{0, 0, 0, 0, 0}}; - - /// @brief Successful (2,3), (3,2), (2,6), (6,2), and (4,4) moves. - Move_tracker successful_moves_{{0, 0, 0, 0, 0}}; - - /// @brief Number of passes of ergodic moves on triangulation. - std::int_fast32_t passes_{100}; - - /// @brief How often to print/write output. - std::int_fast32_t checkpoint_{10}; - - /// @brief Make a move of the selected type - /// - /// This function handles making a **move_type** move - /// by delegating to the particular named function, which handles - /// the bookkeeping for **attempted_moves_**. This function then - /// handles the bookkeeping for successful_moves_ and updates the - /// counters for N3_31_, N3_22_, and N1_TL_ accordingly. - /// - /// \done Add exception handling for moves to gracefully recover - /// \done Use MoveManager RAII class - /// - /// @param move The type of move - void make_move(const move_type move) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called.\n"; -#endif - - // Make working copies - boost::optional maybe_moved_universe{universe_}; - auto maybe_move_count = boost::make_optional(true, attempted_moves_); - - // Initialize MoveManager - MoveManager - this_move(std::move(maybe_moved_universe), std::move(maybe_move_count)); - - // Setup moves - auto move_23_lambda = - [](SimplicialManifold manifold, - Move_tracker& attempted_moves) -> SimplicialManifold { - return make_23_move(std::move(manifold), attempted_moves); - }; - auto move_32_lambda = - [](SimplicialManifold manifold, - Move_tracker& attempted_moves) -> SimplicialManifold { - return make_32_move(std::move(manifold), attempted_moves); - }; - auto move_26_lambda = - [](SimplicialManifold manifold, - Move_tracker& attempted_moves) -> SimplicialManifold { - return make_26_move(std::move(manifold), attempted_moves); - }; - auto move_62_lambda = - [](SimplicialManifold manifold, - Move_tracker& attempted_moves) -> SimplicialManifold { - return make_62_move(std::move(manifold), attempted_moves); - }; - - switch (move) - { - case move_type::TWO_THREE: - { - function_ref - move_function(move_23_lambda); - maybe_moved_universe = this_move.operator()(move_function); - } - break; - case move_type::THREE_TWO: - { - function_ref - move_function(move_32_lambda); - maybe_moved_universe = this_move.operator()(move_function); - } - break; - case move_type::TWO_SIX: - { - function_ref - move_function(move_26_lambda); - maybe_moved_universe = this_move.operator()(move_function); - } - break; - case move_type::SIX_TWO: - { - function_ref - move_function(move_62_lambda); - maybe_moved_universe = this_move.operator()(move_function); - } - break; - case move_type::FOUR_FOUR: - break; - } - - // Check if move completed successfully and update if so - if (maybe_moved_universe) { - swap(universe_, maybe_moved_universe.get()); - swap(attempted_moves_, this_move.attempted_moves_.get()); - ++successful_moves_[to_integral(move)]; - } - - // Update counters - N1_TL_ = universe_.geometry->N1_TL(); - N3_31_13_ = universe_.geometry->N3_31_13(); - N3_22_ = universe_.geometry->N3_22(); - } // make_move() - - public: - /// @brief All simplices - /// @return The current total number of simplices - auto CurrentTotalSimplices() const noexcept { return N3_31_13_ + N3_22_; } - - /// @brief Gets attempted (2,3) moves. - /// @return attempted_moves_[0] - auto TwoThreeMoves() const noexcept { return attempted_moves_[0]; } - - /// @brief Gets successful (2,3) moves. - /// @return successful_moves_[0] - auto SuccessfulTwoThreeMoves() const noexcept - { - return successful_moves_[0]; - } - - /// @brief Gets attempted (3,2) moves. - /// @return attempted_moves_[1] - auto ThreeTwoMoves() const noexcept { return attempted_moves_[1]; } - - /// @brief Gets successful (3,2) moves. - /// @return std::get<1>(successful_moves_) - auto SuccessfulThreeTwoMoves() const noexcept - { - return successful_moves_[1]; - } - - /// @brief Gets attempted (2,6) moves. - /// @return return attempted_moves_[2] - auto TwoSixMoves() const noexcept { return attempted_moves_[2]; } - - /// @brief Gets successful (2,6) moves. - /// @return std::get<2>(successful_moves_) - auto SuccessfulTwoSixMoves() const noexcept - { - return successful_moves_[2]; - } - - /// @brief Gets attempted (6,2) moves. - /// @return return attempted_moves_[3] - auto SixTwoMoves() const noexcept { return attempted_moves_[3]; } - - /// @brief Gets successful (6,2) moves. - /// @return std::get<3>(attempted_moves_) - auto SuccessfulSixTwoMoves() const noexcept - { - return successful_moves_[3]; - } - - /// @brief Gets attempted (4,4) moves. - /// @return attempted_moves_[4] - auto FourFourMoves() const noexcept { return attempted_moves_[4]; } - - /// @brief Gets successful (4,4) moves. - /// @return std::get<4>(attempted_moves_) - auto SuccessfulFourFourMoves() const noexcept - { - return successful_moves_[4]; - } - - /// @brief Displays results of run to standard output - void print_run() - { - std::cout << "Simplices: " << CurrentTotalSimplices() << "\n"; - std::cout << "Timeslices: " - << this->universe_.geometry->max_timevalue().get() << "\n"; - std::cout << "N3_31_13_: " << N3_31_13_ << "\n"; - std::cout << "N3_22_: " << N3_22_ << "\n"; - std::cout << "Timelike edges: " << N1_TL_ << "\n"; - std::cout << "Successful (2,3) moves: " << SuccessfulTwoThreeMoves() - << "\n"; - std::cout << "Attempted (2,3) moves: " << TwoThreeMoves() << "\n"; - std::cout << "Successful (3,2) moves: " << SuccessfulThreeTwoMoves() - << "\n"; - std::cout << "Attempted (3,2) moves: " << ThreeTwoMoves() << "\n"; - std::cout << "Successful (2,6) moves: " << SuccessfulTwoSixMoves() << "\n"; - std::cout << "Attempted (2,6) moves: " << TwoSixMoves() << "\n"; - std::cout << "Successful (6,2) moves: " << SuccessfulSixTwoMoves() << "\n"; - std::cout << "Attempted (6,2) moves: " << SixTwoMoves() << "\n"; - std::cout << "Successful (4,4) moves: " << SuccessfulFourFourMoves() - << "\n"; - std::cout << "Attempted (4,4) moves: " << FourFourMoves() << "\n"; - } -}; // MoveAlgorithm - -#endif // SRC_MOVE_ALGORITHM_HPP_ diff --git a/include/MoveAlways.hpp b/include/MoveAlways.hpp deleted file mode 100644 index 1e70fe2f74..0000000000 --- a/include/MoveAlways.hpp +++ /dev/null @@ -1,88 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2017 Adam Getchell -/// -/// Always picks a random move on the foliated Delaunay triangulations. -/// For testing purposes. -/// -/// @file MoveAlways.hpp -/// @brief Always randomly selects moves to perform on Delaunay Triangulations -/// @author Adam Getchell -/// @bug The call operator segfaults in Release mode - -#ifndef SRC_MOVE_ALWAYS_HPP_ -#define SRC_MOVE_ALWAYS_HPP_ - -#include -#include - -class MoveAlways : public MoveAlgorithm -{ - public: - /// @brief Default constructor using default values - MoveAlways() = default; - - /// @brief Set passes and checkpoint with MoveAlgorithm 2-argument constructor - /// @param passes Number of passes through triangulation - /// @param checkpoint Number of passes per checkpoint - MoveAlways(const std::int_fast32_t passes, const std::int_fast32_t checkpoint) - : MoveAlgorithm(passes, checkpoint) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called." << std::endl; -#endif - } - - /// @brief Call operator - /// @tparam T Type of manifold - /// @param universe Manifold on which to operate - /// @return Manifold upon which moves have been completed - template - auto operator()(T&& universe) -> decltype(universe) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called." << std::endl; -#endif - std::cout << "Starting Move Always algorithm ...\n"; - // Populate member data - universe_ = std::move(universe); - N1_TL_ = universe_.geometry->N1_TL(); - N3_31_13_ = universe_.geometry->N3_31_13(); - N3_22_ = universe_.geometry->N3_22(); - - std::cout << "Making random moves ..." << std::endl; - // Loop through passes_ - for (std::int_fast32_t pass_number = 1; pass_number <= passes_; ++pass_number) { - auto total_simplices_this_pass = CurrentTotalSimplices(); - // Loop through CurrentTotalSimplices - for (std::int_fast32_t move_attempt = 0; - move_attempt < total_simplices_this_pass; ++move_attempt) - { - // Pick a move to attempt - auto move_choice = generate_random_signed(0, 3); -#ifndef NDEBUG - std::cout << "Move choice = " << move_choice << std::endl; -#endif - - // Convert std::int_fast32_t move_choice to move_type enum - auto move = static_cast(move_choice); - make_move(move); - } // End loop through CurrentTotalSimplices - - // Do stuff on checkpoint_ - if ((pass_number % checkpoint_) == 0) { - std::cout << "Pass " << pass_number << std::endl; - // write results to a file - write_file(universe_, topology_type::SPHERICAL, 3, - universe_.geometry->number_of_cells(), - universe_.geometry->max_timevalue().get()); - } - } // End loop through passes_ - // output results - std::cout << "Run results: " << std::endl; - print_run(); - return universe_; - } -}; // MoveAlways - -#endif // SRC_MOVE_ALWAYS_HPP_ diff --git a/include/MoveManager.hpp b/include/MoveManager.hpp deleted file mode 100644 index f03b556360..0000000000 --- a/include/MoveManager.hpp +++ /dev/null @@ -1,192 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2016-2017 Adam Getchell -/// -/// Resource Acquisition Is Initialization class for managing exception-safe -/// ergodic (foliation-preserving Pachner) moves. -/// See http://www.stroustrup.com/except.pdf and -/// http://exceptionsafecode.com for details. -/// -/// @file MoveManager.hpp -/// @brief RAII class to manage exception-safe foliation-preserving -/// Pachner moves -/// @author Adam Getchell - -#ifndef SRC_MOVEMANAGER_HPP_ -#define SRC_MOVEMANAGER_HPP_ - -#include -#include -#include -#include -#include -#include -#include -#include - -using move_invariants = std::array; - -/// @class MoveManager -/// @brief RAII Function object to handle moves -/// @tparam T1 SimplicialManifold type -/// @tparam T2 Move counter type -template -class MoveManager -{ - public: - /// @brief An option type SimplicialManifold - T1 universe_; - - /// @brief An option type move counter - T2 attempted_moves_; - - /// @brief A count of N3_31, N3_22, N3_13, N1_TL, N1_SL, N0 - move_invariants check{{0, 0, 0, 0, 0, 0}}; - - /// @brief Perfect forwarding constructor initializer - /// - /// Because a SimplicialManifold is move-only and uses std::unique_ptrs, - /// this RAII class should be initialized with option types. The general - /// pattern is to make option-types and pass those to the ctor, and then - /// check that the returned data structures are non-empty before consuming - /// them. Any thrown exceptions will call the destructor, so the returned - /// data structures will be empty and the option types will evaluate to false. - /// - /// @param universe Initializes universe_ - /// @param attempted_moves Initializes attempted_moves_ - MoveManager(T1&& universe, T2&& attempted_moves) - : universe_{std::forward(universe)} - , attempted_moves_{std::forward(attempted_moves)} - {} - - /// Default dtor - ~MoveManager() = default; - /// Delete copy ctor - MoveManager(MoveManager const& source) = delete; - /// Delete copy assignment - MoveManager& operator=(MoveManager const& rhs) = delete; - /// Delete move ctor - MoveManager(MoveManager&& source) = delete; - /// Delete move assignment - MoveManager& operator=(MoveManager&& rhs) = delete; - - auto ArrayDifference(Move_tracker first, Move_tracker second) - { - for (int j = 0; j < 5; ++j) { - if (first[j] - second[j] != 0) return j; - } - throw std::runtime_error("No move found!"); - } - - bool check_move_postconditions(Move_tracker new_moves, Move_tracker old_moves) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called." << std::endl; -#endif - auto move = static_cast(ArrayDifference(new_moves, old_moves)); - switch (move) - { - case move_type::TWO_THREE: - { - return (check[0] == universe_.get().geometry->N3_31() && - check[1] == universe_.get().geometry->N3_22() - 1 && - check[2] == universe_.get().geometry->N3_13() && - check[3] == universe_.get().geometry->N1_TL() - 1 && - check[4] == universe_.get().geometry->N1_SL() && - check[5] == universe_.get().geometry->N0()); - } - case move_type::THREE_TWO: - { - return (check[0] == universe_.get().geometry->N3_31() && - check[1] == universe_.get().geometry->N3_22() + 1 && - check[2] == universe_.get().geometry->N3_13() && - check[3] == universe_.get().geometry->N1_TL() + 1 && - check[4] == universe_.get().geometry->N1_SL() && - check[5] == universe_.get().geometry->N0()); - } - case move_type::TWO_SIX: - { - return (check[0] == universe_.get().geometry->N3_31() - 2 && - check[1] == universe_.get().geometry->N3_22() && - check[2] == universe_.get().geometry->N3_13() - 2 && - check[3] == universe_.get().geometry->N1_TL() - 2 && - check[4] == universe_.get().geometry->N1_SL() - 3 && - check[5] == universe_.get().geometry->N0() - 1); - } - case move_type::SIX_TWO: - { - return (check[0] == universe_.get().geometry->N3_31() + 2 && - check[1] == universe_.get().geometry->N3_22() && - check[2] == universe_.get().geometry->N3_13() + 2 && - check[3] == universe_.get().geometry->N1_TL() + 2 && - check[4] == universe_.get().geometry->N1_SL() + 3 && - check[5] == universe_.get().geometry->N0() + 1); - } - case move_type::FOUR_FOUR: - { - return false; - } - } - } - /// @brief Function call - /// @param move A function_ref to the move being performed - /// @return The results of move on universe_ - auto operator()( - function_ref move) - { -#ifndef NDEBUG - std::cout << __PRETTY_FUNCTION__ << " called." << std::endl; -#endif - - try - { - // Look at moves made so far - auto old_moves = attempted_moves_.get(); - // auto N3_31_13_ = universe_.get().geometry->N3_31(); - check[0] = universe_.get().geometry->N3_31(); - check[1] = universe_.get().geometry->N3_22(); - check[2] = universe_.get().geometry->N3_13(); - check[3] = universe_.get().geometry->N1_TL(); - check[4] = universe_.get().geometry->N1_SL(); - check[5] = universe_.get().geometry->N0(); - - // Now make new move - universe_.get() = move(universe_.get(), attempted_moves_.get()); - - // Check move invariants - if (!universe_) throw std::runtime_error("working manifold is empty!"); - if (!universe_.get().triangulation->tds().is_valid()) - throw std::runtime_error("Move invalidated triangulation."); - if (!attempted_moves_) - throw std::runtime_error("attempted_moves_ is empty!"); - - auto moves_are_good = - check_move_postconditions(attempted_moves_.get(), old_moves); -#ifndef NDEBUG - std::cout << "Moves are good: " << std::boolalpha << moves_are_good - << std::endl; -#endif - if (!moves_are_good) - throw std::runtime_error("Move postconditions violated."); - - // Return results of valid move - return universe_; - } - - catch (const std::exception& ex) - { - std::cerr << "Caught move error: " << ex.what() << std::endl; - } - - catch (...) - { - std::cerr << "Caught non-std::exception!" << std::endl; - } - // Disengage boost::optional value which returns results of invalid move - // Only works on recent versions of Boost (>1.63) - universe_ = {}; - return universe_; - } -}; - -#endif // SRC_MOVEMANAGER_HPP_ diff --git a/include/Move_always.hpp b/include/Move_always.hpp new file mode 100644 index 0000000000..99fdb2f303 --- /dev/null +++ b/include/Move_always.hpp @@ -0,0 +1,168 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2017 Adam Getchell + ******************************************************************************/ + +/// @file Move_always.hpp +/// @brief Randomly selects moves to always perform on triangulations +/// @author Adam Getchell +/// @details Picks a random move on the FoliatedTriangulation. +/// For testing purposes. + +#ifndef INCLUDE_MOVE_ALWAYS_HPP_ +#define INCLUDE_MOVE_ALWAYS_HPP_ + +#include + +#include "Move_command.hpp" +#include "Move_strategy.hpp" + +/// @brief The Move Always algorithm +template + requires(ManifoldType::dimension == 3) +class MoveStrategy // NOLINT +{ + using Counter = move_tracker::MoveTracker; + + /// @brief The number of move passes executed by the algorithm + /// @details Each move pass makes a number of attempts equal to the number + /// of simplices in the triangulation. + Int_precision m_passes{1}; + + /// @brief The number of passes before a checkpoint + /// @details Each checkpoint writes a file containing the current + /// triangulation. + Int_precision m_checkpoint{1}; + + /// @brief The number of moves that were attempted by a MoveCommand + Counter m_attempted_moves; + + /// @brief The number of moves that succeeded in the MoveCommand + Counter m_successful_moves; + + /// @brief The number of moves that a MoveCommand failed to make due to an + /// error. + Counter m_failed_moves; + + public: + /// @brief Default ctor + MoveStrategy() = default; + + /// @brief Constructor for MoveAlways + /// @param t_number_of_passes Number of passes to run + /// @param t_checkpoint Number of passes per checkpoint + [[maybe_unused]] MoveStrategy(Int_precision const t_number_of_passes, + Int_precision const t_checkpoint) + : m_passes{t_number_of_passes}, m_checkpoint{t_checkpoint} + { + if (m_passes < 0) + { + throw std::invalid_argument{"MoveAlways passes cannot be negative"}; + } + if (m_checkpoint <= 0) + { + throw std::invalid_argument{ + "MoveAlways checkpoint interval must be positive"}; + } + } + + /// @returns The number of passes made on a triangulation + [[nodiscard]] auto passes() const { return m_passes; } + + /// @returns The number of passes per checkpoint + [[nodiscard]] auto checkpoint() const { return m_checkpoint; } + + /// @returns The MoveTracker of attempted moves + auto get_attempted() const { return m_attempted_moves; } + + /// @returns The MoveTracker of successful moves + auto get_succeeded() const { return m_successful_moves; } + + /// @returns The array of failed moves + auto get_failed() const { return m_failed_moves; } + + /// @brief Call operator + auto operator()(ManifoldType const& t_manifold) -> ManifoldType + { +#ifndef NDEBUG + spdlog::debug("{} called.\n", __PRETTY_FUNCTION__); +#endif + fmt::print("Starting Move Always algorithm in {}+1 dimensions ...\n", + ManifoldType::dimension - 1); + + m_attempted_moves.reset(); + m_successful_moves.reset(); + m_failed_moves.reset(); + + // Start the move command + MoveCommand command(t_manifold); + + fmt::print("Making random moves ...\n"); + + // Loop through passes + for (auto pass_number = 1; pass_number <= m_passes; ++pass_number) + { + fmt::print("=== Pass {} ===\n", pass_number); + auto total_simplices_this_pass = command.get_const_results().N3(); + // Make a random move per simplex + for (auto move_attempt = 0; move_attempt < total_simplices_this_pass; + ++move_attempt) + { + // Pick a move to attempt + auto move_choice = utilities::generate_random_int( + 0, move_tracker::NUMBER_OF_3D_MOVES - 1); +#ifndef NDEBUG + fmt::print("Move choice = {}\n", move_choice); +#endif + command.enqueue(move_tracker::as_move(move_choice)); + } + command.execute(); + // Update attempted, successful, and failed moves + m_attempted_moves += command.get_attempted(); + m_successful_moves += command.get_succeeded(); + m_failed_moves += command.get_failed(); + command.reset_counters(); + + if (pass_number % m_checkpoint == 0) + { + fmt::print("Writing checkpoint for pass {}.\n", pass_number); + print_results(); + utilities::write_file(command.get_results()); + } + } + print_results(); + return command.get_results(); + } + + /// @brief Display results of run + void print_results() + { + fmt::print("=== Move Results ===\n"); + fmt::print("(2,3) moves: {} attempted = {} successful and {} failed.\n", + m_attempted_moves.two_three_moves(), + m_successful_moves.two_three_moves(), + m_failed_moves.two_three_moves()); + fmt::print("(3,2) moves: {} attempted = {} successful and {} failed.\n", + m_attempted_moves.three_two_moves(), + m_successful_moves.three_two_moves(), + m_failed_moves.three_two_moves()); + fmt::print("(2,6) moves: {} attempted = {} successful and {} failed.\n", + m_attempted_moves.two_six_moves(), + m_successful_moves.two_six_moves(), + m_failed_moves.two_six_moves()); + fmt::print("(6,2) moves: {} attempted = {} successful and {} failed.\n", + m_attempted_moves.six_two_moves(), + m_successful_moves.six_two_moves(), + m_failed_moves.six_two_moves()); + fmt::print("(4,4) moves: {} attempted = {} successful and {} failed.\n", + m_attempted_moves.four_four_moves(), + m_successful_moves.four_four_moves(), + m_failed_moves.four_four_moves()); + } +}; + +using MoveAlways_3 = + MoveStrategy; + +#endif // INCLUDE_MOVE_ALWAYS_HPP_ diff --git a/include/Move_command.hpp b/include/Move_command.hpp new file mode 100644 index 0000000000..a825183304 --- /dev/null +++ b/include/Move_command.hpp @@ -0,0 +1,248 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2018 Adam Getchell + ******************************************************************************/ + +/// @file Move_command.hpp +/// @brief Do ergodic moves using the Command pattern +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_MOVECOMMAND_HPP +#define CDT_PLUSPLUS_MOVECOMMAND_HPP + +#include "Apply_move.hpp" +#include "Ergodic_moves_3.hpp" + +template , + typename FunctionType = + boost::compat::function_ref> + requires(ManifoldType::dimension == 3) +class MoveCommand +{ + using Queue = std::deque; + using Counter = move_tracker::MoveTracker; + + /** + * \brief The manifold on which to perform moves + */ + ManifoldType m_manifold; + + /** + * \brief The queue of moves to perform + */ + Queue m_moves; + + /** + * \brief The counter of attempted moves + */ + Counter m_attempted; + + /** + * \brief The counter of successful moves + */ + Counter m_succeeded; + + /** + * \brief The counter of failed moves + */ + Counter m_failed; + + public: + /** + * \brief Remove default ctor + */ + MoveCommand() = delete; + + /** + * \brief MoveCommand ctor + * \param t_manifold The manifold to perform moves on + * \details The manifold to perform moves upon should be copied by value into + * the MoveCommand to ensure moves are executed atomically and either succeed + * or fail and can be discarded without affecting the original manifold. + */ + explicit MoveCommand(ManifoldType t_manifold) + : m_manifold{std::move(t_manifold)} + {} + + /** + * \brief A read-only reference to the manifold + */ + auto get_const_results() const -> ManifoldType const& + { return m_manifold; } // get_const_results + + /** + * \brief Results of the moves invoked by MoveCommand + */ + [[nodiscard]] auto get_results() -> ManifoldType& { return m_manifold; } + + /** + * \brief Attempted moves by MoveCommand + */ + [[nodiscard]] auto get_attempted() const -> Counter const& + { return m_attempted; } // get_attempts + + /** + * \brief Successful moves by MoveCommand + */ + [[nodiscard]] auto get_succeeded() const -> Counter const& + { return m_succeeded; } // get_succeeded + + /** + * \brief Failed moves by MoveCommand + */ + [[nodiscard]] auto get_failed() const -> Counter const& + { return m_failed; } // get_errors + + /** + * \brief Reset counters + */ + void reset_counters() + { + m_attempted.reset(); + m_succeeded.reset(); + m_failed.reset(); + } + + /** + * \brief Push a Pachner move onto the move queue + * \param t_move The move to add + */ + void enqueue(move_tracker::move_type const t_move) + { m_moves.push_front(t_move); } + + /** + * \brief The number of moves on the queue + */ + auto size() const { return m_moves.size(); } + + /** + * \brief Execute all moves in the queue on the manifold + */ + void execute() + { +#ifndef NDEBUG + fmt::print("=== Executing: Before moves ===\n"); + m_manifold.print_details(); + fmt::print("===============================\n"); +#endif + + while (!m_moves.empty()) + { + auto move_type = m_moves.back(); + // Record attempted move + ++m_attempted[as_integer(move_type)]; + // Convert move_type to function + auto move_function = as_move_function(move_type); + // Execute each move on a private candidate so rejection is atomic even + // when a move discovers an error after beginning a topology mutation. + ManifoldType candidate{m_manifold}; + if (auto result = apply_move(candidate, move_function); result) + { + result->update(); + if (result->is_correct()) + { + swap(result.value(), m_manifold); + ++m_succeeded[as_integer(move_type)]; + } + else + { + fmt::print("Move produced an invalid manifold.\n"); + ++m_failed[as_integer(move_type)]; + } + } + else + { + fmt::print("{}\n", result.error()); + // Track failed moves + ++m_failed[as_integer(move_type)]; + } + // Remove move from queue + m_moves.pop_back(); + } +#ifndef NDEBUG + fmt::print("=== After moves ===\n"); + print_attempts(); + print_successful(); + print_errors(); + m_manifold.print_details(); + fmt::print("===================\n"); +#endif + } // execute + + /** + * \brief Execute a move function on a manifold + * \param move The move to execute + * \return The move function to execute + */ + static auto as_move_function(move_tracker::move_type const move) + -> FunctionType + { + switch (move) + { + case move_tracker::move_type::TWO_THREE: return ergodic_moves::do_23_move; + case move_tracker::move_type::THREE_TWO: return ergodic_moves::do_32_move; + case move_tracker::move_type::TWO_SIX: return ergodic_moves::do_26_move; + case move_tracker::move_type::SIX_TWO: return ergodic_moves::do_62_move; + default: return ergodic_moves::do_44_move; + } + } // move_function + + /** + * \brief Print attempted moves + */ + void print_attempts() const + { + fmt::print( + "There were {} attempted (2,3) moves and {} attempted (3,2) moves " + "and {} " + "attempted (2,6) moves and {} attempted (6,2) moves and {} attempted " + "(4,4) " + "moves.\n", + m_attempted.two_three_moves(), m_attempted.three_two_moves(), + m_attempted.two_six_moves(), m_attempted.six_two_moves(), + m_attempted.four_four_moves()); + } + + /** + * \brief Print successful moves + */ + void print_successful() const + { + fmt::print( + "There were {} successful (2,3) moves and {} successful (3,2) moves " + "and {} " + "successful (2,6) moves and {} successful (6,2) moves and {} " + "successful " + "(4,4) " + "moves.\n", + m_succeeded.two_three_moves(), m_succeeded.three_two_moves(), + m_succeeded.two_six_moves(), m_succeeded.six_two_moves(), + m_succeeded.four_four_moves()); + } + + /** + * \brief Print move errors + */ + void print_errors() const + { + if (std::all_of(m_failed.moves_view().begin(), m_failed.moves_view().end(), + [](auto const& value) { return value == 0; })) + { + fmt::print("There were no failed moves.\n"); + } + else + { + fmt::print( + "There were {} failed (2,3) moves and {} failed (3,2) moves and {} " + "failed (2,6) moves and {} failed (6,2) moves and {} failed (4,4) " + "moves.\n", + m_failed.two_three_moves(), m_failed.three_two_moves(), + m_failed.two_six_moves(), m_failed.six_two_moves(), + m_failed.four_four_moves()); + } + } +}; + +#endif // CDT_PLUSPLUS_MOVECOMMAND_HPP diff --git a/include/Move_strategy.hpp b/include/Move_strategy.hpp new file mode 100644 index 0000000000..9bdfbab5e7 --- /dev/null +++ b/include/Move_strategy.hpp @@ -0,0 +1,34 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2017 Adam Getchell + ******************************************************************************/ + +/// @file Move_strategy.hpp +/// @brief Template class for move algorithms (strategies) on manifolds +/// @author Adam Getchell +/// @details Template class for all move algorithms, e.g. Metropolis, +/// MoveAlways. + +#ifndef INCLUDE_MOVE_STRATEGY_HPP_ +#define INCLUDE_MOVE_STRATEGY_HPP_ + +/** + * \brief The algorithms available to make ergodic moves on triangulations + */ +enum class Strategies +{ + MOVE_ALWAYS, + METROPOLIS +}; + +/** + * \brief Select a move algorithm + * \tparam strategies The move algorithm to use + * \tparam ManifoldType The manifold to perform moves on + */ +template +class MoveStrategy +{}; + +#endif // INCLUDE_MOVE_STRATEGY_HPP_ diff --git a/include/Move_tracker.hpp b/include/Move_tracker.hpp new file mode 100644 index 0000000000..88f6795c04 --- /dev/null +++ b/include/Move_tracker.hpp @@ -0,0 +1,218 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2021 Adam Getchell + ******************************************************************************/ + +/// @file Move_tracker.hpp +/// @brief Track ergodic moves +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_MOVE_TRACKER_HPP +#define CDT_PLUSPLUS_MOVE_TRACKER_HPP + +#include +#include +#include +#include +#include + +#include "Settings.hpp" +#include "Utilities.hpp" + +namespace move_tracker +{ + static inline Int_precision constexpr NUMBER_OF_3D_MOVES = 5; + + /** + * \brief The types of 3D ergodic moves + */ + enum class [[nodiscard("This contains data!")]] move_type + { + TWO_THREE = 0, + THREE_TWO = 1, + TWO_SIX = 2, + SIX_TWO = 3, + FOUR_FOUR = 4 + }; + + /** + * \brief Convert enum to integer + * \tparam Enumeration The enum type + * \param value The enum + * \return The integer value of the enum + */ + template + auto as_integer(Enumeration value) -> std::underlying_type_t + { + return static_cast>(value); + } // as_integer + + /** + * \brief Convert integer to move_type + * \param move_choice The move choice integer + * \return The move_type + */ + inline auto as_move(int const move_choice) -> move_type + { + if (move_choice == 0) { return move_type::TWO_THREE; } + if (move_choice == 1) { return move_type::THREE_TWO; } + if (move_choice == 2) { return move_type::TWO_SIX; } + if (move_choice == 3) { return move_type::SIX_TWO; } + return move_type::FOUR_FOUR; + } // as_move + + /** + * \brief Generate random 3D ergodic move + * \return The move_type to be performed + */ + [[nodiscard]] inline auto generate_random_move_3() -> move_type + { + auto move_choice = utilities::generate_random_int(0, 4); +#ifndef NDEBUG + fmt::print("Move choice = {}\n", move_choice); +#endif + return as_move(move_choice); + } // generate_random_move_3 + + /** + * \brief The data and methods to track ergodic moves + * \tparam ManifoldType The type of manifold on which moves are made + */ + template + requires(ManifoldType::dimension == 3) + class MoveTracker + { + using Container = std::array; + + Container moves = {0}; // NOLINT + + public: + /** + * \brief Get a view of the moves + * \return Read-only container of moves + */ + auto moves_view() const { return std::span(moves); } + + /** + * \brief The [] operator for MoveTracker + * \param index The index of the element to be accessed + * \return The number of moves at the index + */ + auto operator[](gsl::index index) -> auto& + { return gsl::at(moves, index); } // operator[] + + /** + * \brief The [] operator for MoveTracker + * \param move The move type to be accessed + * \return The number of moves of that type + */ + auto operator[](move_type const move) -> auto& + { return gsl::at(moves, as_integer(move)); } // operator[] + + /** + * \brief The [] operator for a read-only MoveTracker + * \param move The move type to be accessed + * \return The number of moves of that type + */ + auto operator[](move_type const move) const -> auto& + { return gsl::at(moves, as_integer(move)); } // operator[] + + /** + * \brief The += operator for MoveTracker + * \param rhs The MoveTracker to be added + * \return The sum of the individual elements of the MoveTrackers + */ + auto operator+=(MoveTracker const& rhs) -> MoveTracker& + { + for (std::size_t i = 0; i < moves.size(); ++i) + { + moves[i] += rhs.moves[i]; + } + return *this; + } // operator+= + + /** + * \brief Total moves + * \return The total number of moves in the MoveTracker + */ + auto total() const noexcept + { + return std::accumulate(moves.begin(), moves.end(), Int_precision{0}); + } // total + + /** + * \brief Container size + * \return The size of the container of moves + */ + auto size() const noexcept { return moves.size(); } + + // 3D + + /** + * \brief Write access to (2,3) moves + * \return Reference to number of (2,3) moves + */ + auto two_three_moves() -> auto& { return gsl::at(moves, 0); } + + /** + * \brief Read access to (2,3) moves + * \return Value of number of (2,3) moves + */ + auto two_three_moves() const { return gsl::at(moves, 0); } + + /** + * \brief Write access to (3,2) moves + * \return Reference to number of (3,2) moves + */ + auto three_two_moves() -> auto& { return gsl::at(moves, 1); } + + /** + * \brief Read access to (3,2) moves + * \return Value of number of (3,2) moves + */ + auto three_two_moves() const { return gsl::at(moves, 1); } + + /** + * \brief Write access to (2,6) moves + * \return Reference to number of (2,6) moves + */ + auto two_six_moves() -> auto& { return gsl::at(moves, 2); } + + /** + * \brief Read access to (2,6) moves + * \return Value of number of (2,6) moves + */ + auto two_six_moves() const { return gsl::at(moves, 2); } + + /** + * \brief Write access to (6,2) moves + * \return Reference to number of (6,2) moves + */ + auto six_two_moves() -> auto& { return gsl::at(moves, 3); } + + /** + * \brief Read access to (6,2) moves + * \return Value of number of (6,2) moves + */ + auto six_two_moves() const { return gsl::at(moves, 3); } + + /** + * \brief Write access to (4,4) moves + * \return Reference to number of (4,4) moves + */ + auto four_four_moves() -> auto& { return gsl::at(moves, 4); } + + /** + * \brief Read access to (4,4) moves + * \return Value of number of (4,4) moves + */ + auto four_four_moves() const { return gsl::at(moves, 4); } + + /// @brief Reset all moves counts to zero + void reset() { moves.fill(0); } + }; + +} // namespace move_tracker + +#endif // CDT_PLUSPLUS_MOVE_TRACKER_HPP diff --git a/include/Periodic_3_complex.hpp b/include/Periodic_3_complex.hpp index 65eb05c0f6..098bd80e09 100644 --- a/include/Periodic_3_complex.hpp +++ b/include/Periodic_3_complex.hpp @@ -1,6 +1,6 @@ /// Causal Dynamical Triangulations in C++ using CGAL /// -/// Copyright © 2013-2017 Adam Getchell +/// Copyright © 2013 Adam Getchell /// /// Periodic (toroidal) simplicial complexes @@ -8,16 +8,15 @@ /// @brief Toroidal simplicial complexes /// @author Adam Getchell -#ifndef SRC_PERIODIC_3_COMPLEX_HPP_ -#define SRC_PERIODIC_3_COMPLEX_HPP_ +#ifndef INCLUDE_PERIODIC_3_COMPLEX_HPP_ +#define INCLUDE_PERIODIC_3_COMPLEX_HPP_ #include #include #include - +#include #include #include -#include #include #include @@ -40,10 +39,11 @@ void make_random_T3_simplicial_complex(PDT* T3, std::vector pts; // Generate random points - for (int i = 0; i < n; i++) { + for (int i = 0; i < n; i++) + { PDT::Point p = *in_cube; in_cube++; - pts.push_back(PDT::Point(p.x() + .5, p.y() + .5, p.z() + .5)); + pts.emplace_back(PDT::Point(p.x() + .5, p.y() + .5, p.z() + .5)); } // Iterator range insertion using spatial sorting and dummy point heuristic @@ -52,4 +52,4 @@ void make_random_T3_simplicial_complex(PDT* T3, assert(T3->dimension() == 3); assert(T3->is_valid()); } -#endif // SRC_PERIODIC_3_COMPLEX_HPP_ +#endif // INCLUDE_PERIODIC_3_COMPLEX_HPP_ diff --git a/include/Periodic_3_triangulations.hpp b/include/Periodic_3_triangulations.hpp index 200923796a..34be7017b9 100644 --- a/include/Periodic_3_triangulations.hpp +++ b/include/Periodic_3_triangulations.hpp @@ -1,6 +1,6 @@ /// Causal Dynamical Triangulations in C++ using CGAL /// -/// Copyright © 2013-2017 Adam Getchell +/// Copyright © 2014 Adam Getchell /// /// Periodic (toroidal) 3D triangulations @@ -8,29 +8,28 @@ /// @brief Toroidal 3D triangulations /// @author Adam Getchell -#ifndef SRC_PERIODIC_3_TRIANGULATIONS_HPP_ -#define SRC_PERIODIC_3_TRIANGULATIONS_HPP_ +#ifndef INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ +#define INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ #include #include #include -#include - +#include #include #include -#include +#include #include #include -using K = CGAL::Exact_predicates_inexact_constructions_kernel; -using GT = CGAL::Periodic_3_triangulation_filtered_traits_3; +using K = CGAL::Exact_predicates_inexact_constructions_kernel; +using GT = CGAL::Periodic_3_triangulation_filtered_traits_3; -using VbDS = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>; -using T3Vb = CGAL::Triangulation_vertex_base_3; +using VbDS = CGAL::Periodic_3_triangulation_ds_vertex_base_3<>; +using T3Vb = CGAL::Triangulation_vertex_base_3; -using CbDS = CGAL::Periodic_3_triangulation_ds_cell_base_3<>; -using Cb = CGAL::Triangulation_cell_base_3; +using CbDS = CGAL::Periodic_3_triangulation_ds_cell_base_3<>; +using Cb = CGAL::Triangulation_cell_base_3; /// Allows each vertex to contain an integer denoting its timeslice using VbInfo = CGAL::Triangulation_vertex_base_with_info_3; @@ -39,8 +38,8 @@ using PDT = CGAL::Periodic_3_Delaunay_triangulation_3; using T3Point = PDT::Point; /// Random point generators for d-dimensional points in a d-cube per timeslice -using Kd = CGAL::Cartesian_d; -using Point = Kd::Point_d; +using Kd = CGAL::Cartesian_d; +using Point = Kd::Point_d; /// Make 3D toroidal (periodic) triangulations template @@ -51,30 +50,34 @@ void make_random_T3_triangulation(T* T3, int simplices, int timeslices) noexcept int simplices_per_timeslice = simplices / timeslices; /// We can't directly pick number of simplices as we can in S3 /// but a point has <6 simplices in 3D - int points = simplices / 6; - int points_per_timeslice = simplices_per_timeslice / 6; + int points = simplices / 6; + int points_per_timeslice = simplices_per_timeslice / 6; /// We're working on 2 dimensional random points with the z component /// fixed by the timeslice - const int dim = 2; + int const dim = 2; std::vector v; v.reserve(points); /// In d-dimensions the range of points in a d-cube is the d-th root - double size = sqrt(points_per_timeslice); + double size = sqrt(points_per_timeslice); CGAL::Random_points_in_cube_d gen(dim, size); /// Setup random point creation in a square (2-cube) - for (size_t i = 0; i < timeslices; i++) { + for (int timeslice_index = 0; timeslice_index < timeslices; ++timeslice_index) + { /// Debugging - std::cout << "Timeslice " << i << std::endl; - for (size_t i = 0; i < points_per_timeslice; i++) { + std::cout << "Timeslice " << timeslice_index << std::endl; + for (int point_index = 0; point_index < points_per_timeslice; ++point_index) + { v.push_back(*gen++); } - for (size_t i = 0; i < points_per_timeslice; i++) { - std::cout << " " << v[i] << std::endl; + for (int point_index = 0; point_index < points_per_timeslice; ++point_index) + { + auto const offset = timeslice_index * points_per_timeslice + point_index; + std::cout << " " << v[static_cast(offset)] << std::endl; } } } -#endif // SRC_PERIODIC_3_TRIANGULATIONS_HPP_ +#endif // INCLUDE_PERIODIC_3_TRIANGULATIONS_HPP_ diff --git a/include/S3Action.hpp b/include/S3Action.hpp index 043cce07ed..19e465ccc4 100644 --- a/include/S3Action.hpp +++ b/include/S3Action.hpp @@ -1,39 +1,28 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2014-2017 Adam Getchell -/// -/// Calculates the S3 Bulk (and later, boundary) actions. -/// Uses the GNU MPFR library for arbitrary precision arithmetic on -/// floating point numbers. See http://www.mpfr.org for more details. -/// Note: for performance reasons, variables should not hold successively -/// increasing values. We avoid this by setting each variable only once. -/// See https://gmplib.org/manual/Efficiency.html#Efficiency for details. +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL -/// \done \f$\alpha\f$=-1 S3 bulk action -/// \done \f$\alpha\f$=1 S3 bulk action -/// \done Generic \f$\alpha\f$ S3 bulk action -/// \done Function documentation + Copyright © 2014 Adam Getchell + ******************************************************************************/ /// @file S3Action.hpp /// @brief Calculate S3 bulk actions on 3D Delaunay Triangulations /// @author Adam Getchell -/// @bug -/// scan-build: No bugs found. +/// @details Calculates the S3 Bulk (and later, boundary) actions. +/// Uses the GNU MPFR library for arbitrary precision arithmetic on +/// floating point numbers. See http://www.mpfr.org for more details. +/// Note: for performance reasons, variables should not hold successively +/// increasing values. We avoid this by setting each variable only once. +/// See https://gmplib.org/manual/Efficiency.html#Efficiency for details. -#ifndef SRC_S3ACTION_HPP_ -#define SRC_S3ACTION_HPP_ +#ifndef INCLUDE_S3ACTION_HPP_ +#define INCLUDE_S3ACTION_HPP_ -// #include -#include -#include #include -/// Results are converted to a CGAL multi-precision floating point number. -/// Gmpzf itself is based on GMP (https://gmplib.org), as is MPFR. -using Gmpzf = CGAL::Gmpzf; -// using MP_Float = CGAL::MP_Float; -/// Sets the precision for MPFR. -static constexpr std::int_fast32_t PRECISION = 256; +#include + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wcomment" /// @brief Calculates S3 bulk action for \f$\alpha\f$=-1. /// @@ -52,21 +41,41 @@ static constexpr std::int_fast32_t PRECISION = 256; /// @param K \f$k=\frac{1}{8\pi G_{Newton}}\f$ /// @param Lambda \f$\lambda=k*\Lambda\f$ where \f$\Lambda\f$ is the /// Cosmological constant -/// @return \f$S^{(3)}(\alpha=-1)\f$ as a +/// @returns \f$S^{(3)}(\alpha=-1)\f$ as a /// Gmpzf /// value -inline auto S3_bulk_action_alpha_minus_one(const std::int_fast32_t N1_TL, - const std::int_fast32_t N3_31_13, - const std::int_fast32_t N3_22, - const long double K, - const long double Lambda) noexcept +[[nodiscard]] inline auto S3_bulk_action_alpha_minus_one( + Int_precision const N1_TL, Int_precision const N3_31_13, + Int_precision const N3_22, long double const K, + long double const Lambda) noexcept -> Gmpzf { // Set precision for initialization and assignment functions mpfr_set_default_prec(PRECISION); // Initialize for MPFR - mpfr_t n1_tl, n3_31, n3_22, k, lambda, two, pi, r1, r2, r3, const2673, - const118, r4, r5, r6, r7, const7386, r8, r9, r10, r11, r12, total; + mpfr_t n1_tl; + mpfr_t n3_31; + mpfr_t n3_22; + mpfr_t k; + mpfr_t lambda; + mpfr_t two; + mpfr_t pi; + mpfr_t r1; + mpfr_t r2; + mpfr_t r3; + mpfr_t const2673; + mpfr_t const118; + mpfr_t r4; + mpfr_t r5; + mpfr_t r6; + mpfr_t r7; + mpfr_t const7386; + mpfr_t r8; + mpfr_t r9; + mpfr_t r10; + mpfr_t r11; + mpfr_t r12; + mpfr_t total; mpfr_inits2(PRECISION, pi, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, total, nullptr); @@ -104,9 +113,8 @@ inline auto S3_bulk_action_alpha_minus_one(const std::int_fast32_t N1_TL, mpfr_add(total, r11, r12, MPFR_RNDD); // total = r11+r12 // Convert mpfr_t total to Gmpzf result by using Gmpzf(double d) - // Gmpzf result = Gmpzf(mpfr_get_d(total, MPFR_RNDD)); - // MP_Float result = MP_Float(mpfr_get_ld(total, MPFR_RNDD)); - auto result = mpfr_get_d(total, MPFR_RNDD); + // Perhaps fixable later by switching to MP_Float + auto const result = mpfr_get_d(total, MPFR_RNDD); // Free memory mpfr_clears(n1_tl, n3_31, n3_22, k, lambda, two, pi, r1, r2, r3, const2673, @@ -130,22 +138,42 @@ inline auto S3_bulk_action_alpha_minus_one(const std::int_fast32_t N1_TL, /// @param K \f$k=\frac{1}{8\pi G_{Newton}}\f$ /// @param Lambda \f$\lambda=k*\Lambda\f$ where \f$\Lambda\f$ is the /// Cosmological constant -/// @return \f$S^{(3)}(\alpha=1)\f$ as a +/// @returns \f$S^{(3)}(\alpha=1)\f$ as a /// Gmpzf /// value -inline auto S3_bulk_action_alpha_one(const std::int_fast32_t N1_TL, - const std::int_fast32_t N3_31_13, - const std::int_fast32_t N3_22, - const long double K, - const long double Lambda) noexcept +[[nodiscard]] inline auto S3_bulk_action_alpha_one( + Int_precision const N1_TL, Int_precision const N3_31_13, + Int_precision const N3_22, long double const K, + long double const Lambda) noexcept -> Gmpzf { // Set precision for initialization and assignment functions mpfr_set_default_prec(PRECISION); // Initialize for MPFR - mpfr_t n1_tl, n3_31, n3_22, k, lambda, two, pi, r1, r2, r3, const3548, - const167, r4, r5, r6, r7, const5355, const204, r8, r9, r10, r11, r12, - total; + mpfr_t n1_tl; + mpfr_t n3_31; + mpfr_t n3_22; + mpfr_t k; + mpfr_t lambda; + mpfr_t two; + mpfr_t pi; + mpfr_t r1; + mpfr_t r2; + mpfr_t r3; + mpfr_t const3548; + mpfr_t const167; + mpfr_t r4; + mpfr_t r5; + mpfr_t r6; + mpfr_t r7; + mpfr_t const5355; + mpfr_t const204; + mpfr_t r8; + mpfr_t r9; + mpfr_t r10; + mpfr_t r11; + mpfr_t r12; + mpfr_t total; mpfr_inits2(PRECISION, pi, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, total, nullptr); @@ -183,14 +211,9 @@ inline auto S3_bulk_action_alpha_one(const std::int_fast32_t N1_TL, mpfr_add(r12, r3, r7, MPFR_RNDD); // r12 = r3+r7 mpfr_add(total, r11, r12, MPFR_RNDD); // total = r11+r12 - // Debugging - // std::cout << "S3_bulk_action_alpha_one result is " << mpfr_out_str(stdout, - // 10, 0, total, MPFR_RNDD) << std::endl; - // Convert mpfr_t total to Gmpzf result by using Gmpzf(double d) - // Gmpzf result = Gmpzf(mpfr_get_d(total, MPFR_RNDD)); - // MP_Float result = MP_Float(mpfr_get_ld(total, MPFR_RNDD)); - auto result = mpfr_get_d(total, MPFR_RNDD); + // Perhaps fixable later by switching to MP_Float + auto const result = mpfr_get_d(total, MPFR_RNDD); // Free memory mpfr_clears(n1_tl, n3_31, n3_22, k, lambda, two, pi, r1, r2, r3, const3548, @@ -223,24 +246,83 @@ inline auto S3_bulk_action_alpha_one(const std::int_fast32_t N1_TL, /// @param K \f$k=\frac{1}{8\pi G_{Newton}}\f$ /// @param Lambda \f$\lambda=k*\Lambda\f$ where \f$\Lambda\f$ is the /// Cosmological constant -/// @return \f$S^{(3)}(\alpha)\f$ as a +/// @returns \f$S^{(3)}(\alpha)\f$ as a /// Gmpzf /// value -inline auto S3_bulk_action(const std::int_fast32_t N1_TL, - const std::int_fast32_t N3_31_13, - const std::int_fast32_t N3_22, const long double Alpha, - const long double K, - const long double Lambda) noexcept +[[nodiscard]] inline auto S3_bulk_action( + Int_precision const N1_TL, Int_precision const N3_31_13, + Int_precision const N3_22, long double const Alpha, long double const K, + long double const Lambda) noexcept -> Gmpzf { // Set precision for initialization and assignment functions mpfr_set_default_prec(PRECISION); // Initialize for MPFR - mpfr_t n1_tl, n3_31, n3_22, alpha, k, lambda, two, pi, r1, r2, r3, r4, r5, r6, - three, r7, four, r8, one, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, - r19, r20, r21, twelve, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, - r32, r33, r34, r35, r36, r37, r38, r39, r40, r41, r42, r43, r44, r45, r46, - r47, r48, r49, r50, r51, r52, total; + mpfr_t n1_tl; + mpfr_t n3_31; + mpfr_t n3_22; + mpfr_t alpha; + mpfr_t k; + mpfr_t lambda; + mpfr_t two; + mpfr_t pi; + mpfr_t r1; + mpfr_t r2; + mpfr_t r3; + mpfr_t r4; + mpfr_t r5; + mpfr_t r6; + mpfr_t three; + mpfr_t r7; + mpfr_t four; + mpfr_t r8; + mpfr_t one; + mpfr_t r9; + mpfr_t r10; + mpfr_t r11; + mpfr_t r12; + mpfr_t r13; + mpfr_t r14; + mpfr_t r15; + mpfr_t r16; + mpfr_t r17; + mpfr_t r18; + mpfr_t r19; + mpfr_t r20; + mpfr_t r21; + mpfr_t twelve; + mpfr_t r22; + mpfr_t r23; + mpfr_t r24; + mpfr_t r25; + mpfr_t r26; + mpfr_t r27; + mpfr_t r28; + mpfr_t r29; + mpfr_t r30; + mpfr_t r31; + mpfr_t r32; + mpfr_t r33; + mpfr_t r34; + mpfr_t r35; + mpfr_t r36; + mpfr_t r37; + mpfr_t r38; + mpfr_t r39; + mpfr_t r40; + mpfr_t r41; + mpfr_t r42; + mpfr_t r43; + mpfr_t r44; + mpfr_t r45; + mpfr_t r46; + mpfr_t r47; + mpfr_t r48; + mpfr_t r49; + mpfr_t r50; + mpfr_t r51; + mpfr_t r52; + mpfr_t total; mpfr_inits2(PRECISION, pi, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15, r16, r17, r18, r19, r20, r21, r22, r23, r24, r25, r26, r27, r28, r29, r30, r31, r32, r33, r34, r35, r36, r37, r38, @@ -334,14 +416,9 @@ inline auto S3_bulk_action(const std::int_fast32_t N1_TL, mpfr_add(r52, r5, r30, MPFR_RNDD); // r52 = r5+r30 mpfr_add(total, r51, r52, MPFR_RNDD); // total = r51+r52 - // Debugging - // std::cout << "S3_bulk_action result is " << mpfr_out_str(stdout, 10, 0, - // total, MPFR_RNDD) << std::endl; - // Convert mpfr_t total to Gmpzf result by using Gmpzf(double d) - // Gmpzf result = Gmpzf(mpfr_get_d(total, MPFR_RNDD)); - // MP_Float result = MP_Float(mpfr_get_ld(total, MPFR_RNDD)); - auto result = mpfr_get_d(total, MPFR_RNDD); + // Perhaps fixable later by switching to MP_Float + auto const result = mpfr_get_d(total, MPFR_RNDD); // Free memory mpfr_clears(n1_tl, n3_31, n3_22, alpha, k, lambda, two, pi, r1, r2, r3, r4, @@ -354,4 +431,6 @@ inline auto S3_bulk_action(const std::int_fast32_t N1_TL, return result; } // Gmpzf S3_bulk_action() -#endif // SRC_S3ACTION_HPP_ +#pragma GCC diagnostic pop + +#endif // INCLUDE_S3ACTION_HPP_ diff --git a/include/S3ErgodicMoves.hpp b/include/S3ErgodicMoves.hpp deleted file mode 100644 index eca36db9e3..0000000000 --- a/include/S3ErgodicMoves.hpp +++ /dev/null @@ -1,540 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2014-2017 Adam Getchell -/// -/// Performs the 5 types of ergodic moves on S3 (2+1) spacetimes. -/// -/// @todo Handle neighboring_31_index != 5 condition -/// @todo Debug (6,2) move -/// @todo (4,4) move - -/// @file S3ErgodicMoves.hpp -/// @brief Pachner moves on 3D Delaunay Triangulations -/// @author Adam Getchell, Guarav Nagar - -#ifndef SRC_S3ERGODICMOVES_HPP_ -#define SRC_S3ERGODICMOVES_HPP_ - -// CDT headers -#include - -// CGAL headers -#include - -// C++ headers -// #include -#include -#include -#include -#include - -/// @brief Try a (2,3) move -/// -/// This function performs the (2,3) move by converting the facet -/// between a (3,1) simplex and a (2,2) simplex into its dual edge. -/// -/// @tparam T The manifold type -/// @param universe A SimplicialManifold -/// @param to_be_moved The **Cell_handle** that is tried -/// @return A boolean value whether the move succeeded -template -auto try_23_move(T&& universe, Cell_handle to_be_moved) -{ - auto flipped = false; - // Try every facet of the cell - for (auto i = 0; i < 4; ++i) { - if (universe.triangulation->flip(to_be_moved, i)) { -#ifndef NDEBUG - std::cout << "Facet " << i << " was flippable.\n"; -#endif - - flipped = true; - break; - } - else - { -#ifndef NDEBUG - std::cout << "Facet " << i << " was not flippable.\n"; -#endif - } - } - return flipped; -} // try_23_move() - -/// @brief Make a (2,3) move -/// -/// A (2,3) moves adds a (2,2) simplex and a timelike edge. -/// -/// This function calls **try_23_move()** until it succeeds; the -/// triangulation is no longer Delaunay. -/// -/// @tparam T1 The manifold type -/// @tparam T2 The type of the tuple holding attempted moves -/// @param universe A SimplicialManifold -/// @param attempted_moves A tuple holding a count of the attempted moves -/// @return The SimplicialManifold after the move has been made -template -auto make_23_move(T1&& universe, T2&& attempted_moves) -> decltype(universe) -{ -#ifndef NDEBUG - std::cout << "Attempting (2,3) move.\n"; -#endif - - auto movable_two_two_cells{universe.geometry->two_two}; - - auto not_flipped = true; - while (not_flipped) { - if (movable_two_two_cells.size() == 0) { - throw std::domain_error("No (2,3) move is possible."); - } - // Pick out a random (2,2) which ranges from 0 to size()-1 - auto choice = generate_random_signed(0, movable_two_two_cells.size() - 1); - - Cell_handle to_be_moved = universe.geometry->two_two[choice]; - if (try_23_move(universe, to_be_moved)) not_flipped = false; - - // Remove trial cell - movable_two_two_cells.erase(movable_two_two_cells.begin() + choice); - - // Increment the (2,3) move counter - ++attempted_moves[0]; - } - // Uses return value optimization and allows chaining function calls - // return std::move(universe); - return std::forward(universe); -} // make_23_move() - -/// @brief Try a (3,2) move -/// -/// This function performs a foliation-preserving (3,2) move by converting -/// timelike edge into it's dual facet. -/// -/// @tparam T The manifold type -/// @param universe A SimplicialManifold -/// @param to_be_moved The Edge_handle that is tried -/// @return A boolean value whether the move succeeded -template -auto try_32_move(T&& universe, Edge_handle to_be_moved) -{ - auto flipped = false; - if (universe.triangulation->flip(std::get<0>(to_be_moved), - std::get<1>(to_be_moved), - std::get<2>(to_be_moved))) - { - flipped = true; - } - return flipped; -} // try_32_move() - -/// @brief Make a (3,2) move -/// -/// A (3,2) move removes a (2,2) simplex and a timelike edge. -/// -/// This function calls **try_32_move()** until it succeeds; the -/// triangulation is no longer Delaunay. -/// -/// @tparam T1 The manifold type -/// @tparam T2 The type of the tuple holding attempted moves -/// @param universe A SimplicialManifold -/// @param attempted_moves A tuple holding a count of the attempted moves -/// @return The SimplicialManifold after the move has been made -template -auto make_32_move(T1&& universe, T2&& attempted_moves) -> decltype(universe) -{ -#ifndef NDEBUG - std::cout << "Attempting (3,2) move.\n"; -#endif - - auto movable_timelike_edges{universe.geometry->timelike_edges}; - - auto not_flipped = true; - while (not_flipped) { - if (movable_timelike_edges.size() == 0) { - throw std::domain_error("No (3,2) move is possible."); - } - // Pick a random timelike edge out of the timelike_edges vector - // which ranges from 0 to size()-1 - auto choice = generate_random_signed(0, movable_timelike_edges.size() - 1); - Edge_handle to_be_moved = movable_timelike_edges[choice]; - - if (try_32_move(universe, to_be_moved)) { -#ifndef NDEBUG - std::cout << "Edge " << choice << " was flippable.\n"; -#endif - not_flipped = false; - } - else - { - // Remove chosen edge to try remaining - movable_timelike_edges.erase(movable_timelike_edges.begin() + choice); -#ifndef NDEBUG - std::cout << "Edge " << choice << " was not flippable.\n"; -#endif - } - // Increment the (3,2) move counter - ++attempted_moves[1]; - } - // Uses return value optimization and allows chaining function calls - // return std::move(universe); - return std::forward(universe); -} // make_32_move() - -/// @brief Check a (2,6) move -/// -/// This function checks if a (2,6) move is possible on the i-th -/// neighbor of a (1,3) cell. That is, the i-th neighboring cell must be -/// a (3,1) cell, and of course the base cell must be a (1,3). This preserves -/// the timelike foliation. This condition can be relaxed in the more -/// general case. -/// -/// @param c The presumed (1,3) cell -/// @param i The i-th neighbor of c -/// @return **True** if c is a (1,3) cell and it's i-th neighbor is a (3,1) -inline auto is_26_movable(const Cell_handle& c, unsigned i) -{ - // Source cell should be a 13 - auto source_is_13 = (c->info() == 13); - // Neighbor should be a 31 - auto neighbor_is_31 = (c->neighbor(i)->info() == 31); - return (source_is_13 && neighbor_is_31); -} - -/// @brief Find a (2,6) move -/// -/// This function checks to see if a (2,6) move is possible. Starting with -/// a (1,3) simplex, it checks all neighbors to see if there is a (3,1). -/// If so, the index **n** of that neighbor is passed via an out parameter. -/// -/// @param c The (1,3) simplex that is checked -/// @param n The integer value of the neighboring (3,1) simplex -/// @return **True** if the (2,6) move is possible -inline auto find_26_movable(const Cell_handle& c, int& n) -{ - auto movable = false; - for (int i = 0; i < 4; ++i) { -#ifndef NDEBUG - std::cout << "Neighbor " << i << " is of type " << c->neighbor(i)->info() - << "\n"; -#endif - // Check all neighbors for a (3,1) simplex - if (is_26_movable(c, i)) { - n = i; - movable = true; - } - } - return movable; -} // find_26_movable() - -/// @brief Make a (2,6) move -/// -/// A (2,6) move adds 2 (1,3) simplices and 2 (3,1) simplices for a -/// total of 3 (1,3) simplices and 3 (3,1) simplices. -/// It also adds 2 timelike edges and 3 spacelike edges, for a total -/// of 8 timelike edges and 6 spacelike edges. -/// -/// This function performs the (2,6) move by picking a random (1,3) simplex -/// from GeometryInfo. The **find_26_movable()** function finds the -/// index of the neighboring (3,1) simplex, **neighboring_31_index**, and -/// **has_neighbor()** is used to check the results. -/// -/// After some other values are gathered for debugging purposes, -/// the **v_center** vertex is inserted into the facet delineated by -/// **neighboring_31_index** using **tds().insert_in_facet()**. -/// Finally, the centroid of the common face calculated using -/// **CGAL::centroid()** and assigned to **v_center**, along with a -/// timevalue taken from one of the vertices of the common face. -/// @todo Check Euler condition on insert, ensure not inserting outside -/// -/// @image html 26.png -/// @image latex 26.eps width=7cm -/// -/// @tparam T1 The manifold type -/// @tparam T2 The type of the tuple holding attempted moves -/// @param universe A SimplicialManifold -/// @param attempted_moves A tuple holding a count of the attempted moves -/// of each type given by the **move_type** enum -/// @return The SimplicialManifold{} after the move has been made -template -auto make_26_move(T1&& universe, T2&& attempted_moves) -> decltype(universe) -{ -#ifndef NDEBUG - std::cout << "Attempting (2,6) move.\n"; -#endif - - auto not_moved = true; - while (not_moved) { - // Pick out a random (1,3) from simplex_types - auto choice = generate_random_signed(0, universe.geometry->N3_13() - 1); - - int neighboring_31_index{5}; - Cell_handle bottom = universe.geometry->one_three[choice]; - - if (!universe.triangulation->tds().is_cell(bottom)) - throw std::runtime_error("make_26_move() bottom is not a cell!"); - - if (bottom->info() != 13) - throw std::runtime_error("bottom is not a 13 cell!"); - - if (!find_26_movable(bottom, neighboring_31_index)) - throw std::runtime_error("This cell is not movable."); - -#ifndef NDEBUG - std::cout << "neighboring_31_index is " << neighboring_31_index << "\n"; -#endif - - Cell_handle top = bottom->neighbor(neighboring_31_index); - - // Check has_neighbor() returns the index of the common face - int common_face_index{5}; - bottom->has_neighbor(top, common_face_index); - -#ifndef NDEBUG - std::cout << "bottom's common_face_index with top is " << common_face_index - << "\n"; -#endif - - if (common_face_index == 5) - throw std::runtime_error("make_26_move() common_face_index invalid!"); - - int mirror_common_face_index{5}; - top->has_neighbor(bottom, mirror_common_face_index); - -#ifndef NDEBUG - std::cout << "top's mirror_common_face_index with bottom is " - << mirror_common_face_index << "\n"; -#endif - - if (mirror_common_face_index == 5) - throw std::runtime_error( - "make_26_move() mirror_common_face_index invalid!"); - - // Get indices of vertices of common face with respect to bottom cell - int i1 = (common_face_index + 1) & 3; - int i2 = (common_face_index + 2) & 3; - int i3 = (common_face_index + 3) & 3; - - // Get vertices of the common face - // They're denoted wrt the bottom, but could easily be wrt to top - Vertex_handle v1 = bottom->vertex(i1); - Vertex_handle v2 = bottom->vertex(i2); - Vertex_handle v3 = bottom->vertex(i3); - - // Timeslices of v1, v2, and v3 should be same - if (v1->info() != v2->info() || v1->info() != v3->info()) - throw std::range_error("Timeslices of v1, v2, and v3 don't match!"); - -#ifndef NDEBUG - // Get indices of vertices of common face with respect to top cell - int in1 = top->index(bottom->vertex(i1)); - // int in2 = top->index(bottom->vertex(i2)); - // int in3 = top->index(bottom->vertex(i3)); - Vertex_handle v5 = top->vertex(in1); - (v1 == v5) ? std::cout << "bottom->vertex(i1) == top->vertex(in1)\n" - : std::cout << "bottom->vertex(i1) != top->vertex(in1)\n"; -#endif - - // Is there a neighboring (3,1) simplex? - if (find_26_movable(bottom, neighboring_31_index)) { -#ifndef NDEBUG - std::cout << "(1,3) simplex " << choice << " is movable.\n"; - std::cout << "The neighboring simplex " << neighboring_31_index - << " is of type " - << bottom->neighbor(neighboring_31_index)->info() << "\n"; -#endif - - // Do the (2,6) move - // Insert new vertex - Vertex_handle v_center = universe.triangulation->tds().insert_in_facet( - bottom, neighboring_31_index); - - // Checks - std::vector inc_cells; - universe.triangulation->tds().incident_cells( - v_center, std::back_inserter(inc_cells)); - if (inc_cells.size() != 6) - throw std::logic_error( - "(2,6) center vertex not bounded by 6 simplices!"); - - // Check combinatorial and geometric validity of each cell - for (const auto& cell : inc_cells) { - if (!universe.triangulation->tds().is_valid(cell, true)) - throw std::logic_error( - "A cell resulting from (2,6) move is invalid."); - } - -#ifndef NDEBUG - // Find the center of the facet - // A vertex is a topological object which may be associated with a - // point, which is a geometrical object. - auto center_point = CGAL::centroid(v1->point(), v2->point(), v3->point()); - std::cout << "Center point is: " << center_point << "\n"; - v_center->set_point(center_point); -#endif - - // Assign a timeslice to the new vertex - auto timeslice = v1->info(); - v_center->info() = timeslice; - -#ifndef NDEBUG - // Check we have a vertex - if (universe.triangulation->tds().is_vertex(v_center)) { - std::cout << "It's a vertex in the TDS.\n"; - } - else - { - std::cout << "It's not a vertex in the TDS.\n"; - } - - std::cout << "Spacelike face timeslice is " << timeslice << "\n"; - std::cout << "Inserted vertex " << v_center->point() << " with timeslice " - << v_center->info() << "\n"; -#endif - - if (!universe.triangulation->tds().is_valid(v_center, true, 1)) - throw std::logic_error("Center vertex in (2,6) move invalid!"); - not_moved = false; - } - else - { -#ifndef NDEBUG - std::cout << "(1,3) simplex " << choice << " was not movable.\n"; -#endif - } - // Increment the (2,6) move counter - ++attempted_moves[2]; - } - // return std::move(universe); - return std::forward(universe); -} // make_26_move() - -/// @brief Find a (6,2) move -/// @tparam T The manifold type -/// @param universe A SimplicialManifold -/// @param candidate A vertex to test -/// @return True if a (6,2) move can be made on the candidate vertex -template -auto find_62_movable(T&& universe, Vertex_handle candidate) -{ - std::vector candidate_cells; - // Adjacent (3,1), (2,2), and (1,3) cells - auto adjacent_cell = std::make_tuple(0, 0, 0); - universe.triangulation->incident_cells(candidate, - back_inserter(candidate_cells)); - // We must have 6 cells around the vertex to be able to make a (6,2) move - if (candidate_cells.size() != 6) return false; - - for (const auto& cit : candidate_cells) { - CGAL_triangulation_precondition(universe.triangulation->is_cell(cit)); - if (cit->info() == 31) { - ++std::get<0>(adjacent_cell); - } - else if (cit->info() == 22) - { - ++std::get<1>(adjacent_cell); - } - else if (cit->info() == 13) - { - ++std::get<2>(adjacent_cell); - } - else - { -#ifndef NDEBUG - std::cout << "Probably an edge cell (facet with infinite vertex).\n"; -#endif - return false; - } - } - return ((std::get<0>(adjacent_cell) == 3) && - (std::get<1>(adjacent_cell) == 0) && - (std::get<2>(adjacent_cell) == 3)); -} // find_62_movable() - -/// @brief -/// @param[in,out] universe A SimplicialManifold -/// @param[in,out] attempted_moves A tuple holding a count of the attempted -/// moves of each type given by the **move_type** enum -/// @returns universe The SimplicialManifold after the move has been made - -/// @brief Make a (6,2) move -/// -/// This function performs the (6,2) move by removing a vertex -/// that has 3 (1,3) and 3 (3,1) simplices around it -/// -/// @tparam T1 The manifold type -/// @tparam T2 The type of the tuple holding attempted moves -/// @param universe A SimplicialManifold -/// @param attempted_moves A tuple holding a count of the attempted moves -/// @return The SimplicialManifold after the move has been made -template -auto make_62_move(T1&& universe, T2&& attempted_moves) -> decltype(universe) -{ -#ifndef NDEBUG - std::cout << "Attempting (6,2) move.\n"; -#endif - std::vector tds_vertices = universe.geometry->vertices; - auto not_moved = true; - int_fast32_t tds_vertices_size = tds_vertices.size(); - while ((not_moved) && (tds_vertices_size > 0)) { - auto choice = generate_random_signed(0, tds_vertices_size - 1); - Vertex_handle to_be_moved = tds_vertices[choice]; - // Ensure pre-conditions are satisfied - CGAL_triangulation_precondition(universe.triangulation->dimension() == 3); - CGAL_triangulation_expensive_precondition(is_vertex(to_be_moved)); - if (find_62_movable(universe, to_be_moved)) { - universe.triangulation->remove(to_be_moved); - not_moved = false; - } - tds_vertices.erase(tds_vertices.begin() + choice); // O(|V|) bottleneck - tds_vertices_size--; - // Increment the (6,2) move counter - ++attempted_moves[3]; - } - - if (tds_vertices_size == 0) { - throw std::domain_error("No (6,2) move is possible."); - } - // return std::move(universe); - return std::forward(universe); -} // make_62_move() - -/// @brief -/// @param[in,out] universe A SimplicialManifold -/// @param[in,out] attempted_moves A tuple holding a count of the attempted -/// moves of each type given by the **move_type** enum -/// @returns universe The SimplicialManifold after the move has been made -/// \todo: Make (4,4) move aka 4,4 bistellar flip work. This is on the CGAL -/// TODO list also - -/// @brief Make a (4,4) move -/// -/// This function performs the (4,4) move by replacing a space-like edge -/// with another space-like edge that maintains the number of simplices. -/// -/// @tparam T1 The manifold type -/// @tparam T2 The type of the tuple holding attempted moves -/// @param universe A SimplicialManifold -/// @param attempted_moves A tuple holding a count of the attempted moves -/// @return The SimplicialManifold after the move has been made -template -auto make_44_move(T1&& universe, T2&& attempted_moves) -> decltype(universe) -{ -#ifndef NDEBUG - std::cout << "Attempting (4,4) move.\n"; -#endif - std::vector movable_spacelike_edges{ - universe.geometry->spacelike_edges}; - - auto not_moved = true; // should be true - while ((not_moved) && (!movable_spacelike_edges.empty())) { - // do something - } - if (movable_spacelike_edges.empty()) { - throw std::domain_error("No (4,4) move is possible."); - } - // Increment the (4,4) move counter - ++attempted_moves[4]; - // return std::move(universe); - return std::forward(universe); -} // make_44_move() - -#endif // SRC_S3ERGODICMOVES_HPP_ diff --git a/include/S3Triangulation.hpp b/include/S3Triangulation.hpp deleted file mode 100644 index 29c0292207..0000000000 --- a/include/S3Triangulation.hpp +++ /dev/null @@ -1,311 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2015-2018 Adam Getchell -/// -/// Creates foliated spherical triangulations -/// -/// The number of desired timeslices is given, and -/// successive spheres are created with increasing radii. -/// Each vertex at a given radius is assigned a timeslice so that the -/// entire triangulation will have a preferred foliation of time. -/// -/// \done Insert a 3-sphere into the triangulation data structure. -/// \done Assign each 3-sphere a unique timeslice. -/// \done Iterate over the number of desired timeslices. -/// \done Check/fix issues for large values of simplices and timeslices. -/// \done Iterate over cells and check timeslices of vertices don't differ -/// by more than 1. -/// \done Gather ratio of cells with bad/good foliation. -/// Adjust value of radius to minimize. -/// Recheck the whole triangulation when finished. -/// \done When a cell contains a bad foliation, delete it. Recheck. -/// \done Fixup Delaunay triangulation after bad cells have been deleted. -/// \done Re-written with std::unique_ptr and -/// . -/// Efficient Pure Functional Programming in C++ Using Move Semantics -/// \done -/// Const Correctness. -/// \done Function documentation. -/// \done Multi-threaded operations using Intel TBB. -/// \done Debugging output toggled by macros. - -/// @file S3Triangulation.hpp -/// @brief Functions on 3D Spherical Delaunay Triangulations -/// @author Adam Getchell - -#ifndef SRC_S3TRIANGULATION_HPP_ -#define SRC_S3TRIANGULATION_HPP_ - -/// Toggles detailed per-simplex debugging output -#define DETAILED_DEBUGGING -#undef DETAILED_DEBUGGING - -// CGAL headers -#include -#include -#include -#include -#include - -// C++ headers -#include -#include -#include -#include -#include -#include -#include - -// CDT headers -#include - -using K = CGAL::Exact_predicates_inexact_constructions_kernel; -using Triangulation = CGAL::Triangulation_3; -// Used so that each timeslice is assigned an integer -using Vb = CGAL::Triangulation_vertex_base_with_info_3; -using Cb = CGAL::Triangulation_cell_base_with_info_3; - -// Parallel operations -#ifdef CGAL_LINKED_WITH_TBB -using Tds = CGAL::Triangulation_data_structure_3; -#else -using Tds = CGAL::Triangulation_data_structure_3; -#endif -using Delaunay = CGAL::Delaunay_triangulation_3; -using Cell_handle = Delaunay::Cell_handle; -using Vertex_handle = Delaunay::Vertex_handle; -using Locate_type = Delaunay::Locate_type; -using Point = Delaunay::Point; -using Edge_handle = std::tuple; -using Causal_vertices = std::vector>; -using Move_tracker = std::array; - -enum class move_type -{ - TWO_THREE = 0, - THREE_TWO = 1, - TWO_SIX = 2, - SIX_TWO = 3, - FOUR_FOUR = 4 -}; - -/// The maximum number of passes to fix invalidly foliated simplices -static constexpr std::int_fast32_t MAX_FOLIATION_FIX_PASSES = 500; - -/// The dimensionality of the Delaunay triangulation -static constexpr int DIMENSION = 3; - -/// Initial radius and radial factor -static constexpr double INITIAL_RADIUS = 1.0; -static constexpr double RADIAL_FACTOR = 1.0; - -/// @brief Fix simplices with incorrect foliation -/// -/// This function iterates over all of the cells in the triangulation. -/// Within each cell, it iterates over all of the vertices and reads timeslices. -/// Validity of the cell is first checked by the **is_valid()** function. -/// The foliation validity is then checked by finding maximum and minimum -/// timeslices for all the vertices of a cell and ensuring that the difference -/// is exactly 1. -/// If a cell has a bad foliation, the vertex with the highest timeslice is -/// deleted. The Delaunay triangulation is then recomputed on the remaining -/// vertices. -/// This function is repeatedly called by fix_triangulation() up to -/// **MAX_FOLIATION_FIX_PASSES** times. -/// -/// @param universe_ptr A std::unique_ptr to the triangulation -/// @returns A boolean value if there are invalid simplices -template -auto fix_timeslices(T&& universe_ptr) -{ -// Delaunay::Finite_cells_iterator cit; - std::int_fast32_t min_time{0}; - std::int_fast32_t max_time{0}; - std::int_fast32_t valid{0}; - std::int_fast32_t invalid{0}; - std::int_fast32_t max_vertex{0}; - std::set deleted_vertices; - - // Iterate over all cells in the Delaunay triangulation - for (Delaunay::Finite_cells_iterator cit = universe_ptr->finite_cells_begin(); - cit != universe_ptr->finite_cells_end(); ++cit) - { - if (cit->is_valid()) { // Valid cell - min_time = cit->vertex(0)->info(); - max_time = min_time; -#ifdef DETAILED_DEBUGGING - bool this_cell_foliation_valid = true; -#endif - // Iterate over all vertices in the cell - for (auto i = 0; i < 4; ++i) { - auto current_time = cit->vertex(i)->info(); - - // Classify extreme values - if (current_time < min_time) min_time = current_time; - if (current_time > max_time) { - max_time = current_time; - max_vertex = static_cast(i); - } - } // Finish iterating over vertices - // There should be a difference of 1 between min_time and max_time - if (max_time - min_time != 1) { - invalid++; -#ifdef DETAILED_DEBUGGING - this_cell_foliation_valid = false; -#endif - // Single-threaded delete max vertex - // universe_ptr->remove(cit->vertex(max_vertex)); - - // Parallel delete std::set of max_vertex for all invalid cells - deleted_vertices.emplace(cit->vertex(static_cast(max_vertex))); - } - else - { - ++valid; - } - -#ifdef DETAILED_DEBUGGING - std::cout << "Foliation for cell is " - << ((this_cell_foliation_valid) ? "valid." : "invalid.\n"); - for (auto i = 0; i < 4; ++i) { - std::cout << "Vertex " << i << " is " << cit->vertex(i)->point() - << " with timeslice " << cit->vertex(i)->info() << "\n"; - } -#endif - } - else - { - throw std::runtime_error("Cell handle is invalid!"); - // Or just remove the cell - // universe_ptr->tds().delete_cell(cit); - // This results in a possibly broken Delaunay triangulation - // Or possibly just delete a vertex in the cell, - // perhaps forcing a re-triangulation? - } - } // Finish iterating over cells - - // Delete invalid vertices - universe_ptr->remove(deleted_vertices.begin(), deleted_vertices.end()); - // Check that the triangulation is still valid - // Turned off by -DCGAL_TRIANGULATION_NO_POSTCONDITIONS - // CGAL_triangulation_expensive_postcondition(universe_ptr->is_valid()); - if (!universe_ptr->tds().is_valid()) - throw std::logic_error("Delaunay tds invalid!"); - -#ifndef NDEBUG - std::cout << "There are " << invalid << " invalid simplices and " << valid - << " valid simplices.\n"; -#endif - return invalid == 0; -} // fix_timeslices - -/// @brief Fixes the foliation of the triangulation -/// -/// Runs fix_timeslices() to fix foliation until there are no errors, -/// or MAX_FOLIATION_FIX_PASSES whichever comes first. -/// -/// @param universe_ptr A std::unique_ptr to the triangulation -template -void fix_triangulation(T&& universe_ptr) -{ - for (std::int_fast32_t pass = 0; pass < MAX_FOLIATION_FIX_PASSES; ++pass) { -#ifndef NDEBUG - std::cout << "Fix Pass #" << (pass + 1) << "\n"; -#endif - if (fix_timeslices(universe_ptr)) break; - } - if (!fix_timeslices(universe_ptr)) - throw std::logic_error("Delaunay triangulation not correctly foliated."); -} // fix_triangulation() - -/// @brief Inserts vertices with timeslices into Delaunay triangulation -/// -/// @tparam T Type of universe_ptr -/// @param universe_ptr A unique pointer to triangulation -/// @param cv A data structure of causal vertices -template -void insert_into_triangulation(T&& universe_ptr, Causal_vertices cv) -{ - universe_ptr->insert(cv.begin(), cv.end()); -} // insert_into_triangulation() - -/// @brief Make foliated spheres -/// -/// The radius is used to denote the time value, so we can nest 2-spheres -/// such that our time foliation contains leaves of identical topology. -/// -/// @param simplices The number of desired simplices in the triangulation -/// @param timeslices The number of desired timeslices in the triangulation -/// @return A std::vector> containing random -/// vertices and their corresponding timevalues -auto inline make_foliated_sphere(const std::int_fast32_t simplices, - const std::int_fast32_t timeslices) -{ - // double radius{0}; - const auto points_per_timeslice = - expected_points_per_simplex(DIMENSION, simplices, timeslices); - CGAL_triangulation_precondition(points_per_timeslice >= 2); - Causal_vertices causal_vertices; - using Spherical_points_generator_3 = CGAL::Random_points_on_sphere_3; - - for (std::int_fast32_t i = 0; i < timeslices; ++i) { - auto radius = INITIAL_RADIUS + static_cast(i) * RADIAL_FACTOR; -// CGAL::Random_points_on_sphere_3 gen{radius}; - Spherical_points_generator_3 gen{radius}; - // At each radius, generate a sphere of random points proportional to area - for (std::int_fast32_t j = 0; - j < static_cast(points_per_timeslice * radius); ++j) - { - causal_vertices.emplace_back(std::make_pair(*gen++, radius)); - } // end j - } // end i - return causal_vertices; -} // make_foliated_sphere() - -/// @brief Make a triangulation from foliated 2-spheres -/// -/// This function creates a triangulation from successive spheres. -/// First, the number of points per leaf in the foliation is estimated given -/// the desired number of simplices. -/// Next, make_foliated_sphere() is called to generate nested spheres. -/// The radius of the sphere is assigned as the time value for each vertex -/// in that sphere, which comprises a leaf in the foliation. -/// All vertices in all spheres (along with their time values) are then -/// inserted with insert_into_triangulation() into a Delaunay triangulation -/// (see http://en.wikipedia.org/wiki/Delaunay_triangulation for details). -/// Finally, fix_triangulation() removes cells in the Delaunay triangulation -/// with invalid foliations using fix_timeslices(). A last check is performed -/// to ensure a valid Delaunay triangulation. -/// -/// @param[in] simplices The number of desired simplices in the triangulation -/// @param[in] timeslices The number of timeslices in the triangulation -/// @returns A std::unique_ptr to the foliated triangulation -auto inline make_triangulation(const std::int_fast32_t simplices, - const std::int_fast32_t timeslices) -{ - std::cout << "Generating universe ... \n"; - -#ifdef CGAL_LINKED_WITH_TBB - // Construct the locking data-structure - // using the bounding-box of the points - auto bounding_box_size = static_cast(timeslices + 1); - Delaunay::Lock_data_structure locking_ds{ - CGAL::Bbox_3{-bounding_box_size, -bounding_box_size, -bounding_box_size, - bounding_box_size, bounding_box_size, bounding_box_size}, - 50}; - Delaunay universe{K{}, &locking_ds}; -#else - Delaunay universe{}; -#endif - - auto universe_ptr = std::make_unique(universe); - auto causal_vertices = make_foliated_sphere(simplices, timeslices); - insert_into_triangulation(universe_ptr, causal_vertices); - fix_triangulation(universe_ptr); - if (!universe_ptr->is_valid()) - throw std::logic_error("Delaunay triangulation invalid!"); - return universe_ptr; -} // make_triangulation() - -#endif // SRC_S3TRIANGULATION_HPP_ diff --git a/include/Settings.hpp b/include/Settings.hpp new file mode 100644 index 0000000000..63bbce9fcb --- /dev/null +++ b/include/Settings.hpp @@ -0,0 +1,59 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2020 Adam Getchell + ******************************************************************************/ + +/// @file Settings.hpp +/// @brief Global integer and precision settings +/// @author Adam Getchell +/// @details Global project settings on integer types and MPFR precision + +#ifndef INCLUDE_SETTINGS_HPP_ +#define INCLUDE_SETTINGS_HPP_ + +#include + +#include + +/// Results are converted to a CGAL multi-precision floating point number. +/// Gmpzf itself is based on GMP (https://gmplib.org), as is MPFR. +using Gmpzf = CGAL::Gmpzf; + +/// Sets the type of integer to use throughout the project. +/// These are the base values read into the program or used in calculations. +/// Casts to unsigned types are still necessary for certain library functions +/// to work. + +using Int_precision = std::int32_t; + +#ifdef _WIN32 +#define __PRETTY_FUNCTION__ __FUNCSIG__ +#endif + +// #define CGAL_LINKED_WITH_TBB + +/// Correctly declare global constants +/// See Jonathan Boccara's C++ Pitfalls, January 2021 + +/// Sets the precision for MPFR. +static inline Int_precision constexpr PRECISION = 256; + +/// Default foliated triangulation spacings +static inline double constexpr INITIAL_RADIUS = 1.0; +static inline double constexpr FOLIATION_SPACING = 1.0; + +/// Sets epsilon values for floating point comparisons +static inline double constexpr TOLERANCE = 0.01; + +/// Depends on INITIAL_RADIUS and RADIAL_FACTOR +[[maybe_unused]] static inline Int_precision constexpr GV_BOUNDING_BOX_SIZE = + 100; + +/// Aligns data for ease of access on 64-bit CPUs at the expense of padding +static inline int constexpr ALIGNMENT_64_BIT = 64; + +/// Except when we only need 32 bits +static inline int constexpr ALIGNMENT_32_BIT = 32; + +#endif // INCLUDE_SETTINGS_HPP_ diff --git a/include/SimplicialManifold.hpp b/include/SimplicialManifold.hpp deleted file mode 100644 index 20c5db735e..0000000000 --- a/include/SimplicialManifold.hpp +++ /dev/null @@ -1,573 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2016-2017 Adam Getchell -/// -/// Data structures for operations on simplicial manifolds -/// -/// \done Classify cells as (3,1), (2,2), or (1,3) based on their foliation. -/// A tuple of vectors contain cell handles to the simplices of type (3,1), -/// (2,2), and (1,3) respectively. -/// \done Classify edges as timelike or spacelike so that action can be -/// calculated. -/// \done SimplicialManifold data structure holding a std::unique_ptr to -/// the Delaunay triangulation and a std::tuple of geometry information. -/// \done Move constructor recalculates geometry. -/// -/// @file SimplicialManifold.hpp -/// @brief Data structures for simplicial manifolds -/// @author Adam Getchell - -#ifndef SRC_SIMPLICIALMANIFOLD_HPP_ -#define SRC_SIMPLICIALMANIFOLD_HPP_ - -#include -#include -#include -#include -#include -#include -#include - -using Facet = Delaunay::Facet; - -/// @brief A tuple of the geometric values of the Simplicial Manifold -/// -/// The first element is the vector of (3,1) simplices -/// The second element is the vector of (2,2) simplices -/// The third element is the vector of (1,3) simplices -/// The fourth element is the vector of timelike edges -/// The fifth element is the vector of spacelike edges -/// The sixth element is the vector of vertices -/// -/// Useful for constructing GeometryInfo, which contains this and other -/// information, and in comparing the results of moves, which will change one or -/// more elements of the Geometry_tuple. -using Geometry_tuple = - std::tuple, std::vector, - std::vector, std::vector, - std::vector, std::vector>; - -// Non-member non-friend functions - -/// @brief Classifies edges -/// -/// This function iterates over all edges in the triangulation -/// and classifies them as timelike or spacelike. -/// Timelike edges are stored in the **timelike_edges** vector as an Edge_handle -/// (tuple of Cell_handle, std::int_fast32_t, std::int_fast32_t) for later use by -/// ergodic moves on timelike edges. Spacelike edges are also stored as a -/// vector of Edge_handle **spacelike_edges**, for use by (4,4) moves as -/// well as the distance-finding algorithms. -/// @param[in] universe_ptr A std::unique_ptr to the triangulation -/// @returns A std::pair, std::vector> of -/// timelike edges and spacelike edges -template -auto classify_edges(T&& universe_ptr) -{ -#ifndef NDEBUG - std::cout << "Classifying edges....\n"; -#endif - Delaunay::Finite_edges_iterator eit; - std::vector timelike_edges; - std::vector spacelike_edges; - - // Iterate over all edges in the Delaunay triangulation - for (eit = universe_ptr->finite_edges_begin(); - eit != universe_ptr->finite_edges_end(); ++eit) - { - Cell_handle ch = eit->first; - // Get timevalues of vertices at the edge ends - auto time1 = ch->vertex(eit->second)->info(); - auto time2 = ch->vertex(eit->third)->info(); - - // Make Edge_handle - Edge_handle thisEdge{ - ch, static_cast(ch->index(ch->vertex(eit->second))), - static_cast(ch->index(ch->vertex(eit->third)))}; - - if (time1 != time2) { // We have a timelike edge - timelike_edges.emplace_back(thisEdge); - -#ifdef DETAILED_DEBUGGING - std::cout << "First vertex of edge is " << std::get<1>(thisEdge) - << " and second vertex of edge is " << std::get<2>(thisEdge) - << std::endl; -#endif - } - else - { // We have a spacelike edge - spacelike_edges.emplace_back(thisEdge); - } // endif - } // Finish iterating over edges - -// Display results if debugging -#ifndef NDEBUG - std::cout << "There are " << timelike_edges.size() << " timelike edges and " - << spacelike_edges.size() << " spacelike edges.\n"; -#endif - return std::make_pair(timelike_edges, spacelike_edges); -} // classify_edges() - -/// @brief Classify simplices as (3,1), (2,2), or (1,3) -/// -/// This function iterates over all cells in the triangulation -/// and classifies them as: -/// \f{eqnarray*}{ -/// 31 &=& (3, 1) \\ -/// 22 &=& (2, 2) \\ -/// 13 &=& (1, 3) -/// \f} -/// The vectors **three_one**, **two_two**, and **one_three** contain -/// Cell_handles to all the simplices in the triangulation of that corresponding -/// type. -/// -/// @param[in] universe_ptr A std::unique_ptr to the triangulation -/// @returns A std::tuple of -/// **three_one**, **two_two**, and **one_three** -template -auto classify_simplices(T&& universe_ptr) -{ -#ifndef NDEBUG - std::cout << "Classifying simplices....\n"; -#endif - Delaunay::Finite_cells_iterator cit; - std::vector three_one; - std::vector two_two; - std::vector one_three; - - // Iterate over all cells in the Delaunay triangulation - for (cit = universe_ptr->finite_cells_begin(); - cit != universe_ptr->finite_cells_end(); ++cit) - { - std::int_fast32_t max_values{0}; - std::int_fast32_t min_values{0}; - // Push every time value of every vertex into a list - std::int_fast32_t timevalues[4] = { - cit->vertex(0)->info(), - cit->vertex(1)->info(), - cit->vertex(2)->info(), - cit->vertex(3)->info(), - }; - std::int_fast32_t max_time = - *std::max_element(std::begin(timevalues), std::end(timevalues)); - for (auto elt : timevalues) { - if (elt == max_time) { - ++max_values; - } - else - { - ++min_values; - } - } - - // Classify simplex using max_values and write to cit->info() - if (min_values == 1 && max_values == 3) { - cit->info() = 13; - one_three.emplace_back(cit); - } - else if (min_values == 2 && max_values == 2) - { - cit->info() = 22; - two_two.emplace_back(cit); - } - else if (min_values == 3 && max_values == 1) - { - cit->info() = 31; - three_one.emplace_back(cit); - } - else - { - throw std::runtime_error("Invalid simplex in classify_simplices()!"); - } // endif - } // Finish iterating over cells - -// Display results if debugging -#ifndef NDEBUG - std::cout << "There are " << three_one.size() << " (3,1) simplices and " - << two_two.size() << " (2,2) simplices\n"; - std::cout << "and " << one_three.size() << " (1,3) simplices.\n"; -#endif - return std::make_tuple(three_one, two_two, one_three); -} // classify_simplices() - -template -auto classify_all_simplices(T&& universe_ptr) -{ -#ifndef NDEBUG - std::cout << "Classifying all simplices....\n"; -#endif - - auto cells = classify_simplices(universe_ptr); - auto edges = classify_edges(universe_ptr); - std::vector vertices; - for (auto vit = universe_ptr->finite_vertices_begin(); - vit != universe_ptr->finite_vertices_end(); ++vit) - { - vertices.emplace_back(vit); - } - return std::make_tuple(std::get<0>(cells), std::get<1>(cells), - std::get<2>(cells), edges.first, edges.second, - vertices); -} - -/// @struct -/// @brief A struct containing detailed geometry information -/// -/// GeometryInfo contains information about the geometry of -/// a triangulation. In addition, it defines convenient functions to -/// retrieve commonly used values. This is to save the expense of -/// calculating manually from the triangulation. GeometryInfo() is -/// recalculated using the move assignment operator anytime a -/// SimplicialManifold() is move constructed. -/// The default constructor, destructor, move constructor, copy -/// constructor, and copy assignment operator are explicitly defaulted. -/// See http://en.cppreference.com/w/cpp/language/rule_of_three -struct GeometryInfo -{ - private: - /// @brief (3,1) cells in the foliation - std::vector three_one; - - /// @brief (2,2) cells in the foliation - std::vector two_two; - - /// @brief (1,3) cells in the foliation - std::vector one_three; - - /// @brief Edges spanning two adjacent time slices in the foliation - std::vector timelike_edges; - - /// @brief Non-spanning edges in the foliation - std::vector spacelike_edges; - - /// @brief Vertices of the foliation - std::vector vertices; - - /// @brief Spacelike facets for each timeslice - boost::optional> spacelike_facets; - - /// @brief Actual timevalues of simulation - boost::optional> timevalues; - - public: - /// @brief Getter for spacelike facets - /// @return The multimap of facets - const boost::optional>& getSpacelike_facets() - const - { - return spacelike_facets; - } - - /// @brief Setter for spacelike facets - /// @param spacelike_facets The multimap of facets - void setSpacelike_facets( - const boost::optional>& spacelike_facets) - { - GeometryInfo::spacelike_facets = spacelike_facets; - } - - /// @brief Getter for timevalues - /// @return The set of timevalues - const boost::optional>& getTimevalues() const - { - return timevalues; - } - - /// @brief Setter for timevalues - /// @param timevalues The set of timevalues - void setTimevalues(const boost::optional>& timevalues) - { - GeometryInfo::timevalues = timevalues; - } - - /// @brief Default constructor - GeometryInfo() = default; - - /// @brief Constructor from Geometry_tuple - /// - /// This is usually called as a result of classify_all_simplices(), - /// which itself takes a std::unique_ptr - /// @param geometry Geometry_tuple initializing values - /// @return A populated GeometryInfo{} - explicit GeometryInfo(const Geometry_tuple&& geometry) noexcept - : three_one{std::get<0>(geometry)} - , two_two{std::get<1>(geometry)} - , one_three{std::get<2>(geometry)} - , timelike_edges{std::get<3>(geometry)} - , spacelike_edges{std::get<4>(geometry)} - , vertices{std::get<5>(geometry)} - {} - - /// @brief Default destructor - ~GeometryInfo() = default; - - /// @brief Default move constructor - GeometryInfo(GeometryInfo&&) = default; - - /// @brief Default move assignment operator - // GeometryInfo& operator=(GeometryInfo&&) = default; - GeometryInfo& operator=(Geometry_tuple&& other) - { -#ifndef NDEBUG - std::cout << "GeometryInfo move assignment operator." << std::endl; -#endif - three_one = std::move(std::get<0>(other)); - two_two = std::move(std::get<1>(other)); - one_three = std::move(std::get<2>(other)); - timelike_edges = std::move(std::get<3>(other)); - spacelike_edges = std::move(std::get<4>(other)); - vertices = std::move(std::get<5>(other)); - return *this; - } - - /// @brief Default copy constructor - GeometryInfo(const GeometryInfo&) = default; - - /// @brief Default copy assignment operator - GeometryInfo& operator=(const GeometryInfo&) = default; - - /// @brief Timelike edges - /// @return The number of edges spanning timeslices - auto N1_TL() { return static_cast(timelike_edges.size()); } - - /// @brief Spacelike edges - /// @return The number of edges on same timeslice - auto N1_SL() { return static_cast(spacelike_edges.size()); } - - /// @brief (3,1) simplices - /// @return The total number of simplices with 3 vertices on the t - /// timeslice and 1 vertex on the t+1 timeslice - auto N3_31() { return static_cast(three_one.size()); } - - /// @brief (1,3) simplices - /// @return The total number of simplices with 1 vertex on the t timeslice - /// and 3 vertices on the t+1 timeslice - auto N3_13() { return static_cast(one_three.size()); } - - /// @brief (3,1) and (1,3) simplices - /// @return The total number of simplices with 3 vertices on one - /// timeslice and 1 vertex on the adjacent timeslice. Used to - /// calculate the change in action. - auto N3_31_13() { return N3_31() + N3_13(); } - - /// @brief (2,2) simplices - /// @return The total number of simplices with 2 vertices on one - /// timeslice and 2 vertices on the adjacent timeslice. Used to - /// calculate the change in action. - auto N3_22() { return static_cast(two_two.size()); } - - /// @brief Number of cells - /// - /// This should be the equivalent of - /// SimplicialManifold::triangulation->number_of_finite_cells(), - /// and is used as a check to ensure that GeometryInfo{} matches. - /// @return The number of cells in GeometryInfo{} - auto number_of_cells() { return N3_31() + N3_22() + N3_13(); } - - /// @brief Number of edges - /// - /// This should be the equivalent of - /// SimplicialManifold::triangulation->number_of_finite_edges(), - /// and is used as a check to ensure that GeometryInfo{} matches. - /// @return The number of edges in the triangulation - auto number_of_edges() { return N1_TL() + N1_SL(); } - - // auto max_timevalue() { return *timevalues.crbegin();} - boost::optional max_timevalue() - { - return timevalues ? *timevalues->crbegin() : 0; - } - - boost::optional min_timevalue() - { - return timevalues ? *timevalues->begin() : 0; - } - /// @brief Number of vertices - /// @return The number of vertices in the triangulation - auto N0() { return static_cast(vertices.size()); } - - template - friend auto make_23_move(T1&& universe, T2&& attempted_moves) - -> decltype(universe); - - template - friend auto make_32_move(T1&& universe, T2&& attempted_moves) - -> decltype(universe); - - template - friend auto make_26_move(T1&& universe, T2&& attempted_moves) - -> decltype(universe); - - template - friend auto make_62_move(T1&& universe, T2&& attempted_moves) - -> decltype(universe); - - template - friend auto make_44_move(T1&& universe, T2&& attempted_moves) - -> decltype(universe); - - template - friend auto VolumePerTimeslice(T&& manifold) -> decltype(manifold); -}; - -/// @struct -/// @brief A struct to hold triangulation and geometry information -/// -/// SimplicialManifold contains information about the triangulation and -/// its geometry. In addition, it defines convenient constructors. -struct SimplicialManifold -{ - /// @brief Owning pointer to the Delaunay triangulation - std::unique_ptr triangulation; - - /// @brief Owning pointer to GeometryInfo - std::unique_ptr geometry; - - /// @brief Default constructor - SimplicialManifold() - : triangulation{std::make_unique()} - , geometry{std::make_unique()} - { -#ifndef NDEBUG - std::cout << "SimplicialManifold default ctor.\n"; -#endif - } - - /// @brief Constructor with std::unique_ptr - /// - /// Constructor taking a std::unique_ptr which should be created - /// using make_triangulation(). If you wish to default initialize a - /// SimplicialManifold with no values, use the default - /// constructor SimplicialManifold::SimplicialManifold() instead. - /// Non-static data members are initialized in the order they are declared, - /// (see http://open-std.org/JTC1/SC22/WG21/docs/papers/2016/n4594.pdf, - /// \f$\S\f$ 12.6.2.13.3), so **geometry** depending upon **triangulation** - /// is fine. - /// @param manifold A std::unique_ptr - /// @return A SimplicialManifold{} - explicit SimplicialManifold(std::unique_ptr&& manifold) // NOLINT - : triangulation{std::move(manifold)} - , geometry{std::make_unique( - classify_all_simplices(triangulation))} - { -#ifndef NDEBUG - std::cout << "SimplicialManifold std::unique_ptr ctor.\n"; -#endif - } - - /// @brief make_triangulation constructor - /// - /// Constructor that initializes **triangulation** by calling - /// make_triangulation() and **geometry** by calling - /// classify_all_simplices(). - /// @param simplices The number of desired simplices in the triangulation - /// @param timeslices The number of timeslices in the triangulation - /// @return A populated SimplicialManifold{} - SimplicialManifold(std::int_fast32_t simplices, std::int_fast32_t timeslices) - : triangulation{make_triangulation(simplices, timeslices)} - , geometry{std::make_unique( - classify_all_simplices(triangulation))} - { -#ifndef NDEBUG - std::cout << "SimplicialManifold make_triangulation ctor.\n"; -#endif - } - - /// @brief Destructor - ~SimplicialManifold() - { -#ifndef NDEBUG - std::cout << "SimplicialManifold dtor.\n"; -#endif - this->triangulation = nullptr; - this->geometry = nullptr; - } - - /// @brief Move constructor - /// @param other The SimplicialManifold to be move-constructed from - /// @return A moved-to SimplicialManifold{} - SimplicialManifold(SimplicialManifold&& other) // NOLINT - : triangulation{std::move(other.triangulation)} - , geometry{std::make_unique( - classify_all_simplices(triangulation))} - // , geometry{std::move(other.geometry)} - { -#ifndef NDEBUG - std::cout << "SimplicialManifold move ctor.\n"; -#endif - } - // SimplicialManifold(SimplicialManifold&&) = default; - - /// @brief Move assignment operator - /// @param other The SimplicialManifold to be moved from - /// @return A moved-assigned SimplicialManifold{} - SimplicialManifold& operator=(SimplicialManifold&& other) noexcept - { -#ifndef NDEBUG - std::cout << "SimplicialManifold move assignment operator.\n"; -#endif - triangulation = std::move(other.triangulation); - geometry = std::make_unique( - classify_all_simplices(std::move(triangulation))); - // geometry = std::move(other.geometry); - return *this; - } - // SimplicialManifold& operator=(SimplicialManifold&&) = default; - - /// @brief SimplicialManifold copy constructor - /// @param other The SimplicialManifold to copy - /// @return A copied SimplicialManifold{} - SimplicialManifold(const SimplicialManifold& other) - : triangulation{std::make_unique(*(other.triangulation))} - , geometry{std::make_unique(*(other.geometry))} - { -#ifndef NDEBUG - std::cout << "SimplicialManifold copy ctor.\n"; -#endif - } - - /// @brief Copy assignment operator - /// @return A copy-assigned SimplicialManifold{} - // SimplicialManifold& operator=(const SimplicialManifold&) = default; - SimplicialManifold& operator=(const SimplicialManifold& other) noexcept - { -#ifndef NDEBUG - std::cout << "SimplicialManifold copy assignment operator.\n"; -#endif - SimplicialManifold temp(other); - swap(triangulation, temp.triangulation); - swap(geometry, temp.geometry); - return *this; - } - - /// @brief Exception-safe swap - /// @param first The first SimplicialManifold to be swapped - /// @param second The second SimplicialManifold to be swapped with. - friend void swap(SimplicialManifold& first, - SimplicialManifold& second) noexcept - { -#ifndef NDEBUG - std::cout << "SimplicialManifold swapperator.\n"; -#endif - using std::swap; - swap(first.triangulation, second.triangulation); - swap(first.geometry, second.geometry); - } - - bool reconcile() - { - return (this->triangulation->number_of_vertices() == this->geometry->N0() && - this->triangulation->number_of_finite_edges() == - this->geometry->number_of_edges() && - this->triangulation->number_of_finite_cells() == - this->geometry->number_of_cells()); - } - - void update() - { - geometry = std::make_unique( - classify_all_simplices(std::move(triangulation))); - } -}; - -#endif // SRC_SIMPLICIALMANIFOLD_HPP_ diff --git a/include/Simulation.hpp b/include/Simulation.hpp deleted file mode 100644 index 9e8932d0a2..0000000000 --- a/include/Simulation.hpp +++ /dev/null @@ -1,52 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2016-2017 Adam Getchell -/// -/// Simulation class methods. This is essentially the main loop of CDT. -/// You push algorithms and other methods you want executed onto the -/// Simulation{} using lambdas and Function_refs and the queue() method, and -/// then call start(). -/// -/// Inspired by http://cppcon.org/modernizing-your-c/ - -/// @file Simulation.hpp -/// @brief Simulation class -/// @author Adam Getchell - -#ifndef SRC_SIMULATION_HPP_ -#define SRC_SIMULATION_HPP_ - -#include -#include -#include -#include - -/// @struct -/// @brief Simulation queue of various functions on SimplicialManifold. -struct Simulation -{ - using element = function_ref; - std::vector queue_; - - /// @brief Queue of function objects. - /// @tparam T Function object type - /// @param callable The function to be called - template - void queue(T&& callable) - { - queue_.emplace_back(std::forward(callable)); - } - - /// @brief Start running queued functions in Simulation - /// @param value The SimplicialManifold - /// @return The SimplicialManifold with item applied to it - SimplicialManifold start(SimplicialManifold&& value) const - { - for (const auto& item : queue_) { - value = item(value); - } - return value; - } -}; - -#endif // SRC_SIMULATION_HPP_ diff --git a/include/Sphere_d.hpp b/include/Sphere_d.hpp deleted file mode 100644 index f4f9f09cda..0000000000 --- a/include/Sphere_d.hpp +++ /dev/null @@ -1,76 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2014-2017 Adam Getchell -/// -/// Inserts a given number of points into a d-dimensional sphere of -/// a given radius - -/// \todo Make the vector compatible with the triangulation data structure - -/// @file sphere_d.hpp -/// @brief Functions on d-Spheres -/// @author Adam Getchell -/// @bug -/// scan-build: No bugs found. - -#ifndef SRC_SPHERE_D_HPP_ -#define SRC_SPHERE_D_HPP_ - -/// CGAL headers -#include -#include - -/// C++ headers -#include -#include - -using Kd = CGAL::Cartesian_d; -// typedef Kd::Point_d Point; - -/// @brief Make a d-dimensional sphere -/// -/// The radius is used to denote the time value, so we can nest d-spheres -/// such that our time foliation contains leaves of identical topology. -/// -/// @param number_of_points Number of vertices at a given radius -/// @param dimension Dimension of sphere -/// @param radius Radius of sphere -/// @param output Prints detailed output -/// @param points The points ready to insert -void make_d_sphere(std::int_fast32_t number_of_points, int dimension, double radius, - bool output, std::vector* const points) noexcept -{ - points->reserve(number_of_points); - - CGAL::Random_points_on_sphere_d gen(dimension, radius); - - for (decltype(number_of_points) i = 0; i < number_of_points; ++i) { - points->push_back(*gen++); - } - // If output = true, print out values of points in sphere - if (output) { - std::cout << "Generating " << number_of_points << " random points on " - << "the surface of a sphere in " << dimension << "D" << std::endl - << "of center 0 and radius " << radius << "." << std::endl; - - for (const auto& point : *points) { - std::cout << " " << point << std::endl; - } - } -} // make_d_sphere() - -/// @brief Make a d-dimensional sphere without output -/// -/// Function overload of make_d_sphere to suppress output -/// -/// @param[in] number_of_points Number of vertices at a given radius -/// @param[in] dimension Dimension of sphere -/// @param[in] radius Radius of sphere -/// @param[out] points The points ready to insert -void make_d_sphere(std::int_fast32_t number_of_points, int dimension, double radius, - std::vector* const points) noexcept -{ - make_d_sphere(number_of_points, dimension, radius, false, points); -} // make_d_sphere - -#endif // SRC_SPHERE_D_HPP_ diff --git a/include/Torus_d.hpp b/include/Torus_d.hpp index 84a571583c..24bd74ca52 100644 --- a/include/Torus_d.hpp +++ b/include/Torus_d.hpp @@ -1,20 +1,22 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2014-2017 Adam Getchell -/// -/// Inserts a given number of points into a d-dimensional grid (cube) -/// \todo Make the vector compatible with the triangulation data structure +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2017 Adam Getchell + ******************************************************************************/ /// @file Torus_d.hpp /// @brief Functions on d-dimensional torus /// @author Adam Getchell +/// @details Inserts a given number of points into a d-dimensional grid (cube) +/// @todo Make the vector compatible with the triangulation data structure -#ifndef SRC_TORUS_D_HPP_ -#define SRC_TORUS_D_HPP_ +#ifndef INCLUDE_TORUS_D_HPP_ +#define INCLUDE_TORUS_D_HPP_ #include #include #include +#include #include @@ -22,16 +24,23 @@ using Kd = CGAL::Cartesian_d; using Point = Kd::Point_d; using Creator_d = CGAL::Creator_uniform_d::iterator, Point>; -auto make_d_cube(std::vector v, std::size_t nb_points, int dimension) +/** + * \brief Make a d-dimensional torus + * \param t_points The container of points + * \param t_number_of_points The number of points to insert + * \param t_dimension The dimensionality of the torus + */ +inline void make_d_cube(std::vector& t_points, + std::size_t t_number_of_points, int t_dimension) { - double size = 1.0; + double constexpr size = 1.0; - std::cout << "Generating " << nb_points << " grid points in " << dimension - << "D" << std::endl; + fmt::print("Generating {} grid points in {}D\n", t_number_of_points, + t_dimension); - v.reserve(nb_points); - return CGAL::points_on_cube_grid_d( - dimension, size, nb_points, std::back_inserter(v), Creator_d(dimension)); + t_points.reserve(t_number_of_points); + points_on_cube_grid_d(t_dimension, size, t_number_of_points, + std::back_inserter(t_points), Creator_d(t_dimension)); } -#endif // SRC_TORUS_D_HPP_ +#endif // INCLUDE_TORUS_D_HPP_ diff --git a/include/Triangulation_traits.hpp b/include/Triangulation_traits.hpp new file mode 100644 index 0000000000..cf174a4f4e --- /dev/null +++ b/include/Triangulation_traits.hpp @@ -0,0 +1,60 @@ +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2021 Adam Getchell + ******************************************************************************/ + +/// @file Triangulation_traits.hpp +/// @brief Traits class for particular uses of CGAL +/// @author Adam Getchell + +#ifndef CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP +#define CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP + +#include +#include +#include +#include +#include + +#include "Settings.hpp" + +template +struct TriangulationTraits; + +template <> +struct TriangulationTraits<3> +{ + using Kernel = CGAL::Exact_predicates_inexact_constructions_kernel; + using Vertex_base = + CGAL::Triangulation_vertex_base_with_info_3; + using Cell_base = + CGAL::Triangulation_cell_base_with_info_3; +#ifdef CGAL_LINKED_WITH_TBB + using Tds = CGAL::Triangulation_data_structure_3; +#else + using Tds = CGAL::Triangulation_data_structure_3; +#endif + using Delaunay = CGAL::Delaunay_triangulation_3; + + using Cell_handle = Delaunay::Cell_handle; + using Face_handle = std::pair; + using Facet = Delaunay::Facet; + using Edge_handle = CGAL::Triple; + using Vertex_handle = Delaunay::Vertex_handle; + using Point = Delaunay::Point; + using Causal_vertices = std::vector>; + + /// @brief CGAL::squared_distance + /// See + /// https://doc.cgal.org/latest/Kernel_23/group__squared__distance__grp.html#ga1ff73525660a052564d33fbdd61a4f71 + /// @returns Square of Euclidean distance between two geometric objects + using squared_distance = Kernel::Compute_squared_distance_3; + + using Spherical_points_generator = CGAL::Random_points_on_sphere_3; + + static inline Point const ORIGIN_POINT = Point{0, 0, 0}; +}; // TriangulationTraits<3> + +#endif // CDT_PLUSPLUS_TRIANGULATION_TRAITS_HPP diff --git a/include/Utilities.hpp b/include/Utilities.hpp index e74d4055a1..a5fee511a4 100644 --- a/include/Utilities.hpp +++ b/include/Utilities.hpp @@ -1,46 +1,44 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2013-2017 Adam Getchell -/// -/// Utility functions +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL -/// @file utilities.hpp + Copyright © 2017 Adam Getchell + ******************************************************************************/ + +/// @file Utilities.hpp /// @brief Utility functions /// @author Adam Getchell -#ifndef SRC_UTILITIES_HPP_ -#define SRC_UTILITIES_HPP_ - -/// Toggles detailed random number generator debugging output -#define DETAILED_DEBUGGING -#undef DETAILED_DEBUGGING - -// CGAL headers -#include -#include - -// C headers -#ifndef _WIN32 -#include -#endif +#ifndef INCLUDE_UTILITIES_HPP_ +#define INCLUDE_UTILITIES_HPP_ -// C++ headers #include -#include -#include +#include #include -#include -#include +#include #include #include +#include #include #include -#include +// H. Hinnant date and time library +#include -// H. Hinnant's date and time library -#include +/// clang-15 does not support std::format +// #include -using Gmpzf = CGAL::Gmpzf; +// M. O'Neill Permutation Congruential Generator library +#include "pcg_random.hpp" + +// V. Zverovich {fmt} library +#include + +// G. Melman spdlog library +#include +#include +#include + +// Global project settings +#include "Settings.hpp" enum class topology_type { @@ -48,361 +46,413 @@ enum class topology_type SPHERICAL }; -/// @brief Return an environment variable -/// -/// Uses **getenv** from **/** which has a char* rvalue -/// -/// @param key The string value -/// @return The environment variable corresponding to the key -inline auto getEnvVar(std::string const& key) noexcept -{ - const char* val = getenv(key.c_str()); - val == nullptr ? std::string() : std::string(val); - return val; -} - -/// @brief Return the hostname -/// -/// **auto** doesn't work here as a return type because **name.nodename** is a -/// stack memory address. Uses utsname.h, which isn't present in Windows -/// (easily) so just default to "windows" on that platform. -/// -/// @return The hostname -inline std::string hostname() noexcept +/// @brief Convert topology_type to string output +/// @param t_os The output stream +/// @param t_topology The topology +/// @returns An output string of the topology +inline auto operator<<(std::ostream& t_os, topology_type const& t_topology) + -> std::ostream& { -#ifndef _WIN32 - struct utsname name + switch (t_topology) { - }; - // Ensure uname returns a value - if (uname(&name)) exit(-1); - return name.nodename; -#else - std::string const hostname("windows"); - return hostname; -#endif -} - -/// @brief Return current date and time -/// -/// Use's Howard Hinnant's C++11/14 data and time library and Time Zone Database -/// Parser. https://github.com/HowardHinnant/date -/// -/// @return A formatted string with the system local time -inline const auto currentDateTime() -{ - using namespace date; - using namespace std::chrono; - auto t = make_zoned(current_zone(), system_clock::now()); - return format("%Y-%m-%d.%X%Z", t); -} - -/// @brief Generate useful filenames -/// @param top The topology type from the scoped enum topology_type -/// @param dimensions The number of dimensions of the triangulation -/// @param number_of_simplices The number of simplices in the triangulation -/// @param number_of_timeslices The number of foliated timeslices -/// @return A filename -inline auto generate_filename(const topology_type& top, - const std::int_fast32_t dimensions, - const std::int_fast32_t number_of_simplices, - const std::int_fast32_t number_of_timeslices) noexcept -{ - std::string filename; - if (top == topology_type::SPHERICAL) { - filename += "S"; - } - else - { - filename += "T"; + case topology_type::SPHERICAL: return t_os << "spherical"; + case topology_type::TOROIDAL: return t_os << "toroidal"; + default: return t_os << "none"; } - // std::to_string() works in C++11, but not earlier - filename += std::to_string(dimensions); - - filename += "-"; - - filename += std::to_string(number_of_timeslices); - - filename += "-"; - - filename += std::to_string(number_of_simplices); +} // operator<< - // Get user - filename += "-"; - filename += getEnvVar("USER"); +namespace utilities +{ + /// @brief Return current date and time + /// @details Return current date and time in ISO 8601 format + /// Use Howard Hinnant's date library to format UTC without requiring an + /// external time zone database. + /// @param timestamp The system time point to format + /// @returns A formatted string with the system time in UTC + /// @see https://github.com/HowardHinnant/date + /// @see https://en.cppreference.com/w/cpp/chrono/zoned_time + [[nodiscard]] inline auto current_date_time( + std::chrono::system_clock::time_point const timestamp = + std::chrono::system_clock::now()) + { + auto const time = std::chrono::floor(timestamp); + return date::format("%Y-%m-%d.%TUTC", time); + } // current_date_time + + /// @brief Generate useful filenames + /// @param t_topology The topology type from the scoped enum topology_type + /// @param t_dimension The dimensionality of the triangulation + /// @param t_number_of_simplices The number of simplices in the triangulation + /// @param t_number_of_timeslices The number of time foliations + /// @param t_initial_radius The radius of the first foliation t=1 + /// @param t_foliation_spacing The spacing between foliations + /// @returns A filename + [[nodiscard]] inline auto make_filename(topology_type const& t_topology, + Int_precision t_dimension, + Int_precision t_number_of_simplices, + Int_precision t_number_of_timeslices, + double t_initial_radius, + double t_foliation_spacing) noexcept + -> std::filesystem::path + { + std::string filename; + if (t_topology == topology_type::SPHERICAL) { filename += "S"; } + else + { + filename += "T"; + } + // std::to_string() works in C++11, but not earlier + filename += std::to_string(t_dimension); - // Get machine name - filename += "@"; - filename += hostname(); + filename += "-"; - // Append current time - filename += "-"; - filename += currentDateTime(); + filename += std::to_string(t_number_of_timeslices); - // Append .dat file extension - filename += ".dat"; - return filename; -} + filename += "-"; -/// @brief Print out runtime results -/// -/// This function prints out vertices, edges, facets (2D), and cells (3D). -/// -/// @tparam T The manifold type -/// @param universe A SimplicialManifold -template -void print_results(const T& universe) noexcept -{ - std::cout << universe.triangulation->number_of_vertices() << " vertices and " - << universe.triangulation->number_of_finite_edges() << " edges and " - << universe.triangulation->number_of_finite_facets() << " faces\n" - << "and " << universe.triangulation->number_of_finite_cells() - << " cells.\n"; -} - -/// @brief Print out runtime results including time elapsed -/// -/// This function prints out vertices, edges, facets (2D), cells (3D) -/// and running time on a Triangulation. This calls a simpler version -/// without a timer object. -/// -/// @tparam T1 The manifold type -/// @tparam T2 The timer type -/// @param universe A SimplicialManifold -/// @param timer A timer object used to determine elapsed time -template -void print_results(const T1& universe, const T2& timer) noexcept -{ - print_results(std::as_const(universe)); - - // Display program running time - std::cout << "Running time is " << timer.time() << " seconds.\n"; -} - -/// @brief Writes the runtime results to a file -/// -/// This function writes the Delaunay triangulation to a file. -/// The filename is generated by the **generate_filename()** function. -/// Provides strong exception-safety. -/// -/// @tparam T The manifold type -/// @param universe A SimplicialManifold -/// @param topology The topology type from the scoped enum topology_type -/// @param dimensions The number of dimensions of the triangulation -/// @param number_of_simplices The number of simplices in the triangulation -/// @param number_of_timeslices The number of foliated timeslices -template -void write_file(const T& universe, const topology_type& topology, - const std::int_fast32_t dimensions, - const std::int_fast32_t number_of_simplices, - const std::int_fast32_t number_of_timeslices) -{ - // mutex to protect file access across threads - static std::mutex mutex; + filename += std::to_string(t_number_of_simplices); - std::string filename; - filename.assign(generate_filename(topology, dimensions, number_of_simplices, - number_of_timeslices)); - std::cout << "Writing to file " << filename << "\n"; + filename += "-I"; - std::lock_guard lock(mutex); + filename += std::to_string(t_initial_radius); - std::ofstream file(filename, std::ios::out); - if (!file.is_open()) throw std::runtime_error("Unable to open file."); + filename += "-R"; - file << *universe.triangulation; -} + filename += std::to_string(t_foliation_spacing); -/// @brief Seed sequence class for high-quality pseudo-random number generator -/// -/// From Arthur O'Dwyer's "Mastering the C++17 STL", Chapter 12 -/// @tparam T1 Type of number -template -struct SeedSeq -{ - T1 begin_; - T1 end_; + // Append current time + filename += "-"; + auto timestamp = current_date_time(); + std::replace(timestamp.begin(), timestamp.end(), ':', '-'); + filename += timestamp; - public: - SeedSeq(T1 begin, T1 end) : begin_{begin}, end_{end} {} + // Append .off file extension + filename += ".off"; + return filename; + } // make_filename - template - void generate(T2 b, T2 e) + template + [[nodiscard]] auto make_filename(ManifoldType const& manifold) { - assert((e - b) <= (end_ - begin_)); - std::copy(begin_, begin_ + (e - b), b); - } -}; - -/// @brief Generate random integers -/// -/// This function generates a random integer from [1, max_value] -/// using a non-deterministic random number generator, if supported. There -/// may be exceptions thrown if a random device is not available. See: -/// http://www.cplusplus.com/reference/random/random_device/ -/// for more details. -/// -/// @param min_value The minimum value in the range -/// @param max_value The maximum value in the range -/// @return A random integer between min_value and max_value -inline auto generate_random_signed(const int_fast32_t min_value, - const int_fast32_t max_value) noexcept -{ - // Non-deterministic random number generator - std::random_device rd; - // The simple way which works in C++14 - std::mt19937_64 generator(rd()); - // // The tedious but more accurate way which works in C++17 but not C++14 - // uint32_t numbers[624]; - // // Initial state - // std::generate(numbers, std::end(numbers), std::ref(rd)); - // // Copy into heap-allocated "seed sequence" - // SeedSeq seedSeq(numbers, std::end(numbers)); - // // Initialized mt19937_64 - // std::mt19937 g(seedSeq); - - std::uniform_int_distribution distribution(min_value, max_value); - - auto result = distribution(generator); - -#ifdef DETAILED_DEBUGGING - std::cout << "Random " << (typeid(result)).name() << " is " << result << "\n"; -#endif - - return result; -} // generate_random_signed() - -/// @brief Generate a random timeslice -/// -/// This function generates a random timeslice -/// using **generate_random_unsigned()**. Timeslices go from -/// 1 to max_timeslice. -/// -/// @param max_timeslice The maximum timeslice -/// @return A random timeslice from 1 to max_timeslice -inline auto generate_random_timeslice(const unsigned max_timeslice) noexcept -{ - return generate_random_signed(1, max_timeslice); -} // generate_random_timeslice() - -/// @brief Generate random real numbers -/// -/// This function generates a random real number from [min_value, max_value] -/// using a non-deterministic random number generator, if supported. There -/// may be exceptions thrown if a random device is not available. See: -/// http://www.cplusplus.com/reference/random/random_device/ -/// for more details. -/// -/// @tparam T The real number type -/// @param min_value The minimum value in the range -/// @param max_value The maximum value in the range -/// @return A random real number between min_value and max_value, inclusive -template -auto generate_random_real(const T min_value, const T max_value) noexcept -{ - std::random_device rd; - std::mt19937_64 generator(rd()); - std::uniform_real_distribution distribution(min_value, max_value); + return make_filename(ManifoldType::topology, ManifoldType::dimension, + manifold.N3(), manifold.max_time(), + manifold.initial_radius(), + manifold.foliation_spacing()); + } // make_filename + + /// @brief Print triangulation statistics + /// @tparam TriangulationType The triangulation type + /// @param t_triangulation A triangulation (typically a Delaunay_t<3> + /// triangulation) + template + void print_delaunay(TriangulationType const& t_triangulation) + { + fmt::print( + "Triangulation has {} vertices and {} edges and {} faces and {} " + "simplices.\n", + t_triangulation.number_of_vertices(), + t_triangulation.number_of_finite_edges(), + t_triangulation.number_of_finite_facets(), + t_triangulation.number_of_finite_cells()); + } // print_delaunay + + /// @brief Write triangulation to file + /// @details This function writes the Delaunay triangulation in the manifold + /// to an OFF file. http://www.geomview.org/docs/html/OFF.html#OFF Provides + /// strong exception-safety. + /// @tparam TriangulationType The type of triangulation + /// @param filename The filename to write to + /// @param triangulation The triangulation to write + template + void write_file(std::filesystem::path const& filename, + TriangulationType const& triangulation) + { + static std::mutex mutex; + fmt::print("Writing to file {}\n", filename.string()); + std::scoped_lock const lock(mutex); + std::ofstream file(filename, std::ios::out); + if (!file.is_open()) + { + throw std::filesystem::filesystem_error( + "Could not open file for writing", filename, + std::make_error_code(std::errc::bad_file_descriptor)); + } + file << triangulation; + } // write_file + + /// @brief Write the runtime results to a file + /// @details The filename is generated by the **make_filename()** and + /// writen using another **write_file()** function, which is currently + /// implemented using the << operator for triangulations. + /// @tparam ManifoldType The manifold type + /// @param t_universe The simplicial manifold + template + void write_file(ManifoldType const& t_universe) + { + std::filesystem::path filename; + filename.assign(make_filename(t_universe)); + write_file(filename, t_universe.get_delaunay()); + } // write_file + + /// @brief Read triangulation from file + /// @tparam TriangulationType The type of triangulation + /// @param filename The file to read from + /// @returns A Delaunay triangulation + template + auto read_file(std::filesystem::path const& filename) -> TriangulationType + { + static std::mutex mutex; + fmt::print("Reading from file {}\n", filename.string()); + std::scoped_lock const lock(mutex); + std::ifstream file(filename, std::ios::in); + if (!file.is_open()) + { + throw std::filesystem::filesystem_error( + "Could not open file for reading", filename, + std::make_error_code(std::errc::bad_file_descriptor)); + } + TriangulationType triangulation; + file >> triangulation; + return triangulation; + } // read_file - auto result = distribution(generator); + /// @brief Roll a die with PCG + [[nodiscard]] inline auto die_roll() + { + pcg_extras::seed_seq_from seed_source; + + // Make a random number generator + pcg64 rng(seed_source); + + // Choose random number from 1 to 6 + std::uniform_int_distribution uniform_dist(1, 6); // NOLINT + Int_precision const roll = uniform_dist(rng); + return roll; + } // die_roll() + + /// @brief Generate random numbers + /// + /// Uses Melissa E. O'Neill's Permuted Congruential Generator for high-quality + /// RNG which passes the TestU01 statistical tests. See: + /// http://www.pcg-random.org/paper.html + /// for more details + /// + /// @tparam NumberType The type of number in the RNG + /// @tparam Distribution The distribution type, usually uniform + /// @param t_min_value The minimum value + /// @param t_max_value The maximum value + /// @returns A random value in the distribution between min_value and + /// max_value + template + [[nodiscard]] auto generate_random(NumberType t_min_value, + NumberType t_max_value) + { + pcg_extras::seed_seq_from seed_source; + // Make a random number generator + pcg64 generator(seed_source); + Distribution distribution(t_min_value, t_max_value); + return distribution(generator); + } // generate_random() + + /// @brief Make a high-quality random number generator usable by std::shuffle + /// @returns A RNG + inline auto make_random_generator() + { + pcg_extras::seed_seq_from seed_source; + pcg64 generator(seed_source); + return generator; + } // make_random_generator() + + /// @brief Generate random integers by calling generate_random, preserves + /// template argument deduction + template + [[nodiscard]] auto generate_random_int(IntegerType t_min_value, + IntegerType t_max_value) + { + using int_dist = std::uniform_int_distribution; + return generate_random(t_min_value, t_max_value); + } // generate_random_int() + + /// @brief Generate a random timeslice + template + [[nodiscard]] auto generate_random_timeslice(IntegerType&& t_max_timeslice) + -> decltype(auto) + { + return generate_random_int(static_cast(1), + std::forward(t_max_timeslice)); + } // generate_random_timeslice() + + /// @brief Generate random real numbers by calling generate_random, preserves + /// template argument deduction + template + [[nodiscard]] auto generate_random_real(FloatingPointType t_min_value, + FloatingPointType t_max_value) + { + using real_dist = std::uniform_real_distribution; + return generate_random(t_min_value, + t_max_value); + } // generate_random_real() + /// @brief Generate a probability + [[nodiscard]] inline auto generate_probability() + { + auto constexpr min = 0.0L; + auto constexpr max = 1.0L; + return generate_random_real(min, max); + } // generate_probability() + + /// @brief Calculate expected # of points per simplex + /// + /// Usually, there are less vertices than simplices. + /// Here, we throw away a number of simplices that aren't correctly + /// foliated. + /// The exact formula is given by Dwyer: + /// http://link.springer.com/article/10.1007/BF02574694 + /// + /// @param t_dimension Number of dimensions + /// @param t_number_of_simplices Number of desired simplices + /// @param t_number_of_timeslices Number of desired timeslices + /// @returns The number of points per timeslice to obtain + /// the desired number of simplices + inline auto expected_points_per_timeslice( + Int_precision const t_dimension, Int_precision t_number_of_simplices, + Int_precision t_number_of_timeslices) + { #ifndef NDEBUG - std::cout << "Random trial is " << result << "\n"; + spdlog::debug("{} simplices on {} timeslices desired.\n", + t_number_of_simplices, t_number_of_timeslices); #endif - return result; -} - -/// @brief Generate a random timeslice -/// -/// This function generates a probability -/// using **generate_random_real()**. -/// -/// @return A probability from 0 to 1 -inline auto generate_probability() noexcept -{ - auto min = static_cast(0.0); - auto max = static_cast(1.0); - return generate_random_real(min, max); -} // generate_probability() - -/// @brief Calculate expected # of points per simplex -/// -/// Usually, there are less vertices than simplices. -/// Here, we throw away a number of simplices that aren't correctly -/// foliated. -/// The exact formula is given by Dwyer: -/// http://link.springer.com/article/10.1007/BF02574694 -/// -/// @param dimension Number of dimensions -/// @param simplices Number of desired simplices -/// @param timeslices Number of desired timeslices -/// @param output Prints desired number of simplices on timeslices -/// @return The number of points per timeslice to obtain -/// the desired number of simplices -inline auto expected_points_per_simplex(const int dimension, - const std::int_fast32_t simplices, - const std::int_fast32_t timeslices, - const bool output = true) -{ - if (output) { - std::cout << simplices << " simplices on " << timeslices - << " timeslices desired.\n"; - } - - const auto simplices_per_timeslice = simplices / timeslices; - switch (dimension) - { - case 3: + auto const simplices_per_timeslice = + t_number_of_simplices / t_number_of_timeslices; + if (t_dimension == 3) { // Avoid segfaults for small values - if (simplices == timeslices) { - return 2 * simplices_per_timeslice; - } - else if (simplices < 1000) + if (t_number_of_simplices == t_number_of_timeslices) { - return static_cast(0.4 * simplices_per_timeslice); + return 2 * simplices_per_timeslice; } - else if (simplices < 10000) + if (t_number_of_simplices < 1000) // NOLINT { - return static_cast(0.2 * simplices_per_timeslice); + return static_cast( + 0.4L * // NOLINT + static_cast(simplices_per_timeslice)); } - else if (simplices < 100000) + if (t_number_of_simplices < 10000) // NOLINT { - return static_cast(0.15 * simplices_per_timeslice); + return static_cast( + 0.2L * // NOLINT + static_cast(simplices_per_timeslice)); } - else + if (t_number_of_simplices < 100000) // NOLINT { - return static_cast(0.1 * simplices_per_timeslice); + return static_cast( + 0.15L * // NOLINT + static_cast(simplices_per_timeslice)); } + + return static_cast( + 0.1L * static_cast(simplices_per_timeslice)); // NOLINT } - default: - { - throw std::invalid_argument("Currently, dimensions cannot be >3."); - } + throw std::invalid_argument("Currently, dimensions cannot be >3."); + + } // expected_points_per_timeslice + + /// @brief Convert Gmpzf into a double + /// + /// This function is mainly for testing, since to_double() + /// seems to work. However, if something more elaborate is required + /// this function can be expanded. + /// + /// @param t_value An exact Gmpzf multiple-precision floating point number + /// @returns The double conversion + [[nodiscard]] inline auto Gmpzf_to_double(Gmpzf const& t_value) -> double + { return t_value.to_double(); } // Gmpzf_to_double + + /// @brief Create console and file loggers + /// @details Create a console and file loggers. + /// There are six logging levels by default: + /// | Logging level | Description | + /// | ------------- | -------------------------------------- | + /// | Trace | Used to trace the internals | + /// | Debug | Diagnostic information | + /// | Info | General information | + /// | Warn | Errors that are handled | + /// | Err | Errors which cause a function to fail | + /// | Critical | Errors which cause the program to fail | + /// + /// A logging level covers all levels beneath it, e.g. trace covers + /// everything, critical only shows up in spdlog::level::critical. + /// + /// Logging levels and formatting are set by loggers. + /// The sink is the object that writes the log to the target. + /// + /// So, this function creates 3 sinks: + /// -# Console, which logs *Info* and below to the terminal + /// -# Debug, which logs *Debug* and below to logs/debug-log.txt + /// -# Trace, which logs everything to logs/trace-log.txt + /// + /// If an exception is thrown, then the default global console logger is used. + inline void create_logger() + try + { + auto const console_sink = + std::make_shared(); + console_sink->set_level(spdlog::level::info); + + auto const debug_sink = std::make_shared( + "logs/debug-log.txt", true); + debug_sink->set_level(spdlog::level::debug); + + auto const trace_sink = std::make_shared( + "logs/trace-log.txt", true); + trace_sink->set_level(spdlog::level::trace); + + spdlog::sinks_init_list sink_list = {console_sink, debug_sink, trace_sink}; + + auto const logger = std::make_shared( + "multi_sink", sink_list.begin(), sink_list.end()); + // This allows the logger to capture all events + logger->set_level(spdlog::level::trace); + // The sinks will filter items further via should_log() + logger->info("Multi-sink logger initialized.\n"); + logger->debug("Debug logger initialized.\n"); + logger->trace("Trace logger initialized.\n"); + logger->debug( + "You must build in Debug mode for anything to be recorded in this " + "file.\n"); + + register_logger(logger); + set_default_logger(logger); } -} - -/// @brief Convert Gmpzf into a double -/// -/// This function is mainly for testing, since to_double() -/// seems to work. However, if something more elaborate is required -/// this function can be expanded. -/// -/// @param value An exact Gmpzf multiple-precision floating point number -/// @return The double conversion -inline auto Gmpzf_to_double(const Gmpzf& value) { return value.to_double(); } - -/// @brief Calculate if lower <= value <= upper; used in GoogleTests -/// @tparam T Value type -/// @param arg Value to be compared -/// @param lower Lower bound -/// @param upper Upper bound -/// @return True if arg lies within [lower, upper] -template -bool IsBetween(T arg, T lower, T upper) -{ - return arg >= lower && arg <= upper; -} - -#endif // SRC_UTILITIES_HPP_ + catch (spdlog::spdlog_ex const& ex) + { + // Use default logger + spdlog::error("Logger initialization failed: {}\n", ex.what()); + spdlog::warn("Default logger set.\n"); + + } // create_logger + + /// @brief Covert a CGAL point to a string + /// @tparam Point The type of point (e.g. 3D, 4D) + /// @param t_point The point + /// @returns A string representation of the point + template + auto point_to_str(Point const& t_point) -> std::string + { + std::stringstream stream; + stream << t_point; + return stream.str(); + } // point_to_str + + /// @brief Convert a topology to a string using it's << operator + /// @param t_topology The topology_type to convert + /// @returns A string representation of the topology_type + inline auto topology_to_str(topology_type const& t_topology) -> std::string + { + std::stringstream stream; + stream << t_topology; + return stream.str(); + } // topology_to_str +} // namespace utilities +#endif // INCLUDE_UTILITIES_HPP_ diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 0000000000..ebbdd27cb7 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,115 @@ +[project] +name = "cdt-plusplus-scripts" +version = "0.0.0" +description = "Python support and experiment scripts for CDT++" +requires-python = ">=3.12,<3.13" +dependencies = [] + +[tool.uv] +default-groups = ["dev"] +package = false + +[dependency-groups] +dev = ["ruff==0.15.21", "ty==0.0.59"] +experiments = [ + "comet-ml>=3.58.3,<4", + "matplotlib>=3.10,<4", + "numpy>=2,<3", + "tensorflow>=2.21,<2.22", +] + +[tool.ruff] +line-length = 160 +src = ["src"] +target-version = "py312" + +[tool.ruff.lint] +select = [ + "E", + "F", + "W", + "ANN201", + "ANN202", + "ANN204", + "C90", + "I", + "N", + "UP", + "YTT", + "ASYNC", + "S", + "BLE", + "FBT", + "B", + "A", + "COM", + "C4", + "DTZ", + "FA", + "T10", + "EM", + "EXE", + "FIX", + "FLY", + "FURB", + "ISC", + "ICN", + "LOG", + "G", + "INP", + "PERF", + "PIE", + "T20", + "PYI", + "PT", + "Q", + "RSE", + "RET", + "SLF", + "SIM", + "SLOT", + "TC", + "TID", + "TD", + "ARG", + "PTH", + "ERA", + "PD", + "PGH", + "PL", + "TRY", + "NPY", + "RUF", + "D100", + "D101", + "D102", + "D103", + "D104", + "D105", + "D106", + "D107", +] +fixable = ["ALL"] +ignore = [ + "COM812", # Conflicts with the formatter. + "ERA001", # Historical experiment alternatives remain documented inline. + "FBT001", # Boolean CLI parameters are idiomatic when these scripts gain CLIs. + "FBT002", # Boolean CLI defaults are idiomatic when these scripts gain CLIs. + "ISC001", # Conflicts with the formatter. + "PLR2004", # Scientific constants are clearer at their point of use. + "T201", # These scripts intentionally report progress on the command line. + "TRY300", # Straight-line experiment control flow is clearer here. + "TRY301", # Local exception construction is sufficient for these scripts. +] + +[tool.ruff.lint.per-file-ignores] +"src/*.py" = ["INP001"] + +[tool.ruff.lint.mccabe] +max-complexity = 10 + +[tool.ruff.format] +indent-style = "space" +line-ending = "auto" +quote-style = "double" +skip-magic-trailing-comma = false diff --git a/scan.sh b/scan.sh deleted file mode 100755 index b74fca9fcc..0000000000 --- a/scan.sh +++ /dev/null @@ -1,10 +0,0 @@ -#! /bin/bash - -# MacOS and homebrew specific -rm -rf build/ -mkdir build -cd build -cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug -DCMAKE_C_COMPILER=`locate -l 1 ccc-analyzer` -DCMAKE_CXX_COMPILER=`locate -l 1 c++-analyzer` .. - -#cmake -G Ninja -DCMAKE_BUILD_TYPE=Debug .. -`locate -l 1 scan-build` -o $(pwd)/scanresults -v ninja diff --git a/scripts/bootstrap-vcpkg.bat b/scripts/bootstrap-vcpkg.bat new file mode 100644 index 0000000000..0fe228d806 --- /dev/null +++ b/scripts/bootstrap-vcpkg.bat @@ -0,0 +1,136 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS DISABLEDELAYEDEXPANSION +SET "SCRIPT_DIR=%~dp0" +FOR %%I IN ("%SCRIPT_DIR%..") DO SET "REPO_ROOT=%%~fI" +SET "CDT_VCPKG_MANIFEST=%REPO_ROOT%\vcpkg.json" +SET "MODE=%~1" +REM GitHub release-asset SHA-256 digests for vcpkg-tool 2026-07-13. +SET "TRUSTED_VCPKG_TOOL_TAG=2026-07-13" +SET "TRUSTED_VCPKG_TOOL_SHA256_X64=67958c6a13a35130ff8035bef33097ffe3376a6708577a826cfa41fa592db611" +SET "TRUSTED_VCPKG_TOOL_SHA256_ARM64=8d87ed438db65b0015f624693612cb79d8c35908348c194984c23b63a2da0211" + +IF NOT DEFINED MODE SET "MODE=bootstrap" +IF /I NOT "%MODE%"=="bootstrap" IF /I NOT "%MODE%"=="--check" ( + echo Usage: %~nx0 [--check] 1>&2 + EXIT /B 2 +) + +WHERE git.exe >NUL 2>NUL +IF ERRORLEVEL 1 ( + echo git.exe is required to bootstrap vcpkg. 1>&2 + EXIT /B 1 +) + +WHERE powershell.exe >NUL 2>NUL +IF ERRORLEVEL 1 ( + echo powershell.exe is required to read the vcpkg manifest baseline. 1>&2 + EXIT /B 1 +) + +SET "BASELINE=" +FOR /F "usebackq delims=" %%I IN (`powershell.exe -NoLogo -NoProfile -NonInteractive -Command "$json = Get-Content -Raw -LiteralPath $env:CDT_VCPKG_MANIFEST; $baseline = (ConvertFrom-Json -InputObject $json).'builtin-baseline'; if ($baseline -notmatch '^[0-9a-f]{40}$') { exit 1 }; $baseline"`) DO SET "BASELINE=%%I" +IF NOT DEFINED BASELINE ( + echo Unable to read a 40-character builtin-baseline from %CDT_VCPKG_MANIFEST%. 1>&2 + EXIT /B 1 +) + +IF DEFINED CDT_VCPKG_CACHE_DIR ( + SET "VCPKG_DIR=%CDT_VCPKG_CACHE_DIR%" +) ELSE ( + SET "VCPKG_DIR=%REPO_ROOT%\.cache\vcpkg" +) + +IF EXIST "%VCPKG_DIR%\.git\." ( + git -C "%VCPKG_DIR%" remote get-url origin 2>NUL ^| FINDSTR /X /C:"https://github.com/microsoft/vcpkg.git" >NUL + IF ERRORLEVEL 1 ( + echo Refusing to reuse %VCPKG_DIR% because its origin is not microsoft/vcpkg. 1>&2 + EXIT /B 1 + ) + + git -C "%VCPKG_DIR%" status --short 2>NUL ^| FINDSTR . >NUL + IF NOT ERRORLEVEL 1 ( + echo Refusing to reuse a modified vcpkg checkout at %VCPKG_DIR%. 1>&2 + EXIT /B 1 + ) + + git -C "%VCPKG_DIR%" rev-parse HEAD 2>NUL ^| FINDSTR /X /I /C:"%BASELINE%" >NUL + IF NOT ERRORLEVEL 1 IF EXIST "%VCPKG_DIR%\vcpkg.exe" ( + CALL :VALIDATE_CACHED_VCPKG "%VCPKG_DIR%" + IF NOT ERRORLEVEL 1 ( + echo Using vcpkg at %VCPKG_DIR% ^(%BASELINE%^) + EXIT /B 0 + ) + ) +) ELSE IF EXIST "%VCPKG_DIR%\." ( + DIR /B /A "%VCPKG_DIR%" 2>NUL ^| FINDSTR . >NUL + IF NOT ERRORLEVEL 1 ( + echo Refusing to initialize vcpkg in non-empty directory %VCPKG_DIR%. 1>&2 + EXIT /B 1 + ) +) + +IF /I "%MODE%"=="--check" ( + echo VCPKG_ROOT is not a clean official checkout at baseline %BASELINE%: %VCPKG_DIR% 1>&2 + EXIT /B 1 +) + +IF NOT EXIST "%VCPKG_DIR%\.git\." ( + IF NOT EXIST "%VCPKG_DIR%\." MD "%VCPKG_DIR%" + IF ERRORLEVEL 1 EXIT /B 1 + git -C "%VCPKG_DIR%" init + IF ERRORLEVEL 1 EXIT /B 1 + git -C "%VCPKG_DIR%" remote add origin https://github.com/microsoft/vcpkg.git + IF ERRORLEVEL 1 EXIT /B 1 +) + +git -C "%VCPKG_DIR%" fetch --depth 1 origin "%BASELINE%" +IF ERRORLEVEL 1 EXIT /B 1 +git -C "%VCPKG_DIR%" checkout --detach "%BASELINE%" +IF ERRORLEVEL 1 EXIT /B 1 +CALL "%VCPKG_DIR%\bootstrap-vcpkg.bat" -disableMetrics +IF ERRORLEVEL 1 EXIT /B 1 +CALL :VALIDATE_CACHED_VCPKG "%VCPKG_DIR%" +IF ERRORLEVEL 1 ( + echo Bootstrapped vcpkg does not match the tool release pinned by %BASELINE%. 1>&2 + EXIT /B 1 +) + +echo Bootstrapped vcpkg at %VCPKG_DIR% ^(%BASELINE%^) +EXIT /B 0 + +:VALIDATE_CACHED_VCPKG +SETLOCAL +SET "VALIDATE_DIR=%~1" +SET "EXPECTED_TOOL_TAG=" +IF NOT EXIST "%VALIDATE_DIR%\scripts\vcpkg-tool-metadata.txt" ( + ENDLOCAL + EXIT /B 1 +) +FOR /F "usebackq tokens=1,* delims==" %%A IN ("%VALIDATE_DIR%\scripts\vcpkg-tool-metadata.txt") DO ( + IF /I "%%A"=="VCPKG_TOOL_RELEASE_TAG" SET "EXPECTED_TOOL_TAG=%%B" +) +IF NOT DEFINED EXPECTED_TOOL_TAG ( + ENDLOCAL + EXIT /B 1 +) +IF /I NOT "%EXPECTED_TOOL_TAG%"=="%TRUSTED_VCPKG_TOOL_TAG%" ( + ENDLOCAL + EXIT /B 1 +) +ECHO(%EXPECTED_TOOL_TAG%| FINDSTR /R /X "[0-9][0-9][0-9][0-9]-[0-9][0-9]-[0-9][0-9]" >NUL +IF ERRORLEVEL 1 ( + ENDLOCAL + EXIT /B 1 +) +SET "EXPECTED_TOOL_SHA256=%TRUSTED_VCPKG_TOOL_SHA256_X64%" +IF /I "%PROCESSOR_ARCHITECTURE%"=="ARM64" SET "EXPECTED_TOOL_SHA256=%TRUSTED_VCPKG_TOOL_SHA256_ARM64%" +IF /I "%PROCESSOR_ARCHITEW6432%"=="ARM64" SET "EXPECTED_TOOL_SHA256=%TRUSTED_VCPKG_TOOL_SHA256_ARM64%" +powershell.exe -NoLogo -NoProfile -NonInteractive -Command "$actual = (Get-FileHash -Algorithm SHA256 -LiteralPath (Join-Path $env:VALIDATE_DIR 'vcpkg.exe')).Hash.ToLowerInvariant(); if ($actual -ne $env:EXPECTED_TOOL_SHA256) { exit 1 }" +IF ERRORLEVEL 1 ( + ENDLOCAL + EXIT /B 1 +) +"%VALIDATE_DIR%\vcpkg.exe" version 2>NUL | FINDSTR /B /I /L /C:"vcpkg package management program version %EXPECTED_TOOL_TAG%-" >NUL +SET "VALIDATION_RESULT=%ERRORLEVEL%" +ENDLOCAL & EXIT /B %VALIDATION_RESULT% diff --git a/scripts/bootstrap-vcpkg.sh b/scripts/bootstrap-vcpkg.sh new file mode 100755 index 0000000000..50225734e4 --- /dev/null +++ b/scripts/bootstrap-vcpkg.sh @@ -0,0 +1,132 @@ +#!/usr/bin/env bash + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +manifest="${repo_root}/vcpkg.json" +vcpkg_dir="${CDT_VCPKG_CACHE_DIR:-${repo_root}/.cache/vcpkg}" +mode="${1:-bootstrap}" +trusted_vcpkg_tool_tag="2026-07-13" + +metadata_value() +{ + local key="${1}" + sed -nE "s/^${key}=(.*)$/\\1/p" "${vcpkg_dir}/scripts/vcpkg-tool-metadata.txt" +} + +compute_sha512() +{ + local file="${1}" + if command -v sha512sum >/dev/null; then + sha512sum "${file}" | awk '{print $1}' + elif command -v shasum >/dev/null; then + shasum -a 512 "${file}" | awk '{print $1}' + else + printf 'A SHA-512 utility is required to validate the cached vcpkg binary.\n' >&2 + return 1 + fi +} + +validate_cached_vcpkg() +{ + local metadata="${vcpkg_dir}/scripts/vcpkg-tool-metadata.txt" + local expected_sha_key="" + local expected_tag="" + local expected_sha="" + local actual_sha="" + + [[ -f "${metadata}" && -x "${vcpkg_dir}/vcpkg" ]] || return 1 + + expected_tag="$(metadata_value VCPKG_TOOL_RELEASE_TAG)" + [[ "${expected_tag}" == "${trusted_vcpkg_tool_tag}" ]] || return 1 + + case "$(uname -s):$(uname -m)" in + Darwin:*) + expected_sha_key="VCPKG_MACOS_SHA" + ;; + Linux:aarch64 | Linux:arm64) + expected_sha_key="VCPKG_GLIBC_ARM64_SHA" + ;; + Linux:x86_64 | Linux:amd64) + if ldd --version 2>&1 | grep -qi musl; then + expected_sha_key="VCPKG_MUSLC_SHA" + else + expected_sha_key="VCPKG_GLIBC_SHA" + fi + ;; + *) + return 1 + ;; + esac + + expected_sha="$(metadata_value "${expected_sha_key}")" + [[ "${expected_sha}" =~ ^[0-9a-f]{128}$ ]] || return 1 + actual_sha="$(compute_sha512 "${vcpkg_dir}/vcpkg")" || return 1 + [[ "${actual_sha}" == "${expected_sha}" ]] || return 1 + + "${vcpkg_dir}/vcpkg" version 2>/dev/null | + grep -q "^vcpkg package management program version ${trusted_vcpkg_tool_tag}-" +} + +if [[ "${mode}" != "bootstrap" && "${mode}" != "--check" ]]; then + printf 'Usage: %s [--check]\n' "$0" >&2 + exit 2 +fi + +baseline="$( + sed -nE 's/^[[:space:]]*"builtin-baseline":[[:space:]]*"([0-9a-f]{40})",?$/\1/p' \ + "${manifest}" +)" + +if [[ ! "${baseline}" =~ ^[0-9a-f]{40}$ ]]; then + printf 'Unable to read a 40-character builtin-baseline from %s\n' "${manifest}" >&2 + exit 1 +fi + +if [[ -d "${vcpkg_dir}/.git" ]]; then + origin="$(git -C "${vcpkg_dir}" remote get-url origin 2>/dev/null || true)" + if [[ "${origin}" != "https://github.com/microsoft/vcpkg.git" ]]; then + printf 'Refusing to reuse %s because its origin is not microsoft/vcpkg.\n' "${vcpkg_dir}" >&2 + exit 1 + fi + if [[ -n "$(git -C "${vcpkg_dir}" status --short --untracked-files=no)" ]]; then + printf 'Refusing to reuse a modified vcpkg checkout at %s.\n' "${vcpkg_dir}" >&2 + exit 1 + fi + if [[ -x "${vcpkg_dir}/vcpkg" ]] && + [[ "$(git -C "${vcpkg_dir}" rev-parse HEAD 2>/dev/null || true)" == "${baseline}" ]] && + validate_cached_vcpkg; then + printf 'Using vcpkg at %s (%s)\n' "${vcpkg_dir}" "${baseline}" + exit 0 + fi +elif [[ -d "${vcpkg_dir}" ]] && + [[ -n "$(find "${vcpkg_dir}" -mindepth 1 -maxdepth 1 -print -quit)" ]]; then + printf 'Refusing to initialize vcpkg in non-empty directory %s.\n' "${vcpkg_dir}" >&2 + exit 1 +fi + +if [[ "${mode}" == "--check" ]]; then + printf 'VCPKG_ROOT is not a clean official checkout at baseline %s: %s\n' \ + "${baseline}" "${vcpkg_dir}" >&2 + exit 1 +fi + +if [[ ! -d "${vcpkg_dir}/.git" ]]; then + mkdir -p "${vcpkg_dir}" + git -C "${vcpkg_dir}" init + git -C "${vcpkg_dir}" remote add origin https://github.com/microsoft/vcpkg.git +fi + +git -C "${vcpkg_dir}" fetch --depth 1 origin "${baseline}" +git -C "${vcpkg_dir}" checkout --detach "${baseline}" +rm -f -- "${vcpkg_dir}/vcpkg" +"${vcpkg_dir}/bootstrap-vcpkg.sh" -disableMetrics + +if ! validate_cached_vcpkg; then + printf 'Bootstrapped vcpkg does not match the tool release pinned by %s.\n' \ + "${baseline}" >&2 + exit 1 +fi + +printf 'Bootstrapped vcpkg at %s (%s)\n' "${vcpkg_dir}" "${baseline}" diff --git a/scripts/build.bat b/scripts/build.bat new file mode 100644 index 0000000000..c7731ee8d0 --- /dev/null +++ b/scripts/build.bat @@ -0,0 +1,51 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS +SET "SCRIPT_DIR=%~dp0" +FOR %%I IN ("%SCRIPT_DIR%..") DO SET "REPO_ROOT=%%~fI" + +IF DEFINED CDT_VCPKG_CACHE_DIR ( + SET "PINNED_VCPKG_ROOT=%CDT_VCPKG_CACHE_DIR%" +) ELSE ( + SET "PINNED_VCPKG_ROOT=%REPO_ROOT%\.cache\vcpkg" +) + +IF DEFINED VCPKG_ROOT ( + SET "CDT_VCPKG_CACHE_DIR=%VCPKG_ROOT%" + CALL "%SCRIPT_DIR%bootstrap-vcpkg.bat" --check >NUL 2>NUL + IF NOT ERRORLEVEL 1 GOTO VCPKG_READY + echo Ignoring VCPKG_ROOT=%VCPKG_ROOT%; using the repository-pinned checkout instead. 1>&2 +) + +SET "CDT_VCPKG_CACHE_DIR=%PINNED_VCPKG_ROOT%" +SET "VCPKG_ROOT=%PINNED_VCPKG_ROOT%" +CALL "%SCRIPT_DIR%bootstrap-vcpkg.bat" || EXIT /B 1 + +:VCPKG_READY +SET "VCPKG_ROOT=%CDT_VCPKG_CACHE_DIR%" +CD /D "%REPO_ROOT%" || EXIT /B 1 +CALL :PREPARE_CMAKE_CACHE || EXIT /B 1 +cmake --preset reference -S . || EXIT /B 1 +cmake --build --preset reference || EXIT /B 1 +ctest --preset reference-smoke || EXIT /B 1 +EXIT /B 0 + +:PREPARE_CMAKE_CACHE +SET "CMAKE_CACHE=%REPO_ROOT%\out\build\reference\CMakeCache.txt" +SET "EXPECTED_TOOLCHAIN=%VCPKG_ROOT:\=/%/scripts/buildsystems/vcpkg.cmake" +SET "EXPECTED_INSTALLED=%REPO_ROOT:\=/%/out/build/reference/vcpkg_installed" +SET "CACHED_TOOLCHAIN=" +SET "CACHED_INSTALLED=" +IF EXIST "%CMAKE_CACHE%" FOR /F "tokens=1,* delims==" %%A IN ('FINDSTR /B /C:"CMAKE_TOOLCHAIN_FILE:" "%CMAKE_CACHE%"') DO SET "CACHED_TOOLCHAIN=%%B" +IF EXIST "%CMAKE_CACHE%" FOR /F "tokens=1,* delims==" %%A IN ('FINDSTR /B /C:"VCPKG_INSTALLED_DIR:" "%CMAKE_CACHE%"') DO SET "CACHED_INSTALLED=%%B" +SET "CACHED_TOOLCHAIN=%CACHED_TOOLCHAIN:\=/%" +SET "CACHED_INSTALLED=%CACHED_INSTALLED:\=/%" +IF EXIST "%CMAKE_CACHE%" IF /I NOT "%CACHED_TOOLCHAIN%"=="%EXPECTED_TOOLCHAIN%" GOTO REFRESH_CMAKE_CACHE +IF EXIST "%CMAKE_CACHE%" IF /I NOT "%CACHED_INSTALLED%"=="%EXPECTED_INSTALLED%" GOTO REFRESH_CMAKE_CACHE +EXIT /B 0 + +:REFRESH_CMAKE_CACHE +ECHO vcpkg configuration changed; refreshing CMake configuration state. 1>&2 +DEL /F /Q "%CMAKE_CACHE%" || EXIT /B 1 +IF EXIST "%REPO_ROOT%\out\build\reference\CMakeFiles\." RMDIR /S /Q "%REPO_ROOT%\out\build\reference\CMakeFiles" || EXIT /B 1 +EXIT /B 0 diff --git a/scripts/build.sh b/scripts/build.sh new file mode 100755 index 0000000000..88559f01dd --- /dev/null +++ b/scripts/build.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +reference_build_dir="${repo_root}/out/build/reference" + +source "${script_dir}/prepare-vcpkg.sh" +prepare_reference_environment +prepare_vcpkg "${repo_root}" +prepare_cmake_cache "${reference_build_dir}" + +cd -- "${repo_root}" +cmake --preset reference -S "${repo_root}" +cmake --build --preset reference +ctest --preset reference-smoke diff --git a/scripts/clang-tidy.sh b/scripts/clang-tidy.sh new file mode 100755 index 0000000000..517fce7b56 --- /dev/null +++ b/scripts/clang-tidy.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env bash + +# Before running this script, make sure $VCPKG_ROOT is set, e.g. +# VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" +if command -v just >/dev/null; then + llvm_version="$(just --justfile "${repo_root}/Justfile" --evaluate llvm_version)" +elif command -v pkgx >/dev/null; then + llvm_version="$(pkgx +just.systems -- just --justfile "${repo_root}/Justfile" --evaluate llvm_version)" +else + echo "just is required to resolve the pinned LLVM version; install it or install pkgx." >&2 + exit 1 +fi +clang_tidy_vcpkg_installed_dir="${repo_root}/.cache/vcpkg-installed/clang-tidy-llvm-${llvm_version}" + +if [[ "${CDT_CLANG_TIDY_ACTIVE:-0}" != 1 ]] && command -v pkgx >/dev/null; then + export CDT_CLANG_TIDY_ACTIVE=1 + exec pkgx +just.systems "+llvm.org@${llvm_version}" +cmake.org +ninja-build.org -- "${BASH_SOURCE[0]}" "$@" +fi + +command -v clang-tidy >/dev/null || { + echo "clang-tidy ${llvm_version} is required; install it or install pkgx." >&2 + exit 1 +} +clang-tidy --version | grep -Eq "LLVM version ${llvm_version}([.]|$)" || { + echo "clang-tidy ${llvm_version} is required; found $(clang-tidy --version | head -n 1)." >&2 + exit 1 +} + +source "${script_dir}/prepare-vcpkg.sh" +prepare_vcpkg "${repo_root}" + +rm -rf -- "${build_dir}" +cmake -S "${repo_root}" -B "${build_dir}" -G Ninja \ + -DVCPKG_INSTALLED_DIR="${clang_tidy_vcpkg_installed_dir}" \ + -D ENABLE_CLANG_TIDY=ON -D ENABLE_TESTING=OFF +cmake --build "${build_dir}" --parallel 1 diff --git a/scripts/codecov.sh b/scripts/codecov.sh new file mode 100755 index 0000000000..ffe18db3ba --- /dev/null +++ b/scripts/codecov.sh @@ -0,0 +1,30 @@ +#!/usr/bin/env bash + +# Before running this script, make sure $VCPKG_ROOT is set, e.g. +# VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" +coverage_file="${build_dir}/coverage.info" + +rm -rf -- "${build_dir}" +cmake -S "${repo_root}" -B "${build_dir}" -D ENABLE_COVERAGE:BOOL=TRUE \ + -D CMAKE_BUILD_TYPE=Debug \ + --trace-source="${repo_root}/CMakeLists.txt" \ + --trace-source="${repo_root}/cmake/Coverage.cmake" +cmake --build "${build_dir}" --config Debug +ctest --test-dir "${build_dir}" --schedule-random -V -j2 +lcov --directory "${build_dir}" --capture --output-file "${coverage_file}" +lcov --remove "${coverage_file}" '/usr/*' '*/usr/include/*' '*/vcpkg/*' --output-file "${coverage_file}" +lcov --list "${coverage_file}" + +if ! command -v codecovcli >/dev/null; then + echo "codecovcli is required; install the supported Codecov CLI with 'pip install codecov-cli'." >&2 + exit 1 +fi + +cd -- "${repo_root}" +codecovcli --verbose upload-process --disable-search --fail-on-error -f "${coverage_file}" diff --git a/scripts/debug.sh b/scripts/debug.sh new file mode 100755 index 0000000000..b4eae34109 --- /dev/null +++ b/scripts/debug.sh @@ -0,0 +1,16 @@ +#!/usr/bin/env bash + +# Before running this script, make sure $VCPKG_ROOT is set, e.g. +# VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" + +cd -- "${repo_root}" +rm -rf -- "${build_dir}" +cmake --preset debug +cmake --build "${build_dir}" +ctest --test-dir "${build_dir}" --output-on-failure -j2 diff --git a/scripts/fast-build.bat b/scripts/fast-build.bat new file mode 100644 index 0000000000..e9c8390312 --- /dev/null +++ b/scripts/fast-build.bat @@ -0,0 +1,50 @@ +@echo off + +SETLOCAL ENABLEEXTENSIONS +SET "SCRIPT_DIR=%~dp0" +FOR %%I IN ("%SCRIPT_DIR%..") DO SET "REPO_ROOT=%%~fI" + +IF DEFINED CDT_VCPKG_CACHE_DIR ( + SET "PINNED_VCPKG_ROOT=%CDT_VCPKG_CACHE_DIR%" +) ELSE ( + SET "PINNED_VCPKG_ROOT=%REPO_ROOT%\.cache\vcpkg" +) + +IF DEFINED VCPKG_ROOT ( + SET "CDT_VCPKG_CACHE_DIR=%VCPKG_ROOT%" + CALL "%SCRIPT_DIR%bootstrap-vcpkg.bat" --check >NUL 2>NUL + IF NOT ERRORLEVEL 1 GOTO VCPKG_READY + echo Ignoring VCPKG_ROOT=%VCPKG_ROOT%; using the repository-pinned checkout instead. 1>&2 +) + +SET "CDT_VCPKG_CACHE_DIR=%PINNED_VCPKG_ROOT%" +SET "VCPKG_ROOT=%PINNED_VCPKG_ROOT%" +CALL "%SCRIPT_DIR%bootstrap-vcpkg.bat" || EXIT /B 1 + +:VCPKG_READY +SET "VCPKG_ROOT=%CDT_VCPKG_CACHE_DIR%" +CD /D "%REPO_ROOT%" || EXIT /B 1 +CALL :PREPARE_CMAKE_CACHE || EXIT /B 1 +cmake --preset reference -S . || EXIT /B 1 +cmake --build --preset reference --target cdt || EXIT /B 1 +EXIT /B 0 + +:PREPARE_CMAKE_CACHE +SET "CMAKE_CACHE=%REPO_ROOT%\out\build\reference\CMakeCache.txt" +SET "EXPECTED_TOOLCHAIN=%VCPKG_ROOT:\=/%/scripts/buildsystems/vcpkg.cmake" +SET "EXPECTED_INSTALLED=%REPO_ROOT:\=/%/out/build/reference/vcpkg_installed" +SET "CACHED_TOOLCHAIN=" +SET "CACHED_INSTALLED=" +IF EXIST "%CMAKE_CACHE%" FOR /F "tokens=1,* delims==" %%A IN ('FINDSTR /B /C:"CMAKE_TOOLCHAIN_FILE:" "%CMAKE_CACHE%"') DO SET "CACHED_TOOLCHAIN=%%B" +IF EXIST "%CMAKE_CACHE%" FOR /F "tokens=1,* delims==" %%A IN ('FINDSTR /B /C:"VCPKG_INSTALLED_DIR:" "%CMAKE_CACHE%"') DO SET "CACHED_INSTALLED=%%B" +SET "CACHED_TOOLCHAIN=%CACHED_TOOLCHAIN:\=/%" +SET "CACHED_INSTALLED=%CACHED_INSTALLED:\=/%" +IF EXIST "%CMAKE_CACHE%" IF /I NOT "%CACHED_TOOLCHAIN%"=="%EXPECTED_TOOLCHAIN%" GOTO REFRESH_CMAKE_CACHE +IF EXIST "%CMAKE_CACHE%" IF /I NOT "%CACHED_INSTALLED%"=="%EXPECTED_INSTALLED%" GOTO REFRESH_CMAKE_CACHE +EXIT /B 0 + +:REFRESH_CMAKE_CACHE +ECHO vcpkg configuration changed; refreshing CMake configuration state. 1>&2 +DEL /F /Q "%CMAKE_CACHE%" || EXIT /B 1 +IF EXIST "%REPO_ROOT%\out\build\reference\CMakeFiles\." RMDIR /S /Q "%REPO_ROOT%\out\build\reference\CMakeFiles" || EXIT /B 1 +EXIT /B 0 diff --git a/scripts/fast-build.sh b/scripts/fast-build.sh new file mode 100755 index 0000000000..1ef73e9026 --- /dev/null +++ b/scripts/fast-build.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash + +# Before running this script, make sure $VCPKG_ROOT names the pinned checkout. + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +reference_build_dir="${repo_root}/out/build/reference" + +source "${script_dir}/prepare-vcpkg.sh" +prepare_reference_environment +prepare_vcpkg "${repo_root}" +prepare_cmake_cache "${reference_build_dir}" + +cd -- "${repo_root}" +cmake --preset reference +cmake --build --preset reference --target cdt diff --git a/scripts/gcov.sh b/scripts/gcov.sh new file mode 100755 index 0000000000..6c5f46808b --- /dev/null +++ b/scripts/gcov.sh @@ -0,0 +1,24 @@ +#!/usr/bin/env bash + +# Before running this script, make sure $VCPKG_ROOT is set, e.g. +# VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" +object_dir="${build_dir}/tests/CMakeFiles/CDT_unit_tests.dir" +report_dir="${build_dir}/gcov-reports" + +rm -rf -- "${build_dir}" +cmake -G Ninja -D ENABLE_COVERAGE:BOOL=TRUE -D CMAKE_BUILD_TYPE=Debug -D ENABLE_TESTING:BOOL=TRUE -S "${repo_root}" -B "${build_dir}" +cmake --build "${build_dir}" +ctest --test-dir "${build_dir}" --output-on-failure -j2 +mkdir -p -- "${report_dir}" +cd -- "${report_dir}" +while IFS= read -r -d '' object_file; do + printf 'Processing %s file...\n' "${object_file}" + gcov -o "$(dirname -- "${object_file}")" "${object_file}" +done < <(find "${object_dir}" -name '*.o' -print0) +find "${report_dir}" -maxdepth 1 -type f | wc -l diff --git a/scripts/iwyu.sh b/scripts/iwyu.sh new file mode 100755 index 0000000000..cef63100a5 --- /dev/null +++ b/scripts/iwyu.sh @@ -0,0 +1,17 @@ +#!/usr/bin/env bash + +# This script runs include-what-you-use +# It assumes that you have it installed in a standard location, e.g. brew install include-what-you-use + +# Before running this script, make sure $VCPKG_ROOT is set, e.g. +# VCPKG_ROOT="$HOME"/vcpkg && export VCPKG_ROOT + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" + +rm -rf -- "${build_dir}" +cmake -G Ninja -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -D ENABLE_INCLUDE_WHAT_YOU_USE:BOOL=TRUE -S "${repo_root}" -B "${build_dir}" +cmake --build "${build_dir}" diff --git a/scripts/pkgx-build.sh b/scripts/pkgx-build.sh new file mode 100755 index 0000000000..8773cbb367 --- /dev/null +++ b/scripts/pkgx-build.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash +# shellcheck shell=bash + +set -euo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" + +pkgx_tools=( + +git-scm.org@2.55.0 + +cmake.org@4.4.0 + +ninja-build.org@1.13.2 + +python.org@3.11.15 + +gnu.org/m4@1.4.21 + +gnu.org/autoconf@2.73.0 + +gnu.org/autoconf-archive@2024.10.16 + +gnu.org/automake@1.18.1 + +gnu.org/libtool@2.5.4 + +gnu.org/texinfo@7.3.0 + +freedesktop.org/pkg-config@0.29.2 +) + +if [[ -n "${CDT_PKGX_COMPILER_PACKAGE:-}" ]]; then + pkgx_tools+=("+${CDT_PKGX_COMPILER_PACKAGE}") +fi + +cd -- "${repo_root}" +exec pkgx "${pkgx_tools[@]}" -- "${script_dir}/build.sh" diff --git a/scripts/prepare-vcpkg.sh b/scripts/prepare-vcpkg.sh new file mode 100644 index 0000000000..9b60332db7 --- /dev/null +++ b/scripts/prepare-vcpkg.sh @@ -0,0 +1,80 @@ +#!/usr/bin/env bash + +# Keep pkgx-provided build tools on PATH without allowing their transitive +# headers and libraries to affect compiler detection or dependency resolution. +prepare_reference_environment() +{ + unset CMAKE_PREFIX_PATH + unset CPATH + unset C_INCLUDE_PATH + unset CPLUS_INCLUDE_PATH + unset CC + unset CFLAGS + unset CPPFLAGS + unset CXX + unset CXXFLAGS + unset LDFLAGS + unset LIBRARY_PATH + unset PKG_CONFIG_PATH + + if [[ "$(uname -s)" == "Darwin" ]] && command -v xcode-select >/dev/null && command -v xcrun >/dev/null; then + unset DEVELOPER_DIR + DEVELOPER_DIR="$(xcode-select -p)" + export DEVELOPER_DIR + SDKROOT="$(xcrun --sdk macosx --show-sdk-path)" + CC=/usr/bin/cc + CXX=/usr/bin/c++ + unset ARCHFLAGS + unset MACOSX_DEPLOYMENT_TARGET + export CC CXX SDKROOT + fi +} + +# Source this file and call prepare_vcpkg with the repository root. +prepare_vcpkg() +{ + local repository_root="${1:?repository root is required}" + local pinned_vcpkg_root="${CDT_VCPKG_CACHE_DIR:-${repository_root}/.cache/vcpkg}" + local bootstrap_script="${repository_root}/scripts/bootstrap-vcpkg.sh" + + if [[ -n "${VCPKG_ROOT:-}" ]] && + CDT_VCPKG_CACHE_DIR="${VCPKG_ROOT}" "${bootstrap_script}" --check 2>/dev/null; then + VCPKG_ROOT="$(cd -- "${VCPKG_ROOT}" && pwd -P)" + export VCPKG_ROOT + return + fi + + if [[ -n "${VCPKG_ROOT:-}" ]]; then + printf 'Ignoring VCPKG_ROOT=%s; using the repository-pinned checkout instead.\n' \ + "${VCPKG_ROOT}" >&2 + fi + + export VCPKG_ROOT="${pinned_vcpkg_root}" + "${bootstrap_script}" + VCPKG_ROOT="$(cd -- "${VCPKG_ROOT}" && pwd -P)" + export VCPKG_ROOT +} + +# Keep repeat builds incremental, but discard configuration state when the +# selected vcpkg toolchain actually changes. CMake cannot safely replace a +# cached toolchain after project() has enabled a language. +prepare_cmake_cache() +{ + local build_directory="${1:?build directory is required}" + local cache_file="${build_directory}/CMakeCache.txt" + local expected_toolchain="${VCPKG_ROOT:?VCPKG_ROOT must be set}/scripts/buildsystems/vcpkg.cmake" + local expected_installed_dir="${build_directory}/vcpkg_installed" + local cached_toolchain + local cached_installed_dir + + [[ -f "${cache_file}" ]] || return 0 + + cached_toolchain="$(sed -n 's/^CMAKE_TOOLCHAIN_FILE:[^=]*=//p' "${cache_file}" | head -n 1)" + cached_installed_dir="$(sed -n 's/^VCPKG_INSTALLED_DIR:[^=]*=//p' "${cache_file}" | head -n 1)" + if [[ "${cached_toolchain}" != "${expected_toolchain}" ]] || + [[ "${cached_installed_dir}" != "${expected_installed_dir}" ]]; then + printf 'vcpkg configuration changed; refreshing CMake configuration state.\n' >&2 + cmake -E rm -f "${cache_file}" + cmake -E rm -rf "${build_directory}/CMakeFiles" + fi +} diff --git a/scripts/sanitizer.sh b/scripts/sanitizer.sh new file mode 100755 index 0000000000..cb21288b71 --- /dev/null +++ b/scripts/sanitizer.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +set -euo pipefail + +if [[ "$#" -ne 1 ]]; then + echo "Usage: $0 {asan|lsan|msan|tsan}" >&2 + exit 2 +fi + +sanitizer="$1" +case "${sanitizer}" in + asan | lsan | msan | tsan) ;; + *) + echo "Unsupported sanitizer '${sanitizer}'; expected asan, lsan, msan, or tsan." >&2 + exit 2 + ;; +esac + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" +run_dir="${build_dir}/sanitizer-run" + +if [[ "$(uname -s)" != "Linux" ]]; then + echo "Sanitizer presets are supported on Linux only." >&2 + exit 2 +fi + +source "${script_dir}/prepare-vcpkg.sh" +prepare_vcpkg "${repo_root}" + +rm -rf -- "${build_dir}" +cmake --preset "${sanitizer}" -S "${repo_root}" +cmake --build "${build_dir}" --parallel 2 +ctest --test-dir "${build_dir}" --label-exclude full-suite-duplicate --no-tests=error --output-on-failure -j2 + +mkdir -p -- "${run_dir}" +cd -- "${run_dir}" +"${build_dir}/src/initialize" -s -n32000 -t11 -o +"${build_dir}/src/cdt" -s -n64 -t3 -a.6 -k1.1 -l.1 -p10 --no-output diff --git a/scripts/slurm.sh b/scripts/slurm.sh new file mode 100755 index 0000000000..6d73ca2dab --- /dev/null +++ b/scripts/slurm.sh @@ -0,0 +1,18 @@ +#!/bin/bash -l +# For use on Slurm +# sbatch -p high -t 60 slurm.sh +# Or, interactively, +# srun -p med2 -t 1-00 --mem=100G --ntasks 12 --pty /bin/bash -il +set -eo pipefail + +script_dir="$(cd -- "$(dirname -- "${BASH_SOURCE[0]}")" && pwd)" +repo_root="$(cd -- "${script_dir}/.." && pwd)" +build_dir="${repo_root}/build" + +module load cmake/3.28.1 +module load gcc/13.2.0 +module load autoconf-archive/2022.02.11 +rm -rf -- "${build_dir}" +cmake -D CMAKE_BUILD_TYPE=RelWithDebInfo -D ENABLE_TESTING:BOOL=TRUE -S "${repo_root}" -B "${build_dir}" +cmake --build "${build_dir}" +ctest --test-dir "${build_dir}" --no-tests=error --output-on-failure -j2 diff --git a/slurm.sh b/slurm.sh deleted file mode 100755 index 68acf66503..0000000000 --- a/slurm.sh +++ /dev/null @@ -1,13 +0,0 @@ -#!/bin/bash -l -# For use on Slurm -# sbatch -p high -t 60 slurm.sh -module load cmake gcc boost cgal tbb -rm -rf build/ -mkdir build && cd build -cmake -G Ninja -DTESTS:BOOL=OFF -DCMAKE_BUILD_TYPE=Release .. -cmake --build . -mkdir $HOME/data/`date +%Y-%m-%d.%R%Z` -cp cdt-opt $HOME/data/`date +%Y-%m-%d.%R%Z`/ -cd $HOME/data/`date +%Y-%m-%d.%R%Z` -./cdt-opt 2>>errors 1>>output - diff --git a/sonar-project.properties b/sonar-project.properties deleted file mode 100644 index f6675cba78..0000000000 --- a/sonar-project.properties +++ /dev/null @@ -1,19 +0,0 @@ -sonar.projectKey=CDT-plusplus -sonar.projectName=Causal Dynamical Triangulations in C++ using CGAL -sonar.projectVersion=0.1.8 - -# Metadata for the project -sonar.links.homepage=https://github.com/acgetchell/CDT-plusplus -sonar.links.ci=https://travis-ci.org/acgetchell/CDT-plusplus -sonar.links.issue=https://github.com/acgetchell/CDT-plusplus/issues -sonar.links.scm=https://github.com/acgetchell/CDT-plusplus -sonar.projectBaseDir=/Users/travis/build/acgetchell/CDT-plusplus - -# Standard properties -sonar.language=cpp -sonar.sources=src,include -sonar.tests=test -sonar.exclusions=src/date/**/*,src/docopt/**/* -sonar.host.url=https://sonarcloud.io -sonar.verbose=true -sonar.cfamily.build-wrapper-output=bw_output diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt new file mode 100644 index 0000000000..ce9a8f65fb --- /dev/null +++ b/src/CMakeLists.txt @@ -0,0 +1,67 @@ +add_executable(initialize ${PROJECT_SOURCE_DIR}/src/initialize.cpp) +target_link_libraries( + initialize + PRIVATE project_options + project_warnings + date::date-tz + Boost::program_options + fmt::fmt-header-only + spdlog::spdlog_header_only + TBB::tbb + CGAL::CGAL) +target_compile_features(initialize PRIVATE cxx_std_23) + +add_executable(cdt ${PROJECT_SOURCE_DIR}/src/cdt.cpp) +target_link_libraries( + cdt + PRIVATE project_options + project_warnings + date::date-tz + Boost::program_options + fmt::fmt-header-only + spdlog::spdlog_header_only + TBB::tbb + CGAL::CGAL) +target_compile_features(cdt PRIVATE cxx_std_23) + +# +# Tests ## +# + +add_test(NAME cdt COMMAND $ -s -n127 -t4 -a0.6 -k1.1 -l0.1 -p10) +set_tests_properties(cdt PROPERTIES PASS_REGULAR_EXPRESSION "Writing to file S3-[0-9]+-") + +add_test( + NAME cdt-no-output + COMMAND + ${CMAKE_COMMAND} -DCDT_EXECUTABLE=$ + -DTEST_DIRECTORY=${CMAKE_CURRENT_BINARY_DIR}/cdt-no-output + -P ${PROJECT_SOURCE_DIR}/cmake/RunCdtNoOutputTest.cmake) + +add_test(NAME cdt-triangle-inequalities COMMAND $ -s -n64 -t3 -a0.4 -k1.1 -l0.1) +set_tests_properties(cdt-triangle-inequalities PROPERTIES PASS_REGULAR_EXPRESSION "Triangle inequalities violated") + +add_test(NAME cdt-dimensionality COMMAND $ -s -n64 -t3 -d4 -a0.4 -k1.1 -l0.1) +set_tests_properties(cdt-dimensionality PROPERTIES PASS_REGULAR_EXPRESSION "Currently, dimensions cannot be >3.") + +add_test(NAME cdt-toroidal COMMAND $ -e -n64 -t3 -a0.6 -k1.1 -l0.1) +set_tests_properties(cdt-toroidal PROPERTIES PASS_REGULAR_EXPRESSION "Toroidal triangulations not yet supported.") + +add_test(NAME initialize COMMAND $ -s -n640 -t4 -o) +set_tests_properties(initialize PROPERTIES PASS_REGULAR_EXPRESSION "Writing to file S3-4") +if(WIN32) + # Preserve the known failing scenario for explicit debugging without blocking the portable smoke suite. + set_tests_properties(initialize PROPERTIES LABELS "reference-smoke-exclude") +endif() + +add_test(NAME initialize-minimum-simplices COMMAND $ -s -n1 -t1 -o) +set_tests_properties(initialize-minimum-simplices + PROPERTIES PASS_REGULAR_EXPRESSION "Simplices and timeslices should be greater or equal to 2.") + +add_test(NAME initialize-dimensionality COMMAND $ -s -n64 -t3 -d2 -o) +set_tests_properties(initialize-dimensionality + PROPERTIES PASS_REGULAR_EXPRESSION "Only three-dimensional triangulations are supported.") + +add_test(NAME initialize-toroidal COMMAND $ -e -n64 -t3 -o) +set_tests_properties(initialize-toroidal PROPERTIES PASS_REGULAR_EXPRESSION + "Toroidal triangulations not yet supported.") diff --git a/src/cdt-gv.cpp b/src/cdt-gv.cpp deleted file mode 100644 index b643466d23..0000000000 --- a/src/cdt-gv.cpp +++ /dev/null @@ -1,113 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2015-2018 Adam Getchell -/// -/// A program that visualizes spacetimes -/// -/// Inspired by: -/// http://doc.cgal.org/latest/Geomview/Geomview_2gv_terrain_8cpp-example.html -/// -/// \done Load files generated by cdt.cpp -/// \done Invoke Geomview -/// \done Use docopt -/// for a beautiful command line interface. -/// \todo Parse file and read in points only -/// \todo Colorize/improve output - -/// @file cdt-gv.cpp -/// @brief A pipeline from CDT++ to Geomview -/// , a visualizer -/// @author Adam Getchell - -// CGAL headers -#include -#include -#include -#include -#include - -// C++ headers -#include - -// Docopt -#include "docopt/docopt.h" - -using K = CGAL::Exact_predicates_inexact_constructions_kernel; -using Delaunay = CGAL::Delaunay_triangulation_3; -using Gt3 = CGAL::Projection_traits_xy_3; -using Point3 = Gt3::Point; - -/// Help message parsed by docopt into options -static const char USAGE[]{ - R"(Causal Dynamical Triangulations in C++ using CGAL. - -Copyright (c) 2015-2018 Adam Getchell - -A program that loads d-dimensional triangulated spacetimes -with a defined causal structure generated by cdt.cpp into a GeomView -pipeline for visualization. - -Note that the standard output of CDT++ includes cell neighbors, and should -be truncated to just include points. - -Usage:./cdt-gv --file FILE - -Example: -./cdt --file points.dat -./cdt --f points.dat - -Options: - -h --help Show this message - --version Show program version - -f --file FILENAME The file to load into GeomView -)"}; - -/// @brief The main path of the cdt-gv program -/// -/// @param[in,out] argc Argument count = 1 + number of arguments -/// @param[in,out] argv Argument vector (array) to be passed to docopt -/// @returns Integer value 0 if successful, 1 on failure -int main(int argc, char* const argv[]) -{ - // https://stackoverflow.com/questions/9371238/why-is-reading-lines-from-stdin-much-slower-in-c-than-python?rq=1 - std::ios_base::sync_with_stdio(false); - // docopt option parser - std::map args = - docopt::docopt(USAGE, {argv + 1, argv + argc}, - true, // print help message automatically - "cdt-gv 1.0"); // Version - - // Debugging docopt values - // for (auto const& arg : args) { - // std::cout << arg.first << " " << arg.second << "\n"; - // } - - // Parse docopt::values in args map - auto file = args["--file"].asString(); - - // Test - std::cout << "File to be loaded is " << file << "\n"; - - CGAL::Geomview_stream gv(CGAL::Bbox_3(-1000, -1000, -1000, 1000, 1000, 1000)); - gv.set_line_width(4); - gv.set_bg_color(CGAL::Color(0, 200, 200)); - - Delaunay D; - std::ifstream iFile(file, std::ios::in); - Point3 p; - - // Insert points from file into Delaunay triangulation - while (iFile >> p) { - D.insert(p); - } - - std::cout << "Drawing 3D Delaunay triangulation in wired mode.\n"; - gv.set_wired(true); - gv << D; - - std::cout << "Enter a key to finish.\n"; - char ch; - std::cin >> ch; - - return 0; -} diff --git a/src/cdt-opt.cpp b/src/cdt-opt.cpp deleted file mode 100644 index 7458bbe0b4..0000000000 --- a/src/cdt-opt.cpp +++ /dev/null @@ -1,67 +0,0 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2016-2018 Adam Getchell -/// -/// Full run-through with default options used to calculate -/// optimal values for thermalization, etc. A simpler version -/// that encompasses the entire lifecycle. Also suitable for -/// scripting parallel runs, e.g. -/// -/// ./cdt-opt 2>>errors 1>>output & -/// -/// \done Invoke Metropolis algorithm -/// \todo Print out graph of time-value vs. volume vs. pass number - -/// @file cdt-opt.cpp -/// @brief Outputs values to determine optimizations -/// @author Adam Getchell - -#include - -#include -#include -#include - -int main() -{ - // https://stackoverflow.com/questions/9371238/why-is-reading-lines-from-stdin-much-slower-in-c-than-python?rq=1 - std::ios_base::sync_with_stdio(false); - std::cout << "cdt-opt started at " << currentDateTime() << "\n"; - constexpr int_fast32_t simplices = 64000; - constexpr int_fast32_t timeslices = 16; - /// @brief Constants in units of \f$c=G=\hbar=1 \alpha\approx 0.0397887\f$ - constexpr long double alpha = 0.6; - constexpr long double k = 1.1; - /// @brief \f$\Lambda=2.036\times 10^{-35} s^{-2}\approx 0\f$ - constexpr long double lambda = 0.1; - constexpr int_fast32_t passes = 100; - constexpr int_fast32_t checkpoint = 10; - - // Initialize simulation - Simulation my_simulation; - - // Initialize the Metropolis algorithm - Metropolis my_algorithm(alpha, k, lambda, passes, checkpoint); - - // Make a triangulation - SimplicialManifold universe(simplices, timeslices); - - // Queue up simulation with desired algorithm - my_simulation.queue( - [&my_algorithm](SimplicialManifold s) { return my_algorithm(s); }); - // Measure results - my_simulation.queue( - [](SimplicialManifold s) { return VolumePerTimeslice(s); }); - // my_simulation.queue(print_results()) - - // Run it - universe = my_simulation.start(std::forward(universe)); - - auto max_timevalue = universe.geometry->max_timevalue().get(); - - if (max_timevalue < timeslices) - std::cout << "You wanted " << timeslices << " timeslices, but only got " - << max_timevalue << " .\n"; - - return 0; -} diff --git a/src/cdt-viewer.cpp b/src/cdt-viewer.cpp new file mode 100644 index 0000000000..f2a4984902 --- /dev/null +++ b/src/cdt-viewer.cpp @@ -0,0 +1,163 @@ +/******************************************************************************* +Causal Dynamical Triangulations in C++ using CGAL +Copyright © 2022 Adam Getchell +******************************************************************************/ + +/// @file cdt-viewer.cpp +/// @brief Views 3D spacetimes +/// @author Adam Getchell + +#ifdef NDEBUG +#define DOCTEST_CONFIG_DISABLE +#endif + +#include + +#define DOCTEST_CONFIG_IMPLEMENT + +#include +#include + +#include + +#include "Manifold.hpp" +#include "Utilities.hpp" + +namespace po = boost::program_options; + +static auto constexpr USAGE = + R"(Causal Dynamical Triangulations in C++ using CGAL. + +Copyright (c) 2022 Adam Getchell + +A program that views 3D triangulated spacetimes with a defined causal +structure. Specify the filename of the triangulation to view. + +Usage: + cdt-viewer -f FILENAME + +Options)"; + +auto main(int const argc, char* const argv[]) -> int +try +{ + // Doctest integration into code + doctest::Context context; + context.setOption("no-breaks", + true); // don't break in debugger when assertions fail + context.applyCommandLine(argc, argv); + + int const res = context.run(); // run tests unless --no-run is specified + if (context.shouldExit()) + { // important - query flags (and --exit) rely on the user doing this + return res; // propagate the result of the tests + } + + context.clearFilters(); // important - otherwise the context filters will be + // used during the next evaluation of RUN_ALL_TESTS, + // which will lead to wrong results + + std::string const intro{USAGE}; + // Parsed arguments + std::string filename; + + po::options_description description(intro); + description.add_options()("help,h", "Show this message")( + "version,v", "Show program version")("dry-run", + "Don't actually do anything")( + "filename,f", po::value(&filename), + "Filename of triangulation to view"); + + po::variables_map args; + po::store(po::parse_command_line(argc, argv, description), args); + po::notify(args); + + if (args.count("help")) + { + std::cout << description << "\n"; + return res + EXIT_SUCCESS; + } + + if (args.count("version")) + { + fmt::print("cdt-viewer 1.0\n"); + return res + EXIT_SUCCESS; + } + + if (args.count("dry-run")) + { + fmt::print("Dry run. Exiting.\n"); + return res + EXIT_SUCCESS; + } + + fmt::print("cdt-viewer started at {}\n", utilities::current_date_time()); + fmt::print("Reading triangulation from file {}\n", + std::string_view(filename)); + + // Read from file + auto const dt_in = utilities::read_file>(filename); + + // Draw triangulation + fmt::print("Drawing {}\n", filename); + draw(dt_in); + + return res + EXIT_SUCCESS; +} + +catch (std::exception const& e) +{ + spdlog::critical("Error: {}\n", e.what()); + return EXIT_FAILURE; +} + +catch (...) +{ + spdlog::critical("Something went wrong ... Exiting.\n"); + return EXIT_FAILURE; +} + +SCENARIO("Given a 3D Manifold, it can be written to file and read back in." * + doctest::test_suite("cdt-viewer")) +{ + GIVEN("A 3D Manifold.") + { + auto constexpr simplices = 640; + auto constexpr timeslices = 4; + manifolds::Manifold_3 const manifold(simplices, timeslices); + + WHEN("It is written to file.") + { + auto const filename = utilities::make_filename(manifold); + utilities::write_file(manifold); + + THEN("It can be read back in.") + { + auto dt_in = utilities::read_file>(filename); + REQUIRE(dt_in.is_valid(true)); + REQUIRE_EQ(dt_in.dimension(), manifold.dimensionality()); + REQUIRE_EQ(dt_in.number_of_finite_cells(), manifold.N3()); + REQUIRE_EQ(dt_in.number_of_finite_facets(), manifold.N2()); + REQUIRE_EQ(dt_in.number_of_finite_edges(), manifold.N1()); + REQUIRE_EQ(dt_in.number_of_vertices(), manifold.N0()); + } + THEN("It can be drawn.") + { + auto const dt_in = utilities::read_file>(filename); + CGAL::draw(dt_in); + // Cleanup test file + REQUIRE_NOTHROW(std::filesystem::remove(filename)); + } + } + } + GIVEN("A non-existent filename.") + { + WHEN("It is read back in.") + { + THEN("An exception is thrown.") + { + REQUIRE_THROWS_AS(utilities::read_file>("unused.off"), + std::filesystem::filesystem_error); + } + } + } +} diff --git a/src/cdt.cpp b/src/cdt.cpp index abd57805b1..39db7c4726 100644 --- a/src/cdt.cpp +++ b/src/cdt.cpp @@ -1,40 +1,31 @@ -/// Causal Dynamical Triangulations in C++ using CGAL -/// -/// Copyright © 2014-2018 Adam Getchell -/// -/// A program that generates spacetimes -/// -/// Inspired by https://github.com/ucdavis/CDT -/// -/// @todo Invoke complete set of ergodic (Pachner) moves -/// @todo Fix write_file() to include cell->info() and vertex->info() +/******************************************************************************* + Causal Dynamical Triangulations in C++ using CGAL + + Copyright © 2013–2026 Adam Getchell + ******************************************************************************/ /// @file cdt.cpp /// @brief The main executable /// @author Adam Getchell -/// @bug -/// scan-build: No bugs found. +/// @details A program that generates spacetime ensembles. Inspired by +/// https://github.com/ucdavis/CDT. -// CGAL headers #include -// C++ headers -#include - -// Docopt -#include "docopt/docopt.h" - -// CDT headers +#include #include -#include +#include using Timer = CGAL::Real_timer; -/// Help message parsed by docopt into options -static const char USAGE[]{ +using namespace std; +namespace po = boost::program_options; + +/// Help text used by Boost.Program_options +static string_view constexpr USAGE{ R"(Causal Dynamical Triangulations in C++ using CGAL. -Copyright (c) 2014-2018 Adam Getchell +Copyright (c) 2013-2026 Adam Getchell A program that generates d-dimensional triangulated spacetimes with a defined causal structure and evolves them according @@ -42,185 +33,255 @@ to the Metropolis algorithm. Specify the number of passes to control how much evolution is desired. Each pass attempts a number of ergodic moves equal to the number of simplices in the simulation. -Usage:./cdt (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES [-d DIM] -k K --alpha ALPHA --lambda LAMBDA [-p PASSES] [-c CHECKPOINT] +Usage:./cdt (--spherical | --toroidal) -n SIMPLICES -t TIMESLICES + [-d DIM] + [--init INITIAL RADIUS] + [--foliate FOLIATION SPACING] + [--no-output] + -k K + --alpha ALPHA + --lambda LAMBDA + [-p PASSES] + [-c CHECKPOINT] + +Optional arguments are in square brackets. Examples: ./cdt --spherical -n 32000 -t 11 --alpha 0.6 -k 1.1 --lambda 0.1 --passes 1000 -./cdt --s -n32000 -t11 -a.6 -k1.1 -l.1 -p1000 - -Options: - -h --help Show this message - --version Show program version - -n SIMPLICES Approximate number of simplices - -t TIMESLICES Number of timeslices - -d DIM Dimensionality [default: 3] - -a --alpha ALPHA Negative squared geodesic length of 1-d - timelike edges - -k K K = 1/(8*pi*G_newton) - -l --lambda LAMBDA K * Cosmological constant - -p --passes PASSES Number of passes [default: 100] - -c --checkpoint CHECKPOINT Checkpoint every n passes [default: 10] -)"}; +./cdt -s -n32000 -t11 -a.6 -k1.1 -l.1 -p1000 + +Options)"}; /// @brief The main path of the CDT++ program -/// -/// @param[in,out] argc Argument count = 1 + number of arguments -/// @param[in,out] argv Argument vector (array) to be passed to docopt -/// @returns Integer value 0 if successful, 1 on failure -int main(int argc, char* const argv[]) +/// @param argc Argument count = 1 + number of arguments +/// @param argv Argument vector passed to Boost.Program_options +/// @return Integer value 0 if successful, 1 on failure +auto main(int const argc, char* const argv[]) -> int +try { - // https://stackoverflow.com/questions/9371238/why-is-reading-lines-from-stdin-much-slower-in-c-than-python?rq=1 - std::ios_base::sync_with_stdio(false); - try + std::string const intro{USAGE}; + // Parsed arguments + topology_type topology; + long long simplices; + long long timeslices; + long long dimensions; + double initial_radius; + double foliation_spacing; + long double alpha; + long double k; + long double lambda; + long long passes; + long long checkpoint; + + po::options_description description(intro); + description.add_options()("help,h", "Show this message")( + "version,v", "Show program version")("spherical,s", "Spherical topology")( + "toroidal,e", "Toroidal topology")("simplices,n", + po::value(&simplices), + "Approximate number of simplices")( + "timeslices,t", po::value(×lices), + "Number of timeslices")( + "dimensions,d", po::value(&dimensions)->default_value(3), + "Dimensionality")("init,i", + po::value(&initial_radius)->default_value(1.0), + "Initial radius")( + "foliate,f", po::value(&foliation_spacing)->default_value(1.0), + "Foliation spacing")( + "no-output", "Do not write checkpoint or final triangulation files")( + "alpha,a", po::value(&alpha)->required(), + "Negative squared geodesic length of 1-d timelike edges")( + "k,k", po::value(&k)->required(), "K = 1/(8*pi*G_newton)")( + "lambda,l", po::value(&lambda)->required(), + "K * Cosmological constant")( + "passes,p", po::value(&passes)->default_value(100), + "Number of passes")("checkpoint,c", + po::value(&checkpoint)->default_value(10), + "Checkpoint every n passes"); + + po::variables_map args; + po::store(po::parse_command_line(argc, argv, description), args); + + if (args.count("help")) + { + cout << description << "\n"; + return EXIT_SUCCESS; + } + + if (args.count("version")) + { + fmt::print("CDT++ version 0.1.8\n"); + return EXIT_SUCCESS; + } + + po::notify(args); + auto const write_files = !args.count("no-output"); + + if (args.count("spherical")) { topology = topology_type::SPHERICAL; } + else if (args.count("toroidal")) { topology = topology_type::TOROIDAL; } + else + { + fmt::print("Topology not specified.\n"); + return EXIT_FAILURE; + } + + if (args.count("simplices")) + { + simplices = args["simplices"].as(); + } + else + { + fmt::print("Number of simplices not specified.\n"); + return EXIT_FAILURE; + } + + if (args.count("timeslices")) + { + timeslices = args["timeslices"].as(); + } + else + { + fmt::print("Number of timeslices not specified.\n"); + return EXIT_FAILURE; + } + + // Display job parameters + fmt::print("Topology is {}\n", utilities::topology_to_str(topology)); + fmt::print("Dimensionality: {}+{}\n", dimensions - 1, 1); + fmt::print("Initial radius: {}\n", initial_radius); + fmt::print("Foliation spacing: {}\n", foliation_spacing); + fmt::print("Number of desired simplices: {}\n", simplices); + fmt::print("Number of desired timeslices: {}\n", timeslices); + fmt::print("Number of passes: {}\n", passes); + fmt::print("Checkpoint every {} passes.\n", checkpoint); + fmt::print("=== Parameters ===\n"); + fmt::print("Alpha: {}\n", alpha); + fmt::print("K: {}\n", k); + fmt::print("Lambda: {}\n", lambda); + + // Start running time + Timer timer; + timer.start(); + fmt::print("cdt started at {}\n", utilities::current_date_time()); + + if (simplices < 2 || timeslices < 2) { - // Start running time - Timer t; - t.start(); - - // docopt option parser - std::map args = - docopt::docopt(USAGE, {argv + 1, argv + argc}, - true, // print help message automatically - "CDT 0.1.8"); // Version - - // Debugging - // for (auto const& arg : args) { - // std::cout << arg.first << " " << arg.second << "\n"; - // } - - // Parse docopt::values in args map - auto simplices = std::stol(args["-n"].asString()); - auto timeslices = std::stol(args["-t"].asString()); - auto dimensions = std::stol(args["-d"].asString()); - auto alpha = std::stold(args["--alpha"].asString()); - auto k = std::stold(args["-k"].asString()); - auto lambda = std::stold(args["--lambda"].asString()); - auto passes = std::stol(args["--passes"].asString()); - auto checkpoint = std::stol(args["--checkpoint"].asString()); - - // Topology of simulation - topology_type topology; - if (args["--spherical"].asBool()) { - topology = topology_type::SPHERICAL; - } - else - { - topology = topology_type::TOROIDAL; - } - - // Display job parameters - std::cout << "Topology is " - << (topology == topology_type::TOROIDAL ? " toroidal " - : "spherical ") - << "\n"; - std::cout << "Number of dimensions = " << dimensions << "\n"; - std::cout << "Number of simplices = " << simplices << "\n"; - std::cout << "Number of timeslices = " << timeslices << "\n"; - std::cout << "Alpha = " << alpha << "\n"; - std::cout << "K = " << k << "\n"; - std::cout << "Lambda = " << lambda << "\n"; - std::cout << "Number of passes = " << passes << "\n"; - std::cout << "Checkpoint every n passes = " << checkpoint << "\n"; - std::cout << "User = " << getEnvVar("USER") << "\n"; - std::cout << "Hostname = " << hostname() << "\n"; - - if (simplices < 2 || timeslices < 2) { - t.stop(); - throw std::invalid_argument( - "Simplices and timeslices should be greater or equal to 2."); - } - - // Initialize simulation - Simulation my_simulation; - - // Initialize the Metropolis algorithm - // \todo: add strong exception-safety guarantee on Metropolis functor - Metropolis my_algorithm(alpha, k, lambda, passes, checkpoint); - - // Initialize triangulation - SimplicialManifold universe; - - // Queue up simulation with desired algorithm - my_simulation.queue( - [&my_algorithm](SimplicialManifold s) { return my_algorithm(s); }); - - // Measure results - my_simulation.queue( - [](SimplicialManifold s) { return VolumePerTimeslice(s); }); - - // Ensure Triangle inequalities hold - // See http://arxiv.org/abs/hep-th/0105267 for details - if (dimensions == 3 && std::abs(alpha) < 0.5) { - t.stop(); // End running time counter - throw std::domain_error("Alpha in 3D should be greater than 1/2."); - } - - switch (topology) - { - case topology_type::SPHERICAL: - if (dimensions == 3) { - SimplicialManifold populated_universe(simplices, timeslices); - // SimplicialManifold swapperator for no-throw - swap(universe, populated_universe); - } - else - { - t.stop(); // End running time counter - throw std::invalid_argument("Currently, dimensions cannot be >3."); - } - break; - case topology_type::TOROIDAL: - t.stop(); // End running time counter - throw std::invalid_argument( - "Toroidal triangulations not yet supported."); // NOLINT - } - - if (!fix_timeslices(universe.triangulation)) { - t.stop(); // End running time counter - throw std::logic_error("Delaunay triangulation not correctly foliated."); - } - - std::cout << "Universe has been initialized ...\n"; - std::cout << "Now performing " << passes << " passes of ergodic moves.\n"; - - // The main work of the program - universe = my_simulation.start(std::move(universe)); - - // Output results - t.stop(); // End running time counter - std::cout << "Final Delaunay triangulation has "; - print_results(universe, t); - - // Write results to file - // Strong exception-safety guarantee - // \todo: Fixup so that cell->info() and vertex->info() values - // are written - write_file(universe, topology, dimensions, - universe.triangulation->number_of_finite_cells(), timeslices); - - return 0; + timer.stop(); + throw invalid_argument( + "Simplices and timeslices should be greater or equal to 2."); } - catch (std::domain_error& DomainError) + + if (passes < 0) + { + timer.stop(); + throw invalid_argument("Passes cannot be negative."); + } + if (checkpoint <= 0) { - std::cerr << DomainError.what() << "\n"; - std::cerr << "Triangle inequalities violated ... Exiting.\n"; - return 1; + timer.stop(); + throw invalid_argument("Checkpoint interval must be positive."); } - catch (std::invalid_argument& InvalidArgument) + if (!std::in_range(simplices) || + !std::in_range(timeslices) || + !std::in_range(passes) || + !std::in_range(checkpoint)) { - std::cerr << InvalidArgument.what() << "\n"; - std::cerr << "Invalid parameter ... Exiting.\n"; - return 1; + timer.stop(); + throw out_of_range("Integer argument exceeds the supported range."); } - catch (std::logic_error& LogicError) + + // Ensure Triangle inequalities hold + // See http://arxiv.org/abs/hep-th/0105267 for details + if (dimensions == 3 && abs(alpha) < static_cast(0.5)) // NOLINT { - std::cerr << LogicError.what() << "\n"; - std::cerr << "Simulation startup failed ... Exiting.\n"; - return 1; + timer.stop(); // End running time counter + throw domain_error("Alpha in 3D should be greater than 1/2."); } - catch (...) + + // Initialize the Metropolis algorithm + Metropolis_3 run(alpha, k, lambda, static_cast(passes), + static_cast(checkpoint), write_files); + + // Make a triangulation + manifolds::Manifold_3 universe; + + switch (topology) { - std::cerr << "Something went wrong ... Exiting.\n"; - return 1; + case topology_type::SPHERICAL: + if (dimensions == 3) + { + manifolds::Manifold_3 populated_universe( + static_cast(simplices), + static_cast(timeslices), initial_radius, + foliation_spacing); + // Manifold no-throw swapperator + swap(populated_universe, universe); + } + else + { + timer.stop(); // End running time counter + throw invalid_argument("Currently, dimensions cannot be >3."); + } + break; + case topology_type::TOROIDAL: + timer.stop(); // End running time counter + throw invalid_argument("Toroidal triangulations not yet supported."); } + + // Look at triangulation + universe.print(); + universe.print_details(); + universe.print_volume_per_timeslice(); + + // The main work of the program + auto const result = run(universe); + + // Do we have enough timeslices? + if (auto max_timevalue = result.max_time(); max_timevalue < timeslices) + { + fmt::print("You wanted {} timeslices, but only got {}.\n", timeslices, + max_timevalue); + } + + if (!result.is_valid()) { throw runtime_error("Result is invalid!\n"); } + + // Print results + timer.stop(); // End running time counter + fmt::print("=== Run Results ===\n"); + fmt::print("Running time is {} seconds.\n", timer.time()); + result.print(); + result.print_details(); + result.print_volume_per_timeslice(); + + // Write results to file + if (write_files) { utilities::write_file(result); } + + return EXIT_SUCCESS; +} +catch (domain_error const& DomainError) +{ + spdlog::critical("{}\n", DomainError.what()); + spdlog::critical("Triangle inequalities violated ... Exiting.\n"); + return EXIT_FAILURE; +} +catch (invalid_argument const& InvalidArgument) +{ + spdlog::critical("{}\n", InvalidArgument.what()); + spdlog::critical("Invalid parameter ... Exiting.\n"); + return EXIT_FAILURE; +} +catch (logic_error const& LogicError) +{ + spdlog::critical("{}\n", LogicError.what()); + spdlog::critical("Simulation startup failed ... Exiting.\n"); + return EXIT_FAILURE; +} +catch (runtime_error const& RuntimeError) +{ + spdlog::critical("{}\n", RuntimeError.what()); + return EXIT_FAILURE; +} +catch (...) +{ + spdlog::critical("Something went wrong ... Exiting.\n"); + return EXIT_FAILURE; } diff --git a/src/date/.gitignore b/src/date/.gitignore deleted file mode 100644 index 312695916c..0000000000 --- a/src/date/.gitignore +++ /dev/null @@ -1,194 +0,0 @@ -#ignore thumbnails created by windows -Thumbs.db -#Ignore files build by Visual Studio -*.obj -*.exe -*.pdb -*.user -*.aps -*.pch -*.vspscc -*_i.c -*_p.c -*.ncb -*.suo -*.tlb -*.tlh -*.bak -*.cache -*.ilk -*.log -[Bb]in -[Dd]ebug*/ -*.lib -*.sbr -obj/ -[Rr]elease*/ -_ReSharper*/ -[Tt]est[Rr]esult* -.idea/ -*.opensdf -## Ignore Visual Studio temporary files, build results, and -## files generated by popular Visual Studio add-ons. -# User-specific files -*.suo -*.user -*.userosscache -*.sln.docstates -# User-specific folders -*.sln.ide/ -# Build results -[Dd]ebug/ -[Dd]ebugPublic/ -[Rr]elease/ -[Rr]eleases/ -x64/ -x86/ -build/ -bld/ -[Bb]in/ -[Oo]bj/ -# Roslyn cache directories -*.ide/ -# MSTest test Results -[Tt]est[Rr]esult*/ -[Bb]uild[Ll]og.* -#NUNIT -*.VisualState.xml -TestResult.xml -# Build Results of an ATL Project -[Dd]ebugPS/ -[Rr]eleasePS/ -dlldata.c -*_i.c -*_p.c -*_i.h -*.ilk -*.meta -*.obj -*.pch -*.pdb -*.pgc -*.pgd -*.rsp -*.sbr -*.tlb -*.tli -*.tlh -*.tmp -*.tmp_proj -*.log -*.vspscc -*.vssscc -.builds -*.pidb -*.svclog -*.scc -# Chutzpah Test files -_Chutzpah* -# Visual C++ cache files -ipch/ -*.aps -*.ncb -*.opensdf -*.sdf -*.cachefile -# Visual Studio profiler -*.psess -*.vsp -*.vspx -# TFS 2012 Local Workspace -$tf/ -# Guidance Automation Toolkit -*.gpState -# ReSharper is a .NET coding add-in -_ReSharper*/ -*.[Rr]e[Ss]harper -*.DotSettings.user -# JustCode is a .NET coding addin-in -.JustCode -# TeamCity is a build add-in -_TeamCity* -# DotCover is a Code Coverage Tool -*.dotCover -# NCrunch -_NCrunch_* -.*crunch*.local.xml -# MightyMoose -*.mm.* -AutoTest.Net/ -# Web workbench (sass) -.sass-cache/ -# Installshield output folder -[Ee]xpress/ -# DocProject is a documentation generator add-in -DocProject/buildhelp/ -DocProject/Help/*.HxT -DocProject/Help/*.HxC -DocProject/Help/*.hhc -DocProject/Help/*.hhk -DocProject/Help/*.hhp -DocProject/Help/Html2 -DocProject/Help/html -# Click-Once directory -publish/ -# Publish Web Output -*.[Pp]ublish.xml -*.azurePubxml -# TODO: Comment the next line if you want to checkin your web deploy settings -# but database connection strings (with potential passwords) will be unencrypted -*.pubxml -*.publishproj -# NuGet Packages -*.nupkg -# The packages folder can be ignored because of Package Restore -**/packages/* -# except build/, which is used as an MSBuild target. -!**/packages/build/ -# If using the old MSBuild-Integrated Package Restore, uncomment this: -#!**/packages/repositories.config -# Windows Azure Build Output -csx/ -*.build.csdef -# Windows Store app package directory -AppPackages/ -# Others -sql/ -*.Cache -ClientBin/ -[Ss]tyle[Cc]op.* -~$* -*~ -*.dbmdl -*.dbproj.schemaview -*.pfx -*.publishsettings -node_modules/ -bower_components/ -# RIA/Silverlight projects -Generated_Code/ -# Backup & report files from converting an old project file -# to a newer Visual Studio version. Backup files are not needed, -# because we have git ;-) -_UpgradeReport_Files/ -Backup*/ -UpgradeLog*.XML -UpgradeLog*.htm -# SQL Server files -*.mdf -*.ldf -# Business Intelligence projects -*.rdl.data -*.bim.layout -*.bim_*.settings -# Microsoft Fakes -FakesAssemblies/ -*.suo -*.vcxproj.filters -*.npp -CMakeFiles/* -nbproject/* -*.cd -*.cd -a.out -cmake-build-debug/* diff --git a/src/date/.gitrepo b/src/date/.gitrepo deleted file mode 100644 index d3e24478b7..0000000000 --- a/src/date/.gitrepo +++ /dev/null @@ -1,11 +0,0 @@ -; DO NOT EDIT (unless you know what you are doing) -; -; This subdirectory is a git "subrepo", and this file is maintained by the -; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme -; -[subrepo] - remote = https://github.com/HowardHinnant/date.git - branch = master - commit = 55289f0d73b51b21ed02ec27114384ebd7b94d6c - parent = 7a6cbe4612f95ad9a0ead72273727d548ed541d7 - cmdver = 0.3.1 diff --git a/src/date/CMakeLists.txt b/src/date/CMakeLists.txt deleted file mode 100644 index 4a167ba0b2..0000000000 --- a/src/date/CMakeLists.txt +++ /dev/null @@ -1,158 +0,0 @@ -cmake_minimum_required( VERSION 3.0.2 ) - -project( date_prj ) - -find_package( Threads REQUIRED ) - -enable_testing( ) - -option( USE_SYSTEM_TZ_DB "Use the operating system's timezone database" OFF ) -option( USE_TZ_DB_IN_DOT "Save the timezone database in the current folder" OFF ) -option( BUILD_TZ_STATIC "Build a static version of library" ON ) - -function( print_option OPT ) - if ( NOT DEFINED PRINT_OPTION_CURR_${OPT} OR ( NOT PRINT_OPTION_CURR_${OPT} STREQUAL ${OPT} ) ) - set( PRINT_OPTION_CURR_${OPT} ${${OPT}} CACHE BOOL "" ) - mark_as_advanced(PRINT_OPTION_CURR_${OPT}) - message( "# date: ${OPT} ${${OPT}}" ) - endif( ) -endfunction( ) - -print_option( USE_SYSTEM_TZ_DB ) -print_option( USE_TZ_DB_IN_DOT ) -print_option( BUILD_TZ_STATIC ) - -if( USE_SYSTEM_TZ_DB ) - add_definitions( -DUSE_AUTOLOAD=0 ) - add_definitions( -DHAS_REMOTE_API=0 ) - # cannot set USE_OS_TZDB to 1 on Windows - if( NOT WIN32 ) - add_definitions( -DUSE_OS_TZDB=1 ) - endif( ) -else( ) - add_definitions( -DUSE_AUTOLOAD=1 ) - add_definitions( -DHAS_REMOTE_API=1 ) - add_definitions( -DUSE_OS_TZDB=0 ) - find_package( CURL REQUIRED ) - include_directories( SYSTEM ${CURL_INCLUDE_DIRS} ) - set( OPTIONAL_LIBRARIES ${CURL_LIBRARIES} ) -endif( ) - -if( USE_TZ_DB_IN_DOT ) - add_definitions( -DINSTALL=. ) -endif( ) - -set( HEADER_FOLDER "include" ) -set( SOURCE_FOLDER "src" ) -set( TEST_FOLDER "test" ) - -# This is needed so IDE's live MSVC show header files -set( HEADER_FILES - ${HEADER_FOLDER}/date/chrono_io.h - ${HEADER_FOLDER}/date/date.h - ${HEADER_FOLDER}/date/ios.h - ${HEADER_FOLDER}/date/islamic.h - ${HEADER_FOLDER}/date/iso_week.h - ${HEADER_FOLDER}/date/julian.h - ${HEADER_FOLDER}/date/tz.h - ${HEADER_FOLDER}/date/tz_private.h -) - -if( BUILD_TZ_STATIC ) - add_library( tz STATIC ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp ) -else( ) - add_library( tz SHARED ${HEADER_FILES} ${SOURCE_FOLDER}/tz.cpp ) -endif( ) - -if( NOT TZ_CXX_STANDARD ) - set( TZ_CXX_STANDARD 17 ) -endif( ) - -set_property(TARGET tz PROPERTY CXX_STANDARD ${TZ_CXX_STANDARD}) -target_link_libraries( tz ${CMAKE_THREAD_LIBS_INIT} ${OPTIONAL_LIBRARIES} ) - -# add include folders to the library and targets that consume it -target_include_directories(tz PUBLIC - $ - $ -) - -add_library(date_interface INTERFACE) # an interface (not a library), to enable automatic include_directory (for when just date.h, but not "tz.h and its lib" are needed) - -# add include folders to the INTERFACE and targets that consume it -target_include_directories(date_interface INTERFACE - $ - $ -) - - -install( TARGETS tz DESTINATION lib ) -install( DIRECTORY ${HEADER_FOLDER}/ DESTINATION include/ ) - -add_custom_target( testit COMMAND ${CMAKE_CTEST_COMMAND} ) - -add_dependencies( testit tz ) -function( add_pass_tests TEST_GLOB TEST_PREFIX ) - file( GLOB_RECURSE FILENAMES ${TEST_GLOB} ) - include_directories( "${HEADER_FOLDER}/date" ) - - foreach( TEST_FILE ${FILENAMES} ) - get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE ) - get_filename_component( TEST_EXT ${TEST_FILE} EXT ) - if( NOT ${TEST_EXT} STREQUAL ".fail.cpp" ) - set( PREFIX "${TEST_PREFIX}_pass_${TEST_NAME}" ) - set( BIN_NAME ${PREFIX}_bin ) - set( TST_NAME ${PREFIX}_test ) - add_executable( ${BIN_NAME} EXCLUDE_FROM_ALL ${TEST_FILE} ) - set_property(TARGET ${BIN_NAME} PROPERTY CXX_STANDARD ${TZ_CXX_STANDARD}) - add_test( ${TST_NAME} ${BIN_NAME} ) - target_link_libraries( ${BIN_NAME} tz ) - add_dependencies( testit ${BIN_NAME} ) - endif( ) - endforeach( ) -endfunction( ) - -function( add_fail_tests TEST_GLOB TEST_PREFIX ) - file( GLOB_RECURSE FILENAMES ${TEST_GLOB} ) - - foreach( TEST_FILE ${FILENAMES} ) - get_filename_component( TEST_NAME ${TEST_FILE} NAME_WE ) - get_filename_component( TEST_EXT ${TEST_FILE} EXT ) - - set( TEST_TYPE "_fail" ) - - set( PREFIX "${TEST_PREFIX}_fail_${TEST_NAME}" ) - set( BIN_NAME ${PREFIX}_bin ) - set( TST_NAME ${PREFIX}_test ) - - #target_compile_definitions( ${BIN_NAME} PRIVATE ${TST_NAME} ) - set( TEST_BIN_NAME ${CMAKE_BINARY_DIR}/${BIN_NAME} ) - add_custom_target( ${BIN_NAME} - COMMAND ${PROJECT_SOURCE_DIR}/compile_fail.sh ${TEST_BIN_NAME} ${CMAKE_CXX_COMPILER} -std=c++14 -L${CMAKE_BINARY_DIR}/ -ltz -I${PROJECT_SOURCE_DIR}/${HEADER_FOLDER}/date -o ${BIN_NAME} ${TEST_FILE} - WORKING_DIRECTORY ${CMAKE_BINARY_DIR} - COMMENT ${TST_NAME} - ) - add_test( ${TST_NAME} "${PROJECT_SOURCE_DIR}/test_fail.sh" ${CMAKE_BINARY_DIR}/${BIN_NAME} WORKING_DIRECTORY "${PROJECT_SOURCE_DIR}/" ) - #set_tests_properties( ${TST_NAME} PROPERTIES WILL_FAIL TRUE) - add_dependencies( testit ${BIN_NAME} ) - endforeach( ) -endfunction( ) - -file( GLOB children RELATIVE "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}" "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/*" ) -foreach( child ${children} ) - if( IS_DIRECTORY "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" ) - set( CUR_FOLDER "${PROJECT_SOURCE_DIR}/${TEST_FOLDER}/${child}" ) - add_pass_tests( "${CUR_FOLDER}/*.cpp" ${child} ) - if( NOT WIN32 ) - add_fail_tests( "${CUR_FOLDER}/*.fail.cpp" ${child} ) - endif( ) - endif( ) -endforeach( ) diff --git a/src/date/LICENSE.txt b/src/date/LICENSE.txt deleted file mode 100644 index 79ea0698bb..0000000000 --- a/src/date/LICENSE.txt +++ /dev/null @@ -1,31 +0,0 @@ -The source code in this project is released using the MIT License. There is no -global license for the project because each file is licensed individually with -different author names and/or dates. - -If you contribute to this project, please add your name to the license of each -file you modify. If you have already contributed to this project and forgot to -add your name to the license, please feel free to submit a new P/R to add your -name to the license in each file you modified. - -For convenience, here is a copy of the MIT license found in each file except -without author names or dates: - -The MIT License (MIT) - -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/src/date/README.md b/src/date/README.md deleted file mode 100644 index 4c713f7c31..0000000000 --- a/src/date/README.md +++ /dev/null @@ -1,43 +0,0 @@ -[![Join the chat at https://gitter.im/HowardHinnant/date](https://badges.gitter.im/HowardHinnant/date.svg)](https://gitter.im/HowardHinnant/date?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge) -
- -**[Try it out on wandbox!](https://wandbox.org/permlink/vqwMyTphHJv5iXX7)** - -This is actually several separate C++11/C++14 libraries: - -1. `"date.h"` is a header-only library which builds upon ``. It adds some new `duration` types, and new `time_point` types. It also adds "field" types such as `year_month_day` which is a struct `{year, month, day}`. And it provides convenient means to convert between the "field" types and the `time_point` types. - - * Documentation: http://howardhinnant.github.io/date/date.html - * Video: https://www.youtube.com/watch?v=tzyGjOm8AKo - * Slides: http://schd.ws/hosted_files/cppcon2015/43/hinnant_dates.pdf - -2. `"tz.h"` / `"tz.cpp"` are a timezone library built on top of the `"date.h"` library. This timezone library is a complete parser of the IANA timezone database. It provides for an easy way to access all of the data in this database, using the types from `"date.h"` and ``. The IANA database also includes data on leap seconds, and this library provides utilities to compute with that information as well. - - * Documentation: http://howardhinnant.github.io/date/tz.html - * Video: https://www.youtube.com/watch?v=Vwd3pduVGKY - * Slides: http://schd.ws/hosted_files/cppcon2016/0f/Welcome%20To%20The%20Time%20Zone%20-%20Howard%20Hinnant%20-%20CppCon%202016.pdf - -3. `"iso_week.h"` is a header-only library built on top of the `"date.h"` library which implements the ISO week date calendar. - - * Documentation: http://howardhinnant.github.io/date/iso_week.html - -4. `"julian.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Julian calendar which is fully interoperable with everything above. - - * Documentation: http://howardhinnant.github.io/date/julian.html - -5. `"islamic.h"` is a header-only library built on top of the `"date.h"` library which implements a proleptic Islamic calendar which is fully interoperable with everything above. - - * Documentation: http://howardhinnant.github.io/date/islamic.html - -`"date.h"` and `"tz.h"` are now being proposed for standardization: - - * Current proposal: http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2017/p0355r4.html - * Draft revision: http://howardhinnant.github.io/date/d0355r5.html - * Status: The proposal was approved by LEWG and forwarded to LWG with the recommendation of targeting C++20 at the Albuquerque, NM meeting in Nov. 2017. - -List of projects using this library: - - * www.safe.com - * www.webtoolkit.eu/wt - -If you would like your project (or product) on this list, just let me know. diff --git a/src/date/compile_fail.sh b/src/date/compile_fail.sh deleted file mode 100755 index b6a776a452..0000000000 --- a/src/date/compile_fail.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/bin/bash -export TEST_BIN_NAME=$1 -#echo "Building ${TEST_BIN_NAME}" -shift 1 -export BUILD_COMMAND=$@ -#echo "Build command: ${BUILD_COMMAND}" -eval ${BUILD_COMMAND} >/dev/null 2>/dev/null - -if [ $? -eq 0 ]; then - echo -ne "#!/bin/bash\nexit 1;" > ${TEST_BIN_NAME} -else - echo -ne "#!/bin/bash\nexit 0;" > ${TEST_BIN_NAME} -fi -chmod u+x ${TEST_BIN_NAME} -exit 0; diff --git a/src/date/include/date/chrono_io.h b/src/date/include/date/chrono_io.h deleted file mode 100644 index 21be404097..0000000000 --- a/src/date/include/date/chrono_io.h +++ /dev/null @@ -1,34 +0,0 @@ -#ifndef CHRONO_IO_H -#define CHRONO_IO_H - -// The MIT License (MIT) -// -// Copyright (c) 2016, 2017 Howard Hinnant -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -// This functionality has moved to "date.h" - -#include "date.h" - -#endif // CHRONO_IO_H diff --git a/src/date/include/date/date.h b/src/date/include/date/date.h deleted file mode 100644 index 6f1e2f4f27..0000000000 --- a/src/date/include/date/date.h +++ /dev/null @@ -1,8010 +0,0 @@ -#ifndef DATE_H -#define DATE_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// Copyright (c) 2016 Adrian Colomitchi -// Copyright (c) 2017 Florian Dang -// Copyright (c) 2017 Paul Thompson -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#ifndef HAS_STRING_VIEW -# if __cplusplus >= 201703 -# define HAS_STRING_VIEW 1 -# else -# define HAS_STRING_VIEW 0 -# endif -#endif // HAS_STRING_VIEW - -#include -#include -#include -#include -#include -#if !(__cplusplus >= 201402) -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if HAS_STRING_VIEW -# include -#endif -#include -#include - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wpedantic" -# if __GNUC__ < 5 - // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -# endif -#endif - -namespace date -{ - -//---------------+ -// Configuration | -//---------------+ - -#ifndef ONLY_C_LOCALE -# define ONLY_C_LOCALE 0 -#endif - -#if defined(_MSC_VER) && (!defined(__clang__) || (_MSC_VER < 1910)) -// MSVC -# if _MSC_VER < 1910 -// before VS2017 -# define CONSTDATA const -# define CONSTCD11 -# define CONSTCD14 -# define NOEXCEPT _NOEXCEPT -# else -// VS2017 and later -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 constexpr -# define NOEXCEPT noexcept -# endif - -#elif defined(__SUNPRO_CC) && __SUNPRO_CC <= 0x5150 -// Oracle Developer Studio 12.6 and earlier -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 -# define NOEXCEPT noexcept - -#elif __cplusplus >= 201402 -// C++14 -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 constexpr -# define NOEXCEPT noexcept -#else -// C++11 -# define CONSTDATA constexpr const -# define CONSTCD11 constexpr -# define CONSTCD14 -# define NOEXCEPT noexcept -#endif - -#ifndef HAS_VOID_T -# if __cplusplus >= 201703 -# define HAS_VOID_T 1 -# else -# define HAS_VOID_T 0 -# endif -#endif // HAS_VOID_T - -// Protect from Oracle sun macro -#ifdef sun -# undef sun -#endif - -//-----------+ -// Interface | -//-----------+ - -// durations - -using days = std::chrono::duration - , std::chrono::hours::period>>; - -using weeks = std::chrono::duration - , days::period>>; - -using years = std::chrono::duration - , days::period>>; - -using months = std::chrono::duration - >>; - -// time_point - -template - using sys_time = std::chrono::time_point; - -using sys_days = sys_time; -using sys_seconds = sys_time; - -struct local_t {}; - -template - using local_time = std::chrono::time_point; - -using local_seconds = local_time; -using local_days = local_time; - -// types - -struct last_spec -{ - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day -{ - unsigned char d_; - -public: - day() = default; - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d); - -// month - -class month -{ - unsigned char m_; - -public: - month() = default; - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m); - -// year - -class year -{ - short y_; - -public: - year() = default; - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 year operator-() const NOEXCEPT; - CONSTCD11 year operator+() const NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday -{ - unsigned char wd_; -public: - weekday() = default; - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed -{ - unsigned char wd_ : 4; - unsigned char index_ : 4; - -public: - weekday_indexed() = default; - CONSTCD11 weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last -{ - date::weekday wd_; - -public: - explicit CONSTCD11 weekday_last(const date::weekday& wd) NOEXCEPT; - - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl); - -// year_month - -class year_month -{ - date::year y_; - date::month m_; - -public: - year_month() = default; - CONSTCD11 year_month(const date::year& y, const date::month& m) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day -{ - date::month m_; - date::day d_; - -public: - month_day() = default; - CONSTCD11 month_day(const date::month& m, const date::day& d) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last -{ - date::month m_; - -public: - CONSTCD11 explicit month_day_last(const date::month& m) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday -{ - date::month m_; - date::weekday_indexed wdi_; -public: - CONSTCD11 month_weekday(const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last -{ - date::month m_; - date::weekday_last wdl_; - -public: - CONSTCD11 month_weekday_last(const date::month& m, - const date::weekday_last& wd) NOEXCEPT; - - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day -{ - date::year y_; - date::month m_; - date::day d_; - -public: - year_month_day() = default; - CONSTCD11 year_month_day(const date::year& y, const date::month& m, - const date::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last -{ - date::year y_; - date::month_day_last mdl_; - -public: - CONSTCD11 year_month_day_last(const date::year& y, - const date::month_day_last& mdl) NOEXCEPT; - - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 date::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday -{ - date::year y_; - date::month m_; - date::weekday_indexed wdi_; - -public: - year_month_weekday() = default; - CONSTCD11 year_month_weekday(const date::year& y, const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 date::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last -{ - date::year y_; - date::month m_; - date::weekday_last wdl_; - -public: - CONSTCD11 year_month_weekday_last(const date::year& y, const date::month& m, - const date::weekday_last& wdl) NOEXCEPT; - - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 date::year year() const NOEXCEPT; - CONSTCD11 date::month month() const NOEXCEPT; - CONSTCD11 date::weekday weekday() const NOEXCEPT; - CONSTCD11 date::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 date::day operator "" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 date::year operator "" _y(unsigned long long y) NOEXCEPT; - -// CONSTDATA date::month jan{1}; -// CONSTDATA date::month feb{2}; -// CONSTDATA date::month mar{3}; -// CONSTDATA date::month apr{4}; -// CONSTDATA date::month may{5}; -// CONSTDATA date::month jun{6}; -// CONSTDATA date::month jul{7}; -// CONSTDATA date::month aug{8}; -// CONSTDATA date::month sep{9}; -// CONSTDATA date::month oct{10}; -// CONSTDATA date::month nov{11}; -// CONSTDATA date::month dec{12}; -// -// CONSTDATA date::weekday sun{0u}; -// CONSTDATA date::weekday mon{1u}; -// CONSTDATA date::weekday tue{2u}; -// CONSTDATA date::weekday wed{3u}; -// CONSTDATA date::weekday thu{4u}; -// CONSTDATA date::weekday fri{5u}; -// CONSTDATA date::weekday sat{6u}; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -#if HAS_VOID_T - -template > -struct is_clock - : std::false_type -{}; - -template -struct is_clock> - : std::true_type -{}; - -#endif // HAS_VOID_T - -//----------------+ -// Implementation | -//----------------+ - -// utilities -namespace detail { - -template> -class save_stream -{ - std::basic_ostream& os_; - CharT fill_; - std::ios::fmtflags flags_; - std::locale loc_; - -public: - ~save_stream() - { - os_.fill(fill_); - os_.flags(flags_); - os_.imbue(loc_); - } - - save_stream(const save_stream&) = delete; - save_stream& operator=(const save_stream&) = delete; - - explicit save_stream(std::basic_ostream& os) - : os_(os) - , fill_(os.fill()) - , flags_(os.flags()) - , loc_(os.getloc()) - {} -}; - -template -struct choose_trunc_type -{ - static const int digits = std::numeric_limits::digits; - using type = typename std::conditional - < - digits < 32, - std::int32_t, - typename std::conditional - < - digits < 64, - std::int64_t, -#ifdef __SIZEOF_INT128__ - __int128 -#else - std::int64_t -#endif - >::type - >::type; -}; - -template -CONSTCD11 -inline -typename std::enable_if -< - !std::chrono::treat_as_floating_point::value, - T ->::type -trunc(T t) NOEXCEPT -{ - return t; -} - -template -CONSTCD14 -inline -typename std::enable_if -< - std::chrono::treat_as_floating_point::value, - T ->::type -trunc(T t) NOEXCEPT -{ - using namespace std; - using I = typename choose_trunc_type::type; - CONSTDATA auto digits = numeric_limits::digits; - static_assert(digits < numeric_limits::digits, ""); - CONSTDATA auto max = I{1} << (digits-1); - CONSTDATA auto min = -max; - const auto negative = t < T{0}; - if (min <= t && t <= max && t != 0 && t == t) - { - t = static_cast(static_cast(t)); - if (t == 0 && negative) - t = -t; - } - return t; -} - -template -struct static_gcd -{ - static const std::intmax_t value = static_gcd::value; -}; - -template -struct static_gcd -{ - static const std::intmax_t value = Xp; -}; - -template <> -struct static_gcd<0, 0> -{ - static const std::intmax_t value = 1; -}; - -template -struct no_overflow -{ -private: - static const std::intmax_t gcd_n1_n2 = static_gcd::value; - static const std::intmax_t gcd_d1_d2 = static_gcd::value; - static const std::intmax_t n1 = R1::num / gcd_n1_n2; - static const std::intmax_t d1 = R1::den / gcd_d1_d2; - static const std::intmax_t n2 = R2::num / gcd_n1_n2; - static const std::intmax_t d2 = R2::den / gcd_d1_d2; - static const std::intmax_t max = -((std::intmax_t(1) << - (sizeof(std::intmax_t) * CHAR_BIT - 1)) + 1); - - template - struct mul // overflow == false - { - static const std::intmax_t value = Xp * Yp; - }; - - template - struct mul - { - static const std::intmax_t value = 1; - }; - -public: - static const bool value = (n1 <= max / d2) && (n2 <= max / d1); - typedef std::ratio::value, - mul::value> type; -}; - -} // detail - -// trunc towards zero -template -CONSTCD11 -inline -typename std::enable_if -< - detail::no_overflow::value, - To ->::type -trunc(const std::chrono::duration& d) -{ - return To{detail::trunc(std::chrono::duration_cast(d).count())}; -} - -template -CONSTCD11 -inline -typename std::enable_if -< - !detail::no_overflow::value, - To ->::type -trunc(const std::chrono::duration& d) -{ - using namespace std::chrono; - using rep = typename std::common_type::type; - return To{detail::trunc(duration_cast(duration_cast>(d)).count())}; -} - -#ifndef HAS_CHRONO_ROUNDING -# if defined(_MSC_FULL_VER) && (_MSC_FULL_VER >= 190023918 || (_MSC_FULL_VER >= 190000000 && defined (__clang__))) -# define HAS_CHRONO_ROUNDING 1 -# elif defined(__cpp_lib_chrono) && __cplusplus > 201402 && __cpp_lib_chrono >= 201510 -# define HAS_CHRONO_ROUNDING 1 -# elif defined(_LIBCPP_VERSION) && __cplusplus > 201402 && _LIBCPP_VERSION >= 3800 -# define HAS_CHRONO_ROUNDING 1 -# else -# define HAS_CHRONO_ROUNDING 0 -# endif -#endif // HAS_CHRONO_ROUNDING - -#if HAS_CHRONO_ROUNDING == 0 - -// round down -template -CONSTCD14 -inline -typename std::enable_if -< - detail::no_overflow::value, - To ->::type -floor(const std::chrono::duration& d) -{ - auto t = trunc(d); - if (t > d) - return t - To{1}; - return t; -} - -template -CONSTCD14 -inline -typename std::enable_if -< - !detail::no_overflow::value, - To ->::type -floor(const std::chrono::duration& d) -{ - using namespace std::chrono; - using rep = typename std::common_type::type; - return floor(floor>(d)); -} - -// round to nearest, to even on tie -template -CONSTCD14 -inline -To -round(const std::chrono::duration& d) -{ - auto t0 = floor(d); - auto t1 = t0 + To{1}; - if (t1 == To{0} && t0 < To{0}) - t1 = -t1; - auto diff0 = d - t0; - auto diff1 = t1 - d; - if (diff0 == diff1) - { - if (t0 - trunc(t0/2)*2 == To{0}) - return t0; - return t1; - } - if (diff0 < diff1) - return t0; - return t1; -} - -// round up -template -CONSTCD14 -inline -To -ceil(const std::chrono::duration& d) -{ - auto t = trunc(d); - if (t < d) - return t + To{1}; - return t; -} - -template ::is_signed - >::type> -CONSTCD11 -std::chrono::duration -abs(std::chrono::duration d) -{ - return d >= d.zero() ? d : -d; -} - -// round down -template -CONSTCD11 -inline -std::chrono::time_point -floor(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{date::floor(tp.time_since_epoch())}; -} - -// round to nearest, to even on tie -template -CONSTCD11 -inline -std::chrono::time_point -round(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{round(tp.time_since_epoch())}; -} - -// round up -template -CONSTCD11 -inline -std::chrono::time_point -ceil(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{ceil(tp.time_since_epoch())}; -} - -#else // HAS_CHRONO_ROUNDING == 1 - -using std::chrono::floor; -using std::chrono::ceil; -using std::chrono::round; -using std::chrono::abs; - -#endif // HAS_CHRONO_ROUNDING - -// trunc towards zero -template -CONSTCD11 -inline -std::chrono::time_point -trunc(const std::chrono::time_point& tp) -{ - using std::chrono::time_point; - return time_point{trunc(tp.time_since_epoch())}; -} - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;} -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;} -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;} -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;} - -CONSTCD11 -inline -bool -operator==(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const day& x, const day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const day& x, const day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const day& x, const day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const day& x, const day& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -days -operator-(const day& x, const day& y) NOEXCEPT -{ - return days{static_cast(static_cast(x) - - static_cast(y))}; -} - -CONSTCD11 -inline -day -operator+(const day& x, const days& y) NOEXCEPT -{ - return day{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -day -operator+(const days& x, const day& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -day -operator-(const day& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {if (++m_ == 13) m_ = 1; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {if (--m_ == 0) m_ = 12; return *this;} -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -month& -month::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -month& -month::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;} - -CONSTCD11 -inline -bool -operator==(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const month& x, const month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const month& x, const month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month& x, const month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month& x, const month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -months -operator-(const month& x, const month& y) NOEXCEPT -{ - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline -month -operator+(const month& x, const months& y) NOEXCEPT -{ - auto const mu = static_cast(static_cast(x)) - 1 + y.count(); - auto const yr = (mu >= 0 ? mu : mu-11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline -month -operator+(const months& x, const month& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -month -operator-(const month& x, const months& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) -{ - switch (static_cast(m)) - { - case 1: - os << "Jan"; - break; - case 2: - os << "Feb"; - break; - case 3: - os << "Mar"; - break; - case 4: - os << "Apr"; - break; - case 5: - os << "May"; - break; - case 6: - os << "Jun"; - break; - case 7: - os << "Jul"; - break; - case 8: - os << "Aug"; - break; - case 9: - os << "Sep"; - break; - case 10: - os << "Oct"; - break; - case 11: - os << "Nov"; - break; - case 12: - os << "Dec"; - break; - default: - os << static_cast(m) << " is not a valid month"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;} -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;} -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} -CONSTCD11 inline year year::operator-() const NOEXCEPT {return year{-y_};} -CONSTCD11 inline year year::operator+() const NOEXCEPT {return *this;} - -CONSTCD11 -inline -bool -year::is_leap() const NOEXCEPT -{ - return y_ % 4 == 0 && (y_ % 100 != 0 || y_ % 400 == 0); -} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} - -CONSTCD11 -inline -bool -year::ok() const NOEXCEPT -{ - return y_ != std::numeric_limits::min(); -} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{-32767}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{32767}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6)); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 7) wd_ = 0; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 0) wd_ = 6; return *this;} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -CONSTCD14 -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return static_cast(wd_); -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 0: - os << "Sun"; - break; - case 1: - os << "Mon"; - break; - case 2: - os << "Tue"; - break; - case 3: - os << "Wed"; - break; - case 4: - os << "Thu"; - break; - case 5: - os << "Fri"; - break; - case 6: - os << "Sat"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -date::day -operator "" _d(unsigned long long d) NOEXCEPT -{ - return date::day{static_cast(d)}; -} - -CONSTCD11 -inline -date::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return date::year(static_cast(y)); -} -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA date::last_spec last{}; - -CONSTDATA date::month jan{1}; -CONSTDATA date::month feb{2}; -CONSTDATA date::month mar{3}; -CONSTDATA date::month apr{4}; -CONSTDATA date::month may{5}; -CONSTDATA date::month jun{6}; -CONSTDATA date::month jul{7}; -CONSTDATA date::month aug{8}; -CONSTDATA date::month sep{9}; -CONSTDATA date::month oct{10}; -CONSTDATA date::month nov{11}; -CONSTDATA date::month dec{12}; - -CONSTDATA date::weekday sun{0u}; -CONSTDATA date::weekday mon{1u}; -CONSTDATA date::weekday tue{2u}; -CONSTDATA date::weekday wed{3u}; -CONSTDATA date::weekday thu{4u}; -CONSTDATA date::weekday fri{5u}; -CONSTDATA date::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weekday_indexed - -CONSTCD11 -inline -weekday -weekday_indexed::weekday() const NOEXCEPT -{ - return date::weekday{static_cast(wd_)}; -} - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;} - -CONSTCD11 -inline -bool -weekday_indexed::ok() const NOEXCEPT -{ - return weekday().ok() && 1 <= index_ && index_ <= 5; -} - -#ifdef __GNUC__ -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wconversion" -#endif // __GNUC__ - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const date::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd))) - , index_(static_cast(index)) - {} - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif // __GNUC__ - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - return os << wdi.weekday() << '[' << wdi.index() << ']'; -} - -CONSTCD11 -inline -weekday_indexed -weekday::operator[](unsigned index) const NOEXCEPT -{ - return {*this, index}; -} - -CONSTCD11 -inline -bool -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return x.weekday() == y.weekday() && x.index() == y.index(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return !(x == y); -} - -// weekday_last - -CONSTCD11 inline date::weekday weekday_last::weekday() const NOEXCEPT {return wd_;} -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();} -CONSTCD11 inline weekday_last::weekday_last(const date::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline -bool -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl) -{ - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline -weekday_last -weekday::operator[](last_spec) const NOEXCEPT -{ - return weekday_last{*this}; -} - -// year_month - -CONSTCD11 -inline -year_month::year_month(const date::year& y, const date::month& m) NOEXCEPT - : y_(y) - , m_(m) - {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const months& dm) NOEXCEPT -{ - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month())); -} - -CONSTCD11 -inline -bool -operator>(const year_month& x, const year_month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -year_month -operator+(const year_month& ym, const months& dm) NOEXCEPT -{ - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -CONSTCD14 -inline -year_month -operator-(const year_month& ym, const months& dm) NOEXCEPT -{ - return ym + -dm; -} - -CONSTCD11 -inline -months -operator-(const year_month& x, const year_month& y) NOEXCEPT -{ - return (x.year() - y.year()) + - months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline -year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.month(); -} - -CONSTCD11 -inline -year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym) -{ - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline -month_day::month_day(const date::month& m, const date::day& d) NOEXCEPT - : m_(m) - , d_(d) - {} - -CONSTCD11 inline date::month month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline date::day month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -bool -month_day::ok() const NOEXCEPT -{ - CONSTDATA date::day d[] = - { - date::day(31), date::day(29), date::day(31), - date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), - date::day(31), date::day(30), date::day(31) - }; - return m_.ok() && date::day{1} <= d_ && d_ <= d[static_cast(m_)-1]; -} - -CONSTCD11 -inline -bool -operator==(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())); -} - -CONSTCD11 -inline -bool -operator>(const month_day& x, const month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md) -{ - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();} -CONSTCD11 inline month_day_last::month_day_last(const date::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline -bool -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() < y.month(); -} - -CONSTCD11 -inline -bool -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl) -{ - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline -month_weekday::month_weekday(const date::month& m, - const date::weekday_indexed& wdi) NOEXCEPT - : m_(m) - , wdi_(wdi) - {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_indexed -month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD11 -inline -bool -month_weekday::ok() const NOEXCEPT -{ - return m_.ok() && wdi_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd) -{ - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline -month_weekday_last::month_weekday_last(const date::month& m, - const date::weekday_last& wdl) NOEXCEPT - : m_(m) - , wdl_(wdl) - {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_last -month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD11 -inline -bool -month_weekday_last::ok() const NOEXCEPT -{ - return m_.ok() && wdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) -{ - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline -year_month_day_last::year_month_day_last(const date::year& y, - const date::month_day_last& mdl) NOEXCEPT - : y_(y) - , mdl_(mdl) - {} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();} - -CONSTCD11 -inline -month_day_last -year_month_day_last::month_day_last() const NOEXCEPT -{ - return mdl_; -} - -CONSTCD14 -inline -day -year_month_day_last::day() const NOEXCEPT -{ - CONSTDATA date::day d[] = - { - date::day(31), date::day(28), date::day(31), - date::day(30), date::day(31), date::day(30), - date::day(31), date::day(31), date::day(30), - date::day(31), date::day(30), date::day(31) - }; - return month() != feb || !y_.is_leap() ? - d[static_cast(month()) - 1] : date::day{29}; -} - -CONSTCD14 -inline -year_month_day_last::operator sys_days() const NOEXCEPT -{ - return sys_days(year()/month()/day()); -} - -CONSTCD14 -inline -year_month_day_last::operator local_days() const NOEXCEPT -{ - return local_days(year()/month()/day()); -} - -CONSTCD11 -inline -bool -year_month_day_last::ok() const NOEXCEPT -{ - return y_.ok() && mdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) -{ - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -CONSTCD14 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return ymdl + (-dm); -} - -CONSTCD11 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return {ymdl.year()+dy, ymdl.month_day_last()}; -} - -CONSTCD11 -inline -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dy; -} - -CONSTCD11 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return ymdl + (-dy); -} - -// year_month_day - -CONSTCD11 -inline -year_month_day::year_month_day(const date::year& y, const date::month& m, - const date::day& d) NOEXCEPT - : y_(y) - , m_(m) - , d_(d) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT - : y_(ymdl.year()) - , m_(ymdl.month()) - , d_(ymdl.day()) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(sys_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(local_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD14 -inline -days -year_month_day::to_days() const NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - (m_ <= feb); - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y-399) / 400; - auto const yoe = static_cast(y - era * 400); // [0, 399] - auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365] - auto const doe = yoe * 365 + yoe/4 - yoe/100 + doy; // [0, 146096] - return days{era * 146097 + static_cast(doe) - 719468}; -} - -CONSTCD14 -inline -year_month_day::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_day::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_day::ok() const NOEXCEPT -{ - if (!(y_.ok() && m_.ok())) - return false; - return date::day{1} <= d_ && d_ <= (y_ / m_ / last).day(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())))); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd) -{ - detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - return os; -} - -CONSTCD14 -inline -year_month_day -year_month_day::from_days(days dp) NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 719468; - auto const era = (z >= 0 ? z : z - 146096) / 146097; - auto const doe = static_cast(z - era * 146097); // [0, 146096] - auto const yoe = (doe - doe/1460 + doe/36524 - doe/146096) / 365; // [0, 399] - auto const y = static_cast(yoe) + era * 400; - auto const doy = doe - (365*yoe + yoe/4 - yoe/100); // [0, 365] - auto const mp = (5*doy + 2)/153; // [0, 11] - auto const d = doy - (153*mp+2)/5 + 1; // [1, 31] - auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12] - return year_month_day{date::year{y + (m <= 2)}, date::month(m), date::day(d)}; -} - -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -CONSTCD14 -inline -year_month_day -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return ymd + (-dm); -} - -CONSTCD11 -inline -year_month_day -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return (ymd.year() + dy) / ymd.month() / ymd.day(); -} - -CONSTCD11 -inline -year_month_day -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dy; -} - -CONSTCD11 -inline -year_month_day -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return ymd + (-dy); -} - -// year_month_weekday - -CONSTCD11 -inline -year_month_weekday::year_month_weekday(const date::year& y, const date::month& m, - const date::weekday_indexed& wdi) - NOEXCEPT - : y_(y) - , m_(m) - , wdi_(wdi) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday::weekday() const NOEXCEPT -{ - return wdi_.weekday(); -} - -CONSTCD11 -inline -unsigned -year_month_weekday::index() const NOEXCEPT -{ - return wdi_.index(); -} - -CONSTCD11 -inline -weekday_indexed -year_month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD14 -inline -year_month_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_weekday::ok() const NOEXCEPT -{ - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) - return false; - if (wdi_.index() <= 4) - return true; - auto d2 = wdi_.weekday() - date::weekday(static_cast(y_/m_/1)) + days((wdi_.index()-1)*7 + 1); - return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); -} - -CONSTCD14 -inline -year_month_weekday -year_month_weekday::from_days(days d) NOEXCEPT -{ - sys_days dp{d}; - auto const wd = date::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day())-1)/7+1]}; -} - -CONSTCD14 -inline -days -year_month_weekday::to_days() const NOEXCEPT -{ - auto d = sys_days(y_/m_/1); - return (d + (wdi_.weekday() - date::weekday(d) + days{(wdi_.index()-1)*7}) - ).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) -{ - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -CONSTCD14 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return ymwd + (-dm); -} - -CONSTCD11 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dy; -} - -CONSTCD11 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return ymwd + (-dy); -} - -// year_month_weekday_last - -CONSTCD11 -inline -year_month_weekday_last::year_month_weekday_last(const date::year& y, - const date::month& m, - const date::weekday_last& wdl) NOEXCEPT - : y_(y) - , m_(m) - , wdl_(wdl) - {} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday_last::weekday() const NOEXCEPT -{ - return wdl_.weekday(); -} - -CONSTCD11 -inline -weekday_last -year_month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD14 -inline -year_month_weekday_last::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday_last::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD11 -inline -bool -year_month_weekday_last::ok() const NOEXCEPT -{ - return y_.ok() && m_.ok() && wdl_.ok(); -} - -CONSTCD14 -inline -days -year_month_weekday_last::to_days() const NOEXCEPT -{ - auto const d = sys_days(y_/m_/last); - return (d - (date::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) -{ - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -CONSTCD14 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return ymwdl + (-dm); -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dy; -} - -CONSTCD11 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return ymwdl + (-dy); -} - -// year_month from operator/() - -CONSTCD11 -inline -year_month -operator/(const year& y, const month& m) NOEXCEPT -{ - return {y, m}; -} - -CONSTCD11 -inline -year_month -operator/(const year& y, int m) NOEXCEPT -{ - return y / month(static_cast(m)); -} - -// month_day from operator/() - -CONSTCD11 -inline -month_day -operator/(const month& m, const day& d) NOEXCEPT -{ - return {m, d}; -} - -CONSTCD11 -inline -month_day -operator/(const day& d, const month& m) NOEXCEPT -{ - return m / d; -} - -CONSTCD11 -inline -month_day -operator/(const month& m, int d) NOEXCEPT -{ - return m / day(static_cast(d)); -} - -CONSTCD11 -inline -month_day -operator/(int m, const day& d) NOEXCEPT -{ - return month(static_cast(m)) / d; -} - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;} - -// month_day_last from operator/() - -CONSTCD11 -inline -month_day_last -operator/(const month& m, last_spec) NOEXCEPT -{ - return month_day_last{m}; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, const month& m) NOEXCEPT -{ - return m/last; -} - -CONSTCD11 -inline -month_day_last -operator/(int m, last_spec) NOEXCEPT -{ - return month(static_cast(m))/last; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, int m) NOEXCEPT -{ - return m/last; -} - -// month_weekday from operator/() - -CONSTCD11 -inline -month_weekday -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT -{ - return {m, wdi}; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT -{ - return m / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(int m, const weekday_indexed& wdi) NOEXCEPT -{ - return month(static_cast(m)) / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, int m) NOEXCEPT -{ - return m / wdi; -} - -// month_weekday_last from operator/() - -CONSTCD11 -inline -month_weekday_last -operator/(const month& m, const weekday_last& wdl) NOEXCEPT -{ - return {m, wdl}; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, const month& m) NOEXCEPT -{ - return m / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(int m, const weekday_last& wdl) NOEXCEPT -{ - return month(static_cast(m)) / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, int m) NOEXCEPT -{ - return m / wdl; -} - -// year_month_day from operator/() - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, const day& d) NOEXCEPT -{ - return {ym.year(), ym.month(), d}; -} - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, int d) NOEXCEPT -{ - return ym / day(static_cast(d)); -} - -CONSTCD11 -inline -year_month_day -operator/(const year& y, const month_day& md) NOEXCEPT -{ - return y / md.month() / md.day(); -} - -CONSTCD11 -inline -year_month_day -operator/(int y, const month_day& md) NOEXCEPT -{ - return year(y) / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, const year& y) NOEXCEPT -{ - return y / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, int y) NOEXCEPT -{ - return year(y) / md; -} - -// year_month_day_last from operator/() - -CONSTCD11 -inline -year_month_day_last -operator/(const year_month& ym, last_spec) NOEXCEPT -{ - return {ym.year(), month_day_last{ym.month()}}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const year& y, const month_day_last& mdl) NOEXCEPT -{ - return {y, mdl}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(int y, const month_day_last& mdl) NOEXCEPT -{ - return year(y) / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, const year& y) NOEXCEPT -{ - return y / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, int y) NOEXCEPT -{ - return year(y) / mdl; -} - -// year_month_weekday from operator/() - -CONSTCD11 -inline -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT -{ - return {ym.year(), ym.month(), wdi}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT -{ - return {y, mwd.month(), mwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT -{ - return year(y) / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT -{ - return y / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT -{ - return year(y) / mwd; -} - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT -{ - return {ym.year(), ym.month(), wdl}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT -{ - return {y, mwdl.month(), mwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT -{ - return year(y) / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT -{ - return y / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT -{ - return year(y) / mwdl; -} - -template -struct fields; - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr); - -template -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr); - -// time_of_day - -enum {am = 1, pm}; - -namespace detail -{ - -// width::value is the number of fractional decimal digits in 1/n -// width<0>::value and width<1>::value are defined to be 0 -// If 1/n takes more than 18 fractional decimal digits, -// the result is truncated to 19. -// Example: width<2>::value == 1 -// Example: width<3>::value == 19 -// Example: width<4>::value == 2 -// Example: width<10>::value == 1 -// Example: width<1000>::value == 3 -template -struct width -{ - static CONSTDATA unsigned value = 1 + width::value; -}; - -template -struct width -{ - static CONSTDATA unsigned value = 0; -}; - -template -struct static_pow10 -{ -private: - static CONSTDATA std::uint64_t h = static_pow10::value; -public: - static CONSTDATA std::uint64_t value = h * h * (exp % 2 ? 10 : 1); -}; - -template <> -struct static_pow10<0> -{ - static CONSTDATA std::uint64_t value = 1; -}; - -template -struct make_precision -{ - using type = std::chrono::duration::value>>; - static CONSTDATA unsigned width = w; -}; - -template -struct make_precision -{ - using type = std::chrono::duration; - static CONSTDATA unsigned width = 6; -}; - -template ::type::period::den>::value> -class decimal_format_seconds -{ -public: - using rep = typename std::common_type::type::rep; - using precision = typename make_precision::type; - static auto CONSTDATA width = make_precision::width; - -private: - std::chrono::seconds s_; - precision sub_s_; - -public: - CONSTCD11 decimal_format_seconds() - : s_() - , sub_s_() - {} - - CONSTCD11 explicit decimal_format_seconds(const Duration& d) NOEXCEPT - : s_(std::chrono::duration_cast(d)) - , sub_s_(std::chrono::duration_cast(d - s_)) - {} - - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;} - CONSTCD11 precision subseconds() const NOEXCEPT {return sub_s_;} - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return s_ + sub_s_; - } - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - using namespace std::chrono; - return sub_s_ < std::chrono::seconds{1} && s_ < minutes{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const decimal_format_seconds& x) - { - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << x.s_.count() << - std::use_facet>(os.getloc()).decimal_point(); - os.width(width); - os << static_cast(x.sub_s_.count()); - return os; - } -}; - -template -class decimal_format_seconds -{ - static CONSTDATA unsigned w = 0; -public: - using rep = typename std::common_type::type::rep; - using precision = std::chrono::duration; - static auto CONSTDATA width = make_precision::width; -private: - - std::chrono::seconds s_; - -public: - CONSTCD11 decimal_format_seconds() : s_() {} - CONSTCD11 explicit decimal_format_seconds(const precision& s) NOEXCEPT - : s_(s) - {} - - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_;} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_;} - CONSTCD14 precision to_duration() const NOEXCEPT {return s_;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - using namespace std::chrono; - return s_ < minutes{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const decimal_format_seconds& x) - { - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << x.s_.count(); - return os; - } -}; - -enum class classify -{ - not_valid, - hour, - minute, - second, - subsecond -}; - -template -struct classify_duration -{ - static CONSTDATA classify value = - std::is_convertible::value - ? classify::hour : - std::is_convertible::value - ? classify::minute : - std::is_convertible::value - ? classify::second : - std::chrono::treat_as_floating_point::value - ? classify::not_valid : - classify::subsecond; -}; - -template -inline -CONSTCD11 -typename std::enable_if - < - std::numeric_limits::is_signed, - std::chrono::duration - >::type -abs(std::chrono::duration d) -{ - return d >= d.zero() ? d : -d; -} - -template -inline -CONSTCD11 -typename std::enable_if - < - !std::numeric_limits::is_signed, - std::chrono::duration - >::type -abs(std::chrono::duration d) -{ - return d; -} - -class time_of_day_base -{ -protected: - std::chrono::hours h_; - unsigned char mode_; - bool neg_; - - enum {is24hr}; - - CONSTCD11 time_of_day_base() NOEXCEPT - : h_(0) - , mode_(static_cast(is24hr)) - , neg_(false) - {} - - - CONSTCD11 time_of_day_base(std::chrono::hours h, bool neg, unsigned m) NOEXCEPT - : h_(detail::abs(h)) - , mode_(static_cast(m)) - , neg_(neg) - {} - - CONSTCD14 void make24() NOEXCEPT; - CONSTCD14 void make12() NOEXCEPT; - - CONSTCD14 std::chrono::hours to24hr() const; - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return !neg_ && h_ < days{1}; - } -}; - -CONSTCD14 -inline -std::chrono::hours -time_of_day_base::to24hr() const -{ - auto h = h_; - if (mode_ == am || mode_ == pm) - { - CONSTDATA auto h12 = std::chrono::hours(12); - if (mode_ == pm) - { - if (h != h12) - h = h + h12; - } - else if (h == h12) - h = std::chrono::hours(0); - } - return h; -} - -CONSTCD14 -inline -void -time_of_day_base::make24() NOEXCEPT -{ - h_ = to24hr(); - mode_ = is24hr; -} - -CONSTCD14 -inline -void -time_of_day_base::make12() NOEXCEPT -{ - if (mode_ == is24hr) - { - CONSTDATA auto h12 = std::chrono::hours(12); - if (h_ >= h12) - { - if (h_ > h12) - h_ = h_ - h12; - mode_ = pm; - } - else - { - if (h_ == std::chrono::hours(0)) - h_ = h12; - mode_ = am; - } - } -} - -template ::value> -class time_of_day_storage; - -template -class time_of_day_storage, detail::classify::hour> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - -public: - using precision = std::chrono::hours; - -#if !defined(_MSC_VER) || _MSC_VER >= 1900 - CONSTCD11 time_of_day_storage() NOEXCEPT = default; -#else - CONSTCD11 time_of_day_storage() = default; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1900 */ - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours since_midnight) NOEXCEPT - : base(since_midnight, since_midnight < std::chrono::hours{0}, is24hr) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, unsigned md) NOEXCEPT - : base(h, h < std::chrono::hours{0}, md) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr(); - if (neg_) - p = -p; - return p; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (t.neg_) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << t.h_.count(); - switch (t.mode_) - { - case time_of_day_storage::is24hr: - os << "00"; - break; - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } -}; - -template -class time_of_day_storage, detail::classify::minute> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - -public: - using precision = std::chrono::minutes; - - CONSTCD11 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::minutes since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), - since_midnight < std::chrono::minutes{0}, is24hr) - , m_(detail::abs(since_midnight) - h_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - unsigned md) NOEXCEPT - : base(h, false, md) - , m_(m) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr() + m_; - if (neg_) - p = -p; - return p; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1}; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (t.neg_) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << t.h_.count() << ':'; - os.width(2); - os << t.m_.count(); - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } -}; - -template -class time_of_day_storage, detail::classify::second> - : private detail::time_of_day_base -{ - using base = detail::time_of_day_base; - using dfs = decimal_format_seconds; - - std::chrono::minutes m_; - dfs s_; - -public: - using precision = std::chrono::seconds; - - CONSTCD11 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - , s_() - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::seconds since_midnight) NOEXCEPT - : base(std::chrono::duration_cast(since_midnight), - since_midnight < std::chrono::seconds{0}, is24hr) - , m_(std::chrono::duration_cast(detail::abs(since_midnight) - h_)) - , s_(detail::abs(since_midnight) - h_ - m_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - std::chrono::seconds s, unsigned md) NOEXCEPT - : base(h, false, md) - , m_(m) - , s_(s) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_.seconds();} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr() + s_.to_duration() + m_; - if (neg_) - p = -p; - return p; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1} && - s_.in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (t.neg_) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << t.h_.count() << ':'; - os.width(2); - os << t.m_.count() << ':' << t.s_; - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } - - template - friend - std::basic_ostream& - date::to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec); - - template - friend - std::basic_istream& - date::from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset); -}; - -template -class time_of_day_storage, detail::classify::subsecond> - : private detail::time_of_day_base -{ -public: - using Duration = std::chrono::duration; - using dfs = decimal_format_seconds::type>; - using precision = typename dfs::precision; - -private: - using base = detail::time_of_day_base; - - std::chrono::minutes m_; - dfs s_; - -public: - CONSTCD11 time_of_day_storage() NOEXCEPT - : base() - , m_(0) - , s_() - {} - - CONSTCD11 explicit time_of_day_storage(Duration since_midnight) NOEXCEPT - : base(date::trunc(since_midnight), - since_midnight < Duration{0}, is24hr) - , m_(date::trunc(detail::abs(since_midnight) - h_)) - , s_(detail::abs(since_midnight) - h_ - m_) - {} - - CONSTCD11 explicit time_of_day_storage(std::chrono::hours h, std::chrono::minutes m, - std::chrono::seconds s, precision sub_s, - unsigned md) NOEXCEPT - : base(h, false, md) - , m_(m) - , s_(s + sub_s) - {} - - CONSTCD11 std::chrono::hours hours() const NOEXCEPT {return h_;} - CONSTCD11 std::chrono::minutes minutes() const NOEXCEPT {return m_;} - CONSTCD14 std::chrono::seconds& seconds() NOEXCEPT {return s_.seconds();} - CONSTCD11 std::chrono::seconds seconds() const NOEXCEPT {return s_.seconds();} - CONSTCD11 precision subseconds() const NOEXCEPT {return s_.subseconds();} - CONSTCD11 unsigned mode() const NOEXCEPT {return mode_;} - - CONSTCD14 explicit operator precision() const NOEXCEPT - { - auto p = to24hr() + s_.to_duration() + m_; - if (neg_) - p = -p; - return p; - } - - CONSTCD14 precision to_duration() const NOEXCEPT - { - return static_cast(*this); - } - - CONSTCD14 time_of_day_storage& make24() NOEXCEPT {base::make24(); return *this;} - CONSTCD14 time_of_day_storage& make12() NOEXCEPT {base::make12(); return *this;} - - CONSTCD11 bool in_conventional_range() const NOEXCEPT - { - return base::in_conventional_range() && m_ < std::chrono::hours{1} && - s_.in_conventional_range(); - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const time_of_day_storage& t) - { - using namespace std; - detail::save_stream _(os); - if (t.neg_) - os << '-'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (t.mode_ != am && t.mode_ != pm) - os.width(2); - os << t.h_.count() << ':'; - os.width(2); - os << t.m_.count() << ':' << t.s_; - switch (t.mode_) - { - case am: - os << "am"; - break; - case pm: - os << "pm"; - break; - } - return os; - } - - template - friend - std::basic_ostream& - date::to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec); - - template - friend - std::basic_istream& - date::from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, - std::basic_string* abbrev, std::chrono::minutes* offset); -}; - -} // namespace detail - -template -class time_of_day - : public detail::time_of_day_storage -{ - using base = detail::time_of_day_storage; -public: -#if !defined(_MSC_VER) || _MSC_VER >= 1900 - CONSTCD11 time_of_day() NOEXCEPT = default; -#else - CONSTCD11 time_of_day() = default; -#endif /* !defined(_MSC_VER) || _MSC_VER >= 1900 */ - - CONSTCD11 explicit time_of_day(Duration since_midnight) NOEXCEPT - : base(since_midnight) - {} - - template - CONSTCD11 - explicit time_of_day(Arg0&& arg0, Arg1&& arg1, Args&& ...args) NOEXCEPT - : base(std::forward(arg0), std::forward(arg1), std::forward(args)...) - {} -}; - -template ::value>::type> -CONSTCD11 -inline -time_of_day> -make_time(const std::chrono::duration& d) -{ - return time_of_day>(d); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, unsigned md) -{ - return time_of_day(h, md); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - unsigned md) -{ - return time_of_day(h, m, md); -} - -CONSTCD11 -inline -time_of_day -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - const std::chrono::seconds& s, unsigned md) -{ - return time_of_day(h, m, s, md); -} - -template >::value>::type> -CONSTCD11 -inline -time_of_day> -make_time(const std::chrono::hours& h, const std::chrono::minutes& m, - const std::chrono::seconds& s, const std::chrono::duration& sub_s, - unsigned md) -{ - return time_of_day>(h, m, s, sub_s, md); -} - -template -inline -typename std::enable_if -< - !std::chrono::treat_as_floating_point::value && - std::ratio_less::value - , std::basic_ostream& ->::type -operator<<(std::basic_ostream& os, const sys_time& tp) -{ - auto const dp = date::floor(tp); - return os << year_month_day(dp) << ' ' << make_time(tp-dp); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const sys_days& dp) -{ - return os << year_month_day(dp); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_time& ut) -{ - return (os << sys_time{ut.time_since_epoch()}); -} - -// to_stream - -template -struct fields -{ - year_month_day ymd{year{0}/0/0}; - weekday wd{7u}; - time_of_day tod{}; - - fields() = default; - - fields(year_month_day ymd_) : ymd(ymd_) {} - fields(weekday wd_) : wd(wd_) {} - fields(time_of_day tod_) : tod(tod_) {} - - fields(year_month_day ymd_, weekday wd_) : ymd(ymd_), wd(wd_) {} - fields(year_month_day ymd_, time_of_day tod_) : ymd(ymd_), tod(tod_) {} - - fields(weekday wd_, time_of_day tod_) : wd(wd_), tod(tod_) {} - - fields(year_month_day ymd_, weekday wd_, time_of_day tod_) - : ymd(ymd_) - , wd(wd_) - , tod(tod_) - {} -}; - -namespace detail -{ - -template -unsigned -extract_weekday(std::basic_ostream& os, const fields& fds) -{ - if (!fds.ymd.ok() && !fds.wd.ok()) - { - // fds does not contain a valid weekday - os.setstate(std::ios::failbit); - return 7; - } - unsigned wd; - if (fds.ymd.ok()) - { - wd = static_cast(weekday{fds.ymd}); - if (fds.wd.ok() && wd != static_cast(fds.wd)) - { - // fds.ymd and fds.wd are inconsistent - os.setstate(std::ios::failbit); - return 7; - } - } - else - wd = static_cast(fds.wd); - return wd; -} - -template -unsigned -extract_month(std::basic_ostream& os, const fields& fds) -{ - if (!fds.ymd.month().ok()) - { - // fds does not contain a valid month - os.setstate(std::ios::failbit); - return 0; - } - return static_cast(fds.ymd.month()); -} - -} // namespace detail - -#if ONLY_C_LOCALE - -namespace detail -{ - -inline -std::pair -weekday_names() -{ - using namespace std; - static const string nm[] = - { - "Sunday", - "Monday", - "Tuesday", - "Wednesday", - "Thursday", - "Friday", - "Saturday", - "Sun", - "Mon", - "Tue", - "Wed", - "Thu", - "Fri", - "Sat" - }; - return make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -inline -std::pair -month_names() -{ - using namespace std; - static const string nm[] = - { - "January", - "February", - "March", - "April", - "May", - "June", - "July", - "August", - "September", - "October", - "November", - "December", - "Jan", - "Feb", - "Mar", - "Apr", - "May", - "Jun", - "Jul", - "Aug", - "Sep", - "Oct", - "Nov", - "Dec" - }; - return make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -inline -std::pair -ampm_names() -{ - using namespace std; - static const string nm[] = - { - "AM", - "PM" - }; - return make_pair(nm, nm+sizeof(nm)/sizeof(nm[0])); -} - -template -FwdIter -scan_keyword(std::basic_istream& is, FwdIter kb, FwdIter ke) -{ - using namespace std; - size_t nkw = static_cast(std::distance(kb, ke)); - const unsigned char doesnt_match = '\0'; - const unsigned char might_match = '\1'; - const unsigned char does_match = '\2'; - unsigned char statbuf[100]; - unsigned char* status = statbuf; - unique_ptr stat_hold(0, free); - if (nkw > sizeof(statbuf)) - { - status = (unsigned char*)malloc(nkw); - if (status == nullptr) - throw bad_alloc(); - stat_hold.reset(status); - } - size_t n_might_match = nkw; // At this point, any keyword might match - size_t n_does_match = 0; // but none of them definitely do - // Initialize all statuses to might_match, except for "" keywords are does_match - unsigned char* st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (!ky->empty()) - *st = might_match; - else - { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } - // While there might be a match, test keywords against the next CharT - for (size_t indx = 0; is && n_might_match > 0; ++indx) - { - // Peek at the next CharT but don't consume it - auto ic = is.peek(); - if (ic == EOF) - { - is.setstate(ios::eofbit); - break; - } - auto c = static_cast(toupper(ic)); - bool consume = false; - // For each keyword which might match, see if the indx character is c - // If a match if found, consume c - // If a match is found, and that is the last character in the keyword, - // then that keyword matches. - // If the keyword doesn't match this character, then change the keyword - // to doesn't match - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (*st == might_match) - { - if (c == static_cast(toupper((*ky)[indx]))) - { - consume = true; - if (ky->size() == indx+1) - { - *st = does_match; - --n_might_match; - ++n_does_match; - } - } - else - { - *st = doesnt_match; - --n_might_match; - } - } - } - // consume if we matched a character - if (consume) - { - (void)is.get(); - // If we consumed a character and there might be a matched keyword that - // was marked matched on a previous iteration, then such keywords - // are now marked as not matching. - if (n_might_match + n_does_match > 1) - { - st = status; - for (auto ky = kb; ky != ke; ++ky, ++st) - { - if (*st == does_match && ky->size() != indx+1) - { - *st = doesnt_match; - --n_does_match; - } - } - } - } - } - // We've exited the loop because we hit eof and/or we have no more "might matches". - // Return the first matching result - for (st = status; kb != ke; ++kb, ++st) - if (*st == does_match) - break; - if (kb == ke) - is.setstate(ios_base::failbit); - return kb; -} - -} // namespace detail - -#endif // ONLY_C_LOCALE - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const fields& fds, const std::string* abbrev, - const std::chrono::seconds* offset_sec) -{ - using namespace std; - using namespace std::chrono; - using namespace detail; - tm tm{}; -#if !ONLY_C_LOCALE - auto& facet = use_facet>(os.getloc()); -#endif - const CharT* command = nullptr; - CharT modified = CharT{}; - for (; *fmt; ++fmt) - { - switch (*fmt) - { - case 'a': - case 'A': - if (command) - { - if (modified == CharT{}) - { - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else // ONLY_C_LOCALE - os << weekday_names().first[tm.tm_wday+7*(*fmt == 'a')]; -#endif // ONLY_C_LOCALE - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'b': - case 'B': - case 'h': - if (command) - { - if (modified == CharT{}) - { - tm.tm_mon = static_cast(extract_month(os, fds)) - 1; -#if !ONLY_C_LOCALE - const CharT f[] = {'%', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); -#else // ONLY_C_LOCALE - os << month_names().first[tm.tm_mon+12*(*fmt == 'b')]; -#endif // ONLY_C_LOCALE - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'c': - case 'x': - if (command) - { - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { -#if !ONLY_C_LOCALE - tm = std::tm{}; - auto const& ymd = fds.ymd; - auto ld = local_days(ymd); - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - tm.tm_mday = static_cast(static_cast(ymd.day())); - tm.tm_mon = static_cast(extract_month(os, fds) - 1); - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - CharT f[3] = {'%'}; - auto fe = begin(f) + 1; - if (modified == CharT{'E'}) - *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, begin(f), fe); -#else // ONLY_C_LOCALE - if (*fmt == 'c') - { - auto wd = static_cast(extract_weekday(os, fds)); - os << weekday_names().first[static_cast(wd)+7] - << ' '; - os << month_names().first[extract_month(os, fds)-1+12] << ' '; - auto d = static_cast(static_cast(fds.ymd.day())); - if (d < 10) - os << ' '; - os << d << ' ' - << make_time(duration_cast(fds.tod.to_duration())) - << ' ' << fds.ymd.year(); - - } - else // *fmt == 'x' - { - auto const& ymd = fds.ymd; - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } -#endif // ONLY_C_LOCALE - } - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'C': - if (command) - { - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - if (y >= 0) - { - os.width(2); - os << y/100; - } - else - { - os << CharT{'-'}; - os.width(2); - os << -(y-99)/100; - } -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'E'}) - { - tm.tm_year = y - 1900; - CharT f[3] = {'%', 'E', 'C'}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'd': - case 'e': - if (command) - { - auto d = static_cast(static_cast(fds.ymd.day())); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - save_stream _(os); - if (*fmt == CharT{'d'}) - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << d; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - tm.tm_mday = d; - CharT f[3] = {'%', 'O', *fmt}; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'D': - if (command) - { - if (modified == CharT{}) - { - auto const& ymd = fds.ymd; - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(ymd.month()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.day()) << CharT{'/'}; - os.width(2); - os << static_cast(ymd.year()) % 100; - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'F': - if (command) - { - if (modified == CharT{}) - { - auto const& ymd = fds.ymd; - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(4); - os << static_cast(ymd.year()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.month()) << CharT{'-'}; - os.width(2); - os << static_cast(ymd.day()); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'g': - case 'G': - if (command) - { - if (modified == CharT{}) - { - auto ld = local_days(fds.ymd); - auto y = year_month_day{ld + days{3}}.year(); - auto start = local_days((y - years{1})/date::dec/thu[last]) + (mon-thu); - if (ld < start) - --y; - if (*fmt == CharT{'G'}) - os << y; - else - { - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << std::abs(static_cast(y)) % 100; - } - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'H': - case 'I': - if (command) - { - auto hms = fds.tod; -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - if (*fmt == CharT{'I'}) - hms.make12(); - if (hms.hours() < hours{10}) - os << CharT{'0'}; - os << hms.hours().count(); -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_hour = static_cast(hms.hours().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'j': - if (command) - { - if (modified == CharT{}) - { - auto ld = local_days(fds.ymd); - auto y = fds.ymd.year(); - auto doy = ld - local_days(y/jan/1) + days{1}; - save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(3); - os << doy.count(); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'm': - if (command) - { - auto m = static_cast(fds.ymd.month()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - if (m < 10) - os << CharT{'0'}; - os << m; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_mon = static_cast(m-1); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'M': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - if (fds.tod.minutes() < minutes{10}) - os << CharT{'0'}; - os << fds.tod.minutes().count(); -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_min = static_cast(fds.tod.minutes().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'n': - if (command) - { - if (modified == CharT{}) - os << CharT{'\n'}; - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'p': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#else - if (fds.tod.hours() < hours{12}) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'r': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { - const CharT f[] = {'%', *fmt}; - tm.tm_hour = static_cast(fds.tod.hours().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_sec = static_cast(fds.tod.seconds().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#else - time_of_day tod(duration_cast(fds.tod.to_duration())); - tod.make12(); - save_stream _(os); - os.fill('0'); - os.width(2); - os << tod.hours().count() << CharT{':'}; - os.width(2); - os << tod.minutes().count() << CharT{':'}; - os.width(2); - os << tod.seconds().count() << CharT{' '}; - tod.make24(); - if (tod.hours() < hours{12}) - os << ampm_names().first[0]; - else - os << ampm_names().first[1]; -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'R': - if (command) - { - if (modified == CharT{}) - { - if (fds.tod.hours() < hours{10}) - os << CharT{'0'}; - os << fds.tod.hours().count() << CharT{':'}; - if (fds.tod.minutes() < minutes{10}) - os << CharT{'0'}; - os << fds.tod.minutes().count(); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'S': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - os << fds.tod.s_; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_sec = static_cast(fds.tod.s_.seconds().count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 't': - if (command) - { - if (modified == CharT{}) - os << CharT{'\t'}; - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'T': - if (command) - { - if (modified == CharT{}) - { - os << fds.tod; - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'u': - if (command) - { - auto wd = extract_weekday(os, fds); - if (os.fail()) - return os; -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - os << (wd != 0 ? wd : 7u); -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'U': - if (command) - { - auto const& ymd = fds.ymd; - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - auto st = local_days(sun[1]/jan/ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else - { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; - } - #if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'V': - if (command) - { - auto ld = local_days(fds.ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - auto y = year_month_day{ld + days{3}}.year(); - auto st = local_days((y - years{1})/12/thu[last]) + (mon-thu); - if (ld < st) - { - --y; - st = local_days((y - years{1})/12/thu[last]) + (mon-thu); - } - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - auto const& ymd = fds.ymd; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'w': - if (command) - { - auto wd = extract_weekday(os, fds); - if (os.fail()) - return os; -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - os << wd; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_wday = static_cast(wd); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'W': - if (command) - { - auto const& ymd = fds.ymd; - auto ld = local_days(ymd); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - auto st = local_days(mon[1]/jan/ymd.year()); - if (ld < st) - os << CharT{'0'} << CharT{'0'}; - else - { - auto wn = duration_cast(ld - st).count() + 1; - if (wn < 10) - os << CharT{'0'}; - os << wn; - } -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(ymd.year()) - 1900; - tm.tm_wday = static_cast(extract_weekday(os, fds)); - if (os.fail()) - return os; - tm.tm_yday = static_cast((ld - local_days(ymd.year()/1/1)).count()); - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'X': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{'O'}) - os << CharT{'%'} << modified << *fmt; - else - { - tm = std::tm{}; - tm.tm_sec = static_cast(fds.tod.seconds().count()); - tm.tm_min = static_cast(fds.tod.minutes().count()); - tm.tm_hour = static_cast(fds.tod.hours().count()); - CharT f[3] = {'%'}; - auto fe = begin(f) + 1; - if (modified == CharT{'E'}) - *fe++ = modified; - *fe++ = *fmt; - facet.put(os, os, os.fill(), &tm, begin(f), fe); - } -#else - os << fds.tod; -#endif - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'y': - if (command) - { - auto y = static_cast(fds.ymd.year()); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - y = std::abs(y) % 100; - if (y < 10) - os << CharT{'0'}; - os << y; -#if !ONLY_C_LOCALE - } - else - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = y - 1900; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'Y': - if (command) - { - auto y = fds.ymd.year(); -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - os << y; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'E'}) - { - const CharT f[] = {'%', modified, *fmt}; - tm.tm_year = static_cast(y) - 1900; - facet.put(os, os, os.fill(), &tm, begin(f), end(f)); - } - else - { - os << CharT{'%'} << modified << *fmt; - } -#endif - modified = CharT{}; - command = nullptr; - } - else - os << *fmt; - break; - case 'z': - if (command) - { - if (offset_sec == nullptr) - { - // Can not format %z with unknown offset - os.setstate(ios::failbit); - return os; - } - auto m = duration_cast(*offset_sec); - auto neg = m < minutes{0}; - m = date::abs(m); - auto h = duration_cast(m); - m -= h; - if (neg) - os << CharT{'-'}; - else - os << CharT{'+'}; - if (h < hours{10}) - os << CharT{'0'}; - os << h.count(); - if (modified != CharT{}) - os << CharT{':'}; - if (m < minutes{10}) - os << CharT{'0'}; - os << m.count(); - command = nullptr; - modified = CharT{}; - } - else - os << *fmt; - break; - case 'Z': - if (command) - { - if (modified == CharT{}) - { - if (abbrev == nullptr) - { - // Can not format %Z with unknown time_zone - os.setstate(ios::failbit); - return os; - } - for (auto c : *abbrev) - os << CharT(c); - } - else - { - os << CharT{'%'} << modified << *fmt; - modified = CharT{}; - } - command = nullptr; - } - else - os << *fmt; - break; - case 'E': - case 'O': - if (command) - { - if (modified == CharT{}) - { - modified = *fmt; - } - else - { - os << CharT{'%'} << modified << *fmt; - command = nullptr; - modified = CharT{}; - } - } - else - os << *fmt; - break; - case '%': - if (command) - { - if (modified == CharT{}) - { - os << CharT{'%'}; - command = nullptr; - } - else - { - os << CharT{'%'} << modified << CharT{'%'}; - command = nullptr; - modified = CharT{}; - } - } - else - command = fmt; - break; - default: - if (command) - { - os << CharT{'%'}; - command = nullptr; - } - if (modified != CharT{}) - { - os << modified; - modified = CharT{}; - } - os << *fmt; - break; - } - } - if (command) - os << CharT{'%'}; - if (modified != CharT{}) - os << modified; - return os; -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const year& y) -{ - using CT = std::chrono::seconds; - fields fds{y/0/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const month& m) -{ - using CT = std::chrono::seconds; - fields fds{m/0/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const day& d) -{ - using CT = std::chrono::seconds; - fields fds{d/0/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const weekday& wd) -{ - using CT = std::chrono::seconds; - fields fds{wd}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const year_month& ym) -{ - using CT = std::chrono::seconds; - fields fds{ym/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, const month_day& md) -{ - using CT = std::chrono::seconds; - fields fds{md/0}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const year_month_day& ymd) -{ - using CT = std::chrono::seconds; - fields fds{ymd}; - return to_stream(os, fmt, fds); -} - -template -inline -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const std::chrono::duration& d) -{ - using Duration = std::chrono::duration; - using CT = typename std::common_type::type; - fields fds{time_of_day{d}}; - return to_stream(os, fmt, fds); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const local_time& tp, const std::string* abbrev = nullptr, - const std::chrono::seconds* offset_sec = nullptr) -{ - using CT = typename std::common_type::type; - auto ld = floor(tp); - fields fds{year_month_day{ld}, time_of_day{tp-local_seconds{ld}}}; - return to_stream(os, fmt, fds, abbrev, offset_sec); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const sys_time& tp) -{ - using namespace std::chrono; - using CT = typename std::common_type::type; - const std::string abbrev("UTC"); - CONSTDATA seconds offset{0}; - auto sd = floor(tp); - fields fds{year_month_day{sd}, time_of_day{tp-sys_seconds{sd}}}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -// format - -template -auto -format(const std::locale& loc, const CharT* fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt, tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto -format(const CharT* fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt, tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt, tp); - return os.str(); -} - -template -auto -format(const std::locale& loc, const std::basic_string& fmt, - const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - os.imbue(loc); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -template -auto -format(const std::basic_string& fmt, const Streamable& tp) - -> decltype(to_stream(std::declval&>(), fmt.c_str(), tp), - std::basic_string{}) -{ - std::basic_ostringstream os; - os.exceptions(std::ios::failbit | std::ios::badbit); - to_stream(os, fmt.c_str(), tp); - return os.str(); -} - -// parse - -namespace detail -{ - -template -bool -read_char(std::basic_istream& is, CharT fmt, std::ios::iostate& err) -{ - auto ic = is.get(); - if (Traits::eq_int_type(ic, Traits::eof()) || - !Traits::eq(Traits::to_char_type(ic), fmt)) - { - err |= std::ios::failbit; - is.setstate(std::ios::failbit); - return false; - } - return true; -} - -template -unsigned -read_unsigned(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - unsigned x = 0; - unsigned count = 0; - while (true) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - break; - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) - break; - (void)is.get(); - ++count; - x = 10*x + static_cast(c - '0'); - if (count == M) - break; - } - if (count < m) - is.setstate(std::ios::failbit); - return x; -} - -template -int -read_signed(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - auto ic = is.peek(); - if (!Traits::eq_int_type(ic, Traits::eof())) - { - auto c = static_cast(Traits::to_char_type(ic)); - if (('0' <= c && c <= '9') || c == '-' || c == '+') - { - if (c == '-' || c == '+') - (void)is.get(); - auto x = static_cast(read_unsigned(is, std::max(m, 1u), M)); - if (!is.fail()) - { - if (c == '-') - x = -x; - return x; - } - } - } - if (m > 0) - is.setstate(std::ios::failbit); - return 0; -} - -template -long double -read_long_double(std::basic_istream& is, unsigned m = 1, unsigned M = 10) -{ - using namespace std; - unsigned count = 0; - auto decimal_point = Traits::to_int_type( - use_facet>(is.getloc()).decimal_point()); - string buf; - while (true) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - break; - if (Traits::eq_int_type(ic, decimal_point)) - { - buf += '.'; - decimal_point = Traits::eof(); - is.get(); - } - else - { - auto c = static_cast(Traits::to_char_type(ic)); - if (!('0' <= c && c <= '9')) - break; - buf += c; - (void)is.get(); - } - if (++count == M) - break; - } - if (count < m) - { - is.setstate(std::ios::failbit); - return 0; - } - return std::stold(buf); -} - -struct rs -{ - int& i; - unsigned m; - unsigned M; -}; - -struct ru -{ - int& i; - unsigned m; - unsigned M; -}; - -struct rld -{ - long double& i; - unsigned m; - unsigned M; -}; - -template -void -read(std::basic_istream&) -{ -} - -template -void -read(std::basic_istream& is, CharT a0, Args&& ...args); - -template -void -read(std::basic_istream& is, rs a0, Args&& ...args); - -template -void -read(std::basic_istream& is, ru a0, Args&& ...args); - -template -void -read(std::basic_istream& is, int a0, Args&& ...args); - -template -void -read(std::basic_istream& is, rld a0, Args&& ...args); - -template -void -read(std::basic_istream& is, CharT a0, Args&& ...args) -{ - // No-op if a0 == CharT{} - if (a0 != CharT{}) - { - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - { - is.setstate(std::ios::failbit | std::ios::eofbit); - return; - } - if (!Traits::eq(Traits::to_char_type(ic), a0)) - { - is.setstate(std::ios::failbit); - return; - } - (void)is.get(); - } - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, rs a0, Args&& ...args) -{ - auto x = read_signed(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = x; - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, ru a0, Args&& ...args) -{ - auto x = read_unsigned(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = static_cast(x); - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, int a0, Args&& ...args) -{ - if (a0 != -1) - { - auto u = static_cast(a0); - CharT buf[std::numeric_limits::digits10+2] = {}; - auto e = buf; - do - { - *e++ = CharT(u % 10) + CharT{'0'}; - u /= 10; - } while (u > 0); - std::reverse(buf, e); - for (auto p = buf; p != e && is.rdstate() == std::ios::goodbit; ++p) - read(is, *p); - } - if (is.rdstate() == std::ios::goodbit) - read(is, std::forward(args)...); -} - -template -void -read(std::basic_istream& is, rld a0, Args&& ...args) -{ - auto x = read_long_double(is, a0.m, a0.M); - if (is.fail()) - return; - a0.i = x; - read(is, std::forward(args)...); -} - -} // namespace detail; - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - fields& fds, std::basic_string* abbrev, - std::chrono::minutes* offset) -{ - using namespace std; - using namespace std::chrono; - typename basic_istream::sentry ok{is, true}; - if (ok) - { -#if !ONLY_C_LOCALE - auto& f = use_facet>(is.getloc()); - std::tm tm{}; -#endif - std::basic_string temp_abbrev; - minutes temp_offset{}; - const CharT* command = nullptr; - auto modified = CharT{}; - auto width = -1; - CONSTDATA int not_a_year = numeric_limits::min(); - int Y = not_a_year; - CONSTDATA int not_a_century = not_a_year / 100; - int C = not_a_century; - CONSTDATA int not_a_2digit_year = 100; - int y = not_a_2digit_year; - int m{}; - int d{}; - int j{}; - CONSTDATA int not_a_weekday = 7; - int wd = not_a_weekday; - CONSTDATA int not_a_hour_12_value = 0; - int I = not_a_hour_12_value; - hours h{}; - minutes min{}; - Duration s{}; - int g = not_a_2digit_year; - int G = not_a_year; - CONSTDATA int not_a_week_num = 100; - int V = not_a_week_num; - int U = not_a_week_num; - int W = not_a_week_num; - using detail::read; - using detail::rs; - using detail::ru; - using detail::rld; - for (; *fmt && is.rdstate() == std::ios::goodbit; ++fmt) - { - switch (*fmt) - { - case 'a': - case 'A': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - wd = tm.tm_wday; - is.setstate(err); -#else - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) - wd = i % 7; -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'b': - case 'B': - case 'h': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - m = tm.tm_mon + 1; - is.setstate(err); -#else - auto nm = detail::month_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (!is.fail()) - m = i % 12 + 1; -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'c': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - Y = tm.tm_year + 1900; - m = tm.tm_mon + 1; - d = tm.tm_mday; - h = hours{tm.tm_hour}; - min = minutes{tm.tm_min}; - s = duration_cast(seconds{tm.tm_sec}); - } - is.setstate(err); -#else - auto nm = detail::weekday_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (is.fail()) - goto broken; - wd = i % 7; - ws(is); - nm = detail::month_names(); - i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (is.fail()) - goto broken; - m = i % 12 + 1; - ws(is); - read(is, rs{d, 1, 2}); - if (is.fail()) - goto broken; - ws(is); - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int H; - int M; - long double S; - read(is, ru{H, 1, 2}, CharT{':'}, ru{M, 1, 2}, - CharT{':'}, rld{S, 1, w}); - if (is.fail()) - goto broken; - h = hours{H}; - min = minutes{M}; - s = round(duration{S}); - ws(is); - read(is, rs{Y, 1, 4u}); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'x': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - Y = tm.tm_year + 1900; - m = tm.tm_mon + 1; - d = tm.tm_mday; - } - is.setstate(err); -#else - read(is, ru{m, 1, 2}, CharT{'/'}, ru{d, 1, 2}, CharT{'/'}, - rs{y, 1, 2}); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'X': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - h = hours{tm.tm_hour}; - min = minutes{tm.tm_min}; - s = duration_cast(seconds{tm.tm_sec}); - } - is.setstate(err); -#else - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int H; - int M; - long double S; - read(is, ru{H, 1, 2}, CharT{':'}, ru{M, 1, 2}, - CharT{':'}, rld{S, 1, w}); - if (!is.fail()) - { - h = hours{H}; - min = minutes{M}; - s = round(duration{S}); - } -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'C': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - read(is, rs{C, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - } - else - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - auto tY = tm.tm_year + 1900; - C = (tY >= 0 ? tY : tY-99) / 100; - } - is.setstate(err); - } -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'D': - if (command) - { - if (modified == CharT{}) - read(is, ru{m, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, - ru{d, 1, 2}, CharT{'\0'}, CharT{'/'}, CharT{'\0'}, - rs{y, 1, 2}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'F': - if (command) - { - if (modified == CharT{}) - read(is, rs{Y, 1, width == -1 ? 4u : static_cast(width)}, - CharT{'-'}, ru{m, 1, 2}, CharT{'-'}, ru{d, 1, 2}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'd': - case 'e': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - read(is, rs{d, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - command = nullptr; - width = -1; - modified = CharT{}; - if ((err & ios::failbit) == 0) - d = tm.tm_mday; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'H': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - int H; - read(is, ru{H, 1, width == -1 ? 2u : static_cast(width)}); - if (!is.fail()) - h = hours{H}; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - h = hours{tm.tm_hour}; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'I': - if (command) - { - if (modified == CharT{}) - { - // reads in an hour into I, but most be in [1, 12] - read(is, rs{I, 1, width == -1 ? 2u : static_cast(width)}); - if (I != not_a_hour_12_value) - { - if (!(1 <= I && I <= 12)) - { - I = not_a_hour_12_value; - goto broken; - } - } - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'j': - if (command) - { - if (modified == CharT{}) - read(is, ru{j, 1, width == -1 ? 3u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'M': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - int M; - read(is, ru{M, 1, width == -1 ? 2u : static_cast(width)}); - if (!is.fail()) - min = minutes{M}; -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - min = minutes{tm.tm_min}; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'm': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - read(is, rs{m, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - m = tm.tm_mon + 1; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'n': - case 't': - if (command) - { - // %n matches a single white space character - // %t matches 0 or 1 white space characters - auto ic = is.peek(); - if (Traits::eq_int_type(ic, Traits::eof())) - { - ios_base::iostate err = ios_base::eofbit; - if (*fmt == 'n') - err |= ios_base::failbit; - is.setstate(err); - break; - } - if (isspace(ic)) - { - (void)is.get(); - } - else if (*fmt == 'n') - is.setstate(ios_base::failbit); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'p': - // Error if haven't yet seen %I - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { - if (I == not_a_hour_12_value) - goto broken; - tm = std::tm{}; - tm.tm_hour = I; - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if (err & ios::failbit) - goto broken; - h = hours{tm.tm_hour}; - I = not_a_hour_12_value; - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#else - if (I == not_a_hour_12_value) - goto broken; - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (is.fail()) - goto broken; - h = hours{I}; - if (i == 1) - { - if (h != hours{12}) - h += hours{12}; - } - else if (h == hours{12}) - h = hours{0}; - I = not_a_hour_12_value; -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - - break; - case 'r': - if (command) - { -#if !ONLY_C_LOCALE - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - { - h = hours{tm.tm_hour}; - min = minutes{tm.tm_min}; - s = duration_cast(seconds{tm.tm_sec}); - } - is.setstate(err); -#else - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int H; - int M; - long double S; - read(is, ru{H, 1, 2}, CharT{':'}, ru{M, 1, 2}, - CharT{':'}, rld{S, 1, w}); - if (is.fail() || !(1 <= H && H <= 12)) - goto broken; - ws(is); - auto nm = detail::ampm_names(); - auto i = detail::scan_keyword(is, nm.first, nm.second) - nm.first; - if (is.fail()) - goto broken; - h = hours{H}; - if (i == 1) - { - if (h != hours{12}) - h += hours{12}; - } - else if (h == hours{12}) - h = hours{0}; - min = minutes{M}; - s = round(duration{S}); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'R': - if (command) - { - if (modified == CharT{}) - { - int H, M; - read(is, ru{H, 1, 2}, CharT{'\0'}, CharT{':'}, CharT{'\0'}, - ru{M, 1, 2}, CharT{'\0'}); - if (!is.fail()) - { - h = hours{H}; - min = minutes{M}; - } - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'S': - if (command) - { - #if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - long double S; - read(is, rld{S, 1, width == -1 ? w : static_cast(width)}); - if (!is.fail()) - s = round(duration{S}); -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - s = duration_cast(seconds{tm.tm_sec}); - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'T': - if (command) - { - if (modified == CharT{}) - { - using dfs = detail::decimal_format_seconds; - CONSTDATA auto w = Duration::period::den == 1 ? 2 : 3 + dfs::width; - int H; - int M; - long double S; - read(is, ru{H, 1, 2}, CharT{':'}, ru{M, 1, 2}, - CharT{':'}, rld{S, 1, w}); - if (!is.fail()) - { - h = hours{H}; - min = minutes{M}; - s = round(duration{S}); - } - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'Y': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - read(is, rs{Y, 1, width == -1 ? 4u : static_cast(width)}); -#if !ONLY_C_LOCALE - else if (modified == CharT{'E'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - Y = tm.tm_year + 1900; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'y': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) -#endif - read(is, ru{y, 1, width == -1 ? 2u : static_cast(width)}); -#if !ONLY_C_LOCALE - else - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - Y = tm.tm_year + 1900; - is.setstate(err); - } -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'g': - if (command) - { - if (modified == CharT{}) - read(is, ru{g, 1, width == -1 ? 2u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'G': - if (command) - { - if (modified == CharT{}) - read(is, rs{G, 1, width == -1 ? 4u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'U': - if (command) - { - if (modified == CharT{}) - read(is, ru{U, 1, width == -1 ? 2u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'V': - if (command) - { - if (modified == CharT{}) - read(is, ru{V, 1, width == -1 ? 2u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'W': - if (command) - { - if (modified == CharT{}) - read(is, ru{W, 1, width == -1 ? 2u : static_cast(width)}); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'u': - case 'w': - if (command) - { -#if !ONLY_C_LOCALE - if (modified == CharT{}) - { -#endif - read(is, ru{wd, 1, width == -1 ? 1u : static_cast(width)}); - if (!is.fail() && *fmt == 'u') - { - if (wd == 7) - wd = 0; - else if (wd == 0) - wd = 7; - } -#if !ONLY_C_LOCALE - } - else if (modified == CharT{'O'}) - { - ios_base::iostate err = ios_base::goodbit; - f.get(is, nullptr, is, err, &tm, command, fmt+1); - if ((err & ios::failbit) == 0) - wd = tm.tm_wday; - is.setstate(err); - } - else - read(is, CharT{'%'}, width, modified, *fmt); -#endif - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'E': - case 'O': - if (command) - { - if (modified == CharT{}) - { - modified = *fmt; - } - else - { - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } - else - read(is, *fmt); - break; - case '%': - if (command) - { - if (modified == CharT{}) - read(is, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - command = fmt; - break; - case 'z': - if (command) - { - int H, M; - if (modified == CharT{}) - read(is, rs{H, 2, 2}, ru{M, 2, 2}); - else - read(is, rs{H, 1, 2}, CharT{':'}, ru{M, 2, 2}); - if (!is.fail()) - temp_offset = hours{ H } + minutes{ H < 0 ? -M : M }; - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - case 'Z': - if (command) - { - if (modified == CharT{}) - { - if (!temp_abbrev.empty()) - is.setstate(ios::failbit); - else - { - while (is.rdstate() == std::ios::goodbit) - { - auto i = is.rdbuf()->sgetc(); - if (Traits::eq_int_type(i, Traits::eof())) - { - is.setstate(ios::eofbit); - break; - } - auto wc = Traits::to_char_type(i); - auto c = static_cast(wc); - // is c a valid time zone name or abbreviation character? - if (!(CharT{1} < wc && wc < CharT{127}) || !(isalnum(c) || - c == '_' || c == '/' || c == '-' || c == '+')) - break; - temp_abbrev.push_back(c); - is.rdbuf()->sbumpc(); - } - if (temp_abbrev.empty()) - is.setstate(ios::failbit); - } - } - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - else - read(is, *fmt); - break; - default: - if (command) - { - if (width == -1 && modified == CharT{} && '0' <= *fmt && *fmt <= '9') - { - width = static_cast(*fmt) - '0'; - while ('0' <= fmt[1] && fmt[1] <= '9') - width = 10*width + static_cast(*++fmt) - '0'; - } - else - { - if (modified == CharT{}) - read(is, CharT{'%'}, width, *fmt); - else - read(is, CharT{'%'}, width, modified, *fmt); - command = nullptr; - width = -1; - modified = CharT{}; - } - } - else // !command - { - if (isspace(*fmt)) - ws(is); // space matches 0 or more white space characters - else - read(is, *fmt); - } - break; - } - } - // is.rdstate() != ios::goodbit || *fmt == CharT{} - if (is.rdstate() == ios::goodbit && command) - { - if (modified == CharT{}) - read(is, CharT{'%'}, width); - else - read(is, CharT{'%'}, width, modified); - } - if (is.rdstate() != ios::goodbit && *fmt != CharT{} && !is.fail()) - is.setstate(ios::failbit); - if (!is.fail()) - { - if (y != not_a_2digit_year) - { - // Convert y and an optional C to Y - if (!(0 <= y && y <= 99)) - goto broken; - if (C == not_a_century) - { - if (Y == not_a_year) - { - if (y >= 69) - C = 19; - else - C = 20; - } - else - { - C = (Y >= 0 ? Y : Y-100) / 100; - } - } - int tY; - if (C >= 0) - tY = 100*C + y; - else - tY = 100*(C+1) - (y == 0 ? 100 : y); - if (Y != not_a_year && Y != tY) - goto broken; - Y = tY; - } - if (g != not_a_2digit_year) - { - // Convert g and an optional C to G - if (!(0 <= g && g <= 99)) - goto broken; - if (C == not_a_century) - { - if (G == not_a_year) - { - if (g >= 69) - C = 19; - else - C = 20; - } - else - { - C = (G >= 0 ? G : G-100) / 100; - } - } - int tG; - if (C >= 0) - tG = 100*C + g; - else - tG = 100*(C+1) - (g == 0 ? 100 : g); - if (G != not_a_year && G != tG) - goto broken; - G = tG; - } - if (G != not_a_year) - { - // Convert G, V and wd to Y, m and d - if (V == not_a_week_num || wd == not_a_weekday) - goto broken; - auto ymd = year_month_day{local_days(year{G-1}/dec/thu[last]) + - (mon-thu) + weeks{V-1} + - (weekday{static_cast(wd)}-mon)}; - if (Y == not_a_year) - Y = static_cast(ymd.year()); - else if (year{Y} != ymd.year()) - goto broken; - if (m == 0) - m = static_cast(static_cast(ymd.month())); - else if (month(static_cast(m)) != ymd.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd.day())); - else if (day(static_cast(d)) != ymd.day()) - goto broken; - } - if (j != 0 && Y != not_a_year) - { - auto ymd = year_month_day{local_days(year{Y}/1/1) + days{j-1}}; - if (m == 0) - m = static_cast(static_cast(ymd.month())); - else if (month(static_cast(m)) != ymd.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd.day())); - else if (day(static_cast(d)) != ymd.day()) - goto broken; - } - if (U != not_a_week_num && Y != not_a_year) - { - if (wd == not_a_weekday) - goto broken; - sys_days sd; - if (U == 0) - sd = year{Y-1}/dec/weekday{static_cast(wd)}[last]; - else - sd = sys_days(year{Y}/jan/sun[1]) + weeks{U-1} + - (weekday{static_cast(wd)} - sun); - year_month_day ymd = sd; - if (year{Y} != ymd.year()) - goto broken; - if (m == 0) - m = static_cast(static_cast(ymd.month())); - else if (month(static_cast(m)) != ymd.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd.day())); - else if (day(static_cast(d)) != ymd.day()) - goto broken; - } - if (W != not_a_week_num && Y != not_a_year) - { - if (wd == not_a_weekday) - goto broken; - sys_days sd; - if (W == 0) - sd = year{Y-1}/dec/weekday{static_cast(wd)}[last]; - else - sd = sys_days(year{Y}/jan/mon[1]) + weeks{W-1} + - (weekday{static_cast(wd)} - mon); - year_month_day ymd = sd; - if (year{Y} != ymd.year()) - goto broken; - if (m == 0) - m = static_cast(static_cast(ymd.month())); - else if (month(static_cast(m)) != ymd.month()) - goto broken; - if (d == 0) - d = static_cast(static_cast(ymd.day())); - else if (day(static_cast(d)) != ymd.day()) - goto broken; - } - if (Y < static_cast(year::min()) || Y > static_cast(year::max())) - Y = not_a_year; - auto ymd = year{Y}/m/d; - if (wd != not_a_weekday && ymd.ok()) - { - if (weekday{static_cast(wd)} != weekday(ymd)) - goto broken; - } - fds.ymd = ymd; - fds.tod = time_of_day(hours{h} + minutes{min}); - fds.tod.s_ = detail::decimal_format_seconds{s}; - if (wd != not_a_weekday) - fds.wd = weekday{static_cast(wd)}; - if (abbrev != nullptr) - *abbrev = std::move(temp_abbrev); - if (offset != nullptr) - *offset = temp_offset; - } - return is; - } -broken: - is.setstate(ios_base::failbit); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, year& y, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.year().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - y = fds.ymd.year(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, month& m, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - m = fds.ymd.month(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, day& d, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.day().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - d = fds.ymd.day(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, weekday& wd, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.wd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - wd = fds.wd; - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, year_month& ym, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - ym = fds.ymd.year()/fds.ymd.month(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, month_day& md, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.month().ok() || !fds.ymd.day().ok()) - is.setstate(ios::failbit); - if (!is.fail()) - md = fds.ymd.month()/fds.ymd.day(); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - year_month_day& ymd, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = seconds; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - ymd = fds.ymd; - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - sys_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = round(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - local_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = round(local_seconds{local_days(fds.ymd)} + fds.tod.to_duration()); - return is; -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - std::chrono::duration& d, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using Duration = std::chrono::duration; - using CT = typename common_type::type; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offset); - if (!is.fail()) - d = duration_cast(fds.tod.to_duration()); - return is; -} - -template , - class Alloc = std::allocator> -struct parse_manip -{ - const std::basic_string format_; - Parsable& tp_; - std::basic_string* abbrev_; - std::chrono::minutes* offset_; - -public: - parse_manip(std::basic_string format, Parsable& tp, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) - : format_(std::move(format)) - , tp_(tp) - , abbrev_(abbrev) - , offset_(offset) - {} - -}; - -template -std::basic_istream& -operator>>(std::basic_istream& is, - const parse_manip& x) -{ - return from_stream(is, x.format_.c_str(), x.tp_, x.abbrev_, x.offset_); -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp), - parse_manip{format, tp}) -{ - return {format, tp}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, &abbrev), - parse_manip{format, tp, &abbrev}) -{ - return {format, tp, &abbrev}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, nullptr, &offset), - parse_manip{format, tp, nullptr, &offset}) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -auto -parse(const std::basic_string& format, Parsable& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), - format.c_str(), tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) -{ - return {format, tp, &abbrev, &offset}; -} - -// const CharT* formats - -template -inline -auto -parse(const CharT* format, Parsable& tp) - -> decltype(from_stream(std::declval&>(), format, tp), - parse_manip{format, tp}) -{ - return {format, tp}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, std::basic_string& abbrev) - -> decltype(from_stream(std::declval&>(), format, - tp, &abbrev), - parse_manip{format, tp, &abbrev}) -{ - return {format, tp, &abbrev}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, - tp, nullptr, &offset), - parse_manip{format, tp, nullptr, &offset}) -{ - return {format, tp, nullptr, &offset}; -} - -template -inline -auto -parse(const CharT* format, Parsable& tp, - std::basic_string& abbrev, std::chrono::minutes& offset) - -> decltype(from_stream(std::declval&>(), format, - tp, &abbrev, &offset), - parse_manip{format, tp, &abbrev, &offset}) -{ - return {format, tp, &abbrev, &offset}; -} - -// duration streaming - -namespace detail -{ - -#if __cplusplus >= 201402 && (!defined(__EDG_VERSION__) || __EDG_VERSION__ > 411) \ - && (!defined(__SUNPRO_CC) || __SUNPRO_CC > 0x5150) - -template -class string_literal -{ - CharT p_[N]; - -public: - using const_iterator = const CharT*; - - string_literal(string_literal const&) = default; - string_literal& operator=(string_literal const&) = delete; - - template > - CONSTCD14 string_literal(CharT c) NOEXCEPT - : p_{c} - { - } - - CONSTCD14 string_literal(const CharT(&a)[N]) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template > - CONSTCD14 string_literal(const char(&a)[N]) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template {}>> - CONSTCD14 string_literal(string_literal const& a) NOEXCEPT - : p_{} - { - for (std::size_t i = 0; i < N; ++i) - p_[i] = a[i]; - } - - template > - CONSTCD14 string_literal(const string_literal& x, - const string_literal& y) NOEXCEPT - : p_{} - { - std::size_t i = 0; - for (; i < N1-1; ++i) - p_[i] = x[i]; - for (std::size_t j = 0; j < N2; ++j, ++i) - p_[i] = y[j]; - } - - CONSTCD14 const CharT* data() const NOEXCEPT {return p_;} - CONSTCD14 std::size_t size() const NOEXCEPT {return N-1;} - - CONSTCD14 const_iterator begin() const NOEXCEPT {return p_;} - CONSTCD14 const_iterator end() const NOEXCEPT {return p_ + N-1;} - - CONSTCD14 CharT const& operator[](std::size_t n) const NOEXCEPT - { - return p_[n]; - } - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, const string_literal& s) - { - return os << s.p_; - } -}; - -template -CONSTCD14 -inline -string_literal, - N1 + N2 - 1> -operator+(const string_literal& x, const string_literal& y) NOEXCEPT -{ - using CharT = std::conditional_t; - return string_literal{string_literal{x}, - string_literal{y}}; -} - -template -inline -std::basic_string -operator+(std::basic_string x, - const string_literal& y) NOEXCEPT -{ - x.append(y.data(), y.size()); - return x; -} - -template -CONSTCD14 -inline -string_literal -msl(const CharT(&a)[N]) NOEXCEPT -{ - return string_literal{a}; -} - -template {} || - std::is_same{} || - std::is_same{} || - std::is_same{}>> -CONSTCD14 -inline -string_literal -msl(CharT c) NOEXCEPT -{ - return string_literal{c}; -} - -CONSTCD14 -inline -std::size_t -to_string_len(std::intmax_t i) -{ - std::size_t r = 0; - do - { - i /= 10; - ++r; - } while (i > 0); - return r; -} - -template -CONSTCD14 -inline -std::enable_if_t -< - N < 10, - string_literal -> -msl() NOEXCEPT -{ - return msl(char(N % 10 + '0')); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - 10 <= N, - string_literal -> -msl() NOEXCEPT -{ - return msl() + msl(char(N % 10 + '0')); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - std::ratio::type::den != 1, - string_literal::type::num) + - to_string_len(std::ratio::type::den) + 4> -> -msl(std::ratio) NOEXCEPT -{ - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{'/'}) + - msl() + msl(CharT{']'}); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - std::ratio::type::den == 1, - string_literal::type::num) + 3> -> -msl(std::ratio) NOEXCEPT -{ - using R = typename std::ratio::type; - return msl(CharT{'['}) + msl() + msl(CharT{']'}); -} - -template -CONSTCD14 -inline -auto -msl(std::atto) NOEXCEPT -{ - return msl(CharT{'a'}); -} - -template -CONSTCD14 -inline -auto -msl(std::femto) NOEXCEPT -{ - return msl(CharT{'f'}); -} - -template -CONSTCD14 -inline -auto -msl(std::pico) NOEXCEPT -{ - return msl(CharT{'p'}); -} - -template -CONSTCD14 -inline -auto -msl(std::nano) NOEXCEPT -{ - return msl(CharT{'n'}); -} - -template -CONSTCD14 -inline -std::enable_if_t -< - std::is_same{}, - string_literal -> -msl(std::micro) NOEXCEPT -{ - return string_literal{"\xC2\xB5"}; -} - -template -CONSTCD14 -inline -std::enable_if_t -< - !std::is_same{}, - string_literal -> -msl(std::micro) NOEXCEPT -{ - return string_literal{CharT{static_cast('\xB5')}}; -} - -template -CONSTCD14 -inline -auto -msl(std::milli) NOEXCEPT -{ - return msl(CharT{'m'}); -} - -template -CONSTCD14 -inline -auto -msl(std::centi) NOEXCEPT -{ - return msl(CharT{'c'}); -} - -template -CONSTCD14 -inline -auto -msl(std::deci) NOEXCEPT -{ - return msl(CharT{'d'}); -} - -template -CONSTCD14 -inline -auto -msl(std::deca) NOEXCEPT -{ - return string_literal{"da"}; -} - -template -CONSTCD14 -inline -auto -msl(std::hecto) NOEXCEPT -{ - return msl(CharT{'h'}); -} - -template -CONSTCD14 -inline -auto -msl(std::kilo) NOEXCEPT -{ - return msl(CharT{'k'}); -} - -template -CONSTCD14 -inline -auto -msl(std::mega) NOEXCEPT -{ - return msl(CharT{'M'}); -} - -template -CONSTCD14 -inline -auto -msl(std::giga) NOEXCEPT -{ - return msl(CharT{'G'}); -} - -template -CONSTCD14 -inline -auto -msl(std::tera) NOEXCEPT -{ - return msl(CharT{'T'}); -} - -template -CONSTCD14 -inline -auto -msl(std::peta) NOEXCEPT -{ - return msl(CharT{'P'}); -} - -template -CONSTCD14 -inline -auto -msl(std::exa) NOEXCEPT -{ - return msl(CharT{'E'}); -} - -template -CONSTCD14 -auto -get_units(Period p) -{ - return msl(p) + string_literal{"s"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<1>) -{ - return string_literal{"s"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<60>) -{ - return string_literal{"min"}; -} - -template -CONSTCD14 -auto -get_units(std::ratio<3600>) -{ - return string_literal{"h"}; -} - -#else // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -inline -std::string -to_string(std::uint64_t x) -{ - return std::to_string(x); -} - -template -std::basic_string -to_string(std::uint64_t x) -{ - auto y = std::to_string(x); - return std::basic_string(y.begin(), y.end()); -} - -template -inline -typename std::enable_if -< - std::ratio::type::den != 1, - std::basic_string ->::type -msl(std::ratio) -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{'/'} + - to_string(R::den) + CharT{']'}; -} - -template -inline -typename std::enable_if -< - std::ratio::type::den == 1, - std::basic_string ->::type -msl(std::ratio) -{ - using R = typename std::ratio::type; - return std::basic_string(1, '[') + to_string(R::num) + CharT{']'}; -} - -template -inline -std::basic_string -msl(std::atto) -{ - return {'a'}; -} - -template -inline -std::basic_string -msl(std::femto) -{ - return {'f'}; -} - -template -inline -std::basic_string -msl(std::pico) -{ - return {'p'}; -} - -template -inline -std::basic_string -msl(std::nano) -{ - return {'n'}; -} - -template -inline -typename std::enable_if -< - std::is_same::value, - std::string ->::type -msl(std::micro) -{ - return "\xC2\xB5"; -} - -template -inline -typename std::enable_if -< - !std::is_same::value, - std::basic_string ->::type -msl(std::micro) -{ - return {CharT(static_cast('\xB5'))}; -} - -template -inline -std::basic_string -msl(std::milli) -{ - return {'m'}; -} - -template -inline -std::basic_string -msl(std::centi) -{ - return {'c'}; -} - -template -inline -std::basic_string -msl(std::deci) -{ - return {'d'}; -} - -template -inline -std::basic_string -msl(std::deca) -{ - return {'d', 'a'}; -} - -template -inline -std::basic_string -msl(std::hecto) -{ - return {'h'}; -} - -template -inline -std::basic_string -msl(std::kilo) -{ - return {'k'}; -} - -template -inline -std::basic_string -msl(std::mega) -{ - return {'M'}; -} - -template -inline -std::basic_string -msl(std::giga) -{ - return {'G'}; -} - -template -inline -std::basic_string -msl(std::tera) -{ - return {'T'}; -} - -template -inline -std::basic_string -msl(std::peta) -{ - return {'P'}; -} - -template -inline -std::basic_string -msl(std::exa) -{ - return {'E'}; -} - -template -std::basic_string -get_units(Period p) -{ - return msl(p) + CharT{'s'}; -} - -template -std::basic_string -get_units(std::ratio<1>) -{ - return {'s'}; -} - -template -std::basic_string -get_units(std::ratio<60>) -{ - return {'m', 'i', 'n'}; -} - -template -std::basic_string -get_units(std::ratio<3600>) -{ - return {'h'}; -} - -#endif // __cplusplus < 201402 || (defined(__EDG_VERSION__) && __EDG_VERSION__ <= 411) - -template > -struct make_string; - -template <> -struct make_string -{ - template - static - std::string - from(Rep n) - { - return std::to_string(n); - } -}; - -template -struct make_string -{ - template - static - std::basic_string - from(Rep n) - { - auto s = std::to_string(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -template <> -struct make_string -{ - template - static - std::wstring - from(Rep n) - { - return std::to_wstring(n); - } -}; - -template -struct make_string -{ - template - static - std::basic_string - from(Rep n) - { - auto s = std::to_wstring(n); - return std::basic_string(s.begin(), s.end()); - } -}; - -} // namespace detail - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, - const std::chrono::duration& d) -{ - using namespace detail; - return os << make_string::from(d.count()) + - get_units(typename Period::type{}); -} - -} // namespace date - - -#ifdef __GNUC__ -# pragma GCC diagnostic pop -#endif - - -#endif // DATE_H diff --git a/src/date/include/date/ios.h b/src/date/include/date/ios.h deleted file mode 100644 index 3f791bdb72..0000000000 --- a/src/date/include/date/ios.h +++ /dev/null @@ -1,49 +0,0 @@ -// -// ios.h -// DateTimeLib -// -// The MIT License (MIT) -// -// Copyright (c) 2016 Alexander Kormanovsky -// -// 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. - -#ifndef ios_hpp -#define ios_hpp - -#if __APPLE__ -# include -# if TARGET_OS_IPHONE -# include - - namespace date - { - namespace iOSUtils - { - - std::string get_tzdata_path(); - - } // namespace iOSUtils - } // namespace date - -# endif // TARGET_OS_IPHONE -#else // !__APPLE__ -# define TARGET_OS_IPHONE 0 -#endif // !__APPLE__ -#endif // ios_hpp diff --git a/src/date/include/date/ios.mm b/src/date/include/date/ios.mm deleted file mode 100644 index 247ba7cee5..0000000000 --- a/src/date/include/date/ios.mm +++ /dev/null @@ -1,337 +0,0 @@ -// -// The MIT License (MIT) -// -// Copyright (c) 2016 Alexander Kormanovsky -// -// 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. -// - -#include "ios.h" - -#if TARGET_OS_IPHONE - -#include - -#include -#include -#include - -#ifndef TAR_DEBUG -# define TAR_DEBUG 0 -#endif - -#define INTERNAL_DIR "Library" -#define TZDATA_DIR "tzdata" -#define TARGZ_EXTENSION "tar.gz" - -#define TAR_BLOCK_SIZE 512 -#define TAR_TYPE_POSITION 156 -#define TAR_NAME_POSITION 0 -#define TAR_NAME_SIZE 100 -#define TAR_SIZE_POSITION 124 -#define TAR_SIZE_SIZE 12 - -namespace date -{ - namespace iOSUtils - { - - struct TarInfo - { - char objType; - std::string objName; - size_t realContentSize; // writable size without padding zeroes - size_t blocksContentSize; // adjusted size to 512 bytes blocks - bool success; - }; - - std::string convertCFStringRefPathToCStringPath(CFStringRef ref); - bool extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath); - TarInfo getTarObjectInfo(std::ifstream &readStream); - std::string getTarObject(std::ifstream &readStream, int64_t size); - bool writeFile(const std::string &tzdataPath, const std::string &fileName, - const std::string &data, size_t realContentSize); - - std::string - get_current_timezone() - { - CFTimeZoneRef tzRef = CFTimeZoneCopySystem(); - CFStringRef tzNameRef = CFTimeZoneGetName(tzRef); - CFIndex bufferSize = CFStringGetLength(tzNameRef) + 1; - char buffer[bufferSize]; - - if (CFStringGetCString(tzNameRef, buffer, bufferSize, kCFStringEncodingUTF8)) - { - CFRelease(tzRef); - return std::string(buffer); - } - - CFRelease(tzRef); - - return ""; - } - - std::string - get_tzdata_path() - { - CFURLRef homeUrlRef = CFCopyHomeDirectoryURL(); - CFStringRef homePath = CFURLCopyPath(homeUrlRef); - std::string path(std::string(convertCFStringRefPathToCStringPath(homePath)) + - INTERNAL_DIR + "/" + TZDATA_DIR); - std::string result_path(std::string(convertCFStringRefPathToCStringPath(homePath)) + - INTERNAL_DIR); - - if (access(path.c_str(), F_OK) == 0) - { -#if TAR_DEBUG - printf("tzdata dir exists\n"); -#endif - CFRelease(homeUrlRef); - CFRelease(homePath); - - return result_path; - } - - CFBundleRef mainBundle = CFBundleGetMainBundle(); - CFArrayRef paths = CFBundleCopyResourceURLsOfType(mainBundle, CFSTR(TARGZ_EXTENSION), - NULL); - - if (CFArrayGetCount(paths) != 0) - { - // get archive path, assume there is no other tar.gz in bundle - CFURLRef archiveUrl = static_cast(CFArrayGetValueAtIndex(paths, 0)); - CFStringRef archiveName = CFURLCopyPath(archiveUrl); - archiveUrl = CFBundleCopyResourceURL(mainBundle, archiveName, NULL, NULL); - - extractTzdata(homeUrlRef, archiveUrl, path); - - CFRelease(archiveUrl); - CFRelease(archiveName); - } - - CFRelease(homeUrlRef); - CFRelease(homePath); - CFRelease(paths); - - return result_path; - } - - std::string - convertCFStringRefPathToCStringPath(CFStringRef ref) - { - CFIndex bufferSize = CFStringGetMaximumSizeOfFileSystemRepresentation(ref); - char *buffer = new char[bufferSize]; - CFStringGetFileSystemRepresentation(ref, buffer, bufferSize); - auto result = std::string(buffer); - delete[] buffer; - return result; - } - - bool - extractTzdata(CFURLRef homeUrl, CFURLRef archiveUrl, std::string destPath) - { - std::string TAR_TMP_PATH = "/tmp.tar"; - - CFStringRef homeStringRef = CFURLCopyPath(homeUrl); - auto homePath = convertCFStringRefPathToCStringPath(homeStringRef); - CFRelease(homeStringRef); - - CFStringRef archiveStringRef = CFURLCopyPath(archiveUrl); - auto archivePath = convertCFStringRefPathToCStringPath(archiveStringRef); - CFRelease(archiveStringRef); - - // create Library path - auto libraryPath = homePath + INTERNAL_DIR; - - // create tzdata path - auto tzdataPath = libraryPath + "/" + TZDATA_DIR; - - // -- replace %20 with " " - const std::string search = "%20"; - const std::string replacement = " "; - size_t pos = 0; - - while ((pos = archivePath.find(search, pos)) != std::string::npos) { - archivePath.replace(pos, search.length(), replacement); - pos += replacement.length(); - } - - gzFile tarFile = gzopen(archivePath.c_str(), "rb"); - - // create tar unpacking path - auto tarPath = libraryPath + TAR_TMP_PATH; - - // create tzdata directory - mkdir(destPath.c_str(), S_IRWXU | S_IRWXG | S_IROTH | S_IXOTH); - - // ======= extract tar ======== - - std::ofstream os(tarPath.c_str(), std::ofstream::out | std::ofstream::app); - unsigned int bufferLength = 1024 * 256; // 256Kb - unsigned char *buffer = (unsigned char *)malloc(bufferLength); - bool success = true; - - while (true) - { - int readBytes = gzread(tarFile, buffer, bufferLength); - - if (readBytes > 0) - { - os.write((char *) &buffer[0], readBytes); - } - else - if (readBytes == 0) - { - break; - } - else - if (readBytes == -1) - { - printf("decompression failed\n"); - success = false; - break; - } - else - { - printf("unexpected zlib state\n"); - success = false; - break; - } - } - - os.close(); - free(buffer); - gzclose(tarFile); - - if (!success) - { - remove(tarPath.c_str()); - return false; - } - - // ======== extract files ========= - - uint64_t location = 0; // Position in the file - - // get file size - struct stat stat_buf; - int res = stat(tarPath.c_str(), &stat_buf); - if (res != 0) - { - printf("error file size\n"); - remove(tarPath.c_str()); - return false; - } - int64_t tarSize = stat_buf.st_size; - - // create read stream - std::ifstream is(tarPath.c_str(), std::ifstream::in | std::ifstream::binary); - - // process files - while (location < tarSize) - { - TarInfo info = getTarObjectInfo(is); - - if (!info.success || info.realContentSize == 0) - { - break; // something wrong or all files are read - } - - switch (info.objType) - { - case '0': // file - case '\0': // - { - std::string obj = getTarObject(is, info.blocksContentSize); -#if TAR_DEBUG - size += info.realContentSize; - printf("#%i %s file size %lld written total %ld from %lld\n", ++count, - info.objName.c_str(), info.realContentSize, size, tarSize); -#endif - writeFile(tzdataPath, info.objName, obj, info.realContentSize); - location += info.blocksContentSize; - - break; - } - } - } - - remove(tarPath.c_str()); - - return true; - } - - TarInfo - getTarObjectInfo(std::ifstream &readStream) - { - int64_t length = TAR_BLOCK_SIZE; - char buffer[length]; - char type; - char name[TAR_NAME_SIZE + 1]; - char sizeBuf[TAR_SIZE_SIZE + 1]; - - readStream.read(buffer, length); - - memcpy(&type, &buffer[TAR_TYPE_POSITION], 1); - - memset(&name, '\0', TAR_NAME_SIZE + 1); - memcpy(&name, &buffer[TAR_NAME_POSITION], TAR_NAME_SIZE); - - memset(&sizeBuf, '\0', TAR_SIZE_SIZE + 1); - memcpy(&sizeBuf, &buffer[TAR_SIZE_POSITION], TAR_SIZE_SIZE); - size_t realSize = strtol(sizeBuf, NULL, 8); - size_t blocksSize = realSize + (TAR_BLOCK_SIZE - (realSize % TAR_BLOCK_SIZE)); - - return {type, std::string(name), realSize, blocksSize, true}; - } - - std::string - getTarObject(std::ifstream &readStream, int64_t size) - { - char buffer[size]; - readStream.read(buffer, size); - return std::string(buffer); - } - - bool - writeFile(const std::string &tzdataPath, const std::string &fileName, const std::string &data, - size_t realContentSize) - { - std::ofstream os(tzdataPath + "/" + fileName, std::ofstream::out | std::ofstream::binary); - - if (!os) { - return false; - } - - // trim empty space - char trimmedData[realContentSize + 1]; - memset(&trimmedData, '\0', realContentSize); - memcpy(&trimmedData, data.c_str(), realContentSize); - - // write - os.write(trimmedData, realContentSize); - os.close(); - - return true; - } - - } // namespace iOSUtils -} // namespace date - -#endif // TARGET_OS_IPHONE diff --git a/src/date/include/date/islamic.h b/src/date/include/date/islamic.h deleted file mode 100644 index b18c493f01..0000000000 --- a/src/date/include/date/islamic.h +++ /dev/null @@ -1,3031 +0,0 @@ -#ifndef ISLAMIC_H -#define ISLAMIC_H - -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#include "date.h" - -namespace islamic -{ - -// durations - -using days = date::days; - -using weeks = date::weeks; - -using years = std::chrono::duration - , days::period>>; - -using months = std::chrono::duration - >>; - -// time_point - -using sys_days = date::sys_days; -using local_days = date::local_days; - -// types - -struct last_spec -{ - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day -{ - unsigned char d_; - -public: - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d); - -// month - -class month -{ - unsigned char m_; - -public: - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m); - -// year - -class year -{ - short y_; - -public: - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday -{ - unsigned char wd_; -public: - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - explicit weekday(int) = delete; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed -{ - unsigned char wd_ : 4; - unsigned char index_ : 4; - -public: - CONSTCD11 weekday_indexed(const islamic::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 islamic::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last -{ - islamic::weekday wd_; - -public: - explicit CONSTCD11 weekday_last(const islamic::weekday& wd) NOEXCEPT; - - CONSTCD11 islamic::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl); - -// year_month - -class year_month -{ - islamic::year y_; - islamic::month m_; - -public: - CONSTCD11 year_month(const islamic::year& y, const islamic::month& m) NOEXCEPT; - - CONSTCD11 islamic::year year() const NOEXCEPT; - CONSTCD11 islamic::month month() const NOEXCEPT; - - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day -{ - islamic::month m_; - islamic::day d_; - -public: - CONSTCD11 month_day(const islamic::month& m, const islamic::day& d) NOEXCEPT; - - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last -{ - islamic::month m_; - -public: - CONSTCD11 explicit month_day_last(const islamic::month& m) NOEXCEPT; - - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday -{ - islamic::month m_; - islamic::weekday_indexed wdi_; -public: - CONSTCD11 month_weekday(const islamic::month& m, - const islamic::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last -{ - islamic::month m_; - islamic::weekday_last wdl_; - -public: - CONSTCD11 month_weekday_last(const islamic::month& m, - const islamic::weekday_last& wd) NOEXCEPT; - - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day -{ - islamic::year y_; - islamic::month m_; - islamic::day d_; - -public: - CONSTCD11 year_month_day(const islamic::year& y, const islamic::month& m, - const islamic::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 islamic::year year() const NOEXCEPT; - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last -{ - islamic::year y_; - islamic::month_day_last mdl_; - -public: - CONSTCD11 year_month_day_last(const islamic::year& y, - const islamic::month_day_last& mdl) NOEXCEPT; - - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 islamic::year year() const NOEXCEPT; - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 islamic::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday -{ - islamic::year y_; - islamic::month m_; - islamic::weekday_indexed wdi_; - -public: - CONSTCD11 year_month_weekday(const islamic::year& y, const islamic::month& m, - const islamic::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 islamic::year year() const NOEXCEPT; - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 islamic::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last -{ - islamic::year y_; - islamic::month m_; - islamic::weekday_last wdl_; - -public: - CONSTCD11 year_month_weekday_last(const islamic::year& y, const islamic::month& m, - const islamic::weekday_last& wdl) NOEXCEPT; - - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 islamic::year year() const NOEXCEPT; - CONSTCD11 islamic::month month() const NOEXCEPT; - CONSTCD11 islamic::weekday weekday() const NOEXCEPT; - CONSTCD11 islamic::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 islamic::day operator "" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 islamic::year operator "" _y(unsigned long long y) NOEXCEPT; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -//----------------+ -// Implementation | -//----------------+ - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;} -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;} -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;} -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 30;} - -CONSTCD11 -inline -bool -operator==(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const day& x, const day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const day& x, const day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const day& x, const day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const day& x, const day& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -days -operator-(const day& x, const day& y) NOEXCEPT -{ - return days{static_cast(static_cast(x) - - static_cast(y))}; -} - -CONSTCD11 -inline -day -operator+(const day& x, const days& y) NOEXCEPT -{ - return day{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -day -operator+(const days& x, const day& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -day -operator-(const day& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {if (++m_ == 13) m_ = 1; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {if (--m_ == 0) m_ = 12; return *this;} -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -month& -month::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -month& -month::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;} - -CONSTCD11 -inline -bool -operator==(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const month& x, const month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const month& x, const month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month& x, const month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month& x, const month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -months -operator-(const month& x, const month& y) NOEXCEPT -{ - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline -month -operator+(const month& x, const months& y) NOEXCEPT -{ - auto const mu = static_cast(static_cast(x)) - 1 + y.count(); - auto const yr = (mu >= 0 ? mu : mu-11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline -month -operator+(const months& x, const month& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -month -operator-(const month& x, const months& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) -{ - switch (static_cast(m)) - { - case 1: - os << "Muharram"; - break; - case 2: - os << "Safar"; - break; - case 3: - os << "Rabi' al-awwal"; - break; - case 4: - os << "Rabi' al-thani"; - break; - case 5: - os << "Jumada al-awwal"; - break; - case 6: - os << "Jumada al-Thani"; - break; - case 7: - os << "Rajab"; - break; - case 8: - os << "Sha'ban"; - break; - case 9: - os << "Ramadan"; - break; - case 10: - os << "Shawwal"; - break; - case 11: - os << "Dhu al-Qi'dah"; - break; - case 12: - os << "Dhu al-Hijjah"; - break; - default: - os << static_cast(m) << " is not a valid month"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;} -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;} -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} - -CONSTCD11 -inline -bool -year::is_leap() const NOEXCEPT -{ - int y = y_ - 1; - const int era = (y >= 0 ? y : y-29) / 30; - const unsigned yoe = static_cast(y - era * 30); - switch (yoe) - { - case 1: - case 4: - case 6: - case 9: - case 12: - case 15: - case 17: - case 20: - case 23: - case 25: - case 28: - return true; - default: - return false; - } -} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} -CONSTCD11 inline bool year::ok() const NOEXCEPT {return true;} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{std::numeric_limits::min()}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{std::numeric_limits::max()}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6)); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 7) wd_ = 0; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 0) wd_ = 6; return *this;} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -CONSTCD14 -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return static_cast(wd_); -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 0: - os << "al-Aḥad"; - break; - case 1: - os << "al-Ithnayn"; - break; - case 2: - os << "ath-Thulāthā’"; - break; - case 3: - os << "al-Arba‘ā’"; - break; - case 4: - os << "al-Khamīs"; - break; - case 5: - os << "al-Jum‘ah"; - break; - case 6: - os << "as-Sabt"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -islamic::day -operator "" _d(unsigned long long d) NOEXCEPT -{ - return islamic::day{static_cast(d)}; -} - -CONSTCD11 -inline -islamic::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return islamic::year(static_cast(y)); -} -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA islamic::last_spec last{}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weekday_indexed - -CONSTCD11 -inline -weekday -weekday_indexed::weekday() const NOEXCEPT -{ - return islamic::weekday{static_cast(wd_)}; -} - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;} - -CONSTCD11 -inline -bool -weekday_indexed::ok() const NOEXCEPT -{ - return weekday().ok() && 1 <= index_ && index_ <= 5; -} - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const islamic::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd))) - , index_(static_cast(index)) - {} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - return os << wdi.weekday() << '[' << wdi.index() << ']'; -} - -CONSTCD11 -inline -weekday_indexed -weekday::operator[](unsigned index) const NOEXCEPT -{ - return {*this, index}; -} - -CONSTCD11 -inline -bool -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return x.weekday() == y.weekday() && x.index() == y.index(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return !(x == y); -} - -// weekday_last - -CONSTCD11 inline islamic::weekday weekday_last::weekday() const NOEXCEPT {return wd_;} -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();} -CONSTCD11 inline weekday_last::weekday_last(const islamic::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline -bool -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl) -{ - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline -weekday_last -weekday::operator[](last_spec) const NOEXCEPT -{ - return weekday_last{*this}; -} - -// year_month - -CONSTCD11 -inline -year_month::year_month(const islamic::year& y, const islamic::month& m) NOEXCEPT - : y_(y) - , m_(m) - {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const months& dm) NOEXCEPT -{ - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month())); -} - -CONSTCD11 -inline -bool -operator>(const year_month& x, const year_month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -year_month -operator+(const year_month& ym, const months& dm) NOEXCEPT -{ - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -CONSTCD14 -inline -year_month -operator-(const year_month& ym, const months& dm) NOEXCEPT -{ - return ym + -dm; -} - -CONSTCD11 -inline -months -operator-(const year_month& x, const year_month& y) NOEXCEPT -{ - return (x.year() - y.year()) + - months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline -year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.month(); -} - -CONSTCD11 -inline -year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym) -{ - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline -month_day::month_day(const islamic::month& m, const islamic::day& d) NOEXCEPT - : m_(m) - , d_(d) - {} - -CONSTCD11 inline islamic::month month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline islamic::day month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -bool -month_day::ok() const NOEXCEPT -{ - CONSTDATA islamic::day d[] = - {30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 30_d}; - return m_.ok() && 1_d <= d_ && d_ <= d[static_cast(m_)-1]; -} - -CONSTCD11 -inline -bool -operator==(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())); -} - -CONSTCD11 -inline -bool -operator>(const month_day& x, const month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md) -{ - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();} -CONSTCD11 inline month_day_last::month_day_last(const islamic::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline -bool -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() < y.month(); -} - -CONSTCD11 -inline -bool -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl) -{ - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline -month_weekday::month_weekday(const islamic::month& m, - const islamic::weekday_indexed& wdi) NOEXCEPT - : m_(m) - , wdi_(wdi) - {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_indexed -month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD11 -inline -bool -month_weekday::ok() const NOEXCEPT -{ - return m_.ok() && wdi_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd) -{ - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline -month_weekday_last::month_weekday_last(const islamic::month& m, - const islamic::weekday_last& wdl) NOEXCEPT - : m_(m) - , wdl_(wdl) - {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_last -month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD11 -inline -bool -month_weekday_last::ok() const NOEXCEPT -{ - return m_.ok() && wdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) -{ - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline -year_month_day_last::year_month_day_last(const islamic::year& y, - const islamic::month_day_last& mdl) NOEXCEPT - : y_(y) - , mdl_(mdl) - {} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();} - -CONSTCD11 -inline -month_day_last -year_month_day_last::month_day_last() const NOEXCEPT -{ - return mdl_; -} - -CONSTCD14 -inline -day -year_month_day_last::day() const NOEXCEPT -{ - CONSTDATA islamic::day d[] = - {30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 29_d, 30_d, 29_d}; - return month() != islamic::month(12) || !y_.is_leap() ? - d[static_cast(month())-1] : 30_d; -} - -CONSTCD14 -inline -year_month_day_last::operator sys_days() const NOEXCEPT -{ - return sys_days(year()/month()/day()); -} - -CONSTCD14 -inline -year_month_day_last::operator local_days() const NOEXCEPT -{ - return local_days(year()/month()/day()); -} - -CONSTCD11 -inline -bool -year_month_day_last::ok() const NOEXCEPT -{ - return y_.ok() && mdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) -{ - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -CONSTCD14 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return ymdl + (-dm); -} - -CONSTCD11 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return {ymdl.year()+dy, ymdl.month_day_last()}; -} - -CONSTCD11 -inline -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dy; -} - -CONSTCD11 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return ymdl + (-dy); -} - -// year_month_day - -CONSTCD11 -inline -year_month_day::year_month_day(const islamic::year& y, const islamic::month& m, - const islamic::day& d) NOEXCEPT - : y_(y) - , m_(m) - , d_(d) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT - : y_(ymdl.year()) - , m_(ymdl.month()) - , d_(ymdl.day()) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(sys_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(local_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD14 -inline -days -year_month_day::to_days() const NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - 1; - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y-29) / 30; - auto const yoe = static_cast(y - era * 30); // [0, 29] - auto const doy = 29*(m-1) + m/2 + d-1; // [0, 354] - auto const doe = yoe * 354 + (11*(yoe+1)+3)/30 + doy; // [0, 10630] - return days{era * 10631 + static_cast(doe) - 492148}; -} - -CONSTCD14 -inline -year_month_day::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_day::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_day::ok() const NOEXCEPT -{ - if (!(y_.ok() && m_.ok())) - return false; - return 1_d <= d_ && d_ <= (y_/m_/last).day(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())))); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - return os; -} - -CONSTCD14 -inline -year_month_day -year_month_day::from_days(days dp) NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 492148; - auto const era = (z >= 0 ? z : z - 10630) / 10631; - auto const doe = static_cast(z - era * 10631); // [0, 10630] - auto const yoe = (30*doe + 10646)/10631 - 1; // [0, 29] - auto const y = static_cast(yoe) + era * 30 + 1; - auto const doy = doe - (yoe * 354 + (11*(yoe+1)+3)/30); // [0, 354] - auto const m = (11*doy + 330) / 325; // [1, 12] - auto const d = doy - (29*(m-1) + m/2) + 1; // [1, 30] - return year_month_day{islamic::year{y}, islamic::month(m), islamic::day(d)}; -} - -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -CONSTCD14 -inline -year_month_day -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return ymd + (-dm); -} - -CONSTCD11 -inline -year_month_day -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return (ymd.year() + dy) / ymd.month() / ymd.day(); -} - -CONSTCD11 -inline -year_month_day -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dy; -} - -CONSTCD11 -inline -year_month_day -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return ymd + (-dy); -} - -// year_month_weekday - -CONSTCD11 -inline -year_month_weekday::year_month_weekday(const islamic::year& y, const islamic::month& m, - const islamic::weekday_indexed& wdi) - NOEXCEPT - : y_(y) - , m_(m) - , wdi_(wdi) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday::weekday() const NOEXCEPT -{ - return wdi_.weekday(); -} - -CONSTCD11 -inline -unsigned -year_month_weekday::index() const NOEXCEPT -{ - return wdi_.index(); -} - -CONSTCD11 -inline -weekday_indexed -year_month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD14 -inline -year_month_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_weekday::ok() const NOEXCEPT -{ - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) - return false; - if (wdi_.index() <= 4) - return true; - auto d2 = wdi_.weekday() - islamic::weekday(y_/m_/1) + days((wdi_.index()-1)*7 + 1); - return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); -} - -CONSTCD14 -inline -year_month_weekday -year_month_weekday::from_days(days d) NOEXCEPT -{ - sys_days dp{d}; - auto const wd = islamic::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day())-1)/7+1]}; -} - -CONSTCD14 -inline -days -year_month_weekday::to_days() const NOEXCEPT -{ - auto d = sys_days(y_/m_/1); - return (d + (wdi_.weekday() - islamic::weekday(d) + days{(wdi_.index()-1)*7}) - ).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) -{ - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -CONSTCD14 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return ymwd + (-dm); -} - -CONSTCD11 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dy; -} - -CONSTCD11 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return ymwd + (-dy); -} - -// year_month_weekday_last - -CONSTCD11 -inline -year_month_weekday_last::year_month_weekday_last(const islamic::year& y, - const islamic::month& m, - const islamic::weekday_last& wdl) NOEXCEPT - : y_(y) - , m_(m) - , wdl_(wdl) - {} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday_last::weekday() const NOEXCEPT -{ - return wdl_.weekday(); -} - -CONSTCD11 -inline -weekday_last -year_month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD14 -inline -year_month_weekday_last::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday_last::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD11 -inline -bool -year_month_weekday_last::ok() const NOEXCEPT -{ - return y_.ok() && m_.ok() && wdl_.ok(); -} - -CONSTCD14 -inline -days -year_month_weekday_last::to_days() const NOEXCEPT -{ - auto const d = sys_days(y_/m_/last); - return (d - (islamic::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) -{ - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -CONSTCD14 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return ymwdl + (-dm); -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dy; -} - -CONSTCD11 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return ymwdl + (-dy); -} - -// year_month from operator/() - -CONSTCD11 -inline -year_month -operator/(const year& y, const month& m) NOEXCEPT -{ - return {y, m}; -} - -CONSTCD11 -inline -year_month -operator/(const year& y, int m) NOEXCEPT -{ - return y / month(static_cast(m)); -} - -// month_day from operator/() - -CONSTCD11 -inline -month_day -operator/(const month& m, const day& d) NOEXCEPT -{ - return {m, d}; -} - -CONSTCD11 -inline -month_day -operator/(const day& d, const month& m) NOEXCEPT -{ - return m / d; -} - -CONSTCD11 -inline -month_day -operator/(const month& m, int d) NOEXCEPT -{ - return m / day(static_cast(d)); -} - -CONSTCD11 -inline -month_day -operator/(int m, const day& d) NOEXCEPT -{ - return month(static_cast(m)) / d; -} - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;} - -// month_day_last from operator/() - -CONSTCD11 -inline -month_day_last -operator/(const month& m, last_spec) NOEXCEPT -{ - return month_day_last{m}; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, const month& m) NOEXCEPT -{ - return m/last; -} - -CONSTCD11 -inline -month_day_last -operator/(int m, last_spec) NOEXCEPT -{ - return month(static_cast(m))/last; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, int m) NOEXCEPT -{ - return m/last; -} - -// month_weekday from operator/() - -CONSTCD11 -inline -month_weekday -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT -{ - return {m, wdi}; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT -{ - return m / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(int m, const weekday_indexed& wdi) NOEXCEPT -{ - return month(static_cast(m)) / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, int m) NOEXCEPT -{ - return m / wdi; -} - -// month_weekday_last from operator/() - -CONSTCD11 -inline -month_weekday_last -operator/(const month& m, const weekday_last& wdl) NOEXCEPT -{ - return {m, wdl}; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, const month& m) NOEXCEPT -{ - return m / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(int m, const weekday_last& wdl) NOEXCEPT -{ - return month(static_cast(m)) / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, int m) NOEXCEPT -{ - return m / wdl; -} - -// year_month_day from operator/() - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, const day& d) NOEXCEPT -{ - return {ym.year(), ym.month(), d}; -} - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, int d) NOEXCEPT -{ - return ym / day(static_cast(d)); -} - -CONSTCD11 -inline -year_month_day -operator/(const year& y, const month_day& md) NOEXCEPT -{ - return y / md.month() / md.day(); -} - -CONSTCD11 -inline -year_month_day -operator/(int y, const month_day& md) NOEXCEPT -{ - return year(y) / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, const year& y) NOEXCEPT -{ - return y / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, int y) NOEXCEPT -{ - return year(y) / md; -} - -// year_month_day_last from operator/() - -CONSTCD11 -inline -year_month_day_last -operator/(const year_month& ym, last_spec) NOEXCEPT -{ - return {ym.year(), month_day_last{ym.month()}}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const year& y, const month_day_last& mdl) NOEXCEPT -{ - return {y, mdl}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(int y, const month_day_last& mdl) NOEXCEPT -{ - return year(y) / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, const year& y) NOEXCEPT -{ - return y / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, int y) NOEXCEPT -{ - return year(y) / mdl; -} - -// year_month_weekday from operator/() - -CONSTCD11 -inline -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT -{ - return {ym.year(), ym.month(), wdi}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT -{ - return {y, mwd.month(), mwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT -{ - return year(y) / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT -{ - return y / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT -{ - return year(y) / mwd; -} - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT -{ - return {ym.year(), ym.month(), wdl}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT -{ - return {y, mwdl.month(), mwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT -{ - return year(y) / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT -{ - return y / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT -{ - return year(y) / mwdl; -} - -} // namespace islamic - -#endif // ISLAMIC_H diff --git a/src/date/include/date/iso_week.h b/src/date/include/date/iso_week.h deleted file mode 100644 index 5bbeb0c809..0000000000 --- a/src/date/include/date/iso_week.h +++ /dev/null @@ -1,1745 +0,0 @@ -#ifndef ISO_WEEK_H -#define ISO_WEEK_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// -// 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. - -#include "date.h" - -#include - -namespace iso_week -{ - -// y/wn/wd -// wn/wd/y -// wd/wn/y - -using days = date::days; -using weeks = date::weeks; -using years = date::years; - -// time_point - -using sys_days = date::sys_days; -using local_days = date::local_days; - -// types - -struct last_week -{ - explicit last_week() = default; -}; - -class weekday; -class weeknum; -class year; - -class year_weeknum; -class year_lastweek; -class weeknum_weekday; -class lastweek_weekday; - -class year_weeknum_weekday; -class year_lastweek_weekday; - -// date composition operators - -CONSTCD11 year_weeknum operator/(const year& y, const weeknum& wn) NOEXCEPT; -CONSTCD11 year_weeknum operator/(const year& y, int wn) NOEXCEPT; - -CONSTCD11 year_lastweek operator/(const year& y, last_week wn) NOEXCEPT; - -CONSTCD11 weeknum_weekday operator/(const weeknum& wn, const weekday& wd) NOEXCEPT; -CONSTCD11 weeknum_weekday operator/(const weeknum& wn, int wd) NOEXCEPT; -CONSTCD11 weeknum_weekday operator/(const weekday& wd, const weeknum& wn) NOEXCEPT; -CONSTCD11 weeknum_weekday operator/(const weekday& wd, int wn) NOEXCEPT; - -CONSTCD11 lastweek_weekday operator/(const last_week& wn, const weekday& wd) NOEXCEPT; -CONSTCD11 lastweek_weekday operator/(const last_week& wn, int wd) NOEXCEPT; -CONSTCD11 lastweek_weekday operator/(const weekday& wd, const last_week& wn) NOEXCEPT; - -CONSTCD11 year_weeknum_weekday operator/(const year_weeknum& ywn, const weekday& wd) NOEXCEPT; -CONSTCD11 year_weeknum_weekday operator/(const year_weeknum& ywn, int wd) NOEXCEPT; -CONSTCD11 year_weeknum_weekday operator/(const weeknum_weekday& wnwd, const year& y) NOEXCEPT; -CONSTCD11 year_weeknum_weekday operator/(const weeknum_weekday& wnwd, int y) NOEXCEPT; - -CONSTCD11 year_lastweek_weekday operator/(const year_lastweek& ylw, const weekday& wd) NOEXCEPT; -CONSTCD11 year_lastweek_weekday operator/(const year_lastweek& ylw, int wd) NOEXCEPT; - -CONSTCD11 year_lastweek_weekday operator/(const lastweek_weekday& lwwd, const year& y) NOEXCEPT; -CONSTCD11 year_lastweek_weekday operator/(const lastweek_weekday& lwwd, int y) NOEXCEPT; - -// weekday - -class weekday -{ - unsigned char wd_; -public: - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - CONSTCD11 weekday(date::weekday wd) NOEXCEPT; - explicit weekday(int) = delete; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - weekday& operator++() NOEXCEPT; - weekday operator++(int) NOEXCEPT; - weekday& operator--() NOEXCEPT; - weekday operator--(int) NOEXCEPT; - - weekday& operator+=(const days& d) NOEXCEPT; - weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 operator date::weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; - static CONSTCD11 unsigned char to_iso_encoding(unsigned char) NOEXCEPT; - static CONSTCD11 unsigned from_iso_encoding(unsigned) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// year - -class year -{ - short y_; - -public: - explicit CONSTCD11 year(int y) NOEXCEPT; - - year& operator++() NOEXCEPT; - year operator++(int) NOEXCEPT; - year& operator--() NOEXCEPT; - year operator--(int) NOEXCEPT; - - year& operator+=(const years& y) NOEXCEPT; - year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weeknum - -class weeknum -{ - unsigned char wn_; - -public: - explicit CONSTCD11 weeknum(unsigned wn) NOEXCEPT; - - weeknum& operator++() NOEXCEPT; - weeknum operator++(int) NOEXCEPT; - weeknum& operator--() NOEXCEPT; - weeknum operator--(int) NOEXCEPT; - - weeknum& operator+=(const weeks& y) NOEXCEPT; - weeknum& operator-=(const weeks& y) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weeknum& x, const weeknum& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weeknum& x, const weeknum& y) NOEXCEPT; -CONSTCD11 bool operator< (const weeknum& x, const weeknum& y) NOEXCEPT; -CONSTCD11 bool operator> (const weeknum& x, const weeknum& y) NOEXCEPT; -CONSTCD11 bool operator<=(const weeknum& x, const weeknum& y) NOEXCEPT; -CONSTCD11 bool operator>=(const weeknum& x, const weeknum& y) NOEXCEPT; - -CONSTCD11 weeknum operator+(const weeknum& x, const weeks& y) NOEXCEPT; -CONSTCD11 weeknum operator+(const weeks& x, const weeknum& y) NOEXCEPT; -CONSTCD11 weeknum operator-(const weeknum& x, const weeks& y) NOEXCEPT; -CONSTCD11 weeks operator-(const weeknum& x, const weeknum& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weeknum& wn); - -// year_weeknum - -class year_weeknum -{ - iso_week::year y_; - iso_week::weeknum wn_; - -public: - CONSTCD11 year_weeknum(const iso_week::year& y, const iso_week::weeknum& wn) NOEXCEPT; - - CONSTCD11 iso_week::year year() const NOEXCEPT; - CONSTCD11 iso_week::weeknum weeknum() const NOEXCEPT; - - year_weeknum& operator+=(const years& dy) NOEXCEPT; - year_weeknum& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_weeknum& x, const year_weeknum& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_weeknum& x, const year_weeknum& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_weeknum& x, const year_weeknum& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT; - -CONSTCD11 year_weeknum operator+(const year_weeknum& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_weeknum operator+(const years& dy, const year_weeknum& ym) NOEXCEPT; -CONSTCD11 year_weeknum operator-(const year_weeknum& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_weeknum& ym); - -// year_lastweek - -class year_lastweek -{ - iso_week::year y_; - -public: - CONSTCD11 explicit year_lastweek(const iso_week::year& y) NOEXCEPT; - - CONSTCD11 iso_week::year year() const NOEXCEPT; - CONSTCD14 iso_week::weeknum weeknum() const NOEXCEPT; - - year_lastweek& operator+=(const years& dy) NOEXCEPT; - year_lastweek& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_lastweek& x, const year_lastweek& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_lastweek& x, const year_lastweek& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_lastweek& x, const year_lastweek& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT; - -CONSTCD11 year_lastweek operator+(const year_lastweek& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_lastweek operator+(const years& dy, const year_lastweek& ym) NOEXCEPT; -CONSTCD11 year_lastweek operator-(const year_lastweek& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_lastweek& ym); - -// weeknum_weekday - -class weeknum_weekday -{ - iso_week::weeknum wn_; - iso_week::weekday wd_; - -public: - CONSTCD11 weeknum_weekday(const iso_week::weeknum& wn, - const iso_week::weekday& wd) NOEXCEPT; - - CONSTCD11 iso_week::weeknum weeknum() const NOEXCEPT; - CONSTCD11 iso_week::weekday weekday() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator< (const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator> (const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator<=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator>=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weeknum_weekday& md); - -// lastweek_weekday - -class lastweek_weekday -{ - iso_week::weekday wd_; - -public: - CONSTCD11 explicit lastweek_weekday(const iso_week::weekday& wd) NOEXCEPT; - - CONSTCD11 iso_week::weekday weekday() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator< (const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator> (const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator<=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator>=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const lastweek_weekday& md); - -// year_lastweek_weekday - -class year_lastweek_weekday -{ - iso_week::year y_; - iso_week::weekday wd_; - -public: - CONSTCD11 year_lastweek_weekday(const iso_week::year& y, - const iso_week::weekday& wd) NOEXCEPT; - - year_lastweek_weekday& operator+=(const years& y) NOEXCEPT; - year_lastweek_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 iso_week::year year() const NOEXCEPT; - CONSTCD14 iso_week::weeknum weeknum() const NOEXCEPT; - CONSTCD11 iso_week::weekday weekday() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT; - -CONSTCD11 year_lastweek_weekday operator+(const year_lastweek_weekday& ywnwd, const years& y) NOEXCEPT; -CONSTCD11 year_lastweek_weekday operator+(const years& y, const year_lastweek_weekday& ywnwd) NOEXCEPT; -CONSTCD11 year_lastweek_weekday operator-(const year_lastweek_weekday& ywnwd, const years& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_lastweek_weekday& ywnwd); - -// class year_weeknum_weekday - -class year_weeknum_weekday -{ - iso_week::year y_; - iso_week::weeknum wn_; - iso_week::weekday wd_; - -public: - CONSTCD11 year_weeknum_weekday(const iso_week::year& y, const iso_week::weeknum& wn, - const iso_week::weekday& wd) NOEXCEPT; - CONSTCD14 year_weeknum_weekday(const year_lastweek_weekday& ylwwd) NOEXCEPT; - CONSTCD14 year_weeknum_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_weeknum_weekday(const local_days& dp) NOEXCEPT; - - year_weeknum_weekday& operator+=(const years& y) NOEXCEPT; - year_weeknum_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 iso_week::year year() const NOEXCEPT; - CONSTCD11 iso_week::weeknum weeknum() const NOEXCEPT; - CONSTCD11 iso_week::weekday weekday() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_weeknum_weekday from_days(days dp) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT; - -CONSTCD11 year_weeknum_weekday operator+(const year_weeknum_weekday& ywnwd, const years& y) NOEXCEPT; -CONSTCD11 year_weeknum_weekday operator+(const years& y, const year_weeknum_weekday& ywnwd) NOEXCEPT; -CONSTCD11 year_weeknum_weekday operator-(const year_weeknum_weekday& ywnwd, const years& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_weeknum_weekday& ywnwd); - -//----------------+ -// Implementation | -//----------------+ - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::to_iso_encoding(unsigned char z) NOEXCEPT -{ - return z != 0 ? z : (unsigned char)7; -} - -CONSTCD11 -inline -unsigned -weekday::from_iso_encoding(unsigned z) NOEXCEPT -{ - return z != 7 ? z : 0u; -} - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return to_iso_encoding(static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6))); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(date::weekday wd) NOEXCEPT - : wd_(to_iso_encoding(static_cast(wd))) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 8) wd_ = 1; return *this;} -inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 1) wd_ = 7; return *this;} -inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return wd_; -} - -CONSTCD11 -inline -weekday::operator date::weekday() const NOEXCEPT -{ - return date::weekday{from_iso_encoding(unsigned{wd_})}; -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return 1 <= wd_ && wd_ <= 7;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x) - 1u) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7) + 1u}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 7: - os << "Sun"; - break; - case 1: - os << "Mon"; - break; - case 2: - os << "Tue"; - break; - case 3: - os << "Wed"; - break; - case 4: - os << "Thu"; - break; - case 5: - os << "Fri"; - break; - case 6: - os << "Sat"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -inline year& year::operator++() NOEXCEPT {++y_; return *this;} -inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -inline year& year::operator--() NOEXCEPT {--y_; return *this;} -inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} -CONSTCD11 inline bool year::ok() const NOEXCEPT {return min() <= *this && *this <= max();} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - using namespace std::chrono; - static_assert(sizeof(seconds)*CHAR_BIT >= 41, "seconds may overflow"); - static_assert(sizeof(hours)*CHAR_BIT >= 30, "hours may overflow"); - return sizeof(minutes)*CHAR_BIT < 34 ? - year{1970} + duration_cast(minutes::min()) : - year{std::numeric_limits::min()}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - using namespace std::chrono; - static_assert(sizeof(seconds)*CHAR_BIT >= 41, "seconds may overflow"); - static_assert(sizeof(hours)*CHAR_BIT >= 30, "hours may overflow"); - return sizeof(minutes)*CHAR_BIT < 34 ? - year{1969} + duration_cast(minutes::max()) : - year{std::numeric_limits::max()}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -iso_week::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return iso_week::year(static_cast(y)); -} - -CONSTCD11 -inline -iso_week::weeknum -operator "" _w(unsigned long long wn) NOEXCEPT -{ - return iso_week::weeknum(static_cast(wn)); -} - -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA iso_week::last_week last{}; - -CONSTDATA iso_week::weekday sun{7u}; -CONSTDATA iso_week::weekday mon{1u}; -CONSTDATA iso_week::weekday tue{2u}; -CONSTDATA iso_week::weekday wed{3u}; -CONSTDATA iso_week::weekday thu{4u}; -CONSTDATA iso_week::weekday fri{5u}; -CONSTDATA iso_week::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weeknum - -CONSTCD11 -inline -weeknum::weeknum(unsigned wn) NOEXCEPT - : wn_(static_cast(wn)) - {} - -inline weeknum& weeknum::operator++() NOEXCEPT {++wn_; return *this;} -inline weeknum weeknum::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -inline weeknum& weeknum::operator--() NOEXCEPT {--wn_; return *this;} -inline weeknum weeknum::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -inline -weeknum& -weeknum::operator+=(const weeks& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -inline -weeknum& -weeknum::operator-=(const weeks& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline weeknum::operator unsigned() const NOEXCEPT {return wn_;} -CONSTCD11 inline bool weeknum::ok() const NOEXCEPT {return 1 <= wn_ && wn_ <= 53;} - -CONSTCD11 -inline -bool -operator==(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -weeks -operator-(const weeknum& x, const weeknum& y) NOEXCEPT -{ - return weeks{static_cast(static_cast(x)) - - static_cast(static_cast(y))}; -} - -CONSTCD11 -inline -weeknum -operator+(const weeknum& x, const weeks& y) NOEXCEPT -{ - return weeknum{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -weeknum -operator+(const weeks& x, const weeknum& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -weeknum -operator-(const weeknum& x, const weeks& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weeknum& wn) -{ - date::detail::save_stream _(os); - os << 'W'; - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(wn); - return os; -} - -// year_weeknum - -CONSTCD11 -inline -year_weeknum::year_weeknum(const iso_week::year& y, const iso_week::weeknum& wn) NOEXCEPT - : y_(y) - , wn_(wn) - {} - -CONSTCD11 inline year year_weeknum::year() const NOEXCEPT {return y_;} -CONSTCD11 inline weeknum year_weeknum::weeknum() const NOEXCEPT {return wn_;} -CONSTCD11 inline bool year_weeknum::ok() const NOEXCEPT -{ - return y_.ok() && 1u <= static_cast(wn_) && wn_ <= (y_/last).weeknum(); -} - -inline -year_weeknum& -year_weeknum::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -inline -year_weeknum& -year_weeknum::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return x.year() == y.year() && x.weeknum() == y.weeknum(); -} - -CONSTCD11 -inline -bool -operator!=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.weeknum() < y.weeknum())); -} - -CONSTCD11 -inline -bool -operator>(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_weeknum& x, const year_weeknum& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -year_weeknum -operator+(const year_weeknum& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.weeknum(); -} - -CONSTCD11 -inline -year_weeknum -operator+(const years& dy, const year_weeknum& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_weeknum -operator-(const year_weeknum& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_weeknum& ywn) -{ - return os << ywn.year() << '-' << ywn.weeknum(); -} - - -// year_lastweek - -CONSTCD11 -inline -year_lastweek::year_lastweek(const iso_week::year& y) NOEXCEPT - : y_(y) - {} - -CONSTCD11 inline year year_lastweek::year() const NOEXCEPT {return y_;} - -CONSTCD14 -inline -weeknum -year_lastweek::weeknum() const NOEXCEPT -{ - const auto y = date::year{static_cast(y_)}; - const auto s0 = sys_days((y-years{1})/12/date::thu[date::last]); - const auto s1 = sys_days(y/12/date::thu[date::last]); - return iso_week::weeknum(static_cast(date::trunc(s1-s0).count())); -} - -CONSTCD11 inline bool year_lastweek::ok() const NOEXCEPT {return y_.ok();} - -inline -year_lastweek& -year_lastweek::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -inline -year_lastweek& -year_lastweek::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return x.year() == y.year(); -} - -CONSTCD11 -inline -bool -operator!=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return x.year() < y.year(); -} - -CONSTCD11 -inline -bool -operator>(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_lastweek& x, const year_lastweek& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -year_lastweek -operator+(const year_lastweek& ym, const years& dy) NOEXCEPT -{ - return year_lastweek{ym.year() + dy}; -} - -CONSTCD11 -inline -year_lastweek -operator+(const years& dy, const year_lastweek& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_lastweek -operator-(const year_lastweek& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_lastweek& ywn) -{ - return os << ywn.year() << "-W last"; -} - -// weeknum_weekday - -CONSTCD11 -inline -weeknum_weekday::weeknum_weekday(const iso_week::weeknum& wn, - const iso_week::weekday& wd) NOEXCEPT - : wn_(wn) - , wd_(wd) - {} - -CONSTCD11 inline weeknum weeknum_weekday::weeknum() const NOEXCEPT {return wn_;} -CONSTCD11 inline weekday weeknum_weekday::weekday() const NOEXCEPT {return wd_;} - -CONSTCD14 -inline -bool -weeknum_weekday::ok() const NOEXCEPT -{ - return wn_.ok() && wd_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return x.weeknum() == y.weeknum() && x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return x.weeknum() < y.weeknum() ? true - : (x.weeknum() > y.weeknum() ? false - : (static_cast(x.weekday()) < static_cast(y.weekday()))); -} - -CONSTCD11 -inline -bool -operator>(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const weeknum_weekday& x, const weeknum_weekday& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weeknum_weekday& md) -{ - return os << md.weeknum() << '-' << md.weekday(); -} - -// lastweek_weekday - -CONSTCD11 -inline -lastweek_weekday::lastweek_weekday(const iso_week::weekday& wd) NOEXCEPT - : wd_(wd) - {} - -CONSTCD11 inline weekday lastweek_weekday::weekday() const NOEXCEPT {return wd_;} - -CONSTCD14 -inline -bool -lastweek_weekday::ok() const NOEXCEPT -{ - return wd_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return static_cast(x.weekday()) < static_cast(y.weekday()); -} - -CONSTCD11 -inline -bool -operator>(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const lastweek_weekday& x, const lastweek_weekday& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const lastweek_weekday& md) -{ - return os << "W last-" << md.weekday(); -} - -// year_lastweek_weekday - -CONSTCD11 -inline -year_lastweek_weekday::year_lastweek_weekday(const iso_week::year& y, - const iso_week::weekday& wd) NOEXCEPT - : y_(y) - , wd_(wd) - {} - -inline -year_lastweek_weekday& -year_lastweek_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -inline -year_lastweek_weekday& -year_lastweek_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_lastweek_weekday::year() const NOEXCEPT {return y_;} - -CONSTCD14 -inline -weeknum -year_lastweek_weekday::weeknum() const NOEXCEPT -{ - return (y_ / last).weeknum(); -} - -CONSTCD11 inline weekday year_lastweek_weekday::weekday() const NOEXCEPT {return wd_;} - -CONSTCD14 -inline -year_lastweek_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days(date::year{static_cast(y_)}/date::dec/date::thu[date::last]) - + (sun - thu) - (sun - wd_); -} - -CONSTCD14 -inline -year_lastweek_weekday::operator local_days() const NOEXCEPT -{ - return local_days(date::year{static_cast(y_)}/date::dec/date::thu[date::last]) - + (sun - thu) - (sun - wd_); -} - -CONSTCD11 -inline -bool -year_lastweek_weekday::ok() const NOEXCEPT -{ - return y_.ok() && wd_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (static_cast(x.weekday()) < static_cast(y.weekday()))); -} - -CONSTCD11 -inline -bool -operator>(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -year_lastweek_weekday -operator+(const year_lastweek_weekday& ywnwd, const years& y) NOEXCEPT -{ - return (ywnwd.year() + y) / last / ywnwd.weekday(); -} - -CONSTCD11 -inline -year_lastweek_weekday -operator+(const years& y, const year_lastweek_weekday& ywnwd) NOEXCEPT -{ - return ywnwd + y; -} - -CONSTCD11 -inline -year_lastweek_weekday -operator-(const year_lastweek_weekday& ywnwd, const years& y) NOEXCEPT -{ - return ywnwd + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_lastweek_weekday& ywnwd) -{ - return os << ywnwd.year() << "-W last-" << ywnwd.weekday(); -} - -// year_weeknum_weekday - -CONSTCD11 -inline -year_weeknum_weekday::year_weeknum_weekday(const iso_week::year& y, - const iso_week::weeknum& wn, - const iso_week::weekday& wd) NOEXCEPT - : y_(y) - , wn_(wn) - , wd_(wd) - {} - -CONSTCD14 -inline -year_weeknum_weekday::year_weeknum_weekday(const year_lastweek_weekday& ylwwd) NOEXCEPT - : y_(ylwwd.year()) - , wn_(ylwwd.weeknum()) - , wd_(ylwwd.weekday()) - {} - -CONSTCD14 -inline -year_weeknum_weekday::year_weeknum_weekday(const sys_days& dp) NOEXCEPT - : year_weeknum_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_weeknum_weekday::year_weeknum_weekday(const local_days& dp) NOEXCEPT - : year_weeknum_weekday(from_days(dp.time_since_epoch())) - {} - -inline -year_weeknum_weekday& -year_weeknum_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -inline -year_weeknum_weekday& -year_weeknum_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_weeknum_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline weeknum year_weeknum_weekday::weeknum() const NOEXCEPT {return wn_;} -CONSTCD11 inline weekday year_weeknum_weekday::weekday() const NOEXCEPT {return wd_;} - -CONSTCD14 -inline -year_weeknum_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days(date::year{static_cast(y_)-1}/date::dec/date::thu[date::last]) - + (date::mon - date::thu) + weeks{static_cast(wn_)-1} + (wd_ - mon); -} - -CONSTCD14 -inline -year_weeknum_weekday::operator local_days() const NOEXCEPT -{ - return local_days(date::year{static_cast(y_)-1}/date::dec/date::thu[date::last]) - + (date::mon - date::thu) + weeks{static_cast(wn_)-1} + (wd_ - mon); -} - -CONSTCD14 -inline -bool -year_weeknum_weekday::ok() const NOEXCEPT -{ - return y_.ok() && wd_.ok() && iso_week::weeknum{1u} <= wn_ && wn_ <= year_lastweek{y_}.weeknum(); -} - -CONSTCD14 -inline -year_weeknum_weekday -year_weeknum_weekday::from_days(days d) NOEXCEPT -{ - const auto dp = sys_days{d}; - const auto wd = iso_week::weekday{dp}; - auto y = date::year_month_day{dp + days{3}}.year(); - auto start = sys_days((y - date::years{1})/date::dec/date::thu[date::last]) + (mon-thu); - if (dp < start) - { - --y; - start = sys_days((y - date::years{1})/date::dec/date::thu[date::last]) + (mon-thu); - } - const auto wn = iso_week::weeknum( - static_cast(date::trunc(dp - start).count() + 1)); - return {iso_week::year(static_cast(y)), wn, wd}; -} - -CONSTCD11 -inline -bool -operator==(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.weeknum() == y.weeknum() && x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.weeknum() < y.weeknum() ? true - : (x.weeknum() > y.weeknum() ? false - : (static_cast(x.weekday()) < static_cast(y.weekday()))))); -} - -CONSTCD11 -inline -bool -operator>(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -year_weeknum_weekday -operator+(const year_weeknum_weekday& ywnwd, const years& y) NOEXCEPT -{ - return (ywnwd.year() + y) / ywnwd.weeknum() / ywnwd.weekday(); -} - -CONSTCD11 -inline -year_weeknum_weekday -operator+(const years& y, const year_weeknum_weekday& ywnwd) NOEXCEPT -{ - return ywnwd + y; -} - -CONSTCD11 -inline -year_weeknum_weekday -operator-(const year_weeknum_weekday& ywnwd, const years& y) NOEXCEPT -{ - return ywnwd + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_weeknum_weekday& ywnwd) -{ - return os << ywnwd.year() << '-' << ywnwd.weeknum() << '-' << ywnwd.weekday(); -} - -// date composition operators - -CONSTCD11 -inline -year_weeknum -operator/(const year& y, const weeknum& wn) NOEXCEPT -{ - return {y, wn}; -} - -CONSTCD11 -inline -year_weeknum -operator/(const year& y, int wn) NOEXCEPT -{ - return y/weeknum(static_cast(wn)); -} - -CONSTCD11 -inline -year_lastweek -operator/(const year& y, last_week) NOEXCEPT -{ - return year_lastweek{y}; -} - -CONSTCD11 -inline -weeknum_weekday -operator/(const weeknum& wn, const weekday& wd) NOEXCEPT -{ - return {wn, wd}; -} - -CONSTCD11 -inline -weeknum_weekday -operator/(const weeknum& wn, int wd) NOEXCEPT -{ - return wn/weekday{static_cast(wd)}; -} - -CONSTCD11 -inline -weeknum_weekday -operator/(const weekday& wd, const weeknum& wn) NOEXCEPT -{ - return wn/wd; -} - -CONSTCD11 -inline -weeknum_weekday -operator/(const weekday& wd, int wn) NOEXCEPT -{ - return weeknum{static_cast(wn)}/wd; -} - -CONSTCD11 -inline -lastweek_weekday -operator/(const last_week&, const weekday& wd) NOEXCEPT -{ - return lastweek_weekday{wd}; -} - -CONSTCD11 -inline -lastweek_weekday -operator/(const last_week& wn, int wd) NOEXCEPT -{ - return wn / weekday{static_cast(wd)}; -} - -CONSTCD11 -inline -lastweek_weekday -operator/(const weekday& wd, const last_week& wn) NOEXCEPT -{ - return wn / wd; -} - -CONSTCD11 -inline -year_weeknum_weekday -operator/(const year_weeknum& ywn, const weekday& wd) NOEXCEPT -{ - return {ywn.year(), ywn.weeknum(), wd}; -} - -CONSTCD11 -inline -year_weeknum_weekday -operator/(const year_weeknum& ywn, int wd) NOEXCEPT -{ - return ywn / weekday(static_cast(wd)); -} - -CONSTCD11 -inline -year_weeknum_weekday -operator/(const weeknum_weekday& wnwd, const year& y) NOEXCEPT -{ - return {y, wnwd.weeknum(), wnwd.weekday()}; -} - -CONSTCD11 -inline -year_weeknum_weekday -operator/(const weeknum_weekday& wnwd, int y) NOEXCEPT -{ - return wnwd / year{y}; -} - -CONSTCD11 -inline -year_lastweek_weekday -operator/(const year_lastweek& ylw, const weekday& wd) NOEXCEPT -{ - return {ylw.year(), wd}; -} - -CONSTCD11 -inline -year_lastweek_weekday -operator/(const year_lastweek& ylw, int wd) NOEXCEPT -{ - return ylw / weekday(static_cast(wd)); -} - -CONSTCD11 -inline -year_lastweek_weekday -operator/(const lastweek_weekday& lwwd, const year& y) NOEXCEPT -{ - return {y, lwwd.weekday()}; -} - -CONSTCD11 -inline -year_lastweek_weekday -operator/(const lastweek_weekday& lwwd, int y) NOEXCEPT -{ - return lwwd / year{y}; -} - -} // namespace iso_week - -#endif // ISO_WEEK_H diff --git a/src/date/include/date/julian.h b/src/date/include/date/julian.h deleted file mode 100644 index 4aac96394c..0000000000 --- a/src/date/include/date/julian.h +++ /dev/null @@ -1,3046 +0,0 @@ -#ifndef JULIAN_H -#define JULIAN_H - -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#include "date.h" - -namespace julian -{ - -// durations - -using days = date::days; - -using weeks = date::weeks; - -using years = std::chrono::duration - , days::period>>; - -using months = std::chrono::duration - >>; - -// time_point - -using sys_days = date::sys_days; -using local_days = date::local_days; - -// types - -struct last_spec -{ - explicit last_spec() = default; -}; - -class day; -class month; -class year; - -class weekday; -class weekday_indexed; -class weekday_last; - -class month_day; -class month_day_last; -class month_weekday; -class month_weekday_last; - -class year_month; - -class year_month_day; -class year_month_day_last; -class year_month_weekday; -class year_month_weekday_last; - -// date composition operators - -CONSTCD11 year_month operator/(const year& y, const month& m) NOEXCEPT; -CONSTCD11 year_month operator/(const year& y, int m) NOEXCEPT; - -CONSTCD11 month_day operator/(const day& d, const month& m) NOEXCEPT; -CONSTCD11 month_day operator/(const day& d, int m) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, const day& d) NOEXCEPT; -CONSTCD11 month_day operator/(const month& m, int d) NOEXCEPT; -CONSTCD11 month_day operator/(int m, const day& d) NOEXCEPT; - -CONSTCD11 month_day_last operator/(const month& m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(int m, last_spec) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, const month& m) NOEXCEPT; -CONSTCD11 month_day_last operator/(last_spec, int m) NOEXCEPT; - -CONSTCD11 month_weekday operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(int m, const weekday_indexed& wdi) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT; -CONSTCD11 month_weekday operator/(const weekday_indexed& wdi, int m) NOEXCEPT; - -CONSTCD11 month_weekday_last operator/(const month& m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(int m, const weekday_last& wdl) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, const month& m) NOEXCEPT; -CONSTCD11 month_weekday_last operator/(const weekday_last& wdl, int m) NOEXCEPT; - -CONSTCD11 year_month_day operator/(const year_month& ym, const day& d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year_month& ym, int d) NOEXCEPT; -CONSTCD11 year_month_day operator/(const year& y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(int y, const month_day& md) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, const year& y) NOEXCEPT; -CONSTCD11 year_month_day operator/(const month_day& md, int y) NOEXCEPT; - -CONSTCD11 - year_month_day_last operator/(const year_month& ym, last_spec) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const year& y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(int y, const month_day_last& mdl) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, const year& y) NOEXCEPT; -CONSTCD11 - year_month_day_last operator/(const month_day_last& mdl, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT; - -// Detailed interface - -// day - -class day -{ - unsigned char d_; - -public: - explicit CONSTCD11 day(unsigned d) NOEXCEPT; - - CONSTCD14 day& operator++() NOEXCEPT; - CONSTCD14 day operator++(int) NOEXCEPT; - CONSTCD14 day& operator--() NOEXCEPT; - CONSTCD14 day operator--(int) NOEXCEPT; - - CONSTCD14 day& operator+=(const days& d) NOEXCEPT; - CONSTCD14 day& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator< (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator> (const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const day& x, const day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const day& x, const day& y) NOEXCEPT; - -CONSTCD11 day operator+(const day& x, const days& y) NOEXCEPT; -CONSTCD11 day operator+(const days& x, const day& y) NOEXCEPT; -CONSTCD11 day operator-(const day& x, const days& y) NOEXCEPT; -CONSTCD11 days operator-(const day& x, const day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d); - -// month - -class month -{ - unsigned char m_; - -public: - explicit CONSTCD11 month(unsigned m) NOEXCEPT; - - CONSTCD14 month& operator++() NOEXCEPT; - CONSTCD14 month operator++(int) NOEXCEPT; - CONSTCD14 month& operator--() NOEXCEPT; - CONSTCD14 month operator--(int) NOEXCEPT; - - CONSTCD14 month& operator+=(const months& m) NOEXCEPT; - CONSTCD14 month& operator-=(const months& m) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator< (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator> (const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month& x, const month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month& x, const month& y) NOEXCEPT; - -CONSTCD14 month operator+(const month& x, const months& y) NOEXCEPT; -CONSTCD14 month operator+(const months& x, const month& y) NOEXCEPT; -CONSTCD14 month operator-(const month& x, const months& y) NOEXCEPT; -CONSTCD14 months operator-(const month& x, const month& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m); - -// year - -class year -{ - short y_; - -public: - explicit CONSTCD11 year(int y) NOEXCEPT; - - CONSTCD14 year& operator++() NOEXCEPT; - CONSTCD14 year operator++(int) NOEXCEPT; - CONSTCD14 year& operator--() NOEXCEPT; - CONSTCD14 year operator--(int) NOEXCEPT; - - CONSTCD14 year& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 bool is_leap() const NOEXCEPT; - - CONSTCD11 explicit operator int() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - static CONSTCD11 year min() NOEXCEPT; - static CONSTCD11 year max() NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator< (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator> (const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year& x, const year& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year& x, const year& y) NOEXCEPT; - -CONSTCD11 year operator+(const year& x, const years& y) NOEXCEPT; -CONSTCD11 year operator+(const years& x, const year& y) NOEXCEPT; -CONSTCD11 year operator-(const year& x, const years& y) NOEXCEPT; -CONSTCD11 years operator-(const year& x, const year& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y); - -// weekday - -class weekday -{ - unsigned char wd_; -public: - explicit CONSTCD11 weekday(unsigned wd) NOEXCEPT; - explicit weekday(int) = delete; - CONSTCD11 weekday(const sys_days& dp) NOEXCEPT; - CONSTCD11 explicit weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 weekday& operator++() NOEXCEPT; - CONSTCD14 weekday operator++(int) NOEXCEPT; - CONSTCD14 weekday& operator--() NOEXCEPT; - CONSTCD14 weekday operator--(int) NOEXCEPT; - - CONSTCD14 weekday& operator+=(const days& d) NOEXCEPT; - CONSTCD14 weekday& operator-=(const days& d) NOEXCEPT; - - CONSTCD11 explicit operator unsigned() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - - CONSTCD11 weekday_indexed operator[](unsigned index) const NOEXCEPT; - CONSTCD11 weekday_last operator[](last_spec) const NOEXCEPT; - -private: - static CONSTCD11 unsigned char weekday_from_days(int z) NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday& x, const weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday& x, const weekday& y) NOEXCEPT; - -CONSTCD14 weekday operator+(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 weekday operator+(const days& x, const weekday& y) NOEXCEPT; -CONSTCD14 weekday operator-(const weekday& x, const days& y) NOEXCEPT; -CONSTCD14 days operator-(const weekday& x, const weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd); - -// weekday_indexed - -class weekday_indexed -{ - unsigned char wd_ : 4; - unsigned char index_ : 4; - -public: - CONSTCD11 weekday_indexed(const julian::weekday& wd, unsigned index) NOEXCEPT; - - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi); - -// weekday_last - -class weekday_last -{ - julian::weekday wd_; - -public: - explicit CONSTCD11 weekday_last(const julian::weekday& wd) NOEXCEPT; - - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl); - -// year_month - -class year_month -{ - julian::year y_; - julian::month m_; - -public: - CONSTCD11 year_month(const julian::year& y, const julian::month& m) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - - CONSTCD14 year_month& operator+=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator-=(const months& dm) NOEXCEPT; - CONSTCD14 year_month& operator+=(const years& dy) NOEXCEPT; - CONSTCD14 year_month& operator-=(const years& dy) NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month& x, const year_month& y) NOEXCEPT; - -CONSTCD14 year_month operator+(const year_month& ym, const months& dm) NOEXCEPT; -CONSTCD14 year_month operator+(const months& dm, const year_month& ym) NOEXCEPT; -CONSTCD14 year_month operator-(const year_month& ym, const months& dm) NOEXCEPT; - -CONSTCD11 months operator-(const year_month& x, const year_month& y) NOEXCEPT; -CONSTCD11 year_month operator+(const year_month& ym, const years& dy) NOEXCEPT; -CONSTCD11 year_month operator+(const years& dy, const year_month& ym) NOEXCEPT; -CONSTCD11 year_month operator-(const year_month& ym, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym); - -// month_day - -class month_day -{ - julian::month m_; - julian::day d_; - -public: - CONSTCD11 month_day(const julian::month& m, const julian::day& d) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::day day() const NOEXCEPT; - - CONSTCD14 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day& x, const month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day& x, const month_day& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md); - -// month_day_last - -class month_day_last -{ - julian::month m_; - -public: - CONSTCD11 explicit month_day_last(const julian::month& m) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator< (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator> (const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT; -CONSTCD11 bool operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl); - -// month_weekday - -class month_weekday -{ - julian::month m_; - julian::weekday_indexed wdi_; -public: - CONSTCD11 month_weekday(const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT; -CONSTCD11 bool operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd); - -// month_weekday_last - -class month_weekday_last -{ - julian::month m_; - julian::weekday_last wdl_; - -public: - CONSTCD11 month_weekday_last(const julian::month& m, - const julian::weekday_last& wd) NOEXCEPT; - - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl); - -// class year_month_day - -class year_month_day -{ - julian::year y_; - julian::month m_; - julian::day d_; - -public: - CONSTCD11 year_month_day(const julian::year& y, const julian::month& m, - const julian::day& d) NOEXCEPT; - CONSTCD14 year_month_day(const year_month_day_last& ymdl) NOEXCEPT; - - CONSTCD14 year_month_day(sys_days dp) NOEXCEPT; - CONSTCD14 explicit year_month_day(local_days dp) NOEXCEPT; - - CONSTCD14 year_month_day& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_day from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 bool operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator< (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator> (const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT; -CONSTCD11 bool operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT; - -CONSTCD14 year_month_day operator+(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD14 year_month_day operator+(const months& dm, const year_month_day& ymd) NOEXCEPT; -CONSTCD14 year_month_day operator-(const year_month_day& ymd, const months& dm) NOEXCEPT; -CONSTCD11 year_month_day operator+(const year_month_day& ymd, const years& dy) NOEXCEPT; -CONSTCD11 year_month_day operator+(const years& dy, const year_month_day& ymd) NOEXCEPT; -CONSTCD11 year_month_day operator-(const year_month_day& ymd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd); - -// year_month_day_last - -class year_month_day_last -{ - julian::year y_; - julian::month_day_last mdl_; - -public: - CONSTCD11 year_month_day_last(const julian::year& y, - const julian::month_day_last& mdl) NOEXCEPT; - - CONSTCD14 year_month_day_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_day_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_day_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::month_day_last month_day_last() const NOEXCEPT; - CONSTCD14 julian::day day() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator< (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator> (const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; -CONSTCD11 - bool operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT; - -CONSTCD14 -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl); - -// year_month_weekday - -class year_month_weekday -{ - julian::year y_; - julian::month m_; - julian::weekday_indexed wdi_; - -public: - CONSTCD11 year_month_weekday(const julian::year& y, const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT; - CONSTCD14 year_month_weekday(const sys_days& dp) NOEXCEPT; - CONSTCD14 explicit year_month_weekday(const local_days& dp) NOEXCEPT; - - CONSTCD14 year_month_weekday& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 unsigned index() const NOEXCEPT; - CONSTCD11 julian::weekday_indexed weekday_indexed() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD14 bool ok() const NOEXCEPT; - -private: - static CONSTCD14 year_month_weekday from_days(days dp) NOEXCEPT; - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 - bool operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; -CONSTCD11 - bool operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT; - -CONSTCD14 -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi); - -// year_month_weekday_last - -class year_month_weekday_last -{ - julian::year y_; - julian::month m_; - julian::weekday_last wdl_; - -public: - CONSTCD11 year_month_weekday_last(const julian::year& y, const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT; - - CONSTCD14 year_month_weekday_last& operator+=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const months& m) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator+=(const years& y) NOEXCEPT; - CONSTCD14 year_month_weekday_last& operator-=(const years& y) NOEXCEPT; - - CONSTCD11 julian::year year() const NOEXCEPT; - CONSTCD11 julian::month month() const NOEXCEPT; - CONSTCD11 julian::weekday weekday() const NOEXCEPT; - CONSTCD11 julian::weekday_last weekday_last() const NOEXCEPT; - - CONSTCD14 operator sys_days() const NOEXCEPT; - CONSTCD14 explicit operator local_days() const NOEXCEPT; - CONSTCD11 bool ok() const NOEXCEPT; - -private: - CONSTCD14 days to_days() const NOEXCEPT; -}; - -CONSTCD11 -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD11 -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT; - -CONSTCD14 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT; - -CONSTCD11 -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl); - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 julian::day operator "" _d(unsigned long long d) NOEXCEPT; -CONSTCD11 julian::year operator "" _y(unsigned long long y) NOEXCEPT; - -// CONSTDATA julian::month jan{1}; -// CONSTDATA julian::month feb{2}; -// CONSTDATA julian::month mar{3}; -// CONSTDATA julian::month apr{4}; -// CONSTDATA julian::month may{5}; -// CONSTDATA julian::month jun{6}; -// CONSTDATA julian::month jul{7}; -// CONSTDATA julian::month aug{8}; -// CONSTDATA julian::month sep{9}; -// CONSTDATA julian::month oct{10}; -// CONSTDATA julian::month nov{11}; -// CONSTDATA julian::month dec{12}; - -} // inline namespace literals -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -//----------------+ -// Implementation | -//----------------+ - -// day - -CONSTCD11 inline day::day(unsigned d) NOEXCEPT : d_(static_cast(d)) {} -CONSTCD14 inline day& day::operator++() NOEXCEPT {++d_; return *this;} -CONSTCD14 inline day day::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline day& day::operator--() NOEXCEPT {--d_; return *this;} -CONSTCD14 inline day day::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline day& day::operator+=(const days& d) NOEXCEPT {*this = *this + d; return *this;} -CONSTCD14 inline day& day::operator-=(const days& d) NOEXCEPT {*this = *this - d; return *this;} -CONSTCD11 inline day::operator unsigned() const NOEXCEPT {return d_;} -CONSTCD11 inline bool day::ok() const NOEXCEPT {return 1 <= d_ && d_ <= 31;} - -CONSTCD11 -inline -bool -operator==(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const day& x, const day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const day& x, const day& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const day& x, const day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const day& x, const day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const day& x, const day& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -days -operator-(const day& x, const day& y) NOEXCEPT -{ - return days{static_cast(static_cast(x) - - static_cast(y))}; -} - -CONSTCD11 -inline -day -operator+(const day& x, const days& y) NOEXCEPT -{ - return day{static_cast(x) + static_cast(y.count())}; -} - -CONSTCD11 -inline -day -operator+(const days& x, const day& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -day -operator-(const day& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const day& d) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os.width(2); - os << static_cast(d); - return os; -} - -// month - -CONSTCD11 inline month::month(unsigned m) NOEXCEPT : m_(static_cast(m)) {} -CONSTCD14 inline month& month::operator++() NOEXCEPT {if (++m_ == 13) m_ = 1; return *this;} -CONSTCD14 inline month month::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline month& month::operator--() NOEXCEPT {if (--m_ == 0) m_ = 12; return *this;} -CONSTCD14 inline month month::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -month& -month::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -month& -month::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD11 inline month::operator unsigned() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month::ok() const NOEXCEPT {return 1 <= m_ && m_ <= 12;} - -CONSTCD11 -inline -bool -operator==(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const month& x, const month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month& x, const month& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const month& x, const month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month& x, const month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month& x, const month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -months -operator-(const month& x, const month& y) NOEXCEPT -{ - auto const d = static_cast(x) - static_cast(y); - return months(d <= 11 ? d : d + 12); -} - -CONSTCD14 -inline -month -operator+(const month& x, const months& y) NOEXCEPT -{ - auto const mu = static_cast(static_cast(x)) - 1 + y.count(); - auto const yr = (mu >= 0 ? mu : mu-11) / 12; - return month{static_cast(mu - yr * 12 + 1)}; -} - -CONSTCD14 -inline -month -operator+(const months& x, const month& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -month -operator-(const month& x, const months& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month& m) -{ - switch (static_cast(m)) - { - case 1: - os << "Jan"; - break; - case 2: - os << "Feb"; - break; - case 3: - os << "Mar"; - break; - case 4: - os << "Apr"; - break; - case 5: - os << "May"; - break; - case 6: - os << "Jun"; - break; - case 7: - os << "Jul"; - break; - case 8: - os << "Aug"; - break; - case 9: - os << "Sep"; - break; - case 10: - os << "Oct"; - break; - case 11: - os << "Nov"; - break; - case 12: - os << "Dec"; - break; - default: - os << static_cast(m) << " is not a valid month"; - break; - } - return os; -} - -// year - -CONSTCD11 inline year::year(int y) NOEXCEPT : y_(static_cast(y)) {} -CONSTCD14 inline year& year::operator++() NOEXCEPT {++y_; return *this;} -CONSTCD14 inline year year::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline year& year::operator--() NOEXCEPT {--y_; return *this;} -CONSTCD14 inline year year::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} -CONSTCD14 inline year& year::operator+=(const years& y) NOEXCEPT {*this = *this + y; return *this;} -CONSTCD14 inline year& year::operator-=(const years& y) NOEXCEPT {*this = *this - y; return *this;} - -CONSTCD11 -inline -bool -year::is_leap() const NOEXCEPT -{ - return y_ % 4 == 0; -} - -CONSTCD11 inline year::operator int() const NOEXCEPT {return y_;} -CONSTCD11 inline bool year::ok() const NOEXCEPT {return true;} - -CONSTCD11 -inline -year -year::min() NOEXCEPT -{ - return year{std::numeric_limits::min()}; -} - -CONSTCD11 -inline -year -year::max() NOEXCEPT -{ - return year{std::numeric_limits::max()}; -} - -CONSTCD11 -inline -bool -operator==(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const year& x, const year& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year& x, const year& y) NOEXCEPT -{ - return static_cast(x) < static_cast(y); -} - -CONSTCD11 -inline -bool -operator>(const year& x, const year& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year& x, const year& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year& x, const year& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD11 -inline -years -operator-(const year& x, const year& y) NOEXCEPT -{ - return years{static_cast(x) - static_cast(y)}; -} - -CONSTCD11 -inline -year -operator+(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) + y.count()}; -} - -CONSTCD11 -inline -year -operator+(const years& x, const year& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD11 -inline -year -operator-(const year& x, const years& y) NOEXCEPT -{ - return year{static_cast(x) - y.count()}; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year& y) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::internal); - os.width(4 + (y < year{0})); - os << static_cast(y); - return os; -} - -// weekday - -CONSTCD11 -inline -unsigned char -weekday::weekday_from_days(int z) NOEXCEPT -{ - return static_cast(static_cast( - z >= -4 ? (z+4) % 7 : (z+5) % 7 + 6)); -} - -CONSTCD11 -inline -weekday::weekday(unsigned wd) NOEXCEPT - : wd_(static_cast(wd)) - {} - -CONSTCD11 -inline -weekday::weekday(const sys_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD11 -inline -weekday::weekday(const local_days& dp) NOEXCEPT - : wd_(weekday_from_days(dp.time_since_epoch().count())) - {} - -CONSTCD14 inline weekday& weekday::operator++() NOEXCEPT {if (++wd_ == 7) wd_ = 0; return *this;} -CONSTCD14 inline weekday weekday::operator++(int) NOEXCEPT {auto tmp(*this); ++(*this); return tmp;} -CONSTCD14 inline weekday& weekday::operator--() NOEXCEPT {if (wd_-- == 0) wd_ = 6; return *this;} -CONSTCD14 inline weekday weekday::operator--(int) NOEXCEPT {auto tmp(*this); --(*this); return tmp;} - -CONSTCD14 -inline -weekday& -weekday::operator+=(const days& d) NOEXCEPT -{ - *this = *this + d; - return *this; -} - -CONSTCD14 -inline -weekday& -weekday::operator-=(const days& d) NOEXCEPT -{ - *this = *this - d; - return *this; -} - -CONSTCD11 -inline -weekday::operator unsigned() const NOEXCEPT -{ - return static_cast(wd_); -} - -CONSTCD11 inline bool weekday::ok() const NOEXCEPT {return wd_ <= 6;} - -CONSTCD11 -inline -bool -operator==(const weekday& x, const weekday& y) NOEXCEPT -{ - return static_cast(x) == static_cast(y); -} - -CONSTCD11 -inline -bool -operator!=(const weekday& x, const weekday& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD14 -inline -days -operator-(const weekday& x, const weekday& y) NOEXCEPT -{ - auto const diff = static_cast(x) - static_cast(y); - return days{diff <= 6 ? diff : diff + 7}; -} - -CONSTCD14 -inline -weekday -operator+(const weekday& x, const days& y) NOEXCEPT -{ - auto const wdu = static_cast(static_cast(x)) + y.count(); - auto const wk = (wdu >= 0 ? wdu : wdu-6) / 7; - return weekday{static_cast(wdu - wk * 7)}; -} - -CONSTCD14 -inline -weekday -operator+(const days& x, const weekday& y) NOEXCEPT -{ - return y + x; -} - -CONSTCD14 -inline -weekday -operator-(const weekday& x, const days& y) NOEXCEPT -{ - return x + -y; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday& wd) -{ - switch (static_cast(wd)) - { - case 0: - os << "Sun"; - break; - case 1: - os << "Mon"; - break; - case 2: - os << "Tue"; - break; - case 3: - os << "Wed"; - break; - case 4: - os << "Thu"; - break; - case 5: - os << "Fri"; - break; - case 6: - os << "Sat"; - break; - default: - os << static_cast(wd) << " is not a valid weekday"; - break; - } - return os; -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -inline namespace literals -{ - -CONSTCD11 -inline -julian::day -operator "" _d(unsigned long long d) NOEXCEPT -{ - return julian::day{static_cast(d)}; -} - -CONSTCD11 -inline -julian::year -operator "" _y(unsigned long long y) NOEXCEPT -{ - return julian::year(static_cast(y)); -} -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -CONSTDATA julian::last_spec last{}; - -CONSTDATA julian::month jan{1}; -CONSTDATA julian::month feb{2}; -CONSTDATA julian::month mar{3}; -CONSTDATA julian::month apr{4}; -CONSTDATA julian::month may{5}; -CONSTDATA julian::month jun{6}; -CONSTDATA julian::month jul{7}; -CONSTDATA julian::month aug{8}; -CONSTDATA julian::month sep{9}; -CONSTDATA julian::month oct{10}; -CONSTDATA julian::month nov{11}; -CONSTDATA julian::month dec{12}; - -CONSTDATA julian::weekday sun{0u}; -CONSTDATA julian::weekday mon{1u}; -CONSTDATA julian::weekday tue{2u}; -CONSTDATA julian::weekday wed{3u}; -CONSTDATA julian::weekday thu{4u}; -CONSTDATA julian::weekday fri{5u}; -CONSTDATA julian::weekday sat{6u}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -} // inline namespace literals -#endif - -// weekday_indexed - -CONSTCD11 -inline -weekday -weekday_indexed::weekday() const NOEXCEPT -{ - return julian::weekday{static_cast(wd_)}; -} - -CONSTCD11 inline unsigned weekday_indexed::index() const NOEXCEPT {return index_;} - -CONSTCD11 -inline -bool -weekday_indexed::ok() const NOEXCEPT -{ - return weekday().ok() && 1 <= index_ && index_ <= 5; -} - -CONSTCD11 -inline -weekday_indexed::weekday_indexed(const julian::weekday& wd, unsigned index) NOEXCEPT - : wd_(static_cast(static_cast(wd))) - , index_(static_cast(index)) - {} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_indexed& wdi) -{ - return os << wdi.weekday() << '[' << wdi.index() << ']'; -} - -CONSTCD11 -inline -weekday_indexed -weekday::operator[](unsigned index) const NOEXCEPT -{ - return {*this, index}; -} - -CONSTCD11 -inline -bool -operator==(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return x.weekday() == y.weekday() && x.index() == y.index(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_indexed& x, const weekday_indexed& y) NOEXCEPT -{ - return !(x == y); -} - -// weekday_last - -CONSTCD11 inline julian::weekday weekday_last::weekday() const NOEXCEPT {return wd_;} -CONSTCD11 inline bool weekday_last::ok() const NOEXCEPT {return wd_.ok();} -CONSTCD11 inline weekday_last::weekday_last(const julian::weekday& wd) NOEXCEPT : wd_(wd) {} - -CONSTCD11 -inline -bool -operator==(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return x.weekday() == y.weekday(); -} - -CONSTCD11 -inline -bool -operator!=(const weekday_last& x, const weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const weekday_last& wdl) -{ - return os << wdl.weekday() << "[last]"; -} - -CONSTCD11 -inline -weekday_last -weekday::operator[](last_spec) const NOEXCEPT -{ - return weekday_last{*this}; -} - -// year_month - -CONSTCD11 -inline -year_month::year_month(const julian::year& y, const julian::month& m) NOEXCEPT - : y_(y) - , m_(m) - {} - -CONSTCD11 inline year year_month::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool year_month::ok() const NOEXCEPT {return y_.ok() && m_.ok();} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const months& dm) NOEXCEPT -{ - *this = *this + dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const months& dm) NOEXCEPT -{ - *this = *this - dm; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator+=(const years& dy) NOEXCEPT -{ - *this = *this + dy; - return *this; -} - -CONSTCD14 -inline -year_month& -year_month::operator-=(const years& dy) NOEXCEPT -{ - *this = *this - dy; - return *this; -} - -CONSTCD11 -inline -bool -operator==(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month& x, const year_month& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month())); -} - -CONSTCD11 -inline -bool -operator>(const year_month& x, const year_month& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month& x, const year_month& y) NOEXCEPT -{ - return !(x < y); -} - -CONSTCD14 -inline -year_month -operator+(const year_month& ym, const months& dm) NOEXCEPT -{ - auto dmi = static_cast(static_cast(ym.month())) - 1 + dm.count(); - auto dy = (dmi >= 0 ? dmi : dmi-11) / 12; - dmi = dmi - dy * 12 + 1; - return (ym.year() + years(dy)) / month(static_cast(dmi)); -} - -CONSTCD14 -inline -year_month -operator+(const months& dm, const year_month& ym) NOEXCEPT -{ - return ym + dm; -} - -CONSTCD14 -inline -year_month -operator-(const year_month& ym, const months& dm) NOEXCEPT -{ - return ym + -dm; -} - -CONSTCD11 -inline -months -operator-(const year_month& x, const year_month& y) NOEXCEPT -{ - return (x.year() - y.year()) + - months(static_cast(x.month()) - static_cast(y.month())); -} - -CONSTCD11 -inline -year_month -operator+(const year_month& ym, const years& dy) NOEXCEPT -{ - return (ym.year() + dy) / ym.month(); -} - -CONSTCD11 -inline -year_month -operator+(const years& dy, const year_month& ym) NOEXCEPT -{ - return ym + dy; -} - -CONSTCD11 -inline -year_month -operator-(const year_month& ym, const years& dy) NOEXCEPT -{ - return ym + -dy; -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month& ym) -{ - return os << ym.year() << '/' << ym.month(); -} - -// month_day - -CONSTCD11 -inline -month_day::month_day(const julian::month& m, const julian::day& d) NOEXCEPT - : m_(m) - , d_(d) - {} - -CONSTCD11 inline julian::month month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline julian::day month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -bool -month_day::ok() const NOEXCEPT -{ - CONSTDATA julian::day d[] = - {31_d, 29_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; - return m_.ok() && 1_d <= d_ && d_ <= d[static_cast(m_)-1]; -} - -CONSTCD11 -inline -bool -operator==(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day& x, const month_day& y) NOEXCEPT -{ - return x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())); -} - -CONSTCD11 -inline -bool -operator>(const month_day& x, const month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day& x, const month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day& md) -{ - return os << md.month() << '/' << md.day(); -} - -// month_day_last - -CONSTCD11 inline month month_day_last::month() const NOEXCEPT {return m_;} -CONSTCD11 inline bool month_day_last::ok() const NOEXCEPT {return m_.ok();} -CONSTCD11 inline month_day_last::month_day_last(const julian::month& m) NOEXCEPT : m_(m) {} - -CONSTCD11 -inline -bool -operator==(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() == y.month(); -} - -CONSTCD11 -inline -bool -operator!=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return x.month() < y.month(); -} - -CONSTCD11 -inline -bool -operator>(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const month_day_last& x, const month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_day_last& mdl) -{ - return os << mdl.month() << "/last"; -} - -// month_weekday - -CONSTCD11 -inline -month_weekday::month_weekday(const julian::month& m, - const julian::weekday_indexed& wdi) NOEXCEPT - : m_(m) - , wdi_(wdi) - {} - -CONSTCD11 inline month month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_indexed -month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD11 -inline -bool -month_weekday::ok() const NOEXCEPT -{ - return m_.ok() && wdi_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday& x, const month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday& mwd) -{ - return os << mwd.month() << '/' << mwd.weekday_indexed(); -} - -// month_weekday_last - -CONSTCD11 -inline -month_weekday_last::month_weekday_last(const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT - : m_(m) - , wdl_(wdl) - {} - -CONSTCD11 inline month month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday_last -month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD11 -inline -bool -month_weekday_last::ok() const NOEXCEPT -{ - return m_.ok() && wdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return x.month() == y.month() && x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const month_weekday_last& x, const month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const month_weekday_last& mwdl) -{ - return os << mwdl.month() << '/' << mwdl.weekday_last(); -} - -// year_month_day_last - -CONSTCD11 -inline -year_month_day_last::year_month_day_last(const julian::year& y, - const julian::month_day_last& mdl) NOEXCEPT - : y_(y) - , mdl_(mdl) - {} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day_last& -year_month_day_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_day_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day_last::month() const NOEXCEPT {return mdl_.month();} - -CONSTCD11 -inline -month_day_last -year_month_day_last::month_day_last() const NOEXCEPT -{ - return mdl_; -} - -CONSTCD14 -inline -day -year_month_day_last::day() const NOEXCEPT -{ - CONSTDATA julian::day d[] = - {31_d, 28_d, 31_d, 30_d, 31_d, 30_d, 31_d, 31_d, 30_d, 31_d, 30_d, 31_d}; - return month() != feb || !y_.is_leap() ? d[static_cast(month())-1] : 29_d; -} - -CONSTCD14 -inline -year_month_day_last::operator sys_days() const NOEXCEPT -{ - return sys_days(year()/month()/day()); -} - -CONSTCD14 -inline -year_month_day_last::operator local_days() const NOEXCEPT -{ - return local_days(year()/month()/day()); -} - -CONSTCD11 -inline -bool -year_month_day_last::ok() const NOEXCEPT -{ - return y_.ok() && mdl_.ok(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month_day_last() == y.month_day_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month_day_last() < y.month_day_last())); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day_last& x, const year_month_day_last& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day_last& ymdl) -{ - return os << ymdl.year() << '/' << ymdl.month_day_last(); -} - -CONSTCD14 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return (ymdl.year() / ymdl.month() + dm) / last; -} - -CONSTCD14 -inline -year_month_day_last -operator+(const months& dm, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dm; -} - -CONSTCD14 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const months& dm) NOEXCEPT -{ - return ymdl + (-dm); -} - -CONSTCD11 -inline -year_month_day_last -operator+(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return {ymdl.year()+dy, ymdl.month_day_last()}; -} - -CONSTCD11 -inline -year_month_day_last -operator+(const years& dy, const year_month_day_last& ymdl) NOEXCEPT -{ - return ymdl + dy; -} - -CONSTCD11 -inline -year_month_day_last -operator-(const year_month_day_last& ymdl, const years& dy) NOEXCEPT -{ - return ymdl + (-dy); -} - -// year_month_day - -CONSTCD11 -inline -year_month_day::year_month_day(const julian::year& y, const julian::month& m, - const julian::day& d) NOEXCEPT - : y_(y) - , m_(m) - , d_(d) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(const year_month_day_last& ymdl) NOEXCEPT - : y_(ymdl.year()) - , m_(ymdl.month()) - , d_(ymdl.day()) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(sys_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_day::year_month_day(local_days dp) NOEXCEPT - : year_month_day(from_days(dp.time_since_epoch())) - {} - -CONSTCD11 inline year year_month_day::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_day::month() const NOEXCEPT {return m_;} -CONSTCD11 inline day year_month_day::day() const NOEXCEPT {return d_;} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_day& -year_month_day::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD14 -inline -days -year_month_day::to_days() const NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const y = static_cast(y_) - (m_ <= feb); - auto const m = static_cast(m_); - auto const d = static_cast(d_); - auto const era = (y >= 0 ? y : y-3) / 4; - auto const yoe = static_cast(y - era * 4); // [0, 3] - auto const doy = (153*(m > 2 ? m-3 : m+9) + 2)/5 + d-1; // [0, 365] - auto const doe = yoe * 365 + doy; // [0, 1460] - return days{era * 1461 + static_cast(doe) - 719470}; -} - -CONSTCD14 -inline -year_month_day::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_day::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_day::ok() const NOEXCEPT -{ - if (!(y_.ok() && m_.ok())) - return false; - return 1_d <= d_ && d_ <= (y_/m_/last).day(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && x.day() == y.day(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x == y); -} - -CONSTCD11 -inline -bool -operator<(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return x.year() < y.year() ? true - : (x.year() > y.year() ? false - : (x.month() < y.month() ? true - : (x.month() > y.month() ? false - : (x.day() < y.day())))); -} - -CONSTCD11 -inline -bool -operator>(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return y < x; -} - -CONSTCD11 -inline -bool -operator<=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(y < x); -} - -CONSTCD11 -inline -bool -operator>=(const year_month_day& x, const year_month_day& y) NOEXCEPT -{ - return !(x < y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_day& ymd) -{ - date::detail::save_stream _(os); - os.fill('0'); - os.flags(std::ios::dec | std::ios::right); - os << ymd.year() << '-'; - os.width(2); - os << static_cast(ymd.month()) << '-'; - os << ymd.day(); - return os; -} - -CONSTCD14 -inline -year_month_day -year_month_day::from_days(days dp) NOEXCEPT -{ - static_assert(std::numeric_limits::digits >= 18, - "This algorithm has not been ported to a 16 bit unsigned integer"); - static_assert(std::numeric_limits::digits >= 20, - "This algorithm has not been ported to a 16 bit signed integer"); - auto const z = dp.count() + 719470; - auto const era = (z >= 0 ? z : z - 1460) / 1461; - auto const doe = static_cast(z - era * 1461); // [0, 1460] - auto const yoe = (doe - doe/1460) / 365; // [0, 3] - auto const y = static_cast(yoe) + era * 4; - auto const doy = doe - 365*yoe; // [0, 365] - auto const mp = (5*doy + 2)/153; // [0, 11] - auto const d = doy - (153*mp+2)/5 + 1; // [1, 31] - auto const m = mp < 10 ? mp+3 : mp-9; // [1, 12] - return year_month_day{julian::year{y + (m <= 2)}, julian::month(m), julian::day(d)}; -} - -CONSTCD14 -inline -year_month_day -operator+(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return (ymd.year() / ymd.month() + dm) / ymd.day(); -} - -CONSTCD14 -inline -year_month_day -operator+(const months& dm, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dm; -} - -CONSTCD14 -inline -year_month_day -operator-(const year_month_day& ymd, const months& dm) NOEXCEPT -{ - return ymd + (-dm); -} - -CONSTCD11 -inline -year_month_day -operator+(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return (ymd.year() + dy) / ymd.month() / ymd.day(); -} - -CONSTCD11 -inline -year_month_day -operator+(const years& dy, const year_month_day& ymd) NOEXCEPT -{ - return ymd + dy; -} - -CONSTCD11 -inline -year_month_day -operator-(const year_month_day& ymd, const years& dy) NOEXCEPT -{ - return ymd + (-dy); -} - -// year_month_weekday - -CONSTCD11 -inline -year_month_weekday::year_month_weekday(const julian::year& y, const julian::month& m, - const julian::weekday_indexed& wdi) - NOEXCEPT - : y_(y) - , m_(m) - , wdi_(wdi) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const sys_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday::year_month_weekday(const local_days& dp) NOEXCEPT - : year_month_weekday(from_days(dp.time_since_epoch())) - {} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday& -year_month_weekday::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday::weekday() const NOEXCEPT -{ - return wdi_.weekday(); -} - -CONSTCD11 -inline -unsigned -year_month_weekday::index() const NOEXCEPT -{ - return wdi_.index(); -} - -CONSTCD11 -inline -weekday_indexed -year_month_weekday::weekday_indexed() const NOEXCEPT -{ - return wdi_; -} - -CONSTCD14 -inline -year_month_weekday::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD14 -inline -bool -year_month_weekday::ok() const NOEXCEPT -{ - if (!y_.ok() || !m_.ok() || !wdi_.weekday().ok() || wdi_.index() < 1) - return false; - if (wdi_.index() <= 4) - return true; - auto d2 = wdi_.weekday() - julian::weekday(y_/m_/1) + days((wdi_.index()-1)*7 + 1); - return static_cast(d2.count()) <= static_cast((y_/m_/last).day()); -} - -CONSTCD14 -inline -year_month_weekday -year_month_weekday::from_days(days d) NOEXCEPT -{ - sys_days dp{d}; - auto const wd = julian::weekday(dp); - auto const ymd = year_month_day(dp); - return {ymd.year(), ymd.month(), wd[(static_cast(ymd.day())-1)/7+1]}; -} - -CONSTCD14 -inline -days -year_month_weekday::to_days() const NOEXCEPT -{ - auto d = sys_days(y_/m_/1); - return (d + (wdi_.weekday() - julian::weekday(d) + days{(wdi_.index()-1)*7}) - ).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_indexed() == y.weekday_indexed(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday& x, const year_month_weekday& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday& ymwdi) -{ - return os << ymwdi.year() << '/' << ymwdi.month() - << '/' << ymwdi.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return (ymwd.year() / ymwd.month() + dm) / ymwd.weekday_indexed(); -} - -CONSTCD14 -inline -year_month_weekday -operator+(const months& dm, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dm; -} - -CONSTCD14 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const months& dm) NOEXCEPT -{ - return ymwd + (-dm); -} - -CONSTCD11 -inline -year_month_weekday -operator+(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return {ymwd.year()+dy, ymwd.month(), ymwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator+(const years& dy, const year_month_weekday& ymwd) NOEXCEPT -{ - return ymwd + dy; -} - -CONSTCD11 -inline -year_month_weekday -operator-(const year_month_weekday& ymwd, const years& dy) NOEXCEPT -{ - return ymwd + (-dy); -} - -// year_month_weekday_last - -CONSTCD11 -inline -year_month_weekday_last::year_month_weekday_last(const julian::year& y, - const julian::month& m, - const julian::weekday_last& wdl) NOEXCEPT - : y_(y) - , m_(m) - , wdl_(wdl) - {} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const months& m) NOEXCEPT -{ - *this = *this + m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const months& m) NOEXCEPT -{ - *this = *this - m; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator+=(const years& y) NOEXCEPT -{ - *this = *this + y; - return *this; -} - -CONSTCD14 -inline -year_month_weekday_last& -year_month_weekday_last::operator-=(const years& y) NOEXCEPT -{ - *this = *this - y; - return *this; -} - -CONSTCD11 inline year year_month_weekday_last::year() const NOEXCEPT {return y_;} -CONSTCD11 inline month year_month_weekday_last::month() const NOEXCEPT {return m_;} - -CONSTCD11 -inline -weekday -year_month_weekday_last::weekday() const NOEXCEPT -{ - return wdl_.weekday(); -} - -CONSTCD11 -inline -weekday_last -year_month_weekday_last::weekday_last() const NOEXCEPT -{ - return wdl_; -} - -CONSTCD14 -inline -year_month_weekday_last::operator sys_days() const NOEXCEPT -{ - return sys_days{to_days()}; -} - -CONSTCD14 -inline -year_month_weekday_last::operator local_days() const NOEXCEPT -{ - return local_days{to_days()}; -} - -CONSTCD11 -inline -bool -year_month_weekday_last::ok() const NOEXCEPT -{ - return y_.ok() && m_.ok() && wdl_.ok(); -} - -CONSTCD14 -inline -days -year_month_weekday_last::to_days() const NOEXCEPT -{ - auto const d = sys_days(y_/m_/last); - return (d - (julian::weekday{d} - wdl_.weekday())).time_since_epoch(); -} - -CONSTCD11 -inline -bool -operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return x.year() == y.year() && x.month() == y.month() && - x.weekday_last() == y.weekday_last(); -} - -CONSTCD11 -inline -bool -operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) NOEXCEPT -{ - return !(x == y); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const year_month_weekday_last& ymwdl) -{ - return os << ymwdl.year() << '/' << ymwdl.month() << '/' << ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return (ymwdl.year() / ymwdl.month() + dm) / ymwdl.weekday_last(); -} - -CONSTCD14 -inline -year_month_weekday_last -operator+(const months& dm, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dm; -} - -CONSTCD14 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const months& dm) NOEXCEPT -{ - return ymwdl + (-dm); -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return {ymwdl.year()+dy, ymwdl.month(), ymwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator+(const years& dy, const year_month_weekday_last& ymwdl) NOEXCEPT -{ - return ymwdl + dy; -} - -CONSTCD11 -inline -year_month_weekday_last -operator-(const year_month_weekday_last& ymwdl, const years& dy) NOEXCEPT -{ - return ymwdl + (-dy); -} - -// year_month from operator/() - -CONSTCD11 -inline -year_month -operator/(const year& y, const month& m) NOEXCEPT -{ - return {y, m}; -} - -CONSTCD11 -inline -year_month -operator/(const year& y, int m) NOEXCEPT -{ - return y / month(static_cast(m)); -} - -// month_day from operator/() - -CONSTCD11 -inline -month_day -operator/(const month& m, const day& d) NOEXCEPT -{ - return {m, d}; -} - -CONSTCD11 -inline -month_day -operator/(const day& d, const month& m) NOEXCEPT -{ - return m / d; -} - -CONSTCD11 -inline -month_day -operator/(const month& m, int d) NOEXCEPT -{ - return m / day(static_cast(d)); -} - -CONSTCD11 -inline -month_day -operator/(int m, const day& d) NOEXCEPT -{ - return month(static_cast(m)) / d; -} - -CONSTCD11 inline month_day operator/(const day& d, int m) NOEXCEPT {return m / d;} - -// month_day_last from operator/() - -CONSTCD11 -inline -month_day_last -operator/(const month& m, last_spec) NOEXCEPT -{ - return month_day_last{m}; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, const month& m) NOEXCEPT -{ - return m/last; -} - -CONSTCD11 -inline -month_day_last -operator/(int m, last_spec) NOEXCEPT -{ - return month(static_cast(m))/last; -} - -CONSTCD11 -inline -month_day_last -operator/(last_spec, int m) NOEXCEPT -{ - return m/last; -} - -// month_weekday from operator/() - -CONSTCD11 -inline -month_weekday -operator/(const month& m, const weekday_indexed& wdi) NOEXCEPT -{ - return {m, wdi}; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, const month& m) NOEXCEPT -{ - return m / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(int m, const weekday_indexed& wdi) NOEXCEPT -{ - return month(static_cast(m)) / wdi; -} - -CONSTCD11 -inline -month_weekday -operator/(const weekday_indexed& wdi, int m) NOEXCEPT -{ - return m / wdi; -} - -// month_weekday_last from operator/() - -CONSTCD11 -inline -month_weekday_last -operator/(const month& m, const weekday_last& wdl) NOEXCEPT -{ - return {m, wdl}; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, const month& m) NOEXCEPT -{ - return m / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(int m, const weekday_last& wdl) NOEXCEPT -{ - return month(static_cast(m)) / wdl; -} - -CONSTCD11 -inline -month_weekday_last -operator/(const weekday_last& wdl, int m) NOEXCEPT -{ - return m / wdl; -} - -// year_month_day from operator/() - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, const day& d) NOEXCEPT -{ - return {ym.year(), ym.month(), d}; -} - -CONSTCD11 -inline -year_month_day -operator/(const year_month& ym, int d) NOEXCEPT -{ - return ym / day(static_cast(d)); -} - -CONSTCD11 -inline -year_month_day -operator/(const year& y, const month_day& md) NOEXCEPT -{ - return y / md.month() / md.day(); -} - -CONSTCD11 -inline -year_month_day -operator/(int y, const month_day& md) NOEXCEPT -{ - return year(y) / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, const year& y) NOEXCEPT -{ - return y / md; -} - -CONSTCD11 -inline -year_month_day -operator/(const month_day& md, int y) NOEXCEPT -{ - return year(y) / md; -} - -// year_month_day_last from operator/() - -CONSTCD11 -inline -year_month_day_last -operator/(const year_month& ym, last_spec) NOEXCEPT -{ - return {ym.year(), month_day_last{ym.month()}}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const year& y, const month_day_last& mdl) NOEXCEPT -{ - return {y, mdl}; -} - -CONSTCD11 -inline -year_month_day_last -operator/(int y, const month_day_last& mdl) NOEXCEPT -{ - return year(y) / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, const year& y) NOEXCEPT -{ - return y / mdl; -} - -CONSTCD11 -inline -year_month_day_last -operator/(const month_day_last& mdl, int y) NOEXCEPT -{ - return year(y) / mdl; -} - -// year_month_weekday from operator/() - -CONSTCD11 -inline -year_month_weekday -operator/(const year_month& ym, const weekday_indexed& wdi) NOEXCEPT -{ - return {ym.year(), ym.month(), wdi}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const year& y, const month_weekday& mwd) NOEXCEPT -{ - return {y, mwd.month(), mwd.weekday_indexed()}; -} - -CONSTCD11 -inline -year_month_weekday -operator/(int y, const month_weekday& mwd) NOEXCEPT -{ - return year(y) / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, const year& y) NOEXCEPT -{ - return y / mwd; -} - -CONSTCD11 -inline -year_month_weekday -operator/(const month_weekday& mwd, int y) NOEXCEPT -{ - return year(y) / mwd; -} - -// year_month_weekday_last from operator/() - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year_month& ym, const weekday_last& wdl) NOEXCEPT -{ - return {ym.year(), ym.month(), wdl}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const year& y, const month_weekday_last& mwdl) NOEXCEPT -{ - return {y, mwdl.month(), mwdl.weekday_last()}; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(int y, const month_weekday_last& mwdl) NOEXCEPT -{ - return year(y) / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, const year& y) NOEXCEPT -{ - return y / mwdl; -} - -CONSTCD11 -inline -year_month_weekday_last -operator/(const month_weekday_last& mwdl, int y) NOEXCEPT -{ - return year(y) / mwdl; -} - -} // namespace julian - -#endif // JULIAN_H diff --git a/src/date/include/date/ptz.h b/src/date/include/date/ptz.h deleted file mode 100644 index 78be1d2fd4..0000000000 --- a/src/date/include/date/ptz.h +++ /dev/null @@ -1,592 +0,0 @@ -#ifndef PTZ_H -#define PTZ_H - -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// This header allows Posix-style time zones as specified for TZ here: -// http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08_03 -// -// Posix::time_zone can be constructed with a posix-style string and then used in -// a zoned_time like so: -// -// zoned_time zt{"EST5EDT,M3.2.0,M11.1.0", -// system_clock::now()}; -// or: -// -// Posix::time_zone tz{"EST5EDT,M3.2.0,M11.1.0"}; -// zoned_time zt{tz, system_clock::now()}; -// -// Note, Posix-style time zones are not recommended for all of the reasons described here: -// https://stackoverflow.com/tags/timezone/info -// -// They are provided here as a non-trivial custom time zone example, and if you really -// have to have Posix time zones, you're welcome to use this one. - -#include "date/tz.h" -#include -#include -#include - -namespace Posix -{ - -namespace detail -{ - -#if HAS_STRING_VIEW - -using string_t = std::string_view; - -#else // !HAS_STRING_VIEW - -using string_t = std::string; - -#endif // !HAS_STRING_VIEW - -class rule; - -void throw_invalid(const string_t& s, unsigned i, const string_t& message); -unsigned read_date(const string_t& s, unsigned i, rule& r); -unsigned read_name(const string_t& s, unsigned i, std::string& name); -unsigned read_signed_time(const string_t& s, unsigned i, std::chrono::seconds& t); -unsigned read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t); -unsigned read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u); - -class rule -{ - enum {off, J, M, N}; - - date::month m_; - date::weekday wd_; - unsigned short n_ : 14; - unsigned short mode_ : 2; - std::chrono::duration time_ = std::chrono::hours{2}; - -public: - rule() : mode_(off) {} - - bool ok() const {return mode_ != off;} - date::local_seconds operator()(date::year y) const; - - friend std::ostream& operator<<(std::ostream& os, const rule& r); - friend unsigned read_date(const string_t& s, unsigned i, rule& r); -}; - -inline -date::local_seconds -rule::operator()(date::year y) const -{ - using namespace date; - using sec = std::chrono::seconds; - date::local_seconds t; - switch (mode_) - { - case J: - t = local_days{y/jan/0} + days{n_ + (y.is_leap() && n_ > 59)} + sec{time_}; - break; - case M: - t = (n_ == 5 ? local_days{y/m_/wd_[last]} : local_days{y/m_/wd_[n_]}) + sec{time_}; - break; - case N: - t = local_days{y/jan/1} + days{n_} + sec{time_}; - break; - default: - assert(!"rule called with bad mode"); - } - return t; -} - -inline -std::ostream& -operator<<(std::ostream& os, const rule& r) -{ - switch (r.mode_) - { - case rule::J: - os << 'J' << r.n_ << date::format(" %T", r.time_); - break; - case rule::M: - if (r.n_ == 5) - os << r.m_/r.wd_[date::last]; - else - os << r.m_/r.wd_[r.n_]; - os << date::format(" %T", r.time_); - break; - case rule::N: - os << r.n_ << date::format(" %T", r.time_); - break; - default: - break; - } - return os; -} - -} // namespace detail - -class time_zone -{ - std::string std_abbrev_; - std::string dst_abbrev_ = {}; - std::chrono::seconds offset_; - std::chrono::seconds save_ = std::chrono::hours{1}; - detail::rule start_rule_; - detail::rule end_rule_; - -public: - explicit time_zone(const detail::string_t& name); - - template - date::sys_info get_info(date::sys_time st) const; - template - date::local_info get_info(date::local_time tp) const; - - template - date::sys_time::type> - to_sys(date::local_time tp) const; - - template - date::sys_time::type> - to_sys(date::local_time tp, date::choose z) const; - - template - date::local_time::type> - to_local(date::sys_time tp) const; - - friend std::ostream& operator<<(std::ostream& os, const time_zone& z); - - const time_zone* operator->() const {return this;} -}; - -inline -time_zone::time_zone(const detail::string_t& s) -{ - using namespace detail; - auto i = read_name(s, 0, std_abbrev_); - i = read_signed_time(s, i, offset_); - offset_ = -offset_; - if (i != s.size()) - { - i = read_name(s, i, dst_abbrev_); - if (i != s.size()) - { - if (s[i] != ',') - i = read_signed_time(s, i, save_); - if (i != s.size()) - { - if (s[i] != ',') - throw_invalid(s, i, "Expecting end of string or ',' to start rule"); - ++i; - i = read_date(s, i, start_rule_); - if (i == s.size() || s[i] != ',') - throw_invalid(s, i, "Expecting ',' and then the ending rule"); - ++i; - i = read_date(s, i, end_rule_); - if (i != s.size()) - throw_invalid(s, i, "Found unexpected trailing characters"); - } - } - } -} - -template -date::sys_info -time_zone::get_info(date::sys_time st) const -{ - using namespace date; - using namespace std::chrono; - sys_info r{}; - r.offset = offset_; - if (start_rule_.ok()) - { - auto y = year_month_day{floor(st)}.year(); - auto start = sys_seconds{(start_rule_(y) - offset_).time_since_epoch()}; - auto end = sys_seconds{(end_rule_(y) - (offset_ + save_)).time_since_epoch()}; - if (start <= st && st < end) - { - r.begin = start; - r.end = end; - r.offset += save_; - r.save = ceil(save_); - r.abbrev = dst_abbrev_; - } - else if (st < start) - { - r.begin = sys_seconds{(end_rule_(y-years{1}) - - (offset_ + save_)).time_since_epoch()}; - r.end = start; - r.abbrev = std_abbrev_; - } - else // st >= end - { - r.begin = end; - r.end = sys_seconds{(start_rule_(y+years{1}) - offset_).time_since_epoch()}; - r.abbrev = std_abbrev_; - } - } - else // constant offset - { - r.begin = sys_days{year::min()/jan/1}; - r.end = sys_days{year::max()/dec/last}; - r.abbrev = std_abbrev_; - } - return r; -} - -template -date::local_info -time_zone::get_info(date::local_time tp) const -{ - using namespace date; - using namespace std::chrono; - local_info r{}; - if (start_rule_.ok()) - { - auto y = year_month_day{floor(tp)}.year(); - auto start = sys_seconds{(start_rule_(y) - offset_).time_since_epoch()}; - auto end = sys_seconds{(end_rule_(y) - (offset_ + save_)).time_since_epoch()}; - auto utcs = sys_seconds{floor(tp - offset_).time_since_epoch()}; - auto utcd = sys_seconds{floor(tp - (offset_ + save_)).time_since_epoch()}; - if ((utcs < start) != (utcd < start)) - { - r.first.begin = sys_seconds{(end_rule_(y-years{1}) - - (offset_ + save_)).time_since_epoch()}; - r.first.end = start; - r.first.offset = offset_; - r.first.abbrev = std_abbrev_; - r.second.begin = start; - r.second.end = end; - r.second.abbrev = dst_abbrev_; - r.second.offset = offset_ + save_; - r.second.save = ceil(save_); - r.result = save_ > seconds{0} ? local_info::nonexistent - : local_info::ambiguous; - } - else if ((utcs < end) != (utcd < end)) - { - r.first.begin = start; - r.first.end = end; - r.first.offset = offset_ + save_; - r.first.save = ceil(save_); - r.first.abbrev = dst_abbrev_; - r.second.begin = end; - r.second.end = sys_seconds{(start_rule_(y+years{1}) - - offset_).time_since_epoch()}; - r.second.abbrev = std_abbrev_; - r.second.offset = offset_; - r.result = save_ > seconds{0} ? local_info::ambiguous - : local_info::nonexistent; - } - else if (utcs < start) - { - r.first.begin = sys_seconds{(end_rule_(y-years{1}) - - (offset_ + save_)).time_since_epoch()}; - r.first.end = start; - r.first.offset = offset_; - r.first.abbrev = std_abbrev_; - } - else if (utcs < end) - { - r.first.begin = start; - r.first.end = end; - r.first.offset = offset_ + save_; - r.first.save = ceil(save_); - r.first.abbrev = dst_abbrev_; - } - else - { - r.first.begin = end; - r.first.end = sys_seconds{(start_rule_(y+years{1}) - - offset_).time_since_epoch()}; - r.first.abbrev = std_abbrev_; - r.first.offset = offset_; - } - } - else // constant offset - { - r.first.begin = sys_days{year::min()/jan/1}; - r.first.end = sys_days{year::max()/dec/last}; - r.first.abbrev = std_abbrev_; - r.first.offset = offset_; - } - return r; -} - -template -date::sys_time::type> -time_zone::to_sys(date::local_time tp) const -{ - using namespace date; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - throw nonexistent_local_time(tp, i); - else if (i.result == local_info::ambiguous) - throw ambiguous_local_time(tp, i); - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -template -date::sys_time::type> -time_zone::to_sys(date::local_time tp, date::choose z) const -{ - using namespace date; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - { - return i.first.end; - } - else if (i.result == local_info::ambiguous) - { - if (z == choose::latest) - return sys_time{tp.time_since_epoch()} - i.second.offset; - } - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -template -date::local_time::type> -time_zone::to_local(date::sys_time tp) const -{ - using namespace date; - using namespace std::chrono; - using LT = local_time::type>; - auto i = get_info(tp); - return LT{(tp + i.offset).time_since_epoch()}; -} - -inline -std::ostream& -operator<<(std::ostream& os, const time_zone& z) -{ - using date::operator<<; - os << '{'; - os << z.std_abbrev_ << ", " << z.dst_abbrev_ << date::format(", %T, ", z.offset_) - << date::format("%T, [", z.save_) << z.start_rule_ << ", " << z.end_rule_ << ")}"; - return os; -} - -namespace detail -{ - -inline -void -throw_invalid(const string_t& s, unsigned i, const string_t& message) -{ - throw std::runtime_error(std::string("Invalid time_zone initializer.\n") + - std::string(message) + ":\n" + - s + '\n' + - "\x1b[1;32m" + - std::string(i, '~') + '^' + - std::string(s.size()-i-1, '~') + - "\x1b[0m"); -} - -inline -unsigned -read_date(const string_t& s, unsigned i, rule& r) -{ - using namespace date; - if (i == s.size()) - throw_invalid(s, i, "Expected rule but found end of string"); - if (s[i] == 'J') - { - ++i; - unsigned n; - i = read_unsigned(s, i, 3, n); - r.mode_ = rule::J; - r.n_ = n; - } - else if (s[i] == 'M') - { - ++i; - unsigned m; - i = read_unsigned(s, i, 2, m); - if (i == s.size() || s[i] != '.') - throw_invalid(s, i, "Expected '.' after month"); - ++i; - unsigned n; - i = read_unsigned(s, i, 1, n); - if (i == s.size() || s[i] != '.') - throw_invalid(s, i, "Expected '.' after weekday index"); - ++i; - unsigned wd; - i = read_unsigned(s, i, 1, wd); - r.mode_ = rule::M; - r.m_ = month{m}; - r.wd_ = weekday{wd}; - r.n_ = n; - } - else if (std::isdigit(s[i])) - { - unsigned n; - i = read_unsigned(s, i, 3, n); - r.mode_ = rule::N; - r.n_ = n; - } - else - throw_invalid(s, i, "Expected 'J', 'M', or a digit to start rule"); - if (i != s.size() && s[i] == '/') - { - ++i; - std::chrono::seconds t; - i = read_unsigned_time(s, i, t); - r.time_ = t; - } - return i; -} - -inline -unsigned -read_name(const string_t& s, unsigned i, std::string& name) -{ - if (i == s.size()) - throw_invalid(s, i, "Expected a name but found end of string"); - if (s[i] == '<') - { - ++i; - while (true) - { - if (i == s.size()) - throw_invalid(s, i, - "Expected to find closing '>', but found end of string"); - if (s[i] == '>') - break; - name.push_back(s[i]); - ++i; - } - ++i; - } - else - { - while (i != s.size() && std::isalpha(s[i])) - { - name.push_back(s[i]); - ++i; - } - } - if (name.size() < 3) - throw_invalid(s, i, "Found name to be shorter than 3 characters"); - return i; -} - -inline -unsigned -read_signed_time(const string_t& s, unsigned i, - std::chrono::seconds& t) -{ - if (i == s.size()) - throw_invalid(s, i, "Expected to read signed time, but found end of string"); - bool negative = false; - if (s[i] == '-') - { - negative = true; - ++i; - } - else if (s[i] == '+') - ++i; - i = read_unsigned_time(s, i, t); - if (negative) - t = -t; - return i; -} - -inline -unsigned -read_unsigned_time(const string_t& s, unsigned i, std::chrono::seconds& t) -{ - using namespace std::chrono; - if (i == s.size()) - throw_invalid(s, i, "Expected to read unsigned time, but found end of string"); - unsigned x; - i = read_unsigned(s, i, 2, x); - t = hours{x}; - if (i != s.size() && s[i] == ':') - { - ++i; - i = read_unsigned(s, i, 2, x); - t += minutes{x}; - if (i != s.size() && s[i] == ':') - { - ++i; - i = read_unsigned(s, i, 2, x); - t += seconds{x}; - } - } - return i; -} - -inline -unsigned -read_unsigned(const string_t& s, unsigned i, unsigned limit, unsigned& u) -{ - if (i == s.size() || !std::isdigit(s[i])) - throw_invalid(s, i, "Expected to find a decimal digit"); - u = static_cast(s[i] - '0'); - unsigned count = 1; - for (++i; count < limit && i != s.size() && std::isdigit(s[i]); ++i, ++count) - u = u * 10 + static_cast(s[i] - '0'); - return i; -} - -} // namespace detail - -} // namespace Posix - -namespace date -{ - -template <> -struct zoned_traits -{ - -#if HAS_STRING_VIEW - - static - Posix::time_zone - locate_zone(std::string_view name) - { - return Posix::time_zone{name}; - } - -#else // !HAS_STRING_VIEW - - static - Posix::time_zone - locate_zone(const std::string& name) - { - return Posix::time_zone{name}; - } - - static - Posix::time_zone - locate_zone(const char* name) - { - return Posix::time_zone{name}; - } - -#endif // !HAS_STRING_VIEW - -}; - -} // namespace date - -#endif // PTZ_H diff --git a/src/date/include/date/tz.h b/src/date/include/date/tz.h deleted file mode 100644 index 280a598001..0000000000 --- a/src/date/include/date/tz.h +++ /dev/null @@ -1,2581 +0,0 @@ -#ifndef TZ_H -#define TZ_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// Copyright (c) 2017 Jiangang Zhuang -// Copyright (c) 2017 Aaron Bishop -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -// Get more recent database at http://www.iana.org/time-zones - -// The notion of "current timezone" is something the operating system is expected to "just -// know". How it knows this is system specific. It's often a value set by the user at OS -// installation time and recorded by the OS somewhere. On Linux and Mac systems the current -// timezone name is obtained by looking at the name or contents of a particular file on -// disk. On Windows the current timezone name comes from the registry. In either method, -// there is no guarantee that the "native" current timezone name obtained will match any -// of the "Standard" names in this library's "database". On Linux, the names usually do -// seem to match so mapping functions to map from native to "Standard" are typically not -// required. On Windows, the names are never "Standard" so mapping is always required. -// Technically any OS may use the mapping process but currently only Windows does use it. - -#ifndef USE_OS_TZDB -# define USE_OS_TZDB 0 -#endif - -#ifndef HAS_REMOTE_API -# if USE_OS_TZDB == 0 -# ifdef _WIN32 -# define HAS_REMOTE_API 0 -# else -# define HAS_REMOTE_API 1 -# endif -# else // HAS_REMOTE_API makes no since when using the OS timezone database -# define HAS_REMOTE_API 0 -# endif -#endif - -#ifdef __clang__ -# pragma clang diagnostic push -# pragma clang diagnostic ignored "-Wconstant-logical-operand" -#endif - -static_assert(!(USE_OS_TZDB && HAS_REMOTE_API), - "USE_OS_TZDB and HAS_REMOTE_API can not be used together"); - -#ifdef __clang__ -# pragma clang diagnostic pop -#endif - -#ifndef AUTO_DOWNLOAD -# define AUTO_DOWNLOAD HAS_REMOTE_API -#endif - -static_assert(HAS_REMOTE_API == 0 ? AUTO_DOWNLOAD == 0 : true, - "AUTO_DOWNLOAD can not be turned on without HAS_REMOTE_API"); - -#ifndef USE_SHELL_API -# define USE_SHELL_API 1 -#endif - -#if USE_OS_TZDB -# ifdef _WIN32 -# error "USE_OS_TZDB can not be used on Windows" -# endif -# ifndef MISSING_LEAP_SECONDS -# ifdef __APPLE__ -# define MISSING_LEAP_SECONDS 1 -# else -# define MISSING_LEAP_SECONDS 0 -# endif -# endif -#else -# define MISSING_LEAP_SECONDS 0 -#endif - -#ifndef HAS_DEDUCTION_GUIDES -# if __cplusplus >= 201703 -# define HAS_DEDUCTION_GUIDES 1 -# else -# define HAS_DEDUCTION_GUIDES 0 -# endif -#endif // HAS_DEDUCTION_GUIDES - -#include "date.h" - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#include "tz_private.h" -#endif - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifdef _WIN32 -# ifdef DATE_BUILD_DLL -# define DATE_API __declspec(dllexport) -# elif defined(DATE_USE_DLL) -# define DATE_API __declspec(dllimport) -# else -# define DATE_API -# endif -#else -# ifdef DATE_BUILD_DLL -# define DATE_API __attribute__ ((visibility ("default"))) -# else -# define DATE_API -# endif -#endif - -namespace date -{ - -enum class choose {earliest, latest}; - -namespace detail -{ - struct undocumented; -} - -struct sys_info -{ - sys_seconds begin; - sys_seconds end; - std::chrono::seconds offset; - std::chrono::minutes save; - std::string abbrev; -}; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const sys_info& r) -{ - os << r.begin << '\n'; - os << r.end << '\n'; - os << make_time(r.offset) << "\n"; - os << make_time(r.save) << "\n"; - os << r.abbrev << '\n'; - return os; -} - -struct local_info -{ - enum {unique, nonexistent, ambiguous} result; - sys_info first; - sys_info second; -}; - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const local_info& r) -{ - if (r.result == local_info::nonexistent) - os << "nonexistent between\n"; - else if (r.result == local_info::ambiguous) - os << "ambiguous between\n"; - os << r.first; - if (r.result != local_info::unique) - { - os << "and\n"; - os << r.second; - } - return os; -} - -class nonexistent_local_time - : public std::runtime_error -{ -public: - template - nonexistent_local_time(local_time tp, const local_info& i); - -private: - template - static - std::string - make_msg(local_time tp, const local_info& i); -}; - -template -inline -nonexistent_local_time::nonexistent_local_time(local_time tp, - const local_info& i) - : std::runtime_error(make_msg(tp, i)) -{ -} - -template -std::string -nonexistent_local_time::make_msg(local_time tp, const local_info& i) -{ - assert(i.result == local_info::nonexistent); - std::ostringstream os; - os << tp << " is in a gap between\n" - << local_seconds{i.first.end.time_since_epoch()} + i.first.offset << ' ' - << i.first.abbrev << " and\n" - << local_seconds{i.second.begin.time_since_epoch()} + i.second.offset << ' ' - << i.second.abbrev - << " which are both equivalent to\n" - << i.first.end << " UTC"; - return os.str(); -} - -class ambiguous_local_time - : public std::runtime_error -{ -public: - template - ambiguous_local_time(local_time tp, const local_info& i); - -private: - template - static - std::string - make_msg(local_time tp, const local_info& i); -}; - -template -inline -ambiguous_local_time::ambiguous_local_time(local_time tp, const local_info& i) - : std::runtime_error(make_msg(tp, i)) -{ -} - -template -std::string -ambiguous_local_time::make_msg(local_time tp, const local_info& i) -{ - assert(i.result == local_info::ambiguous); - std::ostringstream os; - os << tp << " is ambiguous. It could be\n" - << tp << ' ' << i.first.abbrev << " == " - << tp - i.first.offset << " UTC or\n" - << tp << ' ' << i.second.abbrev << " == " - << tp - i.second.offset << " UTC"; - return os.str(); -} - -class time_zone; - -#if HAS_STRING_VIEW -DATE_API const time_zone* locate_zone(std::string_view tz_name); -#else -DATE_API const time_zone* locate_zone(const std::string& tz_name); -#endif - -DATE_API const time_zone* current_zone(); - -template -struct zoned_traits -{ -}; - -template <> -struct zoned_traits -{ - static - const time_zone* - default_zone() - { - return date::locate_zone("Etc/UTC"); - } - -#if HAS_STRING_VIEW - - static - const time_zone* - locate_zone(std::string_view name) - { - return date::locate_zone(name); - } - -#else // !HAS_STRING_VIEW - - static - const time_zone* - locate_zone(const std::string& name) - { - return date::locate_zone(name); - } - - static - const time_zone* - locate_zone(const char* name) - { - return date::locate_zone(name); - } - -#endif // !HAS_STRING_VIEW -}; - -template -class zoned_time; - -template -bool -operator==(const zoned_time& x, - const zoned_time& y); - -template -class zoned_time -{ -public: - using duration = typename std::common_type::type; - -private: - TimeZonePtr zone_; - sys_time tp_; - -public: -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::default_zone())> -#endif - zoned_time(); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::default_zone())> -#endif - zoned_time(const sys_time& st); - explicit zoned_time(TimeZonePtr z); - -#if HAS_STRING_VIEW - template ::locate_zone(std::string_view())) - >::value - >::type> - explicit zoned_time(std::string_view name); -#else -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())) - >::value - >::type> -#endif - explicit zoned_time(const std::string& name); -#endif - - template , - sys_time>::value - >::type> - zoned_time(const zoned_time& zt) NOEXCEPT; - - zoned_time(TimeZonePtr z, const sys_time& st); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ()->to_sys(local_time{})), - sys_time - >::value - >::type> -#endif - zoned_time(TimeZonePtr z, const local_time& tp); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ()->to_sys(local_time{}, - choose::earliest)), - sys_time - >::value - >::type> -#endif - zoned_time(TimeZonePtr z, const local_time& tp, choose c); - - template , - sys_time>::value - >::type> - zoned_time(TimeZonePtr z, const zoned_time& zt); - - template , - sys_time>::value - >::type> - zoned_time(TimeZonePtr z, const zoned_time& zt, choose); - -#if HAS_STRING_VIEW - - template ::locate_zone(std::string_view())), - sys_time - >::value - >::type> - zoned_time(std::string_view name, const sys_time& st); - - template ::locate_zone(std::string_view())), - local_time - >::value - >::type> - zoned_time(std::string_view name, const local_time& tp); - - template ::locate_zone(std::string_view())), - local_time, - choose - >::value - >::type> - zoned_time(std::string_view name, const local_time& tp, choose c); - - template ::locate_zone(std::string_view())), - zoned_time - >::value - >::type> - zoned_time(std::string_view name, const zoned_time& zt); - - template ::locate_zone(std::string_view())), - zoned_time, - choose - >::value - >::type> - zoned_time(std::string_view name, const zoned_time& zt, choose); - -#else // !HAS_STRING_VIEW - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - sys_time - >::value - >::type> -#endif - zoned_time(const std::string& name, const sys_time& st); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - sys_time - >::value - >::type> -#endif - zoned_time(const char* name, const sys_time& st); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - local_time - >::value - >::type> -#endif - zoned_time(const std::string& name, const local_time& tp); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - local_time - >::value - >::type> -#endif - zoned_time(const char* name, const local_time& tp); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - local_time, - choose - >::value - >::type> -#endif - zoned_time(const std::string& name, const local_time& tp, choose c); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - local_time, - choose - >::value - >::type> -#endif - zoned_time(const char* name, const local_time& tp, choose c); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - zoned_time - >::value - >::type> -#endif - zoned_time(const std::string& name, const zoned_time& zt); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - zoned_time - >::value - >::type> -#endif - zoned_time(const char* name, const zoned_time& zt); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - zoned_time, - choose - >::value - >::type> -#endif - zoned_time(const std::string& name, const zoned_time& zt, choose); - -#if !defined(_MSC_VER) || (_MSC_VER > 1900) - template ::locate_zone(std::string())), - zoned_time, - choose - >::value - >::type> -#endif - zoned_time(const char* name, const zoned_time& zt, choose); - -#endif // !HAS_STRING_VIEW - - zoned_time& operator=(const sys_time& st); - zoned_time& operator=(const local_time& ut); - - explicit operator sys_time() const; - explicit operator local_time() const; - - TimeZonePtr get_time_zone() const; - local_time get_local_time() const; - sys_time get_sys_time() const; - sys_info get_info() const; - - template - friend - bool - operator==(const zoned_time& x, - const zoned_time& y); - - template - friend - std::basic_ostream& - operator<<(std::basic_ostream& os, - const zoned_time& t); - -private: - template friend class zoned_time; -}; - -using zoned_seconds = zoned_time; - -#if HAS_DEDUCTION_GUIDES - -zoned_time() - -> zoned_time; - -template -zoned_time(sys_time) - -> zoned_time>; - -template -zoned_time(TimeZonePtr) - -> zoned_time; - -template -zoned_time(TimeZonePtr, sys_time) - -> zoned_time, TimeZonePtr>; - -template -zoned_time(TimeZonePtr, local_time, choose = choose::earliest) - -> zoned_time, TimeZonePtr>; - -#if HAS_STRING_VIEW - -zoned_time(std::string_view) - -> zoned_time; - -template -zoned_time(std::string_view, sys_time) - -> zoned_time>; - -template -zoned_time(std::string_view, local_time, choose = choose::earliest) - -> zoned_time>; - -#else // !HAS_STRING_VIEW - -zoned_time(std::string) - -> zoned_time; - -template -zoned_time(std::string, sys_time) - -> zoned_time>; - -template -zoned_time(std::string, local_time, choose = choose::earliest) - -> zoned_time>; - -#endif // !HAS_STRING_VIEW - -template -zoned_time(const char*, sys_time) - -> zoned_time>; - -template -zoned_time(const char*, local_time, choose = choose::earliest) - -> zoned_time>; - -template -zoned_time(TimeZonePtr, zoned_time) - -> zoned_time; - -template -zoned_time(TimeZonePtr, zoned_time, choose) - -> zoned_time; - -#endif // HAS_DEDUCTION_GUIDES - -template -inline -bool -operator==(const zoned_time& x, - const zoned_time& y) -{ - return x.zone_ == y.zone_ && x.tp_ == y.tp_; -} - -template -inline -bool -operator!=(const zoned_time& x, - const zoned_time& y) -{ - return !(x == y); -} - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - -namespace detail -{ -# if USE_OS_TZDB - struct transition; - struct expanded_ttinfo; -# else // !USE_OS_TZDB - struct zonelet; - class Rule; -# endif // !USE_OS_TZDB -} - -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - -class time_zone -{ -private: - std::string name_; -#if USE_OS_TZDB - std::vector transitions_; - std::vector ttinfos_; -#else // !USE_OS_TZDB - std::vector zonelets_; -#endif // !USE_OS_TZDB - std::unique_ptr adjusted_; - -public: -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - time_zone(time_zone&&) = default; - time_zone& operator=(time_zone&&) = default; -#else // defined(_MSC_VER) && (_MSC_VER < 1900) - time_zone(time_zone&& src); - time_zone& operator=(time_zone&& src); -#endif // defined(_MSC_VER) && (_MSC_VER < 1900) - - DATE_API explicit time_zone(const std::string& s, detail::undocumented); - - const std::string& name() const NOEXCEPT; - - template sys_info get_info(sys_time st) const; - template local_info get_info(local_time tp) const; - - template - sys_time::type> - to_sys(local_time tp) const; - - template - sys_time::type> - to_sys(local_time tp, choose z) const; - - template - local_time::type> - to_local(sys_time tp) const; - - friend bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT; - friend bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT; - friend DATE_API std::ostream& operator<<(std::ostream& os, const time_zone& z); - -#if !USE_OS_TZDB - DATE_API void add(const std::string& s); -#endif // !USE_OS_TZDB - -private: - DATE_API sys_info get_info_impl(sys_seconds tp) const; - DATE_API local_info get_info_impl(local_seconds tp) const; - - template - sys_time::type> - to_sys_impl(local_time tp, choose z, std::false_type) const; - template - sys_time::type> - to_sys_impl(local_time tp, choose, std::true_type) const; - -#if USE_OS_TZDB - DATE_API void init() const; - DATE_API void init_impl(); - DATE_API sys_info - load_sys_info(std::vector::const_iterator i) const; - - template - DATE_API void - load_data(std::istream& inf, std::int32_t tzh_leapcnt, std::int32_t tzh_timecnt, - std::int32_t tzh_typecnt, std::int32_t tzh_charcnt); -#else // !USE_OS_TZDB - DATE_API sys_info get_info_impl(sys_seconds tp, int timezone) const; - DATE_API void adjust_infos(const std::vector& rules); - DATE_API void parse_info(std::istream& in); -#endif // !USE_OS_TZDB -}; - -#if defined(_MSC_VER) && (_MSC_VER < 1900) - -inline -time_zone::time_zone(time_zone&& src) - : name_(std::move(src.name_)) - , zonelets_(std::move(src.zonelets_)) - , adjusted_(std::move(src.adjusted_)) - {} - -inline -time_zone& -time_zone::operator=(time_zone&& src) -{ - name_ = std::move(src.name_); - zonelets_ = std::move(src.zonelets_); - adjusted_ = std::move(src.adjusted_); - return *this; -} - -#endif // defined(_MSC_VER) && (_MSC_VER < 1900) - -inline -const std::string& -time_zone::name() const NOEXCEPT -{ - return name_; -} - -template -inline -sys_info -time_zone::get_info(sys_time st) const -{ - using namespace std::chrono; - return get_info_impl(date::floor(st)); -} - -template -inline -local_info -time_zone::get_info(local_time tp) const -{ - using namespace std::chrono; - return get_info_impl(date::floor(tp)); -} - -template -inline -sys_time::type> -time_zone::to_sys(local_time tp) const -{ - return to_sys_impl(tp, choose{}, std::true_type{}); -} - -template -inline -sys_time::type> -time_zone::to_sys(local_time tp, choose z) const -{ - return to_sys_impl(tp, z, std::false_type{}); -} - -template -inline -local_time::type> -time_zone::to_local(sys_time tp) const -{ - using LT = local_time::type>; - auto i = get_info(tp); - return LT{(tp + i.offset).time_since_epoch()}; -} - -inline bool operator==(const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ == y.name_;} -inline bool operator< (const time_zone& x, const time_zone& y) NOEXCEPT {return x.name_ < y.name_;} - -inline bool operator!=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x == y);} -inline bool operator> (const time_zone& x, const time_zone& y) NOEXCEPT {return y < x;} -inline bool operator<=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(y < x);} -inline bool operator>=(const time_zone& x, const time_zone& y) NOEXCEPT {return !(x < y);} - -template -sys_time::type> -time_zone::to_sys_impl(local_time tp, choose z, std::false_type) const -{ - using namespace date; - using namespace std::chrono; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - { - return i.first.end; - } - else if (i.result == local_info::ambiguous) - { - if (z == choose::latest) - return sys_time{tp.time_since_epoch()} - i.second.offset; - } - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -template -sys_time::type> -time_zone::to_sys_impl(local_time tp, choose, std::true_type) const -{ - using namespace date; - using namespace std::chrono; - auto i = get_info(tp); - if (i.result == local_info::nonexistent) - throw nonexistent_local_time(tp, i); - else if (i.result == local_info::ambiguous) - throw ambiguous_local_time(tp, i); - return sys_time{tp.time_since_epoch()} - i.first.offset; -} - -#if !USE_OS_TZDB - -class link -{ -private: - std::string name_; - std::string target_; -public: - DATE_API explicit link(const std::string& s); - - const std::string& name() const {return name_;} - const std::string& target() const {return target_;} - - friend bool operator==(const link& x, const link& y) {return x.name_ == y.name_;} - friend bool operator< (const link& x, const link& y) {return x.name_ < y.name_;} - - friend DATE_API std::ostream& operator<<(std::ostream& os, const link& x); -}; - -inline bool operator!=(const link& x, const link& y) {return !(x == y);} -inline bool operator> (const link& x, const link& y) {return y < x;} -inline bool operator<=(const link& x, const link& y) {return !(y < x);} -inline bool operator>=(const link& x, const link& y) {return !(x < y);} - -#endif // !USE_OS_TZDB - -#if !MISSING_LEAP_SECONDS - -class leap -{ -private: - sys_seconds date_; - -public: -#if USE_OS_TZDB - DATE_API explicit leap(const sys_seconds& s, detail::undocumented); -#else - DATE_API explicit leap(const std::string& s, detail::undocumented); -#endif - - sys_seconds date() const {return date_;} - - friend bool operator==(const leap& x, const leap& y) {return x.date_ == y.date_;} - friend bool operator< (const leap& x, const leap& y) {return x.date_ < y.date_;} - - template - friend - bool - operator==(const leap& x, const sys_time& y) - { - return x.date_ == y; - } - - template - friend - bool - operator< (const leap& x, const sys_time& y) - { - return x.date_ < y; - } - - template - friend - bool - operator< (const sys_time& x, const leap& y) - { - return x < y.date_; - } - - friend DATE_API std::ostream& operator<<(std::ostream& os, const leap& x); -}; - -inline bool operator!=(const leap& x, const leap& y) {return !(x == y);} -inline bool operator> (const leap& x, const leap& y) {return y < x;} -inline bool operator<=(const leap& x, const leap& y) {return !(y < x);} -inline bool operator>=(const leap& x, const leap& y) {return !(x < y);} - -template -inline -bool -operator==(const sys_time& x, const leap& y) -{ - return y == x; -} - -template -inline -bool -operator!=(const leap& x, const sys_time& y) -{ - return !(x == y); -} - -template -inline -bool -operator!=(const sys_time& x, const leap& y) -{ - return !(x == y); -} - -template -inline -bool -operator> (const leap& x, const sys_time& y) -{ - return y < x; -} - -template -inline -bool -operator> (const sys_time& x, const leap& y) -{ - return y < x; -} - -template -inline -bool -operator<=(const leap& x, const sys_time& y) -{ - return !(y < x); -} - -template -inline -bool -operator<=(const sys_time& x, const leap& y) -{ - return !(y < x); -} - -template -inline -bool -operator>=(const leap& x, const sys_time& y) -{ - return !(x < y); -} - -template -inline -bool -operator>=(const sys_time& x, const leap& y) -{ - return !(x < y); -} - -#endif // !MISSING_LEAP_SECONDS - -#ifdef _WIN32 - -namespace detail -{ - -// The time zone mapping is modelled after this data file: -// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml -// and the field names match the element names from the mapZone element -// of windowsZones.xml. -// The website displays this file here: -// http://www.unicode.org/cldr/charts/latest/supplemental/zone_tzid.html -// The html view is sorted before being displayed but is otherwise the same -// There is a mapping between the os centric view (in this case windows) -// the html displays uses and the generic view the xml file. -// That mapping is this: -// display column "windows" -> xml field "other". -// display column "region" -> xml field "territory". -// display column "tzid" -> xml field "type". -// This structure uses the generic terminology because it could be -// used to to support other os/native name conversions, not just windows, -// and using the same generic names helps retain the connection to the -// origin of the data that we are using. -struct timezone_mapping -{ - timezone_mapping(const char* other, const char* territory, const char* type) - : other(other), territory(territory), type(type) - { - } - timezone_mapping() = default; - std::string other; - std::string territory; - std::string type; -}; - -} // detail - -#endif // _WIN32 - -struct tzdb -{ - std::string version = "unknown"; - std::vector zones; -#if !USE_OS_TZDB - std::vector links; -#endif -#if !MISSING_LEAP_SECONDS - std::vector leaps; -#endif -#if !USE_OS_TZDB - std::vector rules; -#endif -#ifdef _WIN32 - std::vector mappings; -#endif - tzdb* next = nullptr; - - tzdb() = default; -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - tzdb(tzdb&&) = default; - tzdb& operator=(tzdb&&) = default; -#else // defined(_MSC_VER) && (_MSC_VER < 1900) - tzdb(tzdb&& src) - : version(std::move(src.version)) - , zones(std::move(src.zones)) - , links(std::move(src.links)) - , leaps(std::move(src.leaps)) - , rules(std::move(src.rules)) - , mappings(std::move(src.mappings)) - {} - - tzdb& operator=(tzdb&& src) - { - version = std::move(src.version); - zones = std::move(src.zones); - links = std::move(src.links); - leaps = std::move(src.leaps); - rules = std::move(src.rules); - mappings = std::move(src.mappings); - return *this; - } -#endif // defined(_MSC_VER) && (_MSC_VER < 1900) - -#if HAS_STRING_VIEW - const time_zone* locate_zone(std::string_view tz_name) const; -#else - const time_zone* locate_zone(const std::string& tz_name) const; -#endif - const time_zone* current_zone() const; -}; - -using TZ_DB = tzdb; - -DATE_API std::ostream& -operator<<(std::ostream& os, const tzdb& db); - -DATE_API const tzdb& get_tzdb(); - -class tzdb_list -{ - std::atomic head_{nullptr}; - -public: - ~tzdb_list(); - tzdb_list() = default; - tzdb_list(tzdb_list&& x) noexcept; - - const tzdb& front() const noexcept {return *head_;} - tzdb& front() noexcept {return *head_;} - - class const_iterator; - - const_iterator begin() const noexcept; - const_iterator end() const noexcept; - - const_iterator cbegin() const noexcept; - const_iterator cend() const noexcept; - - const_iterator erase_after(const_iterator p) noexcept; - - struct undocumented_helper; -private: - void push_front(tzdb* tzdb) noexcept; -}; - -class tzdb_list::const_iterator -{ - tzdb* p_ = nullptr; - - explicit const_iterator(tzdb* p) noexcept : p_{p} {} -public: - const_iterator() = default; - - using iterator_category = std::forward_iterator_tag; - using value_type = tzdb; - using reference = const value_type&; - using pointer = const value_type*; - using difference_type = std::ptrdiff_t; - - reference operator*() const noexcept {return *p_;} - pointer operator->() const noexcept {return p_;} - - const_iterator& operator++() noexcept {p_ = p_->next; return *this;} - const_iterator operator++(int) noexcept {auto t = *this; ++(*this); return t;} - - friend - bool - operator==(const const_iterator& x, const const_iterator& y) noexcept - {return x.p_ == y.p_;} - - friend - bool - operator!=(const const_iterator& x, const const_iterator& y) noexcept - {return !(x == y);} - - friend class tzdb_list; -}; - -inline -tzdb_list::const_iterator -tzdb_list::begin() const noexcept -{ - return const_iterator{head_}; -} - -inline -tzdb_list::const_iterator -tzdb_list::end() const noexcept -{ - return const_iterator{nullptr}; -} - -inline -tzdb_list::const_iterator -tzdb_list::cbegin() const noexcept -{ - return begin(); -} - -inline -tzdb_list::const_iterator -tzdb_list::cend() const noexcept -{ - return end(); -} - -DATE_API tzdb_list& get_tzdb_list(); - -#if !USE_OS_TZDB - -DATE_API const tzdb& reload_tzdb(); -DATE_API void set_install(const std::string& install); - -#endif // !USE_OS_TZDB - -#if HAS_REMOTE_API - -DATE_API std::string remote_version(); -DATE_API bool remote_download(const std::string& version); -DATE_API bool remote_install(const std::string& version); - -#endif - -// zoned_time - -namespace detail -{ - -template -inline -T* -to_raw_pointer(T* p) noexcept -{ - return p; -} - -template -inline -auto -to_raw_pointer(Pointer p) noexcept - -> decltype(detail::to_raw_pointer(p.operator->())) -{ - return detail::to_raw_pointer(p.operator->()); -} - -} // namespace detail - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time() - : zone_(zoned_traits::default_zone()) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const sys_time& st) - : zone_(zoned_traits::default_zone()) - , tp_(st) - {} - -template -inline -zoned_time::zoned_time(TimeZonePtr z) - : zone_(std::move(z)) - {assert(detail::to_raw_pointer(zone_) != nullptr);} - -#if HAS_STRING_VIEW - -template -template -inline -zoned_time::zoned_time(std::string_view name) - : zoned_time(zoned_traits::locate_zone(name)) - {} - -#else // !HAS_STRING_VIEW - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name) - : zoned_time(zoned_traits::locate_zone(name)) - {} - -#endif // !HAS_STRING_VIEW - -template -template -inline -zoned_time::zoned_time(const zoned_time& zt) NOEXCEPT - : zone_(zt.zone_) - , tp_(zt.tp_) - {} - -template -inline -zoned_time::zoned_time(TimeZonePtr z, const sys_time& st) - : zone_(std::move(z)) - , tp_(st) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(TimeZonePtr z, const local_time& t) - : zone_(std::move(z)) - , tp_(zone_->to_sys(t)) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(TimeZonePtr z, const local_time& t, - choose c) - : zone_(std::move(z)) - , tp_(zone_->to_sys(t, c)) - {} - -template -template -inline -zoned_time::zoned_time(TimeZonePtr z, - const zoned_time& zt) - : zone_(std::move(z)) - , tp_(zt.tp_) - {} - -template -template -inline -zoned_time::zoned_time(TimeZonePtr z, - const zoned_time& zt, choose) - : zoned_time(std::move(z), zt) - {} - -#if HAS_STRING_VIEW - -template -template -inline -zoned_time::zoned_time(std::string_view name, - const sys_time& st) - : zoned_time(zoned_traits::locate_zone(name), st) - {} - -template -template -inline -zoned_time::zoned_time(std::string_view name, - const local_time& t) - : zoned_time(zoned_traits::locate_zone(name), t) - {} - -template -template -inline -zoned_time::zoned_time(std::string_view name, - const local_time& t, choose c) - : zoned_time(zoned_traits::locate_zone(name), t, c) - {} - -template -template -inline -zoned_time::zoned_time(std::string_view name, const zoned_time& zt) - : zoned_time(zoned_traits::locate_zone(name), zt) - {} - -template -template -inline -zoned_time::zoned_time(std::string_view name, - const zoned_time& zt, choose c) - : zoned_time(zoned_traits::locate_zone(name), zt, c) - {} - -#else // !HAS_STRING_VIEW - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name, - const sys_time& st) - : zoned_time(zoned_traits::locate_zone(name), st) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const char* name, - const sys_time& st) - : zoned_time(zoned_traits::locate_zone(name), st) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name, - const local_time& t) - : zoned_time(zoned_traits::locate_zone(name), t) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const char* name, - const local_time& t) - : zoned_time(zoned_traits::locate_zone(name), t) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name, - const local_time& t, choose c) - : zoned_time(zoned_traits::locate_zone(name), t, c) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const char* name, - const local_time& t, choose c) - : zoned_time(zoned_traits::locate_zone(name), t, c) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name, - const zoned_time& zt) - : zoned_time(zoned_traits::locate_zone(name), zt) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const char* name, const zoned_time& zt) - : zoned_time(zoned_traits::locate_zone(name), zt) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const std::string& name, - const zoned_time& zt, choose c) - : zoned_time(zoned_traits::locate_zone(name), zt, c) - {} - -template -#if !defined(_MSC_VER) || (_MSC_VER > 1900) -template -#endif -inline -zoned_time::zoned_time(const char* name, - const zoned_time& zt, choose c) - : zoned_time(zoned_traits::locate_zone(name), zt, c) - {} - -#endif // HAS_STRING_VIEW - -template -inline -zoned_time& -zoned_time::operator=(const sys_time& st) -{ - tp_ = st; - return *this; -} - -template -inline -zoned_time& -zoned_time::operator=(const local_time& ut) -{ - tp_ = zone_->to_sys(ut); - return *this; -} - -template -inline -zoned_time::operator local_time::duration>() const -{ - return get_local_time(); -} - -template -inline -zoned_time::operator sys_time::duration>() const -{ - return get_sys_time(); -} - -template -inline -TimeZonePtr -zoned_time::get_time_zone() const -{ - return zone_; -} - -template -inline -local_time::duration> -zoned_time::get_local_time() const -{ - return zone_->to_local(tp_); -} - -template -inline -sys_time::duration> -zoned_time::get_sys_time() const -{ - return tp_; -} - -template -inline -sys_info -zoned_time::get_info() const -{ - return zone_->get_info(tp_); -} - -// make_zoned_time - -inline -zoned_time -make_zoned() -{ - return zoned_time(); -} - -template -inline -zoned_time::type> -make_zoned(const sys_time& tp) -{ - return zoned_time::type>(tp); -} - -template 1900) - , class = typename std::enable_if - < - std::is_class - < - typename std::decay - < - decltype(*detail::to_raw_pointer(std::declval())) - >::type - >{} - >::type -#endif - > -inline -zoned_time -make_zoned(TimeZonePtr z) -{ - return zoned_time(std::move(z)); -} - -inline -zoned_seconds -make_zoned(const std::string& name) -{ - return zoned_seconds(name); -} - -template 1900) - , class = typename std::enable_if - < - std::is_class())>::type>{} - >::type -#endif - > -inline -zoned_time::type, TimeZonePtr> -make_zoned(TimeZonePtr zone, const local_time& tp) -{ - return zoned_time::type, - TimeZonePtr>(std::move(zone), tp); -} - -template 1900) - , class = typename std::enable_if - < - std::is_class())>::type>{} - >::type -#endif - > -inline -zoned_time::type, TimeZonePtr> -make_zoned(TimeZonePtr zone, const local_time& tp, choose c) -{ - return zoned_time::type, - TimeZonePtr>(std::move(zone), tp, c); -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const local_time& tp) -{ - return zoned_time::type>(name, tp); -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const local_time& tp, choose c) -{ - return zoned_time::type>(name, tp, c); -} - -template -inline -zoned_time -make_zoned(TimeZonePtr zone, const zoned_time& zt) -{ - return zoned_time(std::move(zone), zt); -} - -template -inline -zoned_time -make_zoned(const std::string& name, const zoned_time& zt) -{ - return zoned_time(name, zt); -} - -template -inline -zoned_time -make_zoned(TimeZonePtr zone, const zoned_time& zt, choose c) -{ - return zoned_time(std::move(zone), zt, c); -} - -template -inline -zoned_time -make_zoned(const std::string& name, const zoned_time& zt, choose c) -{ - return zoned_time(name, zt, c); -} - -template 1900) - , class = typename std::enable_if - < - std::is_class())>::type>{} - >::type -#endif - > -inline -zoned_time::type, TimeZonePtr> -make_zoned(TimeZonePtr zone, const sys_time& st) -{ - return zoned_time::type, - TimeZonePtr>(std::move(zone), st); -} - -template -inline -zoned_time::type> -make_zoned(const std::string& name, const sys_time& st) -{ - return zoned_time::type>(name, st); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const zoned_time& tp) -{ - using duration = typename zoned_time::duration; - using LT = local_time; - auto const tz = tp.get_time_zone(); - auto const st = tp.get_sys_time(); - auto const info = tz->get_info(st); - return to_stream(os, fmt, LT{(st+info.offset).time_since_epoch()}, - &info.abbrev, &info.offset); -} - -template -inline -std::basic_ostream& -operator<<(std::basic_ostream& os, const zoned_time& t) -{ - const CharT fmt[] = {'%', 'F', ' ', '%', 'T', ' ', '%', 'Z', CharT{}}; - return to_stream(os, fmt, t); -} - -#if !MISSING_LEAP_SECONDS - -class utc_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static CONSTDATA bool is_steady = false; - - static time_point now(); - - template - static - std::chrono::time_point::type> - to_sys(const std::chrono::time_point&); - - template - static - std::chrono::time_point::type> - from_sys(const std::chrono::time_point&); -}; - -template - using utc_time = std::chrono::time_point; - -using utc_seconds = utc_time; - -template -utc_time::type> -utc_clock::from_sys(const sys_time& st) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto const& leaps = get_tzdb().leaps; - auto const lt = std::upper_bound(leaps.begin(), leaps.end(), st); - return utc_time{st.time_since_epoch() + seconds{lt-leaps.begin()}}; -} - -// Return pair -// first is true if ut is during a leap second insertion, otherwise false. -// If ut is during a leap second insertion, that leap second is included in the count -template -std::pair -is_leap_second(date::utc_time const& ut) -{ - using namespace date; - using namespace std::chrono; - using duration = typename std::common_type::type; - auto const& leaps = get_tzdb().leaps; - auto tp = sys_time{ut.time_since_epoch()}; - auto const lt = std::upper_bound(leaps.begin(), leaps.end(), tp); - auto ds = seconds{lt-leaps.begin()}; - tp -= ds; - auto ls = false; - if (lt > leaps.begin()) - { - if (tp < lt[-1]) - { - if (tp >= lt[-1].date() - seconds{1}) - ls = true; - else - --ds; - } - } - return {ls, ds}; -} - -template -sys_time::type> -utc_clock::to_sys(const utc_time& ut) -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - auto ls = is_leap_second(ut); - auto tp = sys_time{ut.time_since_epoch() - ls.second}; - if (ls.first) - tp = floor(tp) + seconds{1} - duration{1}; - return tp; -} - -inline -utc_clock::time_point -utc_clock::now() -{ - using namespace std::chrono; - return from_sys(system_clock::now()); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const utc_time& t) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - const string abbrev("UTC"); - CONSTDATA seconds offset{0}; - auto ls = is_leap_second(t); - auto tp = sys_time{t.time_since_epoch() - ls.second}; - auto const sd = floor(tp); - year_month_day ymd = sd; - auto time = make_time(tp - sys_seconds{sd}); - time.seconds() += seconds{ls.first}; - fields fds{ymd, time}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const utc_time& t) -{ - const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; - return to_stream(os, fmt, t); -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - utc_time& tp, std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok()) - is.setstate(ios::failbit); - if (!is.fail()) - { - bool is_60_sec = fds.tod.seconds() == seconds{60}; - if (is_60_sec) - fds.tod.seconds() -= seconds{1}; - auto tmp = to_utc_time(sys_days(fds.ymd) - *offptr + fds.tod.to_duration()); - if (is_60_sec) - tmp += seconds{1}; - if (is_60_sec != is_leap_second(tmp).first || !fds.tod.in_conventional_range()) - { - is.setstate(ios::failbit); - return is; - } - tp = time_point_cast(tmp); - } - return is; -} - -// tai_clock - -class tai_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static const bool is_steady = false; - - static time_point now(); - - template - static - std::chrono::time_point::type> - to_utc(const std::chrono::time_point&) NOEXCEPT; - - template - static - std::chrono::time_point::type> - from_utc(const std::chrono::time_point&) NOEXCEPT; -}; - -template - using tai_time = std::chrono::time_point; - -using tai_seconds = tai_time; - -template -inline -utc_time::type> -tai_clock::to_utc(const tai_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return utc_time{t.time_since_epoch()} - - (sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1) + seconds{10}); -} - -template -inline -tai_time::type> -tai_clock::from_utc(const utc_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return tai_time{t.time_since_epoch()} + - (sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1) + seconds{10}); -} - -inline -tai_clock::time_point -tai_clock::now() -{ - using namespace std::chrono; - return from_utc(utc_clock::now()); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const tai_time& t) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - const string abbrev("TAI"); - CONSTDATA seconds offset{0}; - auto tp = sys_time{t.time_since_epoch()} - - seconds(sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1)); - auto const sd = floor(tp); - year_month_day ymd = sd; - auto time = make_time(tp - sys_seconds{sd}); - fields fds{ymd, time}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const tai_time& t) -{ - const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; - return to_stream(os, fmt, t); -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - tai_time& tp, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = tai_time{duration_cast( - (sys_days(fds.ymd) + - (sys_days(year{1970}/jan/1) - sys_days(year{1958}/jan/1)) - - *offptr + fds.tod.to_duration()).time_since_epoch())}; - return is; -} - -// gps_clock - -class gps_clock -{ -public: - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - static const bool is_steady = false; - - static time_point now(); - - template - static - std::chrono::time_point::type> - to_utc(const std::chrono::time_point&) NOEXCEPT; - - template - static - std::chrono::time_point::type> - from_utc(const std::chrono::time_point&) NOEXCEPT; - -}; - -template - using gps_time = std::chrono::time_point; - -using gps_seconds = gps_time; - -template -inline -utc_time::type> -gps_clock::to_utc(const gps_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return utc_time{t.time_since_epoch()} + - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1) + seconds{9}); -} - -template -inline -gps_time::type> -gps_clock::from_utc(const utc_time& t) NOEXCEPT -{ - using namespace std::chrono; - using duration = typename std::common_type::type; - return gps_time{t.time_since_epoch()} - - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1) + seconds{9}); -} - -inline -gps_clock::time_point -gps_clock::now() -{ - using namespace std::chrono; - return from_utc(utc_clock::now()); -} - -template -std::basic_ostream& -to_stream(std::basic_ostream& os, const CharT* fmt, - const gps_time& t) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - const string abbrev("GPS"); - CONSTDATA seconds offset{0}; - auto tp = sys_time{t.time_since_epoch()} + - seconds(sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1)); - auto const sd = floor(tp); - year_month_day ymd = sd; - auto time = make_time(tp - sys_seconds{sd}); - fields fds{ymd, time}; - return to_stream(os, fmt, fds, &abbrev, &offset); -} - -template -std::basic_ostream& -operator<<(std::basic_ostream& os, const gps_time& t) -{ - const CharT fmt[] = {'%', 'F', ' ', '%', 'T', CharT{}}; - return to_stream(os, fmt, t); -} - -template > -std::basic_istream& -from_stream(std::basic_istream& is, const CharT* fmt, - gps_time& tp, - std::basic_string* abbrev = nullptr, - std::chrono::minutes* offset = nullptr) -{ - using namespace std; - using namespace std::chrono; - using CT = typename common_type::type; - minutes offset_local{}; - auto offptr = offset ? offset : &offset_local; - fields fds{}; - from_stream(is, fmt, fds, abbrev, offptr); - if (!fds.ymd.ok() || !fds.tod.in_conventional_range()) - is.setstate(ios::failbit); - if (!is.fail()) - tp = gps_time{duration_cast( - (sys_days(fds.ymd) - - (sys_days(year{1980}/jan/sun[1]) - sys_days(year{1970}/jan/1)) - - *offptr + fds.tod.to_duration()).time_since_epoch())}; - return is; -} - -#if !defined(_MSC_VER) || _MSC_VER > 1912 - -// clock_time_conversion - -template -struct clock_time_conversion -{}; - -template <> -struct clock_time_conversion -{ - template - sys_time - operator()(const sys_time& st) const - { - return st; - } -}; - -template <> -struct clock_time_conversion -{ - template - utc_time - operator()(const utc_time& ut) const - { - return ut; - } -}; - -template <> -struct clock_time_conversion -{ - template - utc_time::type> - operator()(const sys_time& st) const - { - return utc_clock::from_sys(st); - } -}; - -template <> -struct clock_time_conversion -{ - template - sys_time::type> - operator()(const utc_time& ut) const - { - return utc_clock::to_sys(ut); - } -}; - -template -struct clock_time_conversion -{ - template - std::chrono::time_point - operator()(const std::chrono::time_point& tp) const - { - return tp; - } -}; - -namespace ctc_detail -{ - -template - using time_point = std::chrono::time_point; - -using std::declval; -using std::chrono::system_clock; - -//Check if TimePoint is time for given clock, -//if not emits hard error -template -struct return_clock_time -{ - using clock_time_point = time_point; - using type = TimePoint; - - static_assert(std::is_same::value, - "time point with appropariate clock shall be returned"); -}; - -// Check if Clock has to_sys method accepting TimePoint with given duration const& and -// returning sys_time. If so has nested type member equal to return type to_sys. -template -struct return_to_sys -{}; - -template -struct return_to_sys - < - Clock, Duration, - decltype(Clock::to_sys(declval const&>()), void()) - > - : return_clock_time - < - system_clock, - decltype(Clock::to_sys(declval const&>())) - > -{}; - -// Similiar to above -template -struct return_from_sys -{}; - -template -struct return_from_sys - < - Clock, Duration, - decltype(Clock::from_sys(declval const&>()), - void()) - > - : return_clock_time - < - Clock, - decltype(Clock::from_sys(declval const&>())) - > -{}; - -// Similiar to above -template -struct return_to_utc -{}; - -template -struct return_to_utc - < - Clock, Duration, - decltype(Clock::to_utc(declval const&>()), void()) - > - : return_clock_time - < - utc_clock, - decltype(Clock::to_utc(declval const&>()))> -{}; - -// Similiar to above -template -struct return_from_utc -{}; - -template -struct return_from_utc - < - Clock, Duration, - decltype(Clock::from_utc(declval const&>()), - void()) - > - : return_clock_time - < - Clock, - decltype(Clock::from_utc(declval const&>())) - > -{}; - -} // namespace ctc_detail - -template -struct clock_time_conversion -{ - template - typename ctc_detail::return_to_sys::type - operator()(const std::chrono::time_point& tp) const - { - return SrcClock::to_sys(tp); - } -}; - -template -struct clock_time_conversion -{ - template - typename ctc_detail::return_from_sys::type - operator()(const sys_time& st) const - { - return DstClock::from_sys(st); - } -}; - -template -struct clock_time_conversion -{ - template - typename ctc_detail::return_to_utc::type - operator()(const std::chrono::time_point& tp) const - { - return SrcClock::to_utc(tp); - } -}; - -template -struct clock_time_conversion -{ - template - typename ctc_detail::return_from_utc::type - operator()(const utc_time& ut) const - { - return DstClock::from_utc(ut); - } -}; - -namespace clock_cast_detail -{ - -template - using time_point = std::chrono::time_point; -using std::chrono::system_clock; - -template -auto -conv_clock(const time_point& t) - -> decltype(std::declval>()(t)) -{ - return clock_time_conversion{}(t); -} - -//direct trait conversion, 1st candidate -template -auto -cc_impl(const time_point& t, const time_point*) - -> decltype(conv_clock(t)) -{ - return conv_clock(t); -} - -//conversion through sys, 2nd candidate -template -auto -cc_impl(const time_point& t, const void*) - -> decltype(conv_clock(conv_clock(t))) -{ - return conv_clock(conv_clock(t)); -} - -//conversion through utc, 2nd candidate -template -auto -cc_impl(const time_point& t, const void*) - -> decltype(conv_clock(conv_clock(t))) -{ - return conv_clock(conv_clock(t)); -} - -//conversion through sys and utc, 3rd candidate -template -auto -cc_impl(const time_point& t, ...) - -> decltype(conv_clock(conv_clock(conv_clock(t)))) -{ - return conv_clock(conv_clock(conv_clock(t))); -} - -//conversion through utc and sys, 3rd candidate -template -auto -cc_impl(const time_point& t, ...) - -> decltype(conv_clock(conv_clock(conv_clock(t)))) -{ - return conv_clock(conv_clock(conv_clock(t))); -} - -} // namespace clock_cast_detail - -template -auto -clock_cast(const std::chrono::time_point& tp) - -> decltype(clock_cast_detail::cc_impl(tp, &tp)) -{ - return clock_cast_detail::cc_impl(tp, &tp); -} - -#endif // !defined(_MSC_VER) || _MSC_VER > 1912 - -// Deprecated API - -template -inline -sys_time::type> -to_sys_time(const utc_time& t) -{ - return utc_clock::to_sys(t); -} - -template -inline -sys_time::type> -to_sys_time(const tai_time& t) -{ - return utc_clock::to_sys(tai_clock::to_utc(t)); -} - -template -inline -sys_time::type> -to_sys_time(const gps_time& t) -{ - return utc_clock::to_sys(gps_clock::to_utc(t)); -} - - -template -inline -utc_time::type> -to_utc_time(const sys_time& t) -{ - return utc_clock::from_sys(t); -} - -template -inline -utc_time::type> -to_utc_time(const tai_time& t) -{ - return tai_clock::to_utc(t); -} - -template -inline -utc_time::type> -to_utc_time(const gps_time& t) -{ - return gps_clock::to_utc(t); -} - - -template -inline -tai_time::type> -to_tai_time(const sys_time& t) -{ - return tai_clock::from_utc(utc_clock::from_sys(t)); -} - -template -inline -tai_time::type> -to_tai_time(const utc_time& t) -{ - return tai_clock::from_utc(t); -} - -template -inline -tai_time::type> -to_tai_time(const gps_time& t) -{ - return tai_clock::from_utc(gps_clock::to_utc(t)); -} - - -template -inline -gps_time::type> -to_gps_time(const sys_time& t) -{ - return gps_clock::from_utc(utc_clock::from_sys(t)); -} - -template -inline -gps_time::type> -to_gps_time(const utc_time& t) -{ - return gps_clock::from_utc(t); -} - -template -inline -gps_time::type> -to_gps_time(const tai_time& t) -{ - return gps_clock::from_utc(tai_clock::to_utc(t)); -} - -#endif // !MISSING_LEAP_SECONDS - -} // namespace date - -#endif // TZ_H diff --git a/src/date/include/date/tz_private.h b/src/date/include/date/tz_private.h deleted file mode 100644 index 1aaad8edef..0000000000 --- a/src/date/include/date/tz_private.h +++ /dev/null @@ -1,318 +0,0 @@ -#ifndef TZ_PRIVATE_H -#define TZ_PRIVATE_H - -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) -#include "tz.h" -#else -#include "date.h" -#include -#endif - -namespace date -{ - -namespace detail -{ - -#if !USE_OS_TZDB - -enum class tz {utc, local, standard}; - -//forward declare to avoid warnings in gcc 6.2 -class MonthDayTime; -std::istream& operator>>(std::istream& is, MonthDayTime& x); -std::ostream& operator<<(std::ostream& os, const MonthDayTime& x); - - -class MonthDayTime -{ -private: - struct pair - { -#if defined(_MSC_VER) && (_MSC_VER < 1900) - pair() : month_day_(date::jan / 1), weekday_(0U) {} - - pair(const date::month_day& month_day, const date::weekday& weekday) - : month_day_(month_day), weekday_(weekday) {} -#endif - - date::month_day month_day_; - date::weekday weekday_; - }; - - enum Type {month_day, month_last_dow, lteq, gteq}; - - Type type_{month_day}; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - union U -#else - struct U -#endif - { - date::month_day month_day_; - date::month_weekday_last month_weekday_last_; - pair month_day_weekday_; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - U() : month_day_{date::jan/1} {} -#else - U() : - month_day_(date::jan/1), - month_weekday_last_(date::month(0U), date::weekday_last(date::weekday(0U))) - {} - -#endif // !defined(_MSC_VER) || (_MSC_VER >= 1900) - - U& operator=(const date::month_day& x); - U& operator=(const date::month_weekday_last& x); - U& operator=(const pair& x); - } u; - - std::chrono::hours h_{0}; - std::chrono::minutes m_{0}; - std::chrono::seconds s_{0}; - tz zone_{tz::local}; - -public: - MonthDayTime() = default; - MonthDayTime(local_seconds tp, tz timezone); - MonthDayTime(const date::month_day& md, tz timezone); - - date::day day() const; - date::month month() const; - tz zone() const {return zone_;} - - void canonicalize(date::year y); - - sys_seconds - to_sys(date::year y, std::chrono::seconds offset, std::chrono::seconds save) const; - sys_days to_sys_days(date::year y) const; - - sys_seconds to_time_point(date::year y) const; - int compare(date::year y, const MonthDayTime& x, date::year yx, - std::chrono::seconds offset, std::chrono::minutes prev_save) const; - - friend std::istream& operator>>(std::istream& is, MonthDayTime& x); - friend std::ostream& operator<<(std::ostream& os, const MonthDayTime& x); -}; - -// A Rule specifies one or more set of datetimes without using an offset. -// Multiple dates are specified with multiple years. The years in effect -// go from starting_year_ to ending_year_, inclusive. starting_year_ <= -// ending_year_. save_ is in effect for times from the specified time -// onward, including the specified time. When the specified time is -// local, it uses the save_ from the chronologically previous Rule, or if -// there is none, 0. - -//forward declare to avoid warnings in gcc 6.2 -class Rule; -bool operator==(const Rule& x, const Rule& y); -bool operator<(const Rule& x, const Rule& y); -bool operator==(const Rule& x, const date::year& y); -bool operator<(const Rule& x, const date::year& y); -bool operator==(const date::year& x, const Rule& y); -bool operator<(const date::year& x, const Rule& y); -bool operator==(const Rule& x, const std::string& y); -bool operator<(const Rule& x, const std::string& y); -bool operator==(const std::string& x, const Rule& y); -bool operator<(const std::string& x, const Rule& y); -std::ostream& operator<<(std::ostream& os, const Rule& r); - -class Rule -{ -private: - std::string name_; - date::year starting_year_{0}; - date::year ending_year_{0}; - MonthDayTime starting_at_; - std::chrono::minutes save_{0}; - std::string abbrev_; - -public: - Rule() = default; - explicit Rule(const std::string& s); - Rule(const Rule& r, date::year starting_year, date::year ending_year); - - const std::string& name() const {return name_;} - const std::string& abbrev() const {return abbrev_;} - - const MonthDayTime& mdt() const {return starting_at_;} - const date::year& starting_year() const {return starting_year_;} - const date::year& ending_year() const {return ending_year_;} - const std::chrono::minutes& save() const {return save_;} - - static void split_overlaps(std::vector& rules); - - friend bool operator==(const Rule& x, const Rule& y); - friend bool operator<(const Rule& x, const Rule& y); - friend bool operator==(const Rule& x, const date::year& y); - friend bool operator<(const Rule& x, const date::year& y); - friend bool operator==(const date::year& x, const Rule& y); - friend bool operator<(const date::year& x, const Rule& y); - friend bool operator==(const Rule& x, const std::string& y); - friend bool operator<(const Rule& x, const std::string& y); - friend bool operator==(const std::string& x, const Rule& y); - friend bool operator<(const std::string& x, const Rule& y); - - friend std::ostream& operator<<(std::ostream& os, const Rule& r); - -private: - date::day day() const; - date::month month() const; - static void split_overlaps(std::vector& rules, std::size_t i, std::size_t& e); - static bool overlaps(const Rule& x, const Rule& y); - static void split(std::vector& rules, std::size_t i, std::size_t k, - std::size_t& e); -}; - -inline bool operator!=(const Rule& x, const Rule& y) {return !(x == y);} -inline bool operator> (const Rule& x, const Rule& y) {return y < x;} -inline bool operator<=(const Rule& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const Rule& y) {return !(x < y);} - -inline bool operator!=(const Rule& x, const date::year& y) {return !(x == y);} -inline bool operator> (const Rule& x, const date::year& y) {return y < x;} -inline bool operator<=(const Rule& x, const date::year& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const date::year& y) {return !(x < y);} - -inline bool operator!=(const date::year& x, const Rule& y) {return !(x == y);} -inline bool operator> (const date::year& x, const Rule& y) {return y < x;} -inline bool operator<=(const date::year& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const date::year& x, const Rule& y) {return !(x < y);} - -inline bool operator!=(const Rule& x, const std::string& y) {return !(x == y);} -inline bool operator> (const Rule& x, const std::string& y) {return y < x;} -inline bool operator<=(const Rule& x, const std::string& y) {return !(y < x);} -inline bool operator>=(const Rule& x, const std::string& y) {return !(x < y);} - -inline bool operator!=(const std::string& x, const Rule& y) {return !(x == y);} -inline bool operator> (const std::string& x, const Rule& y) {return y < x;} -inline bool operator<=(const std::string& x, const Rule& y) {return !(y < x);} -inline bool operator>=(const std::string& x, const Rule& y) {return !(x < y);} - -struct zonelet -{ - enum tag {has_rule, has_save, is_empty}; - - std::chrono::seconds gmtoff_; - tag tag_ = has_rule; - -#if !defined(_MSC_VER) || (_MSC_VER >= 1900) - union U -#else - struct U -#endif - { - std::string rule_; - std::chrono::minutes save_; - - ~U() {} - U() {} - U(const U&) {} - U& operator=(const U&) = delete; - } u; - - std::string format_; - date::year until_year_{0}; - MonthDayTime until_date_; - sys_seconds until_utc_; - local_seconds until_std_; - local_seconds until_loc_; - std::chrono::minutes initial_save_{}; - std::string initial_abbrev_; - std::pair first_rule_{nullptr, date::year::min()}; - std::pair last_rule_{nullptr, date::year::max()}; - - ~zonelet(); - zonelet(); - zonelet(const zonelet& i); - zonelet& operator=(const zonelet&) = delete; -}; - -#else // USE_OS_TZDB - -struct ttinfo -{ - std::int32_t tt_gmtoff; - unsigned char tt_isdst; - unsigned char tt_abbrind; - unsigned char pad[2]; -}; - -static_assert(sizeof(ttinfo) == 8, ""); - -struct expanded_ttinfo -{ - std::chrono::seconds offset; - std::string abbrev; - bool is_dst; -}; - -struct transition -{ - sys_seconds timepoint; - const expanded_ttinfo* info; - - transition(sys_seconds tp, const expanded_ttinfo* i = nullptr) - : timepoint(tp) - , info(i) - {} - - friend - std::ostream& - operator<<(std::ostream& os, const transition& t) - { - using namespace date; - using namespace std::chrono; - using date::operator<<; - os << t.timepoint << "Z "; - if (t.info->offset >= seconds{0}) - os << '+'; - os << make_time(t.info->offset); - if (t.info->is_dst > 0) - os << " daylight "; - else - os << " standard "; - os << t.info->abbrev; - return os; - } -}; - -#endif // USE_OS_TZDB - -} // namespace detail - -} // namespace date - -#if defined(_MSC_VER) && (_MSC_VER < 1900) -#include "tz.h" -#endif - -#endif // TZ_PRIVATE_H diff --git a/src/date/src/tz.cpp b/src/date/src/tz.cpp deleted file mode 100644 index 39b9eaa9b7..0000000000 --- a/src/date/src/tz.cpp +++ /dev/null @@ -1,3775 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016, 2017 Howard Hinnant -// Copyright (c) 2015 Ville Voutilainen -// Copyright (c) 2016 Alexander Kormanovsky -// Copyright (c) 2016, 2017 Jiangang Zhuang -// Copyright (c) 2017 Nicolas Veloz Savino -// Copyright (c) 2017 Florian Dang -// Copyright (c) 2017 Aaron Bishop -// -// 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. -// -// Our apologies. When the previous paragraph was written, lowercase had not yet -// been invented (that would involve another several millennia of evolution). -// We did not mean to shout. - -#ifdef _WIN32 - // windows.h will be included directly and indirectly (e.g. by curl). - // We need to define these macros to prevent windows.h bringing in - // more than we need and do it early so windows.h doesn't get included - // without these macros having been defined. - // min/max macros interfere with the C++ versions. -# ifndef NOMINMAX -# define NOMINMAX -# endif - // We don't need all that Windows has to offer. -# ifndef WIN32_LEAN_AND_MEAN -# define WIN32_LEAN_AND_MEAN -# endif - - // for wcstombs -# ifndef _CRT_SECURE_NO_WARNINGS -# define _CRT_SECURE_NO_WARNINGS -# endif - - // None of this happens with the MS SDK (at least VS14 which I tested), but: - // Compiling with mingw, we get "error: 'KF_FLAG_DEFAULT' was not declared in this scope." - // and error: 'SHGetKnownFolderPath' was not declared in this scope.". - // It seems when using mingw NTDDI_VERSION is undefined and that - // causes KNOWN_FOLDER_FLAG and the KF_ flags to not get defined. - // So we must define NTDDI_VERSION to get those flags on mingw. - // The docs say though here: - // https://msdn.microsoft.com/en-nz/library/windows/desktop/aa383745(v=vs.85).aspx - // that "If you define NTDDI_VERSION, you must also define _WIN32_WINNT." - // So we declare we require Vista or greater. -# ifdef __MINGW32__ - -# ifndef NTDDI_VERSION -# define NTDDI_VERSION 0x06000000 -# define _WIN32_WINNT _WIN32_WINNT_VISTA -# elif NTDDI_VERSION < 0x06000000 -# warning "If this fails to compile NTDDI_VERSION may be to low. See comments above." -# endif - // But once we define the values above we then get this linker error: - // "tz.cpp:(.rdata$.refptr.FOLDERID_Downloads[.refptr.FOLDERID_Downloads]+0x0): " - // "undefined reference to `FOLDERID_Downloads'" - // which #include cures see: - // https://support.microsoft.com/en-us/kb/130869 -# include - // But with included, the error moves on to: - // error: 'FOLDERID_Downloads' was not declared in this scope - // Which #include cures. -# include - -# endif // __MINGW32__ - -# include -#endif // _WIN32 - -#include "date/tz_private.h" -#include "date/ios.h" - -#ifndef __APPLE__ -# define TARGET_OS_IPHONE 0 -#endif - -#if USE_OS_TZDB -# include -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include -#if USE_OS_TZDB -# include -#endif -#include -#include -#include -#include -#include - -// unistd.h is used on some platforms as part of the the means to get -// the current time zone. On Win32 windows.h provides a means to do it. -// gcc/mingw supports unistd.h on Win32 but MSVC does not. - -#ifdef _WIN32 -# include // _unlink etc. - -# if defined(__clang__) - struct IUnknown; // fix for issue with static_cast<> in objbase.h - // (see https://github.com/philsquared/Catch/issues/690) -# endif - -# include // CoTaskFree, ShGetKnownFolderPath etc. -# if HAS_REMOTE_API -# include // _mkdir -# include // ShFileOperation etc. -# endif // HAS_REMOTE_API -#else // !_WIN32 -# include -# if !USE_OS_TZDB -# include -# endif -# include -# include -# if !USE_SHELL_API -# include -# include -# include -# include -# include -# include -# endif //!USE_SHELL_API -#endif // !_WIN32 - - -#if HAS_REMOTE_API - // Note curl includes windows.h so we must include curl AFTER definitions of things - // that effect windows.h such as NOMINMAX. -#if defined(_MSC_VER) && defined(SHORTENED_CURL_INCLUDE) - // For rmt_curl nuget package -# include -#else -# include -#endif -#endif - -#ifdef _WIN32 -static CONSTDATA char folder_delimiter = '\\'; -#else // !_WIN32 -static CONSTDATA char folder_delimiter = '/'; -#endif // !_WIN32 - -#if defined(__GNUC__) && __GNUC__ < 5 - // GCC 4.9 Bug 61489 Wrong warning with -Wmissing-field-initializers -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wmissing-field-initializers" -#endif // defined(__GNUC__) && __GNUC__ < 5 - -#if !USE_OS_TZDB - -# ifdef _WIN32 - -namespace -{ - struct task_mem_deleter - { - void operator()(wchar_t buf[]) - { - if (buf != nullptr) - CoTaskMemFree(buf); - } - }; - using co_task_mem_ptr = std::unique_ptr; -} - -// We might need to know certain locations even if not using the remote API, -// so keep these routines out of that block for now. -static -std::string -get_known_folder(const GUID& folderid) -{ - std::string folder; - PWSTR pfolder = nullptr; - HRESULT hr = SHGetKnownFolderPath(folderid, KF_FLAG_DEFAULT, nullptr, &pfolder); - if (SUCCEEDED(hr)) - { - co_task_mem_ptr folder_ptr(pfolder); - folder = std::string(folder_ptr.get(), folder_ptr.get() + wcslen(folder_ptr.get())); - } - return folder; -} - -// Usually something like "c:\Users\username\Downloads". -static -std::string -get_download_folder() -{ - return get_known_folder(FOLDERID_Downloads); -} - -# else // !_WIN32 - -# if !defined(INSTALL) || HAS_REMOTE_API - -static -std::string -expand_path(std::string path) -{ -# if TARGET_OS_IPHONE - return date::iOSUtils::get_tzdata_path(); -# else // !TARGET_OS_IPHONE - ::wordexp_t w{}; - std::unique_ptr<::wordexp_t, void(*)(::wordexp_t*)> hold{&w, ::wordfree}; - ::wordexp(path.c_str(), &w, 0); - if (w.we_wordc != 1) - throw std::runtime_error("Cannot expand path: " + path); - path = w.we_wordv[0]; - return path; -# endif // !TARGET_OS_IPHONE -} - -static -std::string -get_download_folder() -{ - return expand_path("~/Downloads"); -} - -# endif // !defined(INSTALL) || HAS_REMOTE_API - -# endif // !_WIN32 - -#endif // !USE_OS_TZDB - -namespace date -{ -// +---------------------+ -// | Begin Configuration | -// +---------------------+ - -using namespace detail; - -#if !USE_OS_TZDB - -static -std::string& -access_install() -{ - static std::string install -#ifndef INSTALL - - = get_download_folder() + folder_delimiter + "tzdata"; - -#else // !INSTALL - -# define STRINGIZEIMP(x) #x -# define STRINGIZE(x) STRINGIZEIMP(x) - - = STRINGIZE(INSTALL) + std::string(1, folder_delimiter) + "tzdata"; - - #undef STRINGIZEIMP - #undef STRINGIZE -#endif // !INSTALL - - return install; -} - -void -set_install(const std::string& s) -{ - access_install() = s; -} - -static -const std::string& -get_install() -{ - static const std::string& ref = access_install(); - return ref; -} - -#if HAS_REMOTE_API -static -std::string -get_download_gz_file(const std::string& version) -{ - auto file = get_install() + version + ".tar.gz"; - return file; -} -#endif // HAS_REMOTE_API - -#endif // !USE_OS_TZDB - -// These can be used to reduce the range of the database to save memory -CONSTDATA auto min_year = date::year::min(); -CONSTDATA auto max_year = date::year::max(); - -CONSTDATA auto min_day = date::jan/1; -CONSTDATA auto max_day = date::dec/31; - -#if USE_OS_TZDB - -CONSTCD14 const sys_seconds min_seconds = sys_days(min_year/min_day); - -#endif // USE_OS_TZDB - -#ifndef _WIN32 - -static -std::string -discover_tz_dir() -{ - struct stat sb; - using namespace std; -# ifndef __APPLE__ - CONSTDATA auto tz_dir_default = "/usr/share/zoneinfo"; - CONSTDATA auto tz_dir_buildroot = "/usr/share/zoneinfo/uclibc"; - - // Check special path which is valid for buildroot with uclibc builds - if(stat(tz_dir_buildroot, &sb) == 0 && S_ISDIR(sb.st_mode)) - return tz_dir_buildroot; - else if(stat(tz_dir_default, &sb) == 0 && S_ISDIR(sb.st_mode)) - return tz_dir_default; - else - throw runtime_error("discover_tz_dir failed to find zoneinfo\n"); -# else // __APPLE__ -# if TARGET_OS_IPHONE - return "/var/db/timezone/zoneinfo"; -# else - CONSTDATA auto timezone = "/etc/localtime"; - if (!(lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0)) - throw runtime_error("discover_tz_dir failed\n"); - string result; - char rp[PATH_MAX+1] = {}; - if (readlink(timezone, rp, sizeof(rp)-1) > 0) - result = string(rp); - else - throw system_error(errno, system_category(), "readlink() failed"); - auto i = result.find("zoneinfo"); - if (i == string::npos) - throw runtime_error("discover_tz_dir failed to find zoneinfo\n"); - i = result.find('/', i); - if (i == string::npos) - throw runtime_error("discover_tz_dir failed to find '/'\n"); - return result.substr(0, i); -# endif -# endif // __APPLE__ -} - -static -const std::string& -get_tz_dir() -{ - static const std::string tz_dir = discover_tz_dir(); - return tz_dir; -} - -#endif - -// +-------------------+ -// | End Configuration | -// +-------------------+ - -namespace detail -{ -struct undocumented {explicit undocumented() = default;}; -} - -#ifndef _MSC_VER -static_assert(min_year <= max_year, "Configuration error"); -#endif - -static std::unique_ptr init_tzdb(); - -tzdb_list::~tzdb_list() -{ - const tzdb* ptr = head_; - head_ = nullptr; - while (ptr != nullptr) - { - auto next = ptr->next; - delete ptr; - ptr = next; - } -} - -tzdb_list::tzdb_list(tzdb_list&& x) noexcept - : head_{x.head_.exchange(nullptr)} -{ -} - -void -tzdb_list::push_front(tzdb* tzdb) noexcept -{ - tzdb->next = head_; - head_ = tzdb; -} - -tzdb_list::const_iterator -tzdb_list::erase_after(const_iterator p) noexcept -{ - auto t = p.p_->next; - p.p_->next = p.p_->next->next; - delete t; - return ++p; -} - -struct tzdb_list::undocumented_helper -{ - static void push_front(tzdb_list& db_list, tzdb* tzdb) noexcept - { - db_list.push_front(tzdb); - } -}; - -static -tzdb_list -create_tzdb() -{ - tzdb_list tz_db; - tzdb_list::undocumented_helper::push_front(tz_db, init_tzdb().release()); - return tz_db; -} - -tzdb_list& -get_tzdb_list() -{ - static tzdb_list tz_db = create_tzdb(); - return tz_db; -} - -#if !USE_OS_TZDB - -#ifdef _WIN32 - -static -void -sort_zone_mappings(std::vector& mappings) -{ - std::sort(mappings.begin(), mappings.end(), - [](const date::detail::timezone_mapping& lhs, - const date::detail::timezone_mapping& rhs)->bool - { - auto other_result = lhs.other.compare(rhs.other); - if (other_result < 0) - return true; - else if (other_result == 0) - { - auto territory_result = lhs.territory.compare(rhs.territory); - if (territory_result < 0) - return true; - else if (territory_result == 0) - { - if (lhs.type < rhs.type) - return true; - } - } - return false; - }); -} - -static -bool -native_to_standard_timezone_name(const std::string& native_tz_name, - std::string& standard_tz_name) -{ - // TOOD! Need be a case insensitive compare? - if (native_tz_name == "UTC") - { - standard_tz_name = "Etc/UTC"; - return true; - } - standard_tz_name.clear(); - // TODO! we can improve on linear search. - const auto& mappings = date::get_tzdb().mappings; - for (const auto& tzm : mappings) - { - if (tzm.other == native_tz_name) - { - standard_tz_name = tzm.type; - return true; - } - } - return false; -} - -// Parse this XML file: -// http://unicode.org/repos/cldr/trunk/common/supplemental/windowsZones.xml -// The parsing method is designed to be simple and quick. It is not overly -// forgiving of change but it should diagnose basic format issues. -// See timezone_mapping structure for more info. -static -std::vector -load_timezone_mappings_from_xml_file(const std::string& input_path) -{ - std::size_t line_num = 0; - std::vector mappings; - std::string line; - - std::ifstream is(input_path); - if (!is.is_open()) - { - // We don't emit file exceptions because that's an implementation detail. - std::string msg = "Error opening time zone mapping file \""; - msg += input_path; - msg += "\"."; - throw std::runtime_error(msg); - } - - auto error = [&input_path, &line_num](const char* info) - { - std::string msg = "Error loading time zone mapping file \""; - msg += input_path; - msg += "\" at line "; - msg += std::to_string(line_num); - msg += ": "; - msg += info; - throw std::runtime_error(msg); - }; - // [optional space]a="b" - auto read_attribute = [&line, &error] - (const char* name, std::string& value, std::size_t startPos) - ->std::size_t - { - value.clear(); - // Skip leading space before attribute name. - std::size_t spos = line.find_first_not_of(' ', startPos); - if (spos == std::string::npos) - spos = startPos; - // Assume everything up to next = is the attribute name - // and that an = will always delimit that. - std::size_t epos = line.find('=', spos); - if (epos == std::string::npos) - error("Expected \'=\' right after attribute name."); - std::size_t name_len = epos - spos; - // Expect the name we find matches the name we expect. - if (line.compare(spos, name_len, name) != 0) - { - std::string msg; - msg = "Expected attribute name \'"; - msg += name; - msg += "\' around position "; - msg += std::to_string(spos); - msg += " but found something else."; - error(msg.c_str()); - } - ++epos; // Skip the '=' that is after the attribute name. - spos = epos; - if (spos < line.length() && line[spos] == '\"') - ++spos; // Skip the quote that is before the attribute value. - else - { - std::string msg = "Expected '\"' to begin value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - epos = line.find('\"', spos); - if (epos == std::string::npos) - { - std::string msg = "Expected '\"' to end value of attribute \'"; - msg += name; - msg += "\'."; - error(msg.c_str()); - } - // Extract everything in between the quotes. Note no escaping is done. - std::size_t value_len = epos - spos; - value.assign(line, spos, value_len); - ++epos; // Skip the quote that is after the attribute value; - return epos; - }; - - // Quick but not overly forgiving XML mapping file processing. - bool mapTimezonesOpenTagFound = false; - bool mapTimezonesCloseTagFound = false; - std::size_t mapZonePos = std::string::npos; - std::size_t mapTimezonesPos = std::string::npos; - CONSTDATA char mapTimeZonesOpeningTag[] = { ""); - mapTimezonesCloseTagFound = (mapTimezonesPos != std::string::npos); - if (!mapTimezonesCloseTagFound) - { - std::size_t commentPos = line.find(" " << x.target_; -} - -// leap - -leap::leap(const std::string& s, detail::undocumented) -{ - using namespace date; - std::istringstream in(s); - in.exceptions(std::ios::failbit | std::ios::badbit); - std::string word; - int y; - MonthDayTime date; - in >> word >> y >> date; - date_ = date.to_time_point(year(y)); -} - -static -bool -file_exists(const std::string& filename) -{ -#ifdef _WIN32 - return ::_access(filename.c_str(), 0) == 0; -#else - return ::access(filename.c_str(), F_OK) == 0; -#endif -} - -#if HAS_REMOTE_API - -// CURL tools - -static -int -curl_global() -{ - if (::curl_global_init(CURL_GLOBAL_DEFAULT) != 0) - throw std::runtime_error("CURL global initialization failed"); - return 0; -} - -namespace -{ - -struct curl_deleter -{ - void operator()(CURL* p) const - { - ::curl_easy_cleanup(p); - } -}; - -} // unnamed namespace - -static -std::unique_ptr -curl_init() -{ - static const auto curl_is_now_initiailized = curl_global(); - (void)curl_is_now_initiailized; - return std::unique_ptr{::curl_easy_init()}; -} - -static -bool -download_to_string(const std::string& url, std::string& str) -{ - str.clear(); - auto curl = curl_init(); - if (!curl) - return false; - std::string version; - curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); - curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb, - void* userp) -> std::size_t - { - auto& userstr = *static_cast(userp); - auto realsize = size * nmemb; - userstr.append(contents, realsize); - return realsize; - }; - curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_cb); - curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &str); - curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false); - auto res = curl_easy_perform(curl.get()); - return (res == CURLE_OK); -} - -namespace -{ - enum class download_file_options { binary, text }; -} - -static -bool -download_to_file(const std::string& url, const std::string& local_filename, - download_file_options opts) -{ - auto curl = curl_init(); - if (!curl) - return false; - curl_easy_setopt(curl.get(), CURLOPT_URL, url.c_str()); - curl_easy_setopt(curl.get(), CURLOPT_SSL_VERIFYPEER, false); - curl_write_callback write_cb = [](char* contents, std::size_t size, std::size_t nmemb, - void* userp) -> std::size_t - { - auto& of = *static_cast(userp); - auto realsize = size * nmemb; - of.write(contents, static_cast(realsize)); - return realsize; - }; - curl_easy_setopt(curl.get(), CURLOPT_WRITEFUNCTION, write_cb); - decltype(curl_easy_perform(curl.get())) res; - { - std::ofstream of(local_filename, - opts == download_file_options::binary ? - std::ofstream::out | std::ofstream::binary : - std::ofstream::out); - of.exceptions(std::ios::badbit); - curl_easy_setopt(curl.get(), CURLOPT_WRITEDATA, &of); - res = curl_easy_perform(curl.get()); - } - return res == CURLE_OK; -} - -std::string -remote_version() -{ - std::string version; - std::string str; - if (download_to_string("https://www.iana.org/time-zones", str)) - { - CONSTDATA char db[] = "/time-zones/releases/tzdata"; - CONSTDATA auto db_size = sizeof(db) - 1; - auto p = str.find(db, 0, db_size); - const int ver_str_len = 5; - if (p != std::string::npos && p + (db_size + ver_str_len) <= str.size()) - version = str.substr(p + db_size, ver_str_len); - } - return version; -} - - -// TODO! Using system() create a process and a console window. -// This is useful to see what errors may occur but is slow and distracting. -// Consider implementing this functionality more directly, such as -// using _mkdir and CreateProcess etc. -// But use the current means now as matches Unix implementations and while -// in proof of concept / testing phase. -// TODO! Use eventually. -static -bool -remove_folder_and_subfolders(const std::string& folder) -{ -# ifdef _WIN32 -# if USE_SHELL_API - // Delete the folder contents by deleting the folder. - std::string cmd = "rd /s /q \""; - cmd += folder; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - // Create a buffer containing the path to delete. It must be terminated - // by two nuls. Who designs these API's... - std::vector from; - from.assign(folder.begin(), folder.end()); - from.push_back('\0'); - from.push_back('\0'); - SHFILEOPSTRUCT fo{}; // Zero initialize. - fo.wFunc = FO_DELETE; - fo.pFrom = from.data(); - fo.fFlags = FOF_NO_UI; - int ret = SHFileOperation(&fo); - if (ret == 0 && !fo.fAnyOperationsAborted) - return true; - return false; -# endif // !USE_SHELL_API -# else // !_WIN32 -# if USE_SHELL_API - return std::system(("rm -R " + folder).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - struct dir_deleter { - dir_deleter() {} - void operator()(DIR* d) const - { - if (d != nullptr) - { - int result = closedir(d); - assert(result == 0); - } - } - }; - using closedir_ptr = std::unique_ptr; - - std::string filename; - struct stat statbuf; - std::size_t folder_len = folder.length(); - struct dirent* p = nullptr; - - closedir_ptr d(opendir(folder.c_str())); - bool r = d.get() != nullptr; - while (r && (p=readdir(d.get())) != nullptr) - { - if (strcmp(p->d_name, ".") == 0 || strcmp(p->d_name, "..") == 0) - continue; - - // + 2 for path delimiter and nul terminator. - std::size_t buf_len = folder_len + strlen(p->d_name) + 2; - filename.resize(buf_len); - std::size_t path_len = static_cast( - snprintf(&filename[0], buf_len, "%s/%s", folder.c_str(), p->d_name)); - assert(path_len == buf_len - 1); - filename.resize(path_len); - - if (stat(filename.c_str(), &statbuf) == 0) - r = S_ISDIR(statbuf.st_mode) - ? remove_folder_and_subfolders(filename) - : unlink(filename.c_str()) == 0; - } - d.reset(); - - if (r) - r = rmdir(folder.c_str()) == 0; - - return r; -# endif // !USE_SHELL_API -# endif // !_WIN32 -} - -static -bool -make_directory(const std::string& folder) -{ -# ifdef _WIN32 -# if USE_SHELL_API - // Re-create the folder. - std::string cmd = "mkdir \""; - cmd += folder; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return _mkdir(folder.c_str()) == 0; -# endif // !USE_SHELL_API -# else // !_WIN32 -# if USE_SHELL_API - return std::system(("mkdir " + folder).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return mkdir(folder.c_str(), 0777) == 0; -# endif // !USE_SHELL_API -# endif // !_WIN32 -} - -static -bool -delete_file(const std::string& file) -{ -# ifdef _WIN32 -# if USE_SHELL_API - std::string cmd = "del \""; - cmd += file; - cmd += '\"'; - return std::system(cmd.c_str()) == 0; -# else // !USE_SHELL_API - return _unlink(file.c_str()) == 0; -# endif // !USE_SHELL_API -# else // !_WIN32 -# if USE_SHELL_API - return std::system(("rm " + file).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return unlink(file.c_str()) == 0; -# endif // !USE_SHELL_API -# endif // !_WIN32 -} - -# ifdef _WIN32 - -static -bool -move_file(const std::string& from, const std::string& to) -{ -# if USE_SHELL_API - std::string cmd = "move \""; - cmd += from; - cmd += "\" \""; - cmd += to; - cmd += '\"'; - return std::system(cmd.c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - return !!::MoveFile(from.c_str(), to.c_str()); -# endif // !USE_SHELL_API -} - -// Usually something like "c:\Program Files". -static -std::string -get_program_folder() -{ - return get_known_folder(FOLDERID_ProgramFiles); -} - -// Note folder can and usually does contain spaces. -static -std::string -get_unzip_program() -{ - std::string path; - - // 7-Zip appears to note its location in the registry. - // If that doesn't work, fall through and take a guess, but it will likely be wrong. - HKEY hKey = nullptr; - if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, "SOFTWARE\\7-Zip", 0, KEY_READ, &hKey) == ERROR_SUCCESS) - { - char value_buffer[MAX_PATH + 1]; // fyi 260 at time of writing. - // in/out parameter. Documentation say that size is a count of bytes not chars. - DWORD size = sizeof(value_buffer) - sizeof(value_buffer[0]); - DWORD tzi_type = REG_SZ; - // Testing shows Path key value is "C:\Program Files\7-Zip\" i.e. always with trailing \. - bool got_value = (RegQueryValueExA(hKey, "Path", nullptr, &tzi_type, - reinterpret_cast(value_buffer), &size) == ERROR_SUCCESS); - RegCloseKey(hKey); // Close now incase of throw later. - if (got_value) - { - // Function does not guarantee to null terminate. - value_buffer[size / sizeof(value_buffer[0])] = '\0'; - path = value_buffer; - if (!path.empty()) - { - path += "7z.exe"; - return path; - } - } - } - path += get_program_folder(); - path += folder_delimiter; - path += "7-Zip\\7z.exe"; - return path; -} - -# if !USE_SHELL_API -static -int -run_program(const std::string& command) -{ - STARTUPINFO si{}; - si.cb = sizeof(si); - PROCESS_INFORMATION pi{}; - - // Allegedly CreateProcess overwrites the command line. Ugh. - std::string mutable_command(command); - if (CreateProcess(nullptr, &mutable_command[0], - nullptr, nullptr, FALSE, CREATE_NO_WINDOW, nullptr, nullptr, &si, &pi)) - { - WaitForSingleObject(pi.hProcess, INFINITE); - DWORD exit_code; - bool got_exit_code = !!GetExitCodeProcess(pi.hProcess, &exit_code); - CloseHandle(pi.hProcess); - CloseHandle(pi.hThread); - // Not 100% sure about this still active thing is correct, - // but I'm going with it because I *think* WaitForSingleObject might - // return in some cases without INFINITE-ly waiting. - // But why/wouldn't GetExitCodeProcess return false in that case? - if (got_exit_code && exit_code != STILL_ACTIVE) - return static_cast(exit_code); - } - return EXIT_FAILURE; -} -# endif // !USE_SHELL_API - -static -std::string -get_download_tar_file(const std::string& version) -{ - auto file = get_install(); - file += folder_delimiter; - file += "tzdata"; - file += version; - file += ".tar"; - return file; -} - -static -bool -extract_gz_file(const std::string& version, const std::string& gz_file, - const std::string& dest_folder) -{ - auto unzip_prog = get_unzip_program(); - bool unzip_result = false; - // Use the unzip program to extract the tar file from the archive. - - // Aim to create a string like: - // "C:\Program Files\7-Zip\7z.exe" x "C:\Users\SomeUser\Downloads\tzdata2016d.tar.gz" - // -o"C:\Users\SomeUser\Downloads\tzdata" - std::string cmd; - cmd = '\"'; - cmd += unzip_prog; - cmd += "\" x \""; - cmd += gz_file; - cmd += "\" -o\""; - cmd += dest_folder; - cmd += '\"'; - -# if USE_SHELL_API - // When using shelling out with std::system() extra quotes are required around the - // whole command. It's weird but necessary it seems, see: - // http://stackoverflow.com/q/27975969/576911 - - cmd = "\"" + cmd + "\""; - if (std::system(cmd.c_str()) == EXIT_SUCCESS) - unzip_result = true; -# else // !USE_SHELL_API - if (run_program(cmd) == EXIT_SUCCESS) - unzip_result = true; -# endif // !USE_SHELL_API - if (unzip_result) - delete_file(gz_file); - - // Use the unzip program extract the data from the tar file that was - // just extracted from the archive. - auto tar_file = get_download_tar_file(version); - cmd = '\"'; - cmd += unzip_prog; - cmd += "\" x \""; - cmd += tar_file; - cmd += "\" -o\""; - cmd += get_install(); - cmd += '\"'; -# if USE_SHELL_API - cmd = "\"" + cmd + "\""; - if (std::system(cmd.c_str()) == EXIT_SUCCESS) - unzip_result = true; -# else // !USE_SHELL_API - if (run_program(cmd) == EXIT_SUCCESS) - unzip_result = true; -# endif // !USE_SHELL_API - - if (unzip_result) - delete_file(tar_file); - - return unzip_result; -} - -static -std::string -get_download_mapping_file(const std::string& version) -{ - auto file = get_install() + version + "windowsZones.xml"; - return file; -} - -# else // !_WIN32 - -# if !USE_SHELL_API -static -int -run_program(const char* prog, const char*const args[]) -{ - pid_t pid = fork(); - if (pid == -1) // Child failed to start. - return EXIT_FAILURE; - - if (pid != 0) - { - // We are in the parent. Child started. Wait for it. - pid_t ret; - int status; - while ((ret = waitpid(pid, &status, 0)) == -1) - { - if (errno != EINTR) - break; - } - if (ret != -1) - { - if (WIFEXITED(status)) - return WEXITSTATUS(status); - } - printf("Child issues!\n"); - - return EXIT_FAILURE; // Not sure what status of child is. - } - else // We are in the child process. Start the program the parent wants to run. - { - - if (execv(prog, const_cast(args)) == -1) // Does not return. - { - perror("unreachable 0\n"); - _Exit(127); - } - printf("unreachable 2\n"); - } - printf("unreachable 2\n"); - // Unreachable. - assert(false); - exit(EXIT_FAILURE); - return EXIT_FAILURE; -} -# endif // !USE_SHELL_API - -static -bool -extract_gz_file(const std::string&, const std::string& gz_file, const std::string&) -{ -# if USE_SHELL_API - bool unzipped = std::system(("tar -xzf " + gz_file + " -C " + get_install()).c_str()) == EXIT_SUCCESS; -# else // !USE_SHELL_API - const char prog[] = {"/usr/bin/tar"}; - const char*const args[] = - { - prog, "-xzf", gz_file.c_str(), "-C", get_install().c_str(), nullptr - }; - bool unzipped = (run_program(prog, args) == EXIT_SUCCESS); -# endif // !USE_SHELL_API - if (unzipped) - { - delete_file(gz_file); - return true; - } - return false; -} - -# endif // !_WIN32 - -bool -remote_download(const std::string& version) -{ - assert(!version.empty()); - -# ifdef _WIN32 - // Download folder should be always available for Windows -# else // !_WIN32 - // Create download folder if it does not exist on UNIX system - auto download_folder = get_download_folder(); - if (!file_exists(download_folder)) - { - make_directory(download_folder); - } -# endif // _WIN32 - - auto url = "https://data.iana.org/time-zones/releases/tzdata" + version + - ".tar.gz"; - bool result = download_to_file(url, get_download_gz_file(version), - download_file_options::binary); -# ifdef _WIN32 - if (result) - { - auto mapping_file = get_download_mapping_file(version); - result = download_to_file("http://unicode.org/repos/cldr/trunk/common/" - "supplemental/windowsZones.xml", - mapping_file, download_file_options::text); - } -# endif // _WIN32 - return result; -} - -bool -remote_install(const std::string& version) -{ - auto success = false; - assert(!version.empty()); - - std::string install = get_install(); - auto gz_file = get_download_gz_file(version); - if (file_exists(gz_file)) - { - if (file_exists(install)) - remove_folder_and_subfolders(install); - if (make_directory(install)) - { - if (extract_gz_file(version, gz_file, install)) - success = true; -# ifdef _WIN32 - auto mapping_file_source = get_download_mapping_file(version); - auto mapping_file_dest = get_install(); - mapping_file_dest += folder_delimiter; - mapping_file_dest += "windowsZones.xml"; - if (!move_file(mapping_file_source, mapping_file_dest)) - success = false; -# endif // _WIN32 - } - } - return success; -} - -#endif // HAS_REMOTE_API - -static -std::string -get_version(const std::string& path) -{ - std::string version; - std::ifstream infile(path + "version"); - if (infile.is_open()) - { - infile >> version; - if (!infile.fail()) - return version; - } - else - { - infile.open(path + "NEWS"); - while (infile) - { - infile >> version; - if (version == "Release") - { - infile >> version; - return version; - } - } - } - throw std::runtime_error("Unable to get Timezone database version from " + path); -} - -static -std::unique_ptr -init_tzdb() -{ - using namespace date; - const std::string install = get_install(); - const std::string path = install + folder_delimiter; - std::string line; - bool continue_zone = false; - std::unique_ptr db(new tzdb); - -#if AUTO_DOWNLOAD - if (!file_exists(install)) - { - auto rv = remote_version(); - if (!rv.empty() && remote_download(rv)) - { - if (!remote_install(rv)) - { - std::string msg = "Timezone database version \""; - msg += rv; - msg += "\" did not install correctly to \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - } - if (!file_exists(install)) - { - std::string msg = "Timezone database not found at \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - db->version = get_version(path); - } - else - { - db->version = get_version(path); - auto rv = remote_version(); - if (!rv.empty() && db->version != rv) - { - if (remote_download(rv)) - { - remote_install(rv); - db->version = get_version(path); - } - } - } -#else // !AUTO_DOWNLOAD - if (!file_exists(install)) - { - std::string msg = "Timezone database not found at \""; - msg += install; - msg += "\""; - throw std::runtime_error(msg); - } - db->version = get_version(path); -#endif // !AUTO_DOWNLOAD - - CONSTDATA char*const files[] = - { - "africa", "antarctica", "asia", "australasia", "backward", "etcetera", "europe", - "pacificnew", "northamerica", "southamerica", "systemv", "leapseconds" - }; - - for (const auto& filename : files) - { - std::ifstream infile(path + filename); - while (infile) - { - std::getline(infile, line); - if (!line.empty() && line[0] != '#') - { - std::istringstream in(line); - std::string word; - in >> word; - if (word == "Rule") - { - db->rules.push_back(Rule(line)); - continue_zone = false; - } - else if (word == "Link") - { - db->links.push_back(link(line)); - continue_zone = false; - } - else if (word == "Leap") - { - db->leaps.push_back(leap(line, detail::undocumented{})); - continue_zone = false; - } - else if (word == "Zone") - { - db->zones.push_back(time_zone(line, detail::undocumented{})); - continue_zone = true; - } - else if (line[0] == '\t' && continue_zone) - { - db->zones.back().add(line); - } - else - { - std::cerr << line << '\n'; - } - } - } - } - std::sort(db->rules.begin(), db->rules.end()); - Rule::split_overlaps(db->rules); - std::sort(db->zones.begin(), db->zones.end()); - db->zones.shrink_to_fit(); - std::sort(db->links.begin(), db->links.end()); - db->links.shrink_to_fit(); - std::sort(db->leaps.begin(), db->leaps.end()); - db->leaps.shrink_to_fit(); - -#ifdef _WIN32 - std::string mapping_file = get_install() + folder_delimiter + "windowsZones.xml"; - db->mappings = load_timezone_mappings_from_xml_file(mapping_file); - sort_zone_mappings(db->mappings); -#endif // _WIN32 - - return db; -} - -const tzdb& -reload_tzdb() -{ -#if AUTO_DOWNLOAD - auto const& v = get_tzdb_list().front().version; - if (!v.empty() && v == remote_version()) - return get_tzdb_list().front(); -#endif // AUTO_DOWNLOAD - tzdb_list::undocumented_helper::push_front(get_tzdb_list(), init_tzdb().release()); - return get_tzdb_list().front(); -} - -#endif // !USE_OS_TZDB - -const tzdb& -get_tzdb() -{ - return get_tzdb_list().front(); -} - -const time_zone* -#if HAS_STRING_VIEW -tzdb::locate_zone(std::string_view tz_name) const -#else -tzdb::locate_zone(const std::string& tz_name) const -#endif -{ - auto zi = std::lower_bound(zones.begin(), zones.end(), tz_name, -#if HAS_STRING_VIEW - [](const time_zone& z, const std::string_view& nm) -#else - [](const time_zone& z, const std::string& nm) -#endif - { - return z.name() < nm; - }); - if (zi == zones.end() || zi->name() != tz_name) - { -#if !USE_OS_TZDB - auto li = std::lower_bound(links.begin(), links.end(), tz_name, -#if HAS_STRING_VIEW - [](const link& z, const std::string_view& nm) -#else - [](const link& z, const std::string& nm) -#endif - { - return z.name() < nm; - }); - if (li != links.end() && li->name() == tz_name) - { - zi = std::lower_bound(zones.begin(), zones.end(), li->target(), - [](const time_zone& z, const std::string& nm) - { - return z.name() < nm; - }); - if (zi != zones.end() && zi->name() == li->target()) - return &*zi; - } -#endif // !USE_OS_TZDB - throw std::runtime_error(std::string(tz_name) + " not found in timezone database"); - } - return &*zi; -} - -const time_zone* -#if HAS_STRING_VIEW -locate_zone(std::string_view tz_name) -#else -locate_zone(const std::string& tz_name) -#endif -{ - return get_tzdb().locate_zone(tz_name); -} - -#if USE_OS_TZDB - -std::ostream& -operator<<(std::ostream& os, const tzdb& db) -{ - os << "Version: " << db.version << "\n\n"; - for (const auto& x : db.zones) - os << x << '\n'; -#if !MISSING_LEAP_SECONDS - os << '\n'; - for (const auto& x : db.leaps) - os << x << '\n'; -#endif // !MISSING_LEAP_SECONDS - return os; -} - -#else // !USE_OS_TZDB - -std::ostream& -operator<<(std::ostream& os, const tzdb& db) -{ - os << "Version: " << db.version << '\n'; - std::string title("--------------------------------------------" - "--------------------------------------------\n" - "Name ""Start Y ""End Y " - "Beginning ""Offset " - "Designator\n" - "--------------------------------------------" - "--------------------------------------------\n"); - int count = 0; - for (const auto& x : db.rules) - { - if (count++ % 50 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Name ""Offset " - "Rule ""Abrev ""Until\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - count = 0; - for (const auto& x : db.zones) - { - if (count++ % 10 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Alias ""To\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - count = 0; - for (const auto& x : db.links) - { - if (count++ % 45 == 0) - os << title; - os << x << '\n'; - } - os << '\n'; - title = std::string("---------------------------------------------------------" - "--------------------------------------------------------\n" - "Leap second on\n" - "---------------------------------------------------------" - "--------------------------------------------------------\n"); - os << title; - for (const auto& x : db.leaps) - os << x << '\n'; - return os; -} - -#endif // !USE_OS_TZDB - -// ----------------------- - -#ifdef _WIN32 - -static -std::string -getTimeZoneKeyName() -{ - DYNAMIC_TIME_ZONE_INFORMATION dtzi{}; - auto result = GetDynamicTimeZoneInformation(&dtzi); - if (result == TIME_ZONE_ID_INVALID) - throw std::runtime_error("current_zone(): GetDynamicTimeZoneInformation()" - " reported TIME_ZONE_ID_INVALID."); - auto wlen = wcslen(dtzi.TimeZoneKeyName); - char buf[128] = {}; - assert(sizeof(buf) >= wlen+1); - wcstombs(buf, dtzi.TimeZoneKeyName, wlen); - if (strcmp(buf, "Coordinated Universal Time") == 0) - return "UTC"; - return buf; -} - -const time_zone* -tzdb::current_zone() const -{ - std::string win_tzid = getTimeZoneKeyName(); - std::string standard_tzid; - if (!native_to_standard_timezone_name(win_tzid, standard_tzid)) - { - std::string msg; - msg = "current_zone() failed: A mapping from the Windows Time Zone id \""; - msg += win_tzid; - msg += "\" was not found in the time zone mapping database."; - throw std::runtime_error(msg); - } - return locate_zone(standard_tzid); -} - -#else // !_WIN32 - -const time_zone* -tzdb::current_zone() const -{ - // On some OS's a file called /etc/localtime may - // exist and it may be either a real file - // containing time zone details or a symlink to such a file. - // On MacOS and BSD Unix if this file is a symlink it - // might resolve to a path like this: - // "/usr/share/zoneinfo/America/Los_Angeles" - // If it does, we try to determine the current - // timezone from the remainder of the path by removing the prefix - // and hoping the rest resolves to valid timezone. - // It may not always work though. If it doesn't then an - // exception will be thrown by local_timezone. - // The path may also take a relative form: - // "../usr/share/zoneinfo/America/Los_Angeles". - { - struct stat sb; - CONSTDATA auto timezone = "/etc/localtime"; - if (lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0) { - using namespace std; - string result; - char rp[PATH_MAX+1] = {}; - if (readlink(timezone, rp, sizeof(rp)-1) > 0) - result = string(rp); - else - throw system_error(errno, system_category(), "readlink() failed"); - - const size_t pos = result.find(get_tz_dir()); - if (pos != result.npos) - result.erase(0, get_tz_dir().size() + 1 + pos); - return locate_zone(result); - } - } - // On embedded systems e.g. buildroot with uclibc the timezone is linked - // into /etc/TZ which is a symlink to path like this: - // "/usr/share/zoneinfo/uclibc/America/Los_Angeles" - // If it does, we try to determine the current - // timezone from the remainder of the path by removing the prefix - // and hoping the rest resolves to valid timezone. - // It may not always work though. If it doesn't then an - // exception will be thrown by local_timezone. - // The path may also take a relative form: - // "../usr/share/zoneinfo/uclibc/America/Los_Angeles". - { - struct stat sb; - CONSTDATA auto timezone = "/etc/TZ"; - if (lstat(timezone, &sb) == 0 && S_ISLNK(sb.st_mode) && sb.st_size > 0) { - using namespace std; - string result; - char rp[PATH_MAX+1] = {}; - if (readlink(timezone, rp, sizeof(rp)-1) > 0) - result = string(rp); - else - throw system_error(errno, system_category(), "readlink() failed"); - - const size_t pos = result.find(get_tz_dir()); - if (pos != result.npos) - result.erase(0, get_tz_dir().size() + 1 + pos); - return locate_zone(result); - } - } - { - // On some versions of some linux distro's (e.g. Ubuntu), - // the current timezone might be in the first line of - // the /etc/timezone file. - std::ifstream timezone_file("/etc/timezone"); - if (timezone_file.is_open()) - { - std::string result; - std::getline(timezone_file, result); - if (!result.empty()) - return locate_zone(result); - } - // Fall through to try other means. - } - { - // On some versions of some bsd distro's (e.g. FreeBSD), - // the current timezone might be in the first line of - // the /var/db/zoneinfo file. - std::ifstream timezone_file("/var/db/zoneinfo"); - if (timezone_file.is_open()) - { - std::string result; - std::getline(timezone_file, result); - if (!result.empty()) - return locate_zone(result); - } - // Fall through to try other means. - } - { - // On some versions of some linux distro's (e.g. Red Hat), - // the current timezone might be in the first line of - // the /etc/sysconfig/clock file as: - // ZONE="US/Eastern" - std::ifstream timezone_file("/etc/sysconfig/clock"); - std::string result; - while (timezone_file) - { - std::getline(timezone_file, result); - auto p = result.find("ZONE=\""); - if (p != std::string::npos) - { - result.erase(p, p+6); - result.erase(result.rfind('"')); - return locate_zone(result); - } - } - // Fall through to try other means. - } - throw std::runtime_error("Could not get current timezone"); -} - -#endif // !_WIN32 - -const time_zone* -current_zone() -{ - return get_tzdb().current_zone(); -} - -} // namespace date - -#if defined(__GNUC__) && __GNUC__ < 5 -# pragma GCC diagnostic pop -#endif diff --git a/src/date/test/clock_cast_test/custom_clock.pass.cpp b/src/date/test/clock_cast_test/custom_clock.pass.cpp deleted file mode 100644 index d9c9d8b39d..0000000000 --- a/src/date/test/clock_cast_test/custom_clock.pass.cpp +++ /dev/null @@ -1,187 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" -#include -#include - -//used to count number of conversion -int conversions = 0; - -//to/from impl -struct mil_clock -{ - using duration = std::common_type_t; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - static constexpr date::sys_days epoch = date::year{2000}/date::month{0}/date::day{1}; - - template - static - std::chrono::time_point> - to_sys(std::chrono::time_point const& tp) - { - ++conversions; - return epoch + tp.time_since_epoch(); - } - - template - static - std::chrono::time_point> - from_sys(std::chrono::time_point const& tp) - { - ++conversions; - using res = std::chrono::time_point>; - return res(tp - epoch); - } - - static time_point now() - { - return from_sys(std::chrono::system_clock::now()); - } -}; - - -date::sys_days const mil_clock::epoch; - -// traits example -struct s2s_clock -{ - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - template - static - std::chrono::time_point - to_sys(std::chrono::time_point const& tp) - { - ++conversions; - return std::chrono::time_point(tp.time_since_epoch()); - } - - template - static - std::chrono::time_point - from_sys(std::chrono::time_point const& tp) - { - ++conversions; - return std::chrono::time_point(tp.time_since_epoch()); - } - - static time_point now() - { - return from_sys(std::chrono::system_clock::now()); - } -}; - -namespace date -{ - template<> - struct clock_time_conversion - { - template - std::chrono::time_point> - operator()(std::chrono::time_point const& tp) - { - ++conversions; - using res = std::chrono::time_point>; - return res(tp.time_since_epoch() - mil_clock::epoch.time_since_epoch()); - } - }; -} - -int -main() -{ - using namespace date; - using sys_clock = std::chrono::system_clock; - - // self - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - - assert(clock_cast(mt) == mt); - } - - // mil <-> sys - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - - assert(clock_cast(st) == mt); - assert(clock_cast(mt) == st); - } - - // mil <-> utc - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - auto ut = utc_clock::from_sys(st); - - assert(clock_cast(ut) == mt); - assert(clock_cast(mt) == ut); - } - - // mil <-> tai - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(clock_cast(mt) == tt); - assert(clock_cast(tt) == mt); - } - - // mil <-> gps - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - auto ut = utc_clock::from_sys(st); - auto gt = gps_clock::from_utc(ut); - - assert(clock_cast(mt) == gt); - assert(clock_cast(gt) == mt); - } - - // s2s -> mil - { - sys_days st(1997_y/dec/12); - auto mt = mil_clock::from_sys(st); - auto s2t = s2s_clock::from_sys(st); - - //direct trait conversion - conversions = 0; - assert(clock_cast(s2t) == mt); - assert(conversions == 1); - - //uses sys_clock - conversions = 0; - assert(clock_cast(mt) == s2t); - assert(conversions == 2); - } -} diff --git a/src/date/test/clock_cast_test/deprecated.pass.cpp b/src/date/test/clock_cast_test/deprecated.pass.cpp deleted file mode 100644 index 74d246e380..0000000000 --- a/src/date/test/clock_cast_test/deprecated.pass.cpp +++ /dev/null @@ -1,90 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" -#include - -int -main() -{ - using namespace date; - - // sys <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - - assert(to_utc_time(st) == ut); - assert(to_sys_time(ut) == st); - } - - // tai <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(to_tai_time(ut) == tt); - assert(to_utc_time(tt) == ut); - } - - // tai <-> sys - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(to_tai_time(st) == tt); - assert(to_sys_time(tt) == st); - } - - // gps <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto gt = gps_clock::from_utc(ut); - - assert(to_gps_time(ut) == gt); - assert(to_utc_time(gt) == ut); - } - - // gps <-> sys - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto gt = gps_clock::from_utc(ut); - - assert(to_gps_time(st) == gt); - assert(to_sys_time(gt) == st); - } - - // tai <-> gps - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - auto gt = gps_clock::from_utc(ut); - - assert(to_gps_time(tt) == gt); - assert(to_tai_time(gt) == tt); - } -} diff --git a/src/date/test/clock_cast_test/noncastable.pass.cpp b/src/date/test/clock_cast_test/noncastable.pass.cpp deleted file mode 100644 index b81139e2ea..0000000000 --- a/src/date/test/clock_cast_test/noncastable.pass.cpp +++ /dev/null @@ -1,247 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" -#include -#include - -template -struct is_clock_castable - : std::false_type -{}; - -template -struct is_clock_castable(typename SourceClock::time_point()), void())> - : std::true_type -{}; - - -//Clock based on steady clock, not related to wall time (sys_clock/utc_clock) -struct steady_based_clock -{ - using duration = std::chrono::steady_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - static time_point now() - { - return time_point(std::chrono::steady_clock::now().time_since_epoch()); - } -}; - -//Traits that allow conversion between steady_clock and steady_based clock -//Does not use wall-time clocks as rally (sys/utc) -namespace date -{ - template<> - struct clock_time_conversion - { - template - std::chrono::time_point - operator()(std::chrono::time_point const& tp) const - { - using res = std::chrono::time_point; - return res(tp.time_since_epoch()); - } - }; - - template<> - struct clock_time_conversion - { - template - std::chrono::time_point - operator()(std::chrono::time_point const& tp) const - { - using res = std::chrono::time_point; - return res(tp.time_since_epoch()); - } - }; -} - -//Ambigous clocks both providing to/from_sys and to/from_utc -//They are mock_ups just returning zero time_point -struct amb1_clock -{ - using duration = std::chrono::seconds; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - static time_point now() - { - return {}; - } - - template - static - std::chrono::time_point - to_sys(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - from_sys(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - to_utc(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - from_utc(std::chrono::time_point const&) - { - return {}; - } -}; - -struct amb2_clock -{ - using duration = std::chrono::seconds; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - static time_point now() - { - return {}; - } - - template - static - std::chrono::time_point - to_sys(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - from_sys(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - to_utc(std::chrono::time_point const&) - { - return {}; - } - - template - static - std::chrono::time_point - from_utc(std::chrono::time_point const&) - { - return {}; - } -}; - -namespace date -{ - //Disambiguates that sys_clock is preffered - template<> - struct clock_time_conversion - { - template - std::chrono::time_point - operator()(std::chrono::time_point const& tp) const - { - return amb1_clock::from_sys(amb2_clock::to_sys(tp)); - } - }; -} - -int -main() -{ - using namespace date; - using namespace std::chrono; - using sys_clock = std::chrono::system_clock; - - //steady_clock (must be different that sys_clock) - static_assert(is_clock_castable::value, "steady_clock -> steady_clock"); - static_assert(!is_clock_castable::value, "steady_clock -> sys_clock"); - static_assert(!is_clock_castable::value, "sys_clock -> steady_clock"); - static_assert(!is_clock_castable::value, "steady_clock -> utc_clock"); - static_assert(!is_clock_castable::value, "utc_clock -> steady_clock"); - static_assert(!is_clock_castable::value, "steady_clock -> tai_clock"); - static_assert(!is_clock_castable::value, "tai_clock -> steady_clock"); - - //steady_based_clock (unrelated to sys_clock and utc_clocks) - static_assert(is_clock_castable::value, "steady_based_clock -> steady_based_clock"); - static_assert(!is_clock_castable::value, "steady_based_clock -> sys_clock"); - static_assert(!is_clock_castable::value, "sys_clock -> steady_based_clock"); - static_assert(!is_clock_castable::value, "steady_based_clock -> utc_clock"); - static_assert(!is_clock_castable::value, "utc_clock -> steady_based_clock"); - static_assert(!is_clock_castable::value, "steady_based_clock -> tai_clock"); - static_assert(!is_clock_castable::value, "tai_clock -> steady_based_clock"); - - //steady_based <-> steady_clock - { - auto s1 = steady_clock::time_point(steady_clock::duration(200)); - auto s2 = steady_based_clock::time_point(steady_based_clock::duration(200)); - - assert(clock_cast(s1) == s2); - assert(clock_cast(s2) == s1); - } - - //ambX <-> sys/utc works as one rally can be used in each case, or one lead to quicker conversione - static_assert(is_clock_castable::value, "amb1_clock -> amb1_clock"); - static_assert(is_clock_castable::value, "amb1_clock -> sys_clock"); - static_assert(is_clock_castable::value, "sys_clock -> amb1_clock"); - static_assert(is_clock_castable::value, "amb1_clock -> utc_clock"); - static_assert(is_clock_castable::value, "utc_clock -> amb1_clock"); - static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); - static_assert(is_clock_castable::value, "tai_clock -> amb1_clock"); - static_assert(is_clock_castable::value, "amb1_clock -> tai_clock"); - static_assert(is_clock_castable::value, "gps_clock -> amb1_clock"); - static_assert(is_clock_castable::value, "amb2_clock -> amb2_clock"); - static_assert(is_clock_castable::value, "amb2_clock -> sys_clock"); - static_assert(is_clock_castable::value, "sys_clock -> amb2_clock"); - static_assert(is_clock_castable::value, "amb2_clock -> utc_clock"); - static_assert(is_clock_castable::value, "utc_clock -> amb2_clock"); - static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); - static_assert(is_clock_castable::value, "tai_clock -> amb2_clock"); - static_assert(is_clock_castable::value, "amb2_clock -> tai_clock"); - static_assert(is_clock_castable::value, "gps_clock -> amb2_clock"); - - //amb1 -> amb2: ambigous because can either go trough sys_clock or utc_clock - static_assert(!is_clock_castable::value, "amb1_clock -> amb2_clock"); - - //amb2 -> amb1: disambiguated via trait specialization - static_assert(is_clock_castable::value, "amb2_clock -> amb1_clock"); -} diff --git a/src/date/test/clock_cast_test/normal_clocks.pass.cpp b/src/date/test/clock_cast_test/normal_clocks.pass.cpp deleted file mode 100644 index 525bc02233..0000000000 --- a/src/date/test/clock_cast_test/normal_clocks.pass.cpp +++ /dev/null @@ -1,102 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" -#include - -int -main() -{ - using namespace date; - using sys_clock = std::chrono::system_clock; - - // self - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(clock_cast(st) == st); - assert(clock_cast(ut) == ut); - assert(clock_cast(tt) == tt); - } - - // sys <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - - assert(clock_cast(st) == ut); - assert(clock_cast(ut) == st); - } - - // tai <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(clock_cast(ut) == tt); - assert(clock_cast(tt) == ut); - } - - // tai <-> sys - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - - assert(clock_cast(st) == tt); - assert(clock_cast(tt) == st); - } - - // gps <-> utc - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto gt = gps_clock::from_utc(ut); - - assert(clock_cast(ut) == gt); - assert(clock_cast(gt) == ut); - } - - // gps <-> sys - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto gt = gps_clock::from_utc(ut); - - assert(clock_cast(st) == gt); - assert(clock_cast(gt) == st); - } - - // tai <-> gps - { - sys_days st(1997_y/dec/12); - auto ut = utc_clock::from_sys(st); - auto tt = tai_clock::from_utc(ut); - auto gt = gps_clock::from_utc(ut); - - assert(clock_cast(tt) == gt); - assert(clock_cast(gt) == tt); - } -} diff --git a/src/date/test/clock_cast_test/to_sys_return_int.fail.cpp b/src/date/test/clock_cast_test/to_sys_return_int.fail.cpp deleted file mode 100644 index 370c68276f..0000000000 --- a/src/date/test/clock_cast_test/to_sys_return_int.fail.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" - -struct bad_clock -{ - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - template - static - int - to_sys(std::chrono::time_point const& tp) - { - return tp.time_since_epoch().count(); - } -}; - -int -main() -{ - using namespace date; - using sys_clock = std::chrono::system_clock; - - auto bt = bad_clock::time_point(); - clock_cast(bt); -} diff --git a/src/date/test/clock_cast_test/to_sys_return_reference.fail.cpp b/src/date/test/clock_cast_test/to_sys_return_reference.fail.cpp deleted file mode 100644 index 5fae1652fd..0000000000 --- a/src/date/test/clock_cast_test/to_sys_return_reference.fail.cpp +++ /dev/null @@ -1,51 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" - -struct bad_clock -{ - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - template - static - date::sys_time const& - to_sys(std::chrono::time_point const& tp) - { - static date::sys_time val; - val = date::sys_time(tp.time_since_epoch()); - return val; - } -}; - -int -main() -{ - using namespace date; - using sys_clock = std::chrono::system_clock; - - auto bt = bad_clock::time_point(); - clock_cast(bt); -} diff --git a/src/date/test/clock_cast_test/to_sys_return_utc_time.fail.cpp b/src/date/test/clock_cast_test/to_sys_return_utc_time.fail.cpp deleted file mode 100644 index d5364ce58a..0000000000 --- a/src/date/test/clock_cast_test/to_sys_return_utc_time.fail.cpp +++ /dev/null @@ -1,49 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Tomasz Kamiński -// -// 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. - -#include "tz.h" - -struct bad_clock -{ - using duration = std::chrono::system_clock::duration; - using rep = duration::rep; - using period = duration::period; - using time_point = std::chrono::time_point; - - template - static - date::utc_time - to_sys(std::chrono::time_point const& tp) - { - return utc_time(tp.time_since_epoch()); - } -}; - -int -main() -{ - using namespace date; - using sys_clock = std::chrono::system_clock; - - auto bt = bad_clock::time_point(); - clock_cast(bt); -} diff --git a/src/date/test/date_test/day.pass.cpp b/src/date/test/date_test/day.pass.cpp deleted file mode 100644 index 0dbdf68816..0000000000 --- a/src/date/test/date_test/day.pass.cpp +++ /dev/null @@ -1,143 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class day -// { -// unsigned char d_; -// public: -// explicit constexpr day(unsigned d) noexcept; -// -// day& operator++() noexcept; -// day operator++(int) noexcept; -// day& operator--() noexcept; -// day operator--(int) noexcept; -// -// day& operator+=(const days& d) noexcept; -// day& operator-=(const days& d) noexcept; -// -// constexpr explicit operator unsigned() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const day& x, const day& y) noexcept; -// constexpr bool operator!=(const day& x, const day& y) noexcept; -// constexpr bool operator< (const day& x, const day& y) noexcept; -// constexpr bool operator> (const day& x, const day& y) noexcept; -// constexpr bool operator<=(const day& x, const day& y) noexcept; -// constexpr bool operator>=(const day& x, const day& y) noexcept; -// -// constexpr day operator+(const day& x, const days& y) noexcept; -// constexpr day operator+(const days& x, const day& y) noexcept; -// constexpr day operator-(const day& x, const days& y) noexcept; -// constexpr days operator-(const day& x, const day& y) noexcept; -// -// constexpr day operator "" _d(unsigned long long d) noexcept; -// std::ostream& operator<<(std::ostream& os, const day& d); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(date::day{1}) == 1, ""); - -static_assert(!date::day{0}.ok(), ""); -static_assert( date::day{1}.ok(), ""); -static_assert( date::day{2}.ok(), ""); -static_assert( date::day{3}.ok(), ""); -static_assert( date::day{29}.ok(), ""); -static_assert( date::day{30}.ok(), ""); -static_assert( date::day{31}.ok(), ""); -static_assert(!date::day{32}.ok(), ""); - -int -main() -{ - using namespace date; - static_assert(std::is_same{}, ""); - - static_assert(1_d == day{1}, ""); - static_assert(2_d == day{2}, ""); - - static_assert( 1_d == 1_d, ""); - static_assert(!(1_d == 2_d), ""); - static_assert(!(2_d == 1_d), ""); - - static_assert(!(1_d != 1_d), ""); - static_assert( 1_d != 2_d, ""); - static_assert( 2_d != 1_d, ""); - - static_assert(!(1_d < 1_d), ""); - static_assert( 1_d < 2_d, ""); - static_assert(!(2_d < 1_d), ""); - - static_assert( 1_d <= 1_d, ""); - static_assert( 1_d <= 2_d, ""); - static_assert(!(2_d <= 1_d), ""); - - static_assert(!(1_d > 1_d), ""); - static_assert(!(1_d > 2_d), ""); - static_assert( 2_d > 1_d, ""); - - static_assert( 1_d >= 1_d, ""); - static_assert(!(1_d >= 2_d), ""); - static_assert( 2_d >= 1_d, ""); - - static_assert(3_d + days{7} == 10_d, ""); - static_assert(days{7} + 3_d == 10_d, ""); - static_assert(3_d + weeks{1} == 10_d, ""); - static_assert(weeks{1} + 3_d == 10_d, ""); - - static_assert(7_d - days{3} == 4_d, ""); - static_assert(3_d - 7_d == days{-4}, ""); - static_assert(25_d - 11_d == weeks{2}, ""); - - auto d = 1_d; - assert(++d == 2_d); - assert(d++ == 2_d); - assert(d == 3_d); - assert(d-- == 3_d); - assert(d == 2_d); - assert(--d == 1_d); - assert((d += days{2}) == 3_d); - assert((d -= days{2}) == 1_d); - - std::ostringstream os; - os << d; - assert(os.str() == "01"); - d += days{11}; - os.str(""); - os << d; - assert(os.str() == "12"); -} diff --git a/src/date/test/date_test/daypday.fail.cpp b/src/date/test/date_test/daypday.fail.cpp deleted file mode 100644 index 80a92c7ef3..0000000000 --- a/src/date/test/date_test/daypday.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// day + day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = 3_d + 7_d; -} diff --git a/src/date/test/date_test/daysmday.fail.cpp b/src/date/test/date_test/daysmday.fail.cpp deleted file mode 100644 index 42db047a95..0000000000 --- a/src/date/test/date_test/daysmday.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// days - day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = days{3} - 7_d; -} diff --git a/src/date/test/date_test/daysmweekday.fail.cpp b/src/date/test/date_test/daysmweekday.fail.cpp deleted file mode 100644 index 05e8e4c934..0000000000 --- a/src/date/test/date_test/daysmweekday.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// days - weekday not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto b = days{1} - sun; -} diff --git a/src/date/test/date_test/detail/decimal_format_seconds.pass.cpp b/src/date/test/date_test/detail/decimal_format_seconds.pass.cpp deleted file mode 100644 index dfb461952d..0000000000 --- a/src/date/test/date_test/detail/decimal_format_seconds.pass.cpp +++ /dev/null @@ -1,145 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// template ::type::period::den>::value> -// class decimal_format_seconds -// { -// public: -// using precision = typename make_precision::type; -// static auto constexpr width = make_precision::width; -// -// private: -// std::chrono::seconds s_; -// precision sub_s_; -// -// public: -// constexpr explicit decimal_format_seconds(const Duration& d) noexcept; -// -// constexpr std::chrono::seconds& seconds() noexcept; -// constexpr std::chrono::seconds seconds() const noexcept; -// constexpr precision subseconds() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// template -// friend -// std::basic_ostream& -// operator<<(std::basic_ostream& os, const decimal_format_seconds& x); -// }; - -#include "date.h" - -#include -#include -#include - -using fortnights = std::chrono::duration, - date::weeks::period>>; - -using microfortnights = std::chrono::duration>; - -int -main() -{ - using namespace date::detail; - using namespace std; - using namespace std::chrono; - - { - using D = decimal_format_seconds; - static_assert(is_same{}, ""); - static_assert(D::width == 0, ""); - D dfs{minutes{3}}; - assert(dfs.seconds() == seconds{180}); - assert(dfs.to_duration() == seconds{180}); - ostringstream out; - out << dfs; - assert(out.str() == "180"); - } - { - using D = decimal_format_seconds; - static_assert(is_same{}, ""); - static_assert(D::width == 0, ""); - D dfs{seconds{3}}; - assert(dfs.seconds() == seconds{3}); - assert(dfs.to_duration() == seconds{3}); - ostringstream out; - out << dfs; - assert(out.str() == "03"); - } - { - using D = decimal_format_seconds; - static_assert(D::width == 3, ""); - static_assert(is_same::type>{}, ""); - D dfs{seconds{3}}; - assert(dfs.seconds() == seconds{3}); - assert(dfs.to_duration() == seconds{3}); - assert(dfs.subseconds() == milliseconds{0}); - ostringstream out; - out << dfs; - assert(out.str() == "03.000"); - } - { - using D = decimal_format_seconds; - static_assert(D::width == 3, ""); - static_assert(is_same::type>{}, ""); - D dfs{milliseconds{3}}; - assert(dfs.seconds() == seconds{0}); - assert(dfs.to_duration() == milliseconds{3}); - assert(dfs.subseconds() == milliseconds{3}); - ostringstream out; - out << dfs; - assert(out.str() == "00.003"); - } - { - using D = decimal_format_seconds; - static_assert(D::width == 4, ""); - using S = make_precision::type; - static_assert(is_same{}, ""); - D dfs{microfortnights{3}}; - assert(dfs.seconds() == seconds{3}); - assert(dfs.to_duration() == S{36288}); - assert(dfs.subseconds() == S{6288}); - ostringstream out; - out << dfs; - assert(out.str() == "03.6288"); - } - { - using CT = common_type::type; - using D = decimal_format_seconds; - static_assert(D::width == 4, ""); - using S = make_precision::type; - static_assert(is_same{}, ""); - D dfs{microfortnights{3}}; - assert(dfs.seconds() == seconds{3}); - assert(dfs.to_duration() == S{36288}); - assert(dfs.subseconds() == S{6288}); - ostringstream out; - out << dfs; - assert(out.str() == "03.6288"); - } -} diff --git a/src/date/test/date_test/detail/make_precision.pass.cpp b/src/date/test/date_test/detail/make_precision.pass.cpp deleted file mode 100644 index efdec1cfa5..0000000000 --- a/src/date/test/date_test/detail/make_precision.pass.cpp +++ /dev/null @@ -1,63 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// template -// struct make_precision -// { -// using type = std::chrono::duration::value>>; -// static constexpr unsigned width = w; -// }; - -#include "date.h" - -#include -#include - -int -main() -{ - using namespace date::detail; - using namespace std; - using namespace std::chrono; - - static_assert(make_precision::width == 0, ""); - static_assert(is_same::type, duration>>{}, ""); - - static_assert(make_precision::width == 1, ""); - static_assert(is_same::type, duration>>{}, ""); - - static_assert(make_precision::width == 2, ""); - static_assert(is_same::type, duration>>{}, ""); - - static_assert(make_precision::width == 3, ""); - static_assert(is_same::type, duration>>{}, ""); - - static_assert(make_precision::width == 18, ""); - static_assert(is_same::type, duration>>{}, ""); - - static_assert(make_precision::width == 6, ""); - static_assert(is_same::type, microseconds>{}, ""); - - static_assert(make_precision::width == 6, ""); - static_assert(is_same::type, microseconds>{}, ""); -} diff --git a/src/date/test/date_test/detail/static_pow10.pass.cpp b/src/date/test/date_test/detail/static_pow10.pass.cpp deleted file mode 100644 index fe44fa422a..0000000000 --- a/src/date/test/date_test/detail/static_pow10.pass.cpp +++ /dev/null @@ -1,50 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// template -// struct static_pow10 -// { -// static constepxr std::uint64_t value = ...; -// }; - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date::detail; - static_assert(static_pow10<0>::value == 1, ""); - static_assert(static_pow10<1>::value == 10, ""); - static_assert(static_pow10<2>::value == 100, ""); - static_assert(static_pow10<3>::value == 1000, ""); - static_assert(static_pow10<4>::value == 10000, ""); - static_assert(static_pow10<5>::value == 100000, ""); - static_assert(static_pow10<6>::value == 1000000, ""); - static_assert(static_pow10<7>::value == 10000000, ""); - static_assert(static_pow10<8>::value == 100000000, ""); - static_assert(static_pow10<9>::value == 1000000000, ""); - static_assert(static_pow10<10>::value == 10000000000, ""); -} diff --git a/src/date/test/date_test/detail/width.pass.cpp b/src/date/test/date_test/detail/width.pass.cpp deleted file mode 100644 index 6fbb7b94c6..0000000000 --- a/src/date/test/date_test/detail/width.pass.cpp +++ /dev/null @@ -1,64 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// width::value is the number of fractional decimal digits in 1/n -// width<0>::value and width<1>::value are defined to be 0 -// If 1/n takes more than 18 fractional decimal digits, -// the result is truncated to 19. -// Example: width<2>::value == 1 -// Example: width<3>::value == 19 -// Example: width<4>::value == 2 -// Example: width<10>::value == 1 -// Example: width<1000>::value == 3 -// template -// -// struct width -// { -// static constexpr unsigned value = ...; -// }; - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date::detail; - static_assert(width<0>::value == 0, ""); - static_assert(width<1>::value == 0, ""); - static_assert(width<2>::value == 1, ""); - static_assert(width<3>::value == 19, ""); - static_assert(width<4>::value == 2, ""); - static_assert(width<5>::value == 1, ""); - static_assert(width<6>::value == 19, ""); - static_assert(width<7>::value == 19, ""); - static_assert(width<8>::value == 3, ""); - static_assert(width<9>::value == 19, ""); - static_assert(width<10>::value == 1, ""); - static_assert(width<100>::value == 2, ""); - static_assert(width<1000>::value == 3, ""); - static_assert(width<10000>::value == 4, ""); - static_assert(width<625>::value == 4, ""); -} diff --git a/src/date/test/date_test/durations.pass.cpp b/src/date/test/date_test/durations.pass.cpp deleted file mode 100644 index 970ddde760..0000000000 --- a/src/date/test/date_test/durations.pass.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// durations -// -// using days = std::chrono::duration -// , std::chrono::hours::period>>; -// -// using weeks = std::chrono::duration -// , days::period>>; -// -// using years = std::chrono::duration -// , days::period>>; -// -// using months = std::chrono::duration -// >>; -// -// time_point -// -// using sys_days = std::chrono::time_point; - -#include "date.h" - -#include - -static_assert(date::days{1} == std::chrono::hours{24}, ""); - -static_assert(date::weeks{1} == date::days{7}, ""); - -static_assert(date::months{12} == date::years{1}, ""); -static_assert(date::days{30} < date::months{1} && date::months{1} < date::days{31}, ""); -static_assert(date::weeks{4} < date::months{1} && date::months{1} < date::weeks{5}, ""); - -static_assert(date::years{400} == date::days{146097}, ""); -static_assert(date::days{365} < date::years{1} && date::years{1} < date::days{366}, ""); -static_assert(date::weeks{52} < date::years{1} && date::years{1} < date::weeks{53}, ""); - -static_assert(std::is_same{}, ""); - -int -main() -{ -} diff --git a/src/date/test/date_test/format/century.pass.cpp b/src/date/test/date_test/format/century.pass.cpp deleted file mode 100644 index 1b401f7bd4..0000000000 --- a/src/date/test/date_test/format/century.pass.cpp +++ /dev/null @@ -1,117 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std::chrono; - std::ostringstream os; - os << format("%C", sys_days{jun/1/20001}); - assert(os.str() == "200"); - - os.str(""); - os << format("%C", sys_days{jun/1/20000}); - assert(os.str() == "200"); - - os.str(""); - os << format("%C", sys_days{jun/1/19999}); - assert(os.str() == "199"); - - os.str(""); - os << format("%C", sys_days{jun/1/2001}); - assert(os.str() == "20"); - - os.str(""); - os << format("%C", sys_days{jun/1/2000}); - assert(os.str() == "20"); - - os.str(""); - os << format("%C", sys_days{jun/1/1999}); - assert(os.str() == "19"); - - os.str(""); - os << format("%C", sys_days{jun/1/101}); - assert(os.str() == "01"); - - os.str(""); - os << format("%C", sys_days{jun/1/100}); - assert(os.str() == "01"); - - os.str(""); - os << format("%C", sys_days{jun/1/99}); - assert(os.str() == "00"); - - os.str(""); - os << format("%C", sys_days{jun/1/1}); - assert(os.str() == "00"); - - os.str(""); - os << format("%C", sys_days{jun/1/0}); - assert(os.str() == "00"); - - os.str(""); - os << format("%C", sys_days{jun/1/-1}); - assert(os.str() == "-01"); - - os.str(""); - os << format("%C", sys_days{jun/1/-99}); - assert(os.str() == "-01"); - - os.str(""); - os << format("%C", sys_days{jun/1/-100}); - assert(os.str() == "-01"); - - os.str(""); - os << format("%C", sys_days{jun/1/-101}); - assert(os.str() == "-02"); - - os.str(""); - os << format("%C", sys_days{jun/1/-1999}); - assert(os.str() == "-20"); - - os.str(""); - os << format("%C", sys_days{jun/1/-2000}); - assert(os.str() == "-20"); - - os.str(""); - os << format("%C", sys_days{jun/1/-2001}); - assert(os.str() == "-21"); - - os.str(""); - os << format("%C", sys_days{jun/1/-19999}); - assert(os.str() == "-200"); - - os.str(""); - os << format("%C", sys_days{jun/1/-20000}); - assert(os.str() == "-200"); - - os.str(""); - os << format("%C", sys_days{jun/1/-20001}); - assert(os.str() == "-201"); -} diff --git a/src/date/test/date_test/format/misc.pass.cpp b/src/date/test/date_test/format/misc.pass.cpp deleted file mode 100644 index 06deb2418b..0000000000 --- a/src/date/test/date_test/format/misc.pass.cpp +++ /dev/null @@ -1,52 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. - -#include "date.h" -#include -#include - -template -void -test(const std::string& in_fmt, const std::string& input, - const std::string& out_fmt, const std::string& output) -{ - using namespace date; - std::istringstream in{input}; - T t; - in >> parse(in_fmt, t); - assert(!in.fail()); - auto s = format(out_fmt, t); - assert(s == output); -} - -int -main() -{ - using namespace date; - test("%Y", "2017", "%Y", "2017"); - test("%m", "3", "%m", "03"); - test("%d", "25", "%d", "25"); - test("%Y-%m", "2017-03", "%Y-%m", "2017-03"); - test("%y%m", "1703", "%Y-%m", "2017-03"); - test("%m/%d", "3/25", "%m/%d", "03/25"); - test("%w", "3", "%w", "3"); -} diff --git a/src/date/test/date_test/format/range.pass.cpp b/src/date/test/date_test/format/range.pass.cpp deleted file mode 100644 index 6a10ba39e9..0000000000 --- a/src/date/test/date_test/format/range.pass.cpp +++ /dev/null @@ -1,78 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. - -#include "date.h" - -#include -#include -#include - -using fortnights = std::chrono::duration, - date::weeks::period>>; - -using microfortnights = std::chrono::duration>; - -int -main() -{ - using namespace date; - using namespace std::chrono; - std::ostringstream os; - os << format("%F %T", sys_days{jan/1/year::min()}); - assert(os.str() == "-32767-01-01 00:00:00"); - os.str(""); - os << format("%F %T", sys_days{dec/last/year::max()}); - assert(os.str() == "32767-12-31 00:00:00"); - os.str(""); - os << format("%F %T", sys_days{dec/last/year::max()} + hours{23} + minutes{59} + - seconds{59} + microseconds{999999}); - assert(os.str() == "32767-12-31 23:59:59.999999"); - os.str(""); - - os << format("%Y-%m-%d %H:%M:%S", sys_days{jan/1/year::min()}); - assert(os.str() == "-32767-01-01 00:00:00"); - os.str(""); - os << format("%Y-%m-%d %H:%M:%S", sys_days{dec/last/year::max()}); - assert(os.str() == "32767-12-31 00:00:00"); - os.str(""); - os << format("%Y-%m-%d %H:%M:%S", sys_days{dec/last/year::max()} + hours{23} + - minutes{59} + seconds{59} + microseconds{999999}); - assert(os.str() == "32767-12-31 23:59:59.999999"); - os.str(""); - - os << format("%F %T", sys_days{jan/1/year::min()} + microfortnights{1}); - assert(os.str() == "-32767-01-01 00:00:01.2096"); - os.str(""); - os << format("%F %T", sys_days{dec/last/year::max()} + microfortnights{1}); - assert(os.str() == "32767-12-31 00:00:01.2096"); - os.str(""); - - os << format("%F %T", jan/1/year::min()); - assert(os.str() == "-32767-01-01 00:00:00"); - os.str(""); - os << format("%F %T", dec/last/year::max()); - assert(os.str() == "32767-12-31 00:00:00"); - os.str(""); -} diff --git a/src/date/test/date_test/format/two_dight_year.pass.cpp b/src/date/test/date_test/format/two_dight_year.pass.cpp deleted file mode 100644 index 3f615b323d..0000000000 --- a/src/date/test/date_test/format/two_dight_year.pass.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std::chrono; - std::ostringstream os; - os << format("%y", sys_days{jun/1/20001}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/20000}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/19999}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/2001}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/2000}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/1999}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/101}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/100}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/99}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/1}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/0}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/-1}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/-99}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/-100}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/-101}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/-1999}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/-2000}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/-2001}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/-19999}); - assert(os.str() == "99"); - - os.str(""); - os << format("%y", sys_days{jun/1/-20000}); - assert(os.str() == "00"); - - os.str(""); - os << format("%y", sys_days{jun/1/-20001}); - assert(os.str() == "01"); - - os.str(""); - os << format("%y", sys_days{jun/1/year::min()}); - assert(os.str() == "67"); -} diff --git a/src/date/test/date_test/last.pass.cpp b/src/date/test/date_test/last.pass.cpp deleted file mode 100644 index 11b991c687..0000000000 --- a/src/date/test/date_test/last.pass.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr struct last_spec {} last{}; - -#include "date.h" - -#include - -static_assert(std::is_same{}, ""); - -int -main() -{ -} diff --git a/src/date/test/date_test/make_time.pass.cpp b/src/date/test/date_test/make_time.pass.cpp deleted file mode 100644 index ec371aede1..0000000000 --- a/src/date/test/date_test/make_time.pass.cpp +++ /dev/null @@ -1,164 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// template ::value>::type> -// constexpr -// time_of_day> -// make_time(std::chrono::duration d) noexcept; - -// constexpr -// time_of_day -// make_time(std::chrono::hours h, unsigned md) noexcept; - -// constexpr -// time_of_day -// make_time(std::chrono::hours h, std::chrono::minutes m, unsigned md) noexcept; - -// constexpr -// time_of_day -// make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s, -// unsigned md) noexcept; - -// template >::value>::type> -// constexpr -// time_of_day> -// make_time(std::chrono::hours h, std::chrono::minutes m, std::chrono::seconds s, -// std::chrono::duration sub_s, unsigned md) noexcept; - -#include "date.h" - -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - { - static_assert(is_same>{}, ""); - auto tod = make_time(nanoseconds{18429000000022}); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.subseconds() == nanoseconds{22}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(microseconds{18429000022}); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.subseconds() == microseconds{22}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(seconds{18429}); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(minutes{307}); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}); - assert(tod.hours() == hours{5}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, minutes{7}, seconds{9}, nanoseconds{22}, pm); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.subseconds() == nanoseconds{22}); - assert(tod.mode() == pm); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, minutes{7}, seconds{9}, microseconds{22}, 0); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.subseconds() == microseconds{22}); - assert(tod.mode() == 0); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, minutes{7}, seconds{9}, milliseconds{22}, am); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.subseconds() == milliseconds{22}); - assert(tod.mode() == am); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, minutes{7}, seconds{9}, am); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.seconds() == seconds{9}); - assert(tod.mode() == am); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, minutes{7}, pm); - assert(tod.hours() == hours{5}); - assert(tod.minutes() == minutes{7}); - assert(tod.mode() == pm); - } - { - static_assert(is_same>{}, ""); - auto tod = make_time(hours{5}, 0); - assert(tod.hours() == hours{5}); - assert(tod.mode() == 0); - } -} diff --git a/src/date/test/date_test/month.pass.cpp b/src/date/test/date_test/month.pass.cpp deleted file mode 100644 index 4dffa6bdf2..0000000000 --- a/src/date/test/date_test/month.pass.cpp +++ /dev/null @@ -1,181 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class month -// { -// unsigned char m_; -// public: -// explicit constexpr month(unsigned m) noexcept; -// -// month& operator++() noexcept; -// month operator++(int) noexcept; -// month& operator--() noexcept; -// month operator--(int) noexcept; -// -// month& operator+=(const months& m) noexcept; -// month& operator-=(const months& m) noexcept; -// -// constexpr explicit operator unsigned() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const month& x, const month& y) noexcept; -// constexpr bool operator!=(const month& x, const month& y) noexcept; -// constexpr bool operator< (const month& x, const month& y) noexcept; -// constexpr bool operator> (const month& x, const month& y) noexcept; -// constexpr bool operator<=(const month& x, const month& y) noexcept; -// constexpr bool operator>=(const month& x, const month& y) noexcept; -// -// constexpr month operator+(const month& x, const months& y) noexcept; -// constexpr month operator+(const months& x, const month& y) noexcept; -// constexpr month operator-(const month& x, const months& y) noexcept; -// constexpr months operator-(const month& x, const month& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const month& m); - -// constexpr month jan{1}; -// constexpr month feb{2}; -// constexpr month mar{3}; -// constexpr month apr{4}; -// constexpr month may{5}; -// constexpr month jun{6}; -// constexpr month jul{7}; -// constexpr month aug{8}; -// constexpr month sep{9}; -// constexpr month oct{10}; -// constexpr month nov{11}; -// constexpr month dec{12}; - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(date::month{1}) == 1, ""); - -static_assert(!date::month{0}.ok(), ""); -static_assert( date::month{1}.ok(), ""); -static_assert( date::month{2}.ok(), ""); -static_assert( date::month{3}.ok(), ""); -static_assert( date::month{4}.ok(), ""); -static_assert( date::month{5}.ok(), ""); -static_assert( date::month{6}.ok(), ""); -static_assert( date::month{7}.ok(), ""); -static_assert( date::month{8}.ok(), ""); -static_assert( date::month{9}.ok(), ""); -static_assert( date::month{10}.ok(), ""); -static_assert( date::month{11}.ok(), ""); -static_assert( date::month{12}.ok(), ""); -static_assert(!date::month{13}.ok(), ""); - -int -main() -{ - using namespace date; - - static_assert(jan == month{1}, ""); - static_assert(feb == month{2}, ""); - static_assert(mar == month{3}, ""); - static_assert(apr == month{4}, ""); - static_assert(may == month{5}, ""); - static_assert(jun == month{6}, ""); - static_assert(jul == month{7}, ""); - static_assert(aug == month{8}, ""); - static_assert(sep == month{9}, ""); - static_assert(oct == month{10}, ""); - static_assert(nov == month{11}, ""); - static_assert(dec == month{12}, ""); - - static_assert(!(jan != jan), ""); - static_assert( jan != feb, ""); - static_assert( feb != jan, ""); - - static_assert(!(jan < jan), ""); - static_assert( jan < feb, ""); - static_assert(!(feb < jan), ""); - - static_assert( jan <= jan, ""); - static_assert( jan <= feb, ""); - static_assert(!(feb <= jan), ""); - - static_assert(!(jan > jan), ""); - static_assert(!(jan > feb), ""); - static_assert( feb > jan, ""); - - static_assert( jan >= jan, ""); - static_assert(!(jan >= feb), ""); - static_assert( feb >= jan, ""); - - assert(mar + months{7} == oct); - assert(mar + months{27} == jun); - assert(months{7} + mar == oct); - assert(months{27} + mar == jun); - - assert(mar - months{7} == aug); - assert(mar - months{27} == dec); - - assert(mar - feb == months{1}); - assert(feb - mar == months{11}); - -#if __cplusplus >= 201402 - static_assert(mar + months{7} == oct, ""); - static_assert(mar + months{27} == jun, ""); - static_assert(months{7} + mar == oct, ""); - static_assert(months{27} + mar == jun, ""); - - static_assert(mar - months{7} == aug, ""); - static_assert(mar - months{27} == dec, ""); - - static_assert(mar - feb == months{1}, ""); - static_assert(feb - mar == months{11}, ""); -#endif - - auto m = dec; - assert(++m == jan); - assert(m++ == jan); - assert(m == feb); - assert(m-- == feb); - assert(m == jan); - assert(--m == dec); - assert((m += months{2}) == feb); - assert((m -= months{2}) == dec); - - std::ostringstream os; - os << m; - assert(os.str() == "Dec"); - m += months{11}; - os.str(""); - os << m; - assert(os.str() == "Nov"); -} diff --git a/src/date/test/date_test/month_day.pass.cpp b/src/date/test/date_test/month_day.pass.cpp deleted file mode 100644 index 5fca9b26e0..0000000000 --- a/src/date/test/date_test/month_day.pass.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class month_day -// { -// public: -// constexpr month_day(const date::month& m, const date::day& d) noexcept; -// -// constexpr date::month month() const noexcept; -// constexpr date::day day() const noexcept; -// -// constexpr bool ok() const noexcept; -// }; - -// constexpr bool operator==(const month_day& x, const month_day& y) noexcept; -// constexpr bool operator!=(const month_day& x, const month_day& y) noexcept; -// constexpr bool operator< (const month_day& x, const month_day& y) noexcept; -// constexpr bool operator> (const month_day& x, const month_day& y) noexcept; -// constexpr bool operator<=(const month_day& x, const month_day& y) noexcept; -// constexpr bool operator>=(const month_day& x, const month_day& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const month_day& md); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace date; - - constexpr month_day md1 = {feb, day{28}}; - constexpr month_day md2 = {mar, day{1}}; -#if __cplusplus >= 201402 - static_assert(md1.ok(), ""); - static_assert(md2.ok(), ""); - static_assert(!month_day{feb, day{32}}.ok(), ""); - static_assert(!month_day{month{0}, day{1}}.ok(), ""); -#endif - static_assert(md1.month() == feb, ""); - static_assert(md1.day() == day{28}, ""); - static_assert(md2.month() == mar, ""); - static_assert(md2.day() == day{1}, ""); - static_assert(md1 == md1, ""); - static_assert(md1 != md2, ""); - static_assert(md1 < md2, ""); - std::ostringstream os; - os << md1; - assert(os.str() == "Feb/28"); -} diff --git a/src/date/test/date_test/month_day_last.pass.cpp b/src/date/test/date_test/month_day_last.pass.cpp deleted file mode 100644 index d458aeebe1..0000000000 --- a/src/date/test/date_test/month_day_last.pass.cpp +++ /dev/null @@ -1,75 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class month_day_last -// { -// public: -// constexpr explicit month_day_last(const date::month& m) noexcept; -// -// constexpr date::month month() const noexcept; -// constexpr bool ok() const noexcept; -// }; - -// constexpr bool operator==(const month_day_last& x, const month_day_last& y) noexcept; -// constexpr bool operator!=(const month_day_last& x, const month_day_last& y) noexcept; -// constexpr bool operator< (const month_day_last& x, const month_day_last& y) noexcept; -// constexpr bool operator> (const month_day_last& x, const month_day_last& y) noexcept; -// constexpr bool operator<=(const month_day_last& x, const month_day_last& y) noexcept; -// constexpr bool operator>=(const month_day_last& x, const month_day_last& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const month_day_last& mdl); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); - -int -main() -{ - using namespace date; - - constexpr month_day_last mdl1{feb}; - constexpr month_day_last mdl2{mar}; - static_assert(mdl1.ok(), ""); - static_assert(mdl2.ok(), ""); - static_assert(!month_day_last{month{0}}.ok(), ""); - static_assert(mdl1.month() == feb, ""); - static_assert(mdl2.month() == mar, ""); - static_assert(mdl1 == mdl1, ""); - static_assert(mdl1 != mdl2, ""); - static_assert(mdl1 < mdl2, ""); - std::ostringstream os; - os << mdl1; - assert(os.str() == "Feb/last"); -} diff --git a/src/date/test/date_test/month_weekday.pass.cpp b/src/date/test/date_test/month_weekday.pass.cpp deleted file mode 100644 index e059d2b812..0000000000 --- a/src/date/test/date_test/month_weekday.pass.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class month_weekday -// { -// public: -// constexpr month_weekday(const date::month& m, -// const date::weekday_indexed& wdi) noexcept; -// -// constexpr date::month month() const noexcept; -// constexpr date::weekday_indexed weekday_indexed() const noexcept; -// -// constexpr bool ok() const noexcept; -// }; - -// constexpr bool operator==(const month_weekday& x, const month_weekday& y) noexcept; -// constexpr bool operator!=(const month_weekday& x, const month_weekday& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const month_weekday& mwd); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace date; - - constexpr month_weekday mwd1 = {feb, sat[4]}; - constexpr month_weekday mwd2 = {mar, mon[1]}; - static_assert(mwd1.ok(), ""); - static_assert(mwd2.ok(), ""); - static_assert(!month_weekday{feb, sat[0]}.ok(), ""); - static_assert(!month_weekday{month{0}, sun[1]}.ok(), ""); - static_assert(mwd1.month() == feb, ""); - static_assert(mwd1.weekday_indexed() == sat[4], ""); - static_assert(mwd2.month() == mar, ""); - static_assert(mwd2.weekday_indexed() == mon[1], ""); - static_assert(mwd1 == mwd1, ""); - static_assert(mwd1 != mwd2, ""); - std::ostringstream os; - os << mwd1; - assert(os.str() == "Feb/Sat[4]"); -} diff --git a/src/date/test/date_test/month_weekday_last.pass.cpp b/src/date/test/date_test/month_weekday_last.pass.cpp deleted file mode 100644 index 4964d5e1a6..0000000000 --- a/src/date/test/date_test/month_weekday_last.pass.cpp +++ /dev/null @@ -1,77 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class month_weekday_last -// { -// public: -// constexpr month_weekday_last(const date::month& m, -// const date::weekday_last& wdl) noexcept; -// -// constexpr date::month month() const noexcept; -// constexpr date::weekday_last weekday_last() const noexcept; -// -// constexpr bool ok() const noexcept; -// }; - -// constexpr -// bool operator==(const month_weekday_last& x, const month_weekday_last& y) noexcept; -// constexpr -// bool operator!=(const month_weekday_last& x, const month_weekday_last& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const month_weekday_last& mwdl); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace date; - - constexpr month_weekday_last mwdl1 = {feb, sat[last]}; - constexpr month_weekday_last mwdl2 = {mar, mon[last]}; - static_assert(mwdl1.ok(), ""); - static_assert(mwdl2.ok(), ""); - static_assert(!month_weekday_last{month{0}, sun[last]}.ok(), ""); - static_assert(mwdl1.month() == feb, ""); - static_assert(mwdl1.weekday_last() == sat[last], ""); - static_assert(mwdl2.month() == mar, ""); - static_assert(mwdl2.weekday_last() == mon[last], ""); - static_assert(mwdl1 == mwdl1, ""); - static_assert(mwdl1 != mwdl2, ""); - std::ostringstream os; - os << mwdl1; - assert(os.str() == "Feb/Sat[last]"); -} diff --git a/src/date/test/date_test/month_weekday_last_less.fail.cpp b/src/date/test/date_test/month_weekday_last_less.fail.cpp deleted file mode 100644 index beee0e14d8..0000000000 --- a/src/date/test/date_test/month_weekday_last_less.fail.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month_weekday_last < month_weekday_last not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - month_weekday_last mwdl1 = {feb, sat[last]}; - month_weekday_last mwdl2 = {mar, mon[last]}; - auto b = mwdl1 < mwdl2; -} diff --git a/src/date/test/date_test/month_weekday_less.fail.cpp b/src/date/test/date_test/month_weekday_less.fail.cpp deleted file mode 100644 index b3ead830c3..0000000000 --- a/src/date/test/date_test/month_weekday_less.fail.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month_weekday < month_weekday not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - month_weekday mwd1 = {feb, sat[4]}; - month_weekday mwd2 = {mar, mon[1]}; - auto b = mwd1 < mwd2; -} diff --git a/src/date/test/date_test/monthpmonth.fail.cpp b/src/date/test/date_test/monthpmonth.fail.cpp deleted file mode 100644 index 0f73aae366..0000000000 --- a/src/date/test/date_test/monthpmonth.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month + month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = mar + jul; -} diff --git a/src/date/test/date_test/months_m_year_month.fail.cpp b/src/date/test/date_test/months_m_year_month.fail.cpp deleted file mode 100644 index 74ada086c2..0000000000 --- a/src/date/test/date_test/months_m_year_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// months - year_month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = months{1} - year_month{2015_y, jan}; -} diff --git a/src/date/test/date_test/months_m_year_month_day.fail.cpp b/src/date/test/date_test/months_m_year_month_day.fail.cpp deleted file mode 100644 index 8d48619d11..0000000000 --- a/src/date/test/date_test/months_m_year_month_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// months - year_month_day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = jan - year_month_day{2015_y, aug, 9_d}; -} diff --git a/src/date/test/date_test/monthsmmonth.fail.cpp b/src/date/test/date_test/monthsmmonth.fail.cpp deleted file mode 100644 index e3fa50c3a8..0000000000 --- a/src/date/test/date_test/monthsmmonth.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// months - month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = months{3} - jul; -} diff --git a/src/date/test/date_test/op_div_day_day.fail.cpp b/src/date/test/date_test/op_div_day_day.fail.cpp deleted file mode 100644 index 891f8140e6..0000000000 --- a/src/date/test/date_test/op_div_day_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// day / day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = 14_d/14_d; -} diff --git a/src/date/test/date_test/op_div_int_month.fail.cpp b/src/date/test/date_test/op_div_int_month.fail.cpp deleted file mode 100644 index 1ecb3c1153..0000000000 --- a/src/date/test/date_test/op_div_int_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// int / month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = 8/aug; -} diff --git a/src/date/test/date_test/op_div_int_year.fail.cpp b/src/date/test/date_test/op_div_int_year.fail.cpp deleted file mode 100644 index 74a31b7d46..0000000000 --- a/src/date/test/date_test/op_div_int_year.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// int / year not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = 8/2015_y; -} diff --git a/src/date/test/date_test/op_div_last_last.fail.cpp b/src/date/test/date_test/op_div_last_last.fail.cpp deleted file mode 100644 index 2dca2212e9..0000000000 --- a/src/date/test/date_test/op_div_last_last.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// last / last not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = last/last; -} diff --git a/src/date/test/date_test/op_div_month_day.pass.cpp b/src/date/test/date_test/op_div_month_day.pass.cpp deleted file mode 100644 index 46062f4ba6..0000000000 --- a/src/date/test/date_test/op_div_month_day.pass.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr month_day operator/(const month& m, const day& d) noexcept; -// constexpr month_day operator/(const month& m, int d) noexcept; -// constexpr month_day operator/(int m, const day& d) noexcept; -// constexpr month_day operator/(const day& d, const month& m) noexcept; -// constexpr month_day operator/(const day& d, int m) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( aug/14_d == month_day{month{8}, day{14}}, ""); - static_assert( aug/14 == month_day{month{8}, day{14}}, ""); - static_assert( 8/14_d == month_day{month{8}, day{14}}, ""); - static_assert(14_d/aug == month_day{month{8}, day{14}}, ""); - static_assert(14_d/8 == month_day{month{8}, day{14}}, ""); -} diff --git a/src/date/test/date_test/op_div_month_day_last.pass.cpp b/src/date/test/date_test/op_div_month_day_last.pass.cpp deleted file mode 100644 index 9de4538e6a..0000000000 --- a/src/date/test/date_test/op_div_month_day_last.pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr month_day_last operator/(const month& m, last_spec) noexcept; -// constexpr month_day_last operator/(int m, last_spec) noexcept; -// constexpr month_day_last operator/(last_spec, const month& m) noexcept; -// constexpr month_day_last operator/(last_spec, int m) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( aug/last == month_day_last{month{8}}, ""); - static_assert( 8/last == month_day_last{month{8}}, ""); - static_assert(last/aug == month_day_last{month{8}}, ""); - static_assert(last/8 == month_day_last{month{8}}, ""); -} diff --git a/src/date/test/date_test/op_div_month_day_month_day.fail.cpp b/src/date/test/date_test/op_div_month_day_month_day.fail.cpp deleted file mode 100644 index 20fcf0f369..0000000000 --- a/src/date/test/date_test/op_div_month_day_month_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month_day / month_day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = (aug/14_d)/(aug/14_d); -} diff --git a/src/date/test/date_test/op_div_month_month.fail.cpp b/src/date/test/date_test/op_div_month_month.fail.cpp deleted file mode 100644 index 85965a75aa..0000000000 --- a/src/date/test/date_test/op_div_month_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month / month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = aug/aug; -} diff --git a/src/date/test/date_test/op_div_month_weekday.pass.cpp b/src/date/test/date_test/op_div_month_weekday.pass.cpp deleted file mode 100644 index a2311fe44a..0000000000 --- a/src/date/test/date_test/op_div_month_weekday.pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr month_weekday operator/(const month& m, const weekday_indexed& wdi) noexcept; -// constexpr month_weekday operator/(int m, const weekday_indexed& wdi) noexcept; -// constexpr month_weekday operator/(const weekday_indexed& wdi, const month& m) noexcept; -// constexpr month_weekday operator/(const weekday_indexed& wdi, int m) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( aug/fri[2] == month_weekday{month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert( 8/fri[2] == month_weekday{month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert(fri[2]/aug == month_weekday{month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert(fri[2]/8 == month_weekday{month{8}, weekday_indexed{weekday{5u}, 2}}, ""); -} diff --git a/src/date/test/date_test/op_div_month_weekday_last.pass.cpp b/src/date/test/date_test/op_div_month_weekday_last.pass.cpp deleted file mode 100644 index 0024960d2b..0000000000 --- a/src/date/test/date_test/op_div_month_weekday_last.pass.cpp +++ /dev/null @@ -1,39 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr month_weekday_last operator/(const month& m, const weekday_last& wdl) noexcept; -// constexpr month_weekday_last operator/(int m, const weekday_last& wdl) noexcept; -// constexpr month_weekday_last operator/(const weekday_last& wdl, const month& m) noexcept; -// constexpr month_weekday_last operator/(const weekday_last& wdl, int m) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( aug/fri[last] == month_weekday_last{month{8}, weekday_last{weekday{5u}}}, ""); - static_assert( 8/fri[last] == month_weekday_last{month{8}, weekday_last{weekday{5u}}}, ""); - static_assert(fri[last]/aug == month_weekday_last{month{8}, weekday_last{weekday{5u}}}, ""); - static_assert(fri[last]/8 == month_weekday_last{month{8}, weekday_last{weekday{5u}}}, ""); -} diff --git a/src/date/test/date_test/op_div_month_year.fail.cpp b/src/date/test/date_test/op_div_month_year.fail.cpp deleted file mode 100644 index c3af87f264..0000000000 --- a/src/date/test/date_test/op_div_month_year.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// month / year not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = aug/2015_y; -} diff --git a/src/date/test/date_test/op_div_survey.pass.cpp b/src/date/test/date_test/op_div_survey.pass.cpp deleted file mode 100644 index 987850f0cd..0000000000 --- a/src/date/test/date_test/op_div_survey.pass.cpp +++ /dev/null @@ -1,437 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -#include "date.h" - -#include - -template -constexpr -auto -test(I i, J j, K k) -> decltype(i/j/k) -{ - return i/j/k; -} - -void -test(...) -{ -} - -int -main() -{ - using std::is_same; - using namespace date; - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); -} diff --git a/src/date/test/date_test/op_div_weekday_indexed_weekday_indexed.fail.cpp b/src/date/test/date_test/op_div_weekday_indexed_weekday_indexed.fail.cpp deleted file mode 100644 index 38def30bc0..0000000000 --- a/src/date/test/date_test/op_div_weekday_indexed_weekday_indexed.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday_indexed / weekday_indexed not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = fri[2]/fri[2]; -} diff --git a/src/date/test/date_test/op_div_weekday_last_weekday_last.fail.cpp b/src/date/test/date_test/op_div_weekday_last_weekday_last.fail.cpp deleted file mode 100644 index c4dba1012f..0000000000 --- a/src/date/test/date_test/op_div_weekday_last_weekday_last.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday_last / weekday_last not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = fri[last]/fri[last]; -} diff --git a/src/date/test/date_test/op_div_year_month.pass.cpp b/src/date/test/date_test/op_div_year_month.pass.cpp deleted file mode 100644 index 48ff6c6d02..0000000000 --- a/src/date/test/date_test/op_div_year_month.pass.cpp +++ /dev/null @@ -1,35 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr year_month operator/(const year& y, const month& m) noexcept; -// constexpr year_month operator/(const year& y, int m) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert(2015_y/aug == year_month{year{2015}, aug}, ""); - static_assert(2015_y/8 == year_month{year{2015}, aug}, ""); -} diff --git a/src/date/test/date_test/op_div_year_month_day.pass.cpp b/src/date/test/date_test/op_div_year_month_day.pass.cpp deleted file mode 100644 index 96baa3f11d..0000000000 --- a/src/date/test/date_test/op_div_year_month_day.pass.cpp +++ /dev/null @@ -1,43 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr year_month_day operator/(const year_month& ym, const day& d) noexcept; -// constexpr year_month_day operator/(const year_month& ym, int d) noexcept; -// constexpr year_month_day operator/(const year& y, const month_day& md) noexcept; -// constexpr year_month_day operator/(int y, const month_day& md) noexcept; -// constexpr year_month_day operator/(const month_day& md, const year& y) noexcept; -// constexpr year_month_day operator/(const month_day& md, int y) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( 2015_y/aug/14_d == year_month_day{year{2015}, month{8}, day{14}}, ""); - static_assert( 2015_y/aug/14 == year_month_day{year{2015}, month{8}, day{14}}, ""); - static_assert( 2015_y/(aug/14_d) == year_month_day{year{2015}, month{8}, day{14}}, ""); - static_assert( 2015/(aug/14_d) == year_month_day{year{2015}, month{8}, day{14}}, ""); - static_assert(aug/14_d/2015_y == year_month_day{year{2015}, month{8}, day{14}}, ""); - static_assert(aug/14_d/2015 == year_month_day{year{2015}, month{8}, day{14}}, ""); -} diff --git a/src/date/test/date_test/op_div_year_month_day_last.pass.cpp b/src/date/test/date_test/op_div_year_month_day_last.pass.cpp deleted file mode 100644 index f98993bbfa..0000000000 --- a/src/date/test/date_test/op_div_year_month_day_last.pass.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr year_month_day_last operator/(const year_month& ym, last_spec) noexcept; -// constexpr year_month_day_last operator/(const year& y, const month_day_last& mdl) noexcept; -// constexpr year_month_day_last operator/(int y, const month_day_last& mdl) noexcept; -// constexpr year_month_day_last operator/(const month_day_last& mdl, const year& y) noexcept; -// constexpr year_month_day_last operator/(const month_day_last& mdl, int y) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert(2015_y/aug/last == year_month_day_last{year{2015}, month_day_last{month{8}}}, ""); - static_assert( 2015_y/(aug/last) == year_month_day_last{year{2015}, month_day_last{month{8}}}, ""); - static_assert( 2015/(aug/last) == year_month_day_last{year{2015}, month_day_last{month{8}}}, ""); - static_assert( aug/last/2015_y == year_month_day_last{year{2015}, month_day_last{month{8}}}, ""); - static_assert( aug/last/2015 == year_month_day_last{year{2015}, month_day_last{month{8}}}, ""); -} diff --git a/src/date/test/date_test/op_div_year_month_weekday.pass.cpp b/src/date/test/date_test/op_div_year_month_weekday.pass.cpp deleted file mode 100644 index 90f2f55a8d..0000000000 --- a/src/date/test/date_test/op_div_year_month_weekday.pass.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr year_month_weekday operator/(const year_month& ym, const weekday_indexed& wdi) noexcept; -// constexpr year_month_weekday operator/(const year& y, const month_weekday& mwd) noexcept; -// constexpr year_month_weekday operator/(int y, const month_weekday& mwd) noexcept; -// constexpr year_month_weekday operator/(const month_weekday& mwd, const year& y) noexcept; -// constexpr year_month_weekday operator/(const month_weekday& mwd, int y) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert(2015_y/aug/fri[2] == year_month_weekday{year{2015}, month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert( 2015_y/(aug/fri[2]) == year_month_weekday{year{2015}, month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert( 2015/(aug/fri[2]) == year_month_weekday{year{2015}, month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert(aug/fri[2]/2015_y == year_month_weekday{year{2015}, month{8}, weekday_indexed{weekday{5u}, 2}}, ""); - static_assert(aug/fri[2]/2015 == year_month_weekday{year{2015}, month{8}, weekday_indexed{weekday{5u}, 2}}, ""); -} diff --git a/src/date/test/date_test/op_div_year_month_weekday_last.pass.cpp b/src/date/test/date_test/op_div_year_month_weekday_last.pass.cpp deleted file mode 100644 index 63f8066977..0000000000 --- a/src/date/test/date_test/op_div_year_month_weekday_last.pass.cpp +++ /dev/null @@ -1,41 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr year_month_weekday_last operator/(const year_month& ym, const weekday_last& wdl) noexcept; -// constexpr year_month_weekday_last operator/(const year& y, const month_weekday_last& mwdl) noexcept; -// constexpr year_month_weekday_last operator/(int y, const month_weekday_last& mwdl) noexcept; -// constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, const year& y) noexcept; -// constexpr year_month_weekday_last operator/(const month_weekday_last& mwdl, int y) noexcept; - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert( 2015_y/aug/fri[last] == year_month_weekday_last{year{2015}, month{8}, weekday_last{weekday{5u}}}, ""); - static_assert( 2015_y/(aug/fri[last]) == year_month_weekday_last{year{2015}, month{8}, weekday_last{weekday{5u}}}, ""); - static_assert( 2015/(aug/fri[last]) == year_month_weekday_last{year{2015}, month{8}, weekday_last{weekday{5u}}}, ""); - static_assert(aug/fri[last]/2015_y == year_month_weekday_last{year{2015}, month{8}, weekday_last{weekday{5u}}}, ""); - static_assert(aug/fri[last]/2015 == year_month_weekday_last{year{2015}, month{8}, weekday_last{weekday{5u}}}, ""); -} diff --git a/src/date/test/date_test/op_div_year_month_year_month.fail.cpp b/src/date/test/date_test/op_div_year_month_year_month.fail.cpp deleted file mode 100644 index 73a9208eed..0000000000 --- a/src/date/test/date_test/op_div_year_month_year_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year_month / year_month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = (2015_y/aug)/(2015_y/aug); -} diff --git a/src/date/test/date_test/op_div_year_year.fail.cpp b/src/date/test/date_test/op_div_year_year.fail.cpp deleted file mode 100644 index c7054d019b..0000000000 --- a/src/date/test/date_test/op_div_year_year.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year / year not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = 2015_y/2015_y; -} diff --git a/src/date/test/date_test/parse.pass.cpp b/src/date/test/date_test/parse.pass.cpp deleted file mode 100644 index 6db370d56d..0000000000 --- a/src/date/test/date_test/parse.pass.cpp +++ /dev/null @@ -1,850 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2016 Howard Hinnant -// -// 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. - -// This test is meant to maintain a record of the sizeof each type. - -#include "date.h" -#include -#include - -void -test_a() -{ - using namespace date; - { - // correct abbreviation - std::istringstream in{"Sun 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct abbreviation - std::istringstream in{"Sun 2016-12-11"}; - sys_days tp; - in >> parse("%A %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct full name - std::istringstream in{"Sunday 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct full name - std::istringstream in{"Sunday 2016-12-11"}; - sys_days tp; - in >> parse("%A %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // not a valid name - std::istringstream in{"Dec 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert( in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 1970_y/1/1); - } - { - // wrong name - std::istringstream in{"Sat 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert( in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 1970_y/1/1); - } - { - // extra ws in input - std::istringstream in{"Sun 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // extra ws in format - std::istringstream in{"Sun 2016-12-11"}; - sys_days tp; - in >> parse("%a %F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } -} - -void -test_b() -{ - using namespace date; - { - // correct abbreviation - std::istringstream in{"Dec 11 2016"}; - sys_days tp; - in >> parse("%b %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct abbreviation - std::istringstream in{"Dec 11 2016"}; - sys_days tp; - in >> parse("%B %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct abbreviation - std::istringstream in{"Dec 11 2016"}; - sys_days tp; - in >> parse("%h %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct full name - std::istringstream in{"December 11 2016"}; - sys_days tp; - in >> parse("%b %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct full name - std::istringstream in{"December 11 2016"}; - sys_days tp; - in >> parse("%B %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // correct full name - std::istringstream in{"December 11 2016"}; - sys_days tp; - in >> parse("%h %d %Y", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 2016_y/12/11); - } - { - // incorrect abbreviation - std::istringstream in{"Dece 11 2016"}; - sys_days tp; - in >> parse("%b %d %Y", tp); - assert( in.fail()); - assert(!in.bad()); - assert(!in.eof()); - assert(tp == 1970_y/1/1); - } -} - -void -test_c() -{ - using namespace date; - using namespace std::chrono; - { - // correct abbreviation - std::istringstream in{"Sun Dec 11 14:02:43 2016"}; - sys_seconds tp; - in >> parse("%c", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{14} + minutes{2} + seconds{43}); - } -} - -void -test_x() -{ - using namespace date; - using namespace std::chrono; - { - // correct abbreviation - std::istringstream in{"12/11/16"}; - sys_seconds tp; - in >> parse("%x", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11}); - } -} - -void -test_X() -{ - using namespace date; - using namespace std::chrono; - { - // correct abbreviation - std::istringstream in{"2016-12-11 14:02:43"}; - sys_seconds tp; - in >> parse("%F %X", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{14} + minutes{2} + seconds{43}); - } -} - -void -test_C() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"20 16 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/11); - } - { - std::istringstream in{"-2 1 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == -101_y/12/11); - } - { - std::istringstream in{"-1 0 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == -100_y/12/11); - } - { - std::istringstream in{"-1 99 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == -99_y/12/11); - } - { - std::istringstream in{"-1 1 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == -1_y/12/11); - } - { - std::istringstream in{"0 0 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 0_y/12/11); - } - { - std::istringstream in{"0 1 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 1_y/12/11); - } - { - std::istringstream in{"0 99 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 99_y/12/11); - } - { - std::istringstream in{"1 0 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 100_y/12/11); - } - { - std::istringstream in{"1 1 12 11"}; - sys_days tp; - in >> parse("%C %y %m %d", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 101_y/12/11); - } -} - -void -test_d() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016 09 12"}; - sys_days tp; - in >> parse("%Y %d %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/9); - } - { - std::istringstream in{"2016 09 12"}; - sys_days tp; - in >> parse("%Y %e %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/9); - } - { - std::istringstream in{"2016 9 12"}; - sys_days tp; - in >> parse("%Y %d %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/9); - } - { - std::istringstream in{"2016 9 12"}; - sys_days tp; - in >> parse("%Y %e %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/9); - } -} - -void -test_D() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"12/11/16"}; - sys_days tp; - in >> parse("%D", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/11); - } -} - -void -test_F() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-13"}; - sys_days tp; - in >> parse("%F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/13); - } - { - std::istringstream in{"2016-12-13"}; - year_month_day tp; - in >> parse("%F", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/12/13); - } -} - -void -test_H() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 15"}; - sys_time tp; - in >> parse("%F %H", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{15}); - } -} - -void -test_Ip() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 1 pm"}; - sys_time tp; - in >> parse("%F %I %p", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{13}); - } - { - std::istringstream in{"2016-12-11 1 am"}; - sys_time tp; - in >> parse("%F %I %p", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{1}); - } -} - -void -test_j() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016 361"}; - sys_days tp; - in >> parse("%Y %j", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } -} - -void -test_m() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016 12 09"}; - sys_days tp; - in >> parse("%Y %d %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/9/12); - } - { - std::istringstream in{"2016 12 9"}; - sys_days tp; - in >> parse("%Y %d %m", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == 2016_y/9/12); - } -} - -void -test_M() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 15"}; - sys_time tp; - in >> parse("%F %M", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + minutes{15}); - } -} - -void -test_S() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 15"}; - sys_seconds tp; - in >> parse("%F %S", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + seconds{15}); - } - { - std::istringstream in{"2016-12-11 15.001"}; - sys_time tp; - in >> parse("%F %S", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + seconds{15} + milliseconds{1}); - } -} - -void -test_T() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 15:43:22"}; - sys_seconds tp; - in >> parse("%F %T", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22}); - } - { - std::istringstream in{"2016-12-11 15:43:22.001"}; - sys_time tp; - in >> parse("%F %T", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22} + - milliseconds{1}); - } - { - std::istringstream in{"2016-12-11 15:43:22"}; - sys_time tp; - in >> parse("%F %T", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{15} + minutes{43} + seconds{22}); - } - { - std::istringstream in{"15:43:22.001"}; - milliseconds d; - in >> parse("%T", d); - assert(!in.fail()); - assert(!in.bad()); - assert(d == hours{15} + minutes{43} + seconds{22} + milliseconds{1}); - } -} - -void -test_p() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-11 11pm"}; - sys_time tp; - in >> parse("%F %I%p", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/11} + hours{23}); - } -} - -void -test_r() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-26 1:36:57 pm"}; - sys_seconds tp; - in >> parse("%F %r", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26} + hours{13} + minutes{36} + seconds{57}); - } -} - -void -test_R() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-26 13:36"}; - sys_seconds tp; - in >> parse("%F %R", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26} + hours{13} + minutes{36}); - } -} - -void -test_U() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-52-1"}; - sys_days tp; - in >> parse("%Y-%U-%w", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } -} - -void -test_W() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-52-1"}; - sys_days tp; - in >> parse("%Y-%W-%w", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } -} - -void -test_GV() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-52-1"}; - sys_days tp; - in >> parse("%G-%V-%w", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } - { - std::istringstream in{"2016-52-1"}; - sys_days tp; - in >> parse("%G-%V-%w", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } - { - std::istringstream in{"20 16-52-1"}; - sys_days tp; - in >> parse("%C %g-%V-%w", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } - { - std::istringstream in{"20 16-52-1"}; - sys_days tp; - in >> parse("%C %g-%V-%u", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26}); - } -} - -void -test_z() -{ - using namespace date; - using namespace std::chrono; - { - std::istringstream in{"2016-12-26 15:53:22 -0500"}; - sys_seconds tp; - in >> parse("%F %T %z", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26} + hours{20} + minutes{53} + seconds{22}); - } - { - std::istringstream in{"2016-12-26 15:53:22 -0500"}; - local_seconds tp; - in >> parse("%F %T %z", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == local_days{2016_y/12/26} + hours{15} + minutes{53} + seconds{22}); - } - { - std::istringstream in{"2016-12-26 15:53:22 -05:00"}; - sys_seconds tp; - in >> parse("%F %T %Ez", tp); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == sys_days{2016_y/12/26} + hours{20} + minutes{53} + seconds{22}); - } -} - -void -test_Z() -{ - using namespace date; - using namespace std::chrono; - { - std::string a; - std::istringstream in{"2016-12-26 15:53:22 word"}; - local_seconds tp; - in >> parse("%F %T %Z", tp, a); - assert(!in.fail()); - assert(!in.bad()); - assert(tp == local_days{2016_y/12/26} + hours{15} + minutes{53} + seconds{22}); - assert(a == "word"); - } -} - -void -test_trailing_Z() -{ - std::string format = "%FT%TZ"; - std::string datetime = "2017-2-15T13:13:13"; - std::istringstream input(datetime); - date::sys_seconds tp; - input >> date::parse(format, tp); - assert(input.fail()); - assert(input.eof()); -} - -void -test_leading_ws() -{ - using namespace std; - using namespace date; - istringstream in{"05/04/17 5/4/17"}; - year_month_day d1, d2; - in >> parse("%D", d1) >> parse("%n%D", d2); - assert(d1 == may/4/2017); - assert(d2 == may/4/2017); -} - -void -test_space() -{ - using namespace std; - using namespace date; - { - istringstream in{"05/04/17"}; - year_month_day d1; - in >> parse(" %D", d1); - assert(d1 == may/4/2017); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse(" %D", d1); - assert(d1 == may/4/2017); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse(" %D", d1); - assert(d1 == may/4/2017); - } -} - -void -test_n() -{ - using namespace std; - using namespace date; - { - istringstream in{"05/04/17"}; - year_month_day d1; - in >> parse("%n%D", d1); - assert(in.fail()); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse("%n%D", d1); - assert(d1 == may/4/2017); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse("%n%D", d1); - assert(in.fail()); - } -} - -void -test_t() -{ - using namespace std; - using namespace date; - { - istringstream in{"05/04/17"}; - year_month_day d1; - in >> parse("%t%D", d1); - assert(d1 == may/4/2017); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse("%t%D", d1); - assert(d1 == may/4/2017); - } - { - istringstream in{" 05/04/17"}; - year_month_day d1; - in >> parse("%t%D", d1); - assert(in.fail()); - } -} - -int -main() -{ - test_a(); - test_b(); - test_c(); - test_C(); - test_d(); - test_D(); - test_F(); - test_H(); - test_Ip(); - test_j(); - test_m(); - test_M(); - test_p(); - test_r(); - test_R(); - test_S(); - test_T(); - test_U(); - test_W(); - test_GV(); - test_x(); - test_X(); - test_z(); - test_Z(); - test_trailing_Z(); - test_leading_ws(); - test_space(); - test_n(); - test_t(); -} diff --git a/src/date/test/date_test/sizeof.pass.cpp b/src/date/test/date_test/sizeof.pass.cpp deleted file mode 100644 index 1d91b667d3..0000000000 --- a/src/date/test/date_test/sizeof.pass.cpp +++ /dev/null @@ -1,62 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// This test is meant to maintain a record of the sizeof each type. - -#include "date.h" - -int -main() -{ - using namespace date; - - static_assert(sizeof(days) == 4, ""); - static_assert(sizeof(weeks) == 4, ""); - static_assert(sizeof(months) == 4, ""); - static_assert(sizeof(years) == 4, ""); - - static_assert(sizeof(sys_days) == 4, ""); - - static_assert(sizeof(last_spec) == 1, ""); - - static_assert(sizeof(day) == 1, ""); - static_assert(sizeof(month) == 1, ""); - static_assert(sizeof(year) == 2, ""); - - static_assert(sizeof(weekday) == 1, ""); - static_assert(sizeof(weekday_indexed) == 1, ""); - static_assert(sizeof(weekday_last) == 1, ""); - - static_assert(sizeof(month_day) == 2, ""); - static_assert(sizeof(month_day_last) == 1, ""); - static_assert(sizeof(month_weekday) == 2, ""); - static_assert(sizeof(month_weekday_last) == 2, ""); - - static_assert(sizeof(year_month) == 4, ""); - - static_assert(sizeof(year_month_day) == 4, ""); - static_assert(sizeof(year_month_day_last) == 4, ""); - static_assert(sizeof(year_month_weekday) == 4, ""); - static_assert(sizeof(year_month_weekday_last) == 4, ""); - - // sizeof time_of_day varies -} diff --git a/src/date/test/date_test/time_of_day_hours.pass.cpp b/src/date/test/date_test/time_of_day_hours.pass.cpp deleted file mode 100644 index 85ebb5031d..0000000000 --- a/src/date/test/date_test/time_of_day_hours.pass.cpp +++ /dev/null @@ -1,104 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// class time_of_day -// { -// public: -// using precision = std::chrono::hours; -// -// constexpr explicit time_of_day(std::chrono::hours since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// std::ostream& operator<<(std::ostream& os, const time_of_day& t); - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day; - - static_assert(is_same{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.mode() == 0, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13}, ""); - static_assert(t1.to_duration() == hours{13}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.mode() == t1.mode()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "1300"); - t2.make12(); - os.str(""); - assert(t2.hours() == hours{1}); - assert(t2.mode() == pm); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1pm"); - t2.make24(); - os.str(""); - assert(t2.hours() == hours{13}); - assert(t2.mode() == 0); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1300"); -} diff --git a/src/date/test/date_test/time_of_day_microfortnights.pass.cpp b/src/date/test/date_test/time_of_day_microfortnights.pass.cpp deleted file mode 100644 index ce48da4fa3..0000000000 --- a/src/date/test/date_test/time_of_day_microfortnights.pass.cpp +++ /dev/null @@ -1,119 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// template -// class time_of_day> -// { -// public: -// using precision = std::chrono::std::chrono::duration; -// -// constexpr explicit time_of_day(precision since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m, -// std::chrono::seconds s, precision sub_s, -// unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr std::chrono::minutes minutes() const noexcept; -// constexpr std::chrono::seconds seconds() const noexcept; -// constexpr precision subseconds() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// template -// std::ostream& -// operator<<(std::ostream& os, const time_of_day>& t); - -#include "date.h" - -#include -#include -#include - -using fortnights = std::chrono::duration, - date::weeks::period>>; - -using microfortnights = std::chrono::duration>; - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day::type>; - - static_assert(is_same>{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13} + minutes{7} + microfortnights{5}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.minutes() == minutes{7}, ""); - static_assert(t1.seconds() == seconds{6}, ""); - static_assert(t1.subseconds() == tod::precision{480}, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13} + minutes{7} - + microfortnights{5}, ""); - static_assert(t1.to_duration() == hours{13} + minutes{7} + microfortnights{5}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.minutes() == t1.minutes()); - assert(t2.seconds() == t1.seconds()); - assert(t2.subseconds() == t1.subseconds()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "13:07:06.0480"); - t2.make12(); - os.str(""); - os << t2; - assert(os.str() == "1:07:06.0480pm"); - t2.make24(); - os.str(""); - os << t2; - assert(os.str() == "13:07:06.0480"); -} diff --git a/src/date/test/date_test/time_of_day_milliseconds.pass.cpp b/src/date/test/date_test/time_of_day_milliseconds.pass.cpp deleted file mode 100644 index 30d690d633..0000000000 --- a/src/date/test/date_test/time_of_day_milliseconds.pass.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// template -// class time_of_day> -// { -// public: -// using precision = std::chrono::std::chrono::duration; -// -// constexpr explicit time_of_day(precision since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m, -// std::chrono::seconds s, precision sub_s, -// unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr std::chrono::minutes minutes() const noexcept; -// constexpr std::chrono::seconds seconds() const noexcept; -// constexpr precision subseconds() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// template -// std::ostream& -// operator<<(std::ostream& os, const time_of_day>& t); - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day; - - static_assert(is_same{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13} + minutes{7} + seconds{5} + milliseconds{22}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.minutes() == minutes{7}, ""); - static_assert(t1.seconds() == seconds{5}, ""); - static_assert(t1.subseconds() == milliseconds{22}, ""); - static_assert(t1.mode() == 0, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13} + minutes{7} - + seconds{5} + milliseconds{22}, ""); - static_assert(t1.to_duration() == hours{13} + minutes{7} + seconds{5} - + milliseconds{22}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.minutes() == t1.minutes()); - assert(t2.seconds() == t1.seconds()); - assert(t2.subseconds() == t1.subseconds()); - assert(t2.mode() == t1.mode()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "13:07:05.022"); - t2.make12(); - os.str(""); - assert(t2.hours() == hours{1}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.subseconds() == milliseconds{22}); - assert(t2.mode() == pm); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1:07:05.022pm"); - t2.make24(); - os.str(""); - assert(t2.hours() == hours{13}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.subseconds() == milliseconds{22}); - assert(t2.mode() == 0); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "13:07:05.022"); -} diff --git a/src/date/test/date_test/time_of_day_minutes.pass.cpp b/src/date/test/date_test/time_of_day_minutes.pass.cpp deleted file mode 100644 index dda8710a14..0000000000 --- a/src/date/test/date_test/time_of_day_minutes.pass.cpp +++ /dev/null @@ -1,110 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// class time_of_day -// { -// public: -// using precision = std::chrono::minutes; -// -// constexpr explicit time_of_day(std::chrono::minutes since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m, -// unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr std::chrono::minutes minutes() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// std::ostream& operator<<(std::ostream& os, const time_of_day& t); - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day; - - static_assert(is_same{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13} + minutes{7}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.minutes() == minutes{7}, ""); - static_assert(t1.mode() == 0, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13} + minutes{7}, ""); - static_assert(t1.to_duration() == hours{13} + minutes{7}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.minutes() == t1.minutes()); - assert(t2.mode() == t1.mode()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "13:07"); - t2.make12(); - os.str(""); - assert(t2.hours() == hours{1}); - assert(t2.minutes() == minutes{7}); - assert(t2.mode() == pm); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1:07pm"); - t2.make24(); - os.str(""); - assert(t2.hours() == hours{13}); - assert(t2.minutes() == minutes{7}); - assert(t2.mode() == 0); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "13:07"); -} diff --git a/src/date/test/date_test/time_of_day_nanoseconds.pass.cpp b/src/date/test/date_test/time_of_day_nanoseconds.pass.cpp deleted file mode 100644 index 9d5e4565b7..0000000000 --- a/src/date/test/date_test/time_of_day_nanoseconds.pass.cpp +++ /dev/null @@ -1,126 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// template -// class time_of_day> -// { -// public: -// using precision = std::chrono::std::chrono::duration; -// -// constexpr explicit time_of_day(precision since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m, -// std::chrono::seconds s, precision sub_s, -// unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr std::chrono::minutes minutes() const noexcept; -// constexpr std::chrono::seconds seconds() const noexcept; -// constexpr precision subseconds() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// template -// std::ostream& -// operator<<(std::ostream& os, const time_of_day>& t); - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day; - - static_assert(is_same{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13} + minutes{7} + seconds{5} + nanoseconds{22}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.minutes() == minutes{7}, ""); - static_assert(t1.seconds() == seconds{5}, ""); - static_assert(t1.subseconds() == nanoseconds{22}, ""); - static_assert(t1.mode() == 0, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13} + minutes{7} - + seconds{5} + nanoseconds{22}, ""); - static_assert(t1.to_duration() == hours{13} + minutes{7} + seconds{5} - + nanoseconds{22}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.minutes() == t1.minutes()); - assert(t2.seconds() == t1.seconds()); - assert(t2.subseconds() == t1.subseconds()); - assert(t2.mode() == t1.mode()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "13:07:05.000000022"); - t2.make12(); - os.str(""); - assert(t2.hours() == hours{1}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.subseconds() == nanoseconds{22}); - assert(t2.mode() == pm); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1:07:05.000000022pm"); - t2.make24(); - os.str(""); - assert(t2.hours() == hours{13}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.subseconds() == nanoseconds{22}); - assert(t2.mode() == 0); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "13:07:05.000000022"); -} diff --git a/src/date/test/date_test/time_of_day_seconds.pass.cpp b/src/date/test/date_test/time_of_day_seconds.pass.cpp deleted file mode 100644 index 09dec9efd8..0000000000 --- a/src/date/test/date_test/time_of_day_seconds.pass.cpp +++ /dev/null @@ -1,116 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// enum {am = 1, pm}; - -// class time_of_day -// { -// public: -// using precision = std::chrono::seconds; -// -// constexpr explicit time_of_day(std::chrono::seconds since_midnight) noexcept; -// constexpr time_of_day(std::chrono::hours h, std::chrono::minutes m, -// std::chrono::seconds s, unsigned md) noexcept; -// -// constexpr std::chrono::hours hours() const noexcept; -// constexpr std::chrono::minutes minutes() const noexcept; -// constexpr std::chrono::seconds seconds() const noexcept; -// constexpr unsigned mode() const noexcept; -// -// constexpr explicit operator precision() const noexcept; -// constexpr precision to_duration() const noexcept; -// -// void make24() noexcept; -// void make12() noexcept; -// }; - -// std::ostream& operator<<(std::ostream& os, const time_of_day& t); - -#include "date.h" - -#include -#include -#include - -int -main() -{ - using namespace date; - using namespace std; - using namespace std::chrono; - - using tod = time_of_day; - - static_assert(is_same{}, ""); - - static_assert( is_trivially_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_trivially_copy_constructible{}, ""); - static_assert( is_trivially_copy_assignable{}, ""); - static_assert( is_trivially_move_constructible{}, ""); - static_assert( is_trivially_move_assignable{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - static_assert(is_nothrow_constructible{}, ""); - static_assert(!is_convertible{}, ""); - - constexpr tod t1 = tod{hours{13} + minutes{7} + seconds{5}}; - static_assert(t1.hours() == hours{13}, ""); - static_assert(t1.minutes() == minutes{7}, ""); - static_assert(t1.seconds() == seconds{5}, ""); - static_assert(t1.mode() == 0, ""); -#if __cplusplus >= 201402 - static_assert(static_cast(t1) == hours{13} + minutes{7} - + seconds{5}, ""); - static_assert(t1.to_duration() == hours{13} + minutes{7} + seconds{5}, ""); -#endif - - auto t2 = t1; - assert(t2.hours() == t1.hours()); - assert(t2.minutes() == t1.minutes()); - assert(t2.seconds() == t1.seconds()); - assert(t2.mode() == t1.mode()); - assert(t2.to_duration() == t1.to_duration()); - ostringstream os; - os << t2; - assert(os.str() == "13:07:05"); - t2.make12(); - os.str(""); - assert(t2.hours() == hours{1}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.mode() == pm); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "1:07:05pm"); - t2.make24(); - os.str(""); - assert(t2.hours() == hours{13}); - assert(t2.minutes() == minutes{7}); - assert(t2.seconds() == seconds{5}); - assert(t2.mode() == 0); - assert(t2.to_duration() == t1.to_duration()); - os << t2; - assert(os.str() == "13:07:05"); -} diff --git a/src/date/test/date_test/weekday.pass.cpp b/src/date/test/date_test/weekday.pass.cpp deleted file mode 100644 index 1a526d0151..0000000000 --- a/src/date/test/date_test/weekday.pass.cpp +++ /dev/null @@ -1,202 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weekday -// { -// unsigned char wd_; -// public: -// explicit constexpr weekday(unsigned wd) noexcept; -// constexpr weekday(const sys_days& dp) noexcept; -// -// weekday& operator++() noexcept; -// weekday operator++(int) noexcept; -// weekday& operator--() noexcept; -// weekday operator--(int) noexcept; -// -// weekday& operator+=(const days& d) noexcept; -// weekday& operator-=(const days& d) noexcept; -// -// constexpr explicit operator unsigned() const noexcept; -// constexpr bool ok() const noexcept; -// -// // tested with weekday_indexed -// constexpr weekday_indexed operator[](unsigned index) const noexcept; -// // tested with weekday_last -// constexpr weekday_last operator[](last_spec) const noexcept; -// }; - -// constexpr bool operator==(const weekday& x, const weekday& y) noexcept; -// constexpr bool operator!=(const weekday& x, const weekday& y) noexcept; - -// constexpr weekday operator+(const weekday& x, const days& y) noexcept; -// constexpr weekday operator+(const days& x, const weekday& y) noexcept; -// constexpr weekday operator-(const weekday& x, const days& y) noexcept; -// constexpr days operator-(const weekday& x, const weekday& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const weekday& wd); - -// constexpr weekday sun{0}; -// constexpr weekday mon{1}; -// constexpr weekday tue{2}; -// constexpr weekday wed{3}; -// constexpr weekday thu{4}; -// constexpr weekday fri{5}; -// constexpr weekday sat{6}; - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(date::weekday{1u}) == 1, ""); - -static_assert( date::weekday{0u}.ok(), ""); -static_assert( date::weekday{1u}.ok(), ""); -static_assert( date::weekday{2u}.ok(), ""); -static_assert( date::weekday{3u}.ok(), ""); -static_assert( date::weekday{4u}.ok(), ""); -static_assert( date::weekday{5u}.ok(), ""); -static_assert( date::weekday{6u}.ok(), ""); -static_assert(!date::weekday{7u}.ok(), ""); - -void -test_weekday_arithmetic() -{ - using namespace date; - constexpr unsigned a[7][7] = - {// - Sun Mon Tue Wed Thu Fri Sat - /*Sun*/ {0, 6, 5, 4, 3, 2, 1}, - /*Mon*/ {1, 0, 6, 5, 4, 3, 2}, - /*Tue*/ {2, 1, 0, 6, 5, 4, 3}, - /*Wed*/ {3, 2, 1, 0, 6, 5, 4}, - /*Thu*/ {4, 3, 2, 1, 0, 6, 5}, - /*Fri*/ {5, 4, 3, 2, 1, 0, 6}, - /*Sat*/ {6, 5, 4, 3, 2, 1, 0} - }; - for (unsigned x = 0; x < 7; ++x) - { - for (unsigned y = 0; y < 7; ++y) - { - assert(weekday{x} - weekday{y} == days{a[x][y]}); - assert(weekday{x} - days{a[x][y]} == weekday{y}); - assert(weekday{x} == weekday{y} + days{a[x][y]}); - assert(weekday{x} == days{a[x][y]} + weekday{y}); - } - } - for (unsigned x = 0; x < 7; ++x) - { - for (int y = -21; y < 21; ++y) - { - weekday wx{x}; - days dy{y}; - wx += dy; - weekday wz = weekday{x} + days{y}; - assert(wx.ok()); - assert(wz.ok()); - assert(wx == wz); - assert(wx - weekday{x} == days{y % 7 + (y % 7 < 0 ? 7 : 0)}); - } - } - for (unsigned x = 0; x < 7; ++x) - { - for (int y = -21; y < 21; ++y) - { - weekday wx{x}; - days dy{y}; - wx -= dy; - assert(wx == weekday{x} + days{-y}); - } - } - for (unsigned x = 0; x < 7; ++x) - { - weekday wx{x}; - assert(++wx - weekday{x} == days{1}); - assert(wx++ - weekday{x} == days{1}); - assert(wx - weekday{x} == days{2}); - assert(wx-- - weekday{x} == days{2}); - assert(wx - weekday{x} == days{1}); - assert(--wx - weekday{x} == days{0}); - } -} - -int -main() -{ - using namespace date; - - static_assert(sun == weekday{0u}, ""); - static_assert(mon == weekday{1u}, ""); - static_assert(tue == weekday{2u}, ""); - static_assert(wed == weekday{3u}, ""); - static_assert(thu == weekday{4u}, ""); - static_assert(fri == weekday{5u}, ""); - static_assert(sat == weekday{6u}, ""); - - static_assert(!(sun != sun), ""); - static_assert( sun != mon, ""); - static_assert( mon != sun, ""); - - test_weekday_arithmetic(); - - std::ostringstream os; - - os << sun; - assert(os.str() == "Sun"); - os.str(""); - - os << mon; - assert(os.str() == "Mon"); - os.str(""); - - os << tue; - assert(os.str() == "Tue"); - os.str(""); - - os << wed; - assert(os.str() == "Wed"); - os.str(""); - - os << thu; - assert(os.str() == "Thu"); - os.str(""); - - os << fri; - assert(os.str() == "Fri"); - os.str(""); - - os << sat; - assert(os.str() == "Sat"); -} diff --git a/src/date/test/date_test/weekday_indexed.pass.cpp b/src/date/test/date_test/weekday_indexed.pass.cpp deleted file mode 100644 index 5d25d2bd4e..0000000000 --- a/src/date/test/date_test/weekday_indexed.pass.cpp +++ /dev/null @@ -1,70 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weekday_indexed -// { -// public: -// weekday_indexed() = default; -// constexpr weekday_indexed(const date::weekday& wd, unsigned index) noexcept; -// -// constexpr date::weekday weekday() const noexcept; -// constexpr unsigned index() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const weekday_indexed& x, const weekday_indexed& y) noexcept; -// constexpr bool operator!=(const weekday_indexed& x, const weekday_indexed& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const weekday_indexed& wdi); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace date; - - constexpr weekday_indexed wdi = sun[1]; - static_assert(wdi.weekday() == sun, ""); - static_assert(wdi.index() == 1, ""); - static_assert(wdi.ok(), ""); - static_assert(wdi == weekday_indexed{sun, 1}, ""); - static_assert(wdi != weekday_indexed{sun, 2}, ""); - static_assert(wdi != weekday_indexed{mon, 1}, ""); - std::ostringstream os; - os << wdi; - assert(os.str() == "Sun[1]"); -} diff --git a/src/date/test/date_test/weekday_last.pass.cpp b/src/date/test/date_test/weekday_last.pass.cpp deleted file mode 100644 index 3c30bf711e..0000000000 --- a/src/date/test/date_test/weekday_last.pass.cpp +++ /dev/null @@ -1,66 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weekday_last -// { -// public: -// explicit constexpr weekday_last(const date::weekday& wd) noexcept; -// -// constexpr date::weekday weekday() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const weekday_last& x, const weekday_last& y) noexcept; -// constexpr bool operator!=(const weekday_last& x, const weekday_last& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const weekday_last& wdl); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); - -int -main() -{ - using namespace date; - - constexpr weekday_last wdl = sun[last]; - static_assert(wdl.weekday() == sun, ""); - static_assert(wdl.ok(), ""); - static_assert(wdl == weekday_last{sun}, ""); - static_assert(wdl != weekday_last{mon}, ""); - std::ostringstream os; - os << wdl; - assert(os.str() == "Sun[last]"); -} diff --git a/src/date/test/date_test/weekday_lessthan.fail.cpp b/src/date/test/date_test/weekday_lessthan.fail.cpp deleted file mode 100644 index a1fbc284e5..0000000000 --- a/src/date/test/date_test/weekday_lessthan.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday < weekday not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto b = sun < mon; -} diff --git a/src/date/test/date_test/weekday_sum.fail.cpp b/src/date/test/date_test/weekday_sum.fail.cpp deleted file mode 100644 index f4290511d7..0000000000 --- a/src/date/test/date_test/weekday_sum.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday + weekday not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto b = sun + mon; -} diff --git a/src/date/test/date_test/year.pass.cpp b/src/date/test/date_test/year.pass.cpp deleted file mode 100644 index 27d9df60e6..0000000000 --- a/src/date/test/date_test/year.pass.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year -// { -// public: -// explicit constexpr year(int y) noexcept; -// -// year& operator++() noexcept; -// year operator++(int) noexcept; -// year& operator--() noexcept; -// year operator--(int) noexcept; -// -// year& operator+=(const years& y) noexcept; -// year& operator-=(const years& y) noexcept; -// -// constexpr bool is_leap() const noexcept; -// -// constexpr explicit operator int() const noexcept; -// constexpr bool ok() const noexcept; -// -// static constexpr year min() noexcept; -// static constexpr year max() noexcept; -// }; - -// constexpr bool operator==(const year& x, const year& y) noexcept; -// constexpr bool operator!=(const year& x, const year& y) noexcept; -// constexpr bool operator< (const year& x, const year& y) noexcept; -// constexpr bool operator> (const year& x, const year& y) noexcept; -// constexpr bool operator<=(const year& x, const year& y) noexcept; -// constexpr bool operator>=(const year& x, const year& y) noexcept; - -// constexpr year operator+(const year& x, const years& y) noexcept; -// constexpr year operator+(const years& x, const year& y) noexcept; -// constexpr year operator-(const year& x, const years& y) noexcept; -// constexpr years operator-(const year& x, const year& y) noexcept; - -// constexpr year operator "" _y(unsigned long long y) noexcept; -// std::ostream& operator<<(std::ostream& os, const year& y); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(date::year{-1}) == -1, ""); - -template -constexpr -inline -std::chrono::duration -as(std::chrono::duration d) -{ - return d; -} - -int -main() -{ - using namespace date; - using namespace std::chrono; - - static_assert(year{2015} == 2015_y, ""); - static_assert(year{2015} != 2016_y, ""); - static_assert(year{2015} < 2016_y, ""); - static_assert(year{2016} > 2015_y, ""); - static_assert(year{2015} <= 2015_y, ""); - static_assert(year{2016} >= 2015_y, ""); - - static_assert(!year{2015}.is_leap(), ""); - static_assert( year{2016}.is_leap(), ""); - - static_assert(year::min().ok(), ""); - static_assert(year{2015}.ok(), ""); - static_assert(year{2016}.ok(), ""); - static_assert(year::max().ok(), ""); - -#if __cplusplus >= 201402 - using int64_t = std::int64_t; - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(days::min()), ""); - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(hours::min()), ""); - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(minutes::min()), ""); - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(seconds::min()), ""); - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(milliseconds::min()), ""); - static_assert(sys_days(year::min()/jan/1) - sys_days(1970_y/jan/1) - >= as(microseconds::min()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(microseconds::max()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(milliseconds::max()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(seconds::max()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(minutes::max()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(hours::max()), ""); - static_assert(sys_days(year::max()/dec/31) - sys_days(1970_y/jan/1) - <= as(days::max()), ""); -#endif - - static_assert(2015_y - 2010_y == years{5}, ""); - static_assert(2015_y - years{5} == 2010_y, ""); - static_assert(2015_y == years{5} + 2010_y, ""); - static_assert(2015_y == 2010_y + years{5}, ""); - - auto y = 2015_y; - std::ostringstream os; - os << y; - assert(os.str() == "2015"); -} diff --git a/src/date/test/date_test/year_month.pass.cpp b/src/date/test/date_test/year_month.pass.cpp deleted file mode 100644 index 2f0054158d..0000000000 --- a/src/date/test/date_test/year_month.pass.cpp +++ /dev/null @@ -1,142 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_month -// { -// public: -// constexpr year_month(const date::year& y, const date::month& m) noexcept; -// -// constexpr date::year year() const noexcept; -// constexpr date::month month() const noexcept; -// -// year_month& operator+=(const months& dm) noexcept; -// year_month& operator-=(const months& dm) noexcept; -// year_month& operator+=(const years& dy) noexcept; -// year_month& operator-=(const years& dy) noexcept; -// -// constexpr bool ok() const noexcept; -// }; - -// constexpr bool operator==(const year_month& x, const year_month& y) noexcept; -// constexpr bool operator!=(const year_month& x, const year_month& y) noexcept; -// constexpr bool operator< (const year_month& x, const year_month& y) noexcept; -// constexpr bool operator> (const year_month& x, const year_month& y) noexcept; -// constexpr bool operator<=(const year_month& x, const year_month& y) noexcept; -// constexpr bool operator>=(const year_month& x, const year_month& y) noexcept; - -// constexpr year_month operator+(const year_month& ym, const months& dm) noexcept; -// constexpr year_month operator+(const months& dm, const year_month& ym) noexcept; -// constexpr year_month operator-(const year_month& ym, const months& dm) noexcept; - -// constexpr months operator-(const year_month& x, const year_month& y) noexcept; -// constexpr year_month operator+(const year_month& ym, const years& dy) noexcept; -// constexpr year_month operator+(const years& dy, const year_month& ym) noexcept; -// constexpr year_month operator-(const year_month& ym, const years& dy) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year_month& ym); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); - -void -test_arithmetic() -{ - using namespace date; - using namespace std::chrono; - - for (int y1 = 2010; y1 <= 2015; ++y1) - { - for (int y2 = 2010; y2 <= 2015; ++y2) - { - for (unsigned m1 = 1; m1 <= 12; ++m1) - { - for (unsigned m2 = 1; m2 <= 12; ++m2) - { - year_month ym1{year{y1}, month{m1}}; - year_month ym2 = {year{y2}, month{m2}}; - months dm = ym1 - ym2; - assert((dm < months{0}) == (ym1 < ym2)); - assert((dm == months{0}) == (ym1 == ym2)); - assert((dm > months{0}) == (ym1 > ym2)); - assert(dm + ym2 == ym1); - assert(ym2 + dm == ym1); - assert(ym1 - dm == ym2); - years dy{y1-y2}; - assert((ym1 + dy == year_month{ym1.year() + dy, ym1.month()})); - assert((dy + ym1 == year_month{ym1.year() + dy, ym1.month()})); - assert((ym1 - dy == year_month{ym1.year() - dy, ym1.month()})); - assert((year_month{ym2} += dm) == ym1); - assert((year_month{ym1} -= dm) == ym2); - assert(((year_month{ym1} += dy) == - year_month{ym1.year() + dy, ym1.month()})); - assert(((year_month{ym1} -= dy) == - year_month{ym1.year() - dy, ym1.month()})); - } - } - } - } -} - -int -main() -{ - using namespace date; - - constexpr year_month ym1 = {2015_y, jun}; - static_assert(ym1.year() == year{2015}, ""); - static_assert(ym1.month() == jun, ""); - static_assert(ym1.ok(), ""); - - constexpr year_month ym2 = {2016_y, may}; - static_assert(ym2.year() == year{2016}, ""); - static_assert(ym2.month() == may, ""); - static_assert(ym2.ok(), ""); - - static_assert(ym1 == ym1, ""); - static_assert(ym1 != ym2, ""); - static_assert(ym1 < ym2, ""); - static_assert(ym1 <= ym2, ""); - static_assert(ym2 > ym1, ""); - static_assert(ym2 >= ym2, ""); - - static_assert(ym2 - ym1 == months{11}, ""); - static_assert(ym1 - ym2 == -months{11}, ""); - - test_arithmetic(); - - std::ostringstream os; - os << ym1; - assert(os.str() == "2015/Jun"); -} diff --git a/src/date/test/date_test/year_month_day.pass.cpp b/src/date/test/date_test/year_month_day.pass.cpp deleted file mode 100644 index 9166888807..0000000000 --- a/src/date/test/date_test/year_month_day.pass.cpp +++ /dev/null @@ -1,244 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_month_day -// { -// public: -// constexpr year_month_day(const date::year& y, const date::month& m, -// const date::day& d) noexcept; -// constexpr year_month_day(const year_month_day_last& ymdl) noexcept; -// constexpr year_month_day(const sys_days& dp) noexcept; -// -// year_month_day& operator+=(const months& m) noexcept; -// year_month_day& operator-=(const months& m) noexcept; -// year_month_day& operator+=(const years& y) noexcept; -// year_month_day& operator-=(const years& y) noexcept; -// -// constexpr date::year year() const noexcept; -// constexpr date::month month() const noexcept; -// constexpr date::day day() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// }; - -// constexpr bool operator==(const year_month_day& x, const year_month_day& y) noexcept; -// constexpr bool operator!=(const year_month_day& x, const year_month_day& y) noexcept; -// constexpr bool operator< (const year_month_day& x, const year_month_day& y) noexcept; -// constexpr bool operator> (const year_month_day& x, const year_month_day& y) noexcept; -// constexpr bool operator<=(const year_month_day& x, const year_month_day& y) noexcept; -// constexpr bool operator>=(const year_month_day& x, const year_month_day& y) noexcept; - -// constexpr year_month_day operator+(const year_month_day& ymd, const months& dm) noexcept; -// constexpr year_month_day operator+(const months& dm, const year_month_day& ymd) noexcept; -// constexpr year_month_day operator-(const year_month_day& ymd, const months& dm) noexcept; -// constexpr year_month_day operator+(const year_month_day& ymd, const years& dy) noexcept; -// constexpr year_month_day operator+(const years& dy, const year_month_day& ymd) noexcept; -// constexpr year_month_day operator-(const year_month_day& ymd, const years& dy) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year_month_day& ymd); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); - -void -test_arithmetic() -{ - using namespace date; - - for (int y1 = 2010; y1 <= 2015; ++y1) - { - for (unsigned m1 = 1; m1 <= 12; ++m1) - { - year_month_day ymd1{year{y1}, month{m1}, 9_d}; - year_month_day ymd2 = ymd1 + months(24); - assert((ymd2 == year_month_day{year{y1+2}, ymd1.month(), ymd1.day()})); - ymd2 = ymd1 - months(24); - assert((ymd2 == year_month_day{year{y1-2}, ymd1.month(), ymd1.day()})); - for (int m2 = -24; m2 <= 24; ++m2) - { - months m{m2}; - year_month_day ymd3 = ymd1 + m; - months dm = year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}; - assert(dm == m + years{2}); - assert(ymd3 - m == ymd1); - assert(ymd3 + -m == ymd1); - assert(-m + ymd3 == ymd1); - assert((year_month_day{ymd1} += m) == ymd3); - assert((year_month_day{ymd3} -= m) == ymd1); - } - for (int y2 = -2; y2 <= 5; ++y2) - { - years y{y2}; - year_month_day ymd3 = ymd1 + y; - years dy = floor(year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}); - assert(dy == y + years{2}); - assert(ymd3 - y == ymd1); - assert(ymd3 + -y == ymd1); - assert(-y + ymd3 == ymd1); - assert((year_month_day{ymd1} += y) == ymd3); - assert((year_month_day{ymd3} -= y) == ymd1); - } - } - } -} - -void -test_day_point_conversion() -{ - using namespace date; - year y = year{-1000}; - year end = 3000_y; - sys_days prev_dp = sys_days(year_month_day{y, jan, 1_d}) - days{1}; - weekday prev_wd = weekday{prev_dp}; - for (; y <= end; ++y) - { - month m = jan; - do - { - day last_day = year_month_day_last{y, month_day_last{m}}.day(); - for (day d = 1_d; d <= last_day; ++d) - { - year_month_day ymd = {y, m, d}; - assert(ymd.ok()); - sys_days dp = ymd; - assert(dp == prev_dp + days{1}); - year_month_day ymd2 = dp; - assert(ymd2 == ymd); - weekday wd = dp; - assert(wd.ok()); - assert(wd == prev_wd + days{1}); - prev_wd = wd; - prev_dp = dp; - } - } while (++m != jan); - } -} - -int -main() -{ - using namespace date; - - constexpr year_month_day ymd1 = {2015_y, aug, 9_d}; -#if __cplusplus >= 201402 - static_assert(ymd1.ok(), ""); -#endif - static_assert(ymd1.year() == 2015_y, ""); - static_assert(ymd1.month() == aug, ""); - static_assert(ymd1.day() == 9_d, ""); - -#if __cplusplus >= 201402 - constexpr sys_days dp = ymd1; - static_assert(dp.time_since_epoch() == days{16656}, ""); - constexpr year_month_day ymd2 = dp; - static_assert(ymd1 == ymd2, ""); -#endif - - constexpr year_month_day ymd3 = {1969_y, dec, 31_d}; -#if __cplusplus >= 201402 - static_assert(ymd3.ok(), ""); -#endif - static_assert(ymd3.year() == 1969_y, ""); - static_assert(ymd3.month() == dec, ""); - static_assert(ymd3.day() == 31_d, ""); - -#if __cplusplus >= 201402 - constexpr sys_days dp3 = ymd3; - static_assert(dp3.time_since_epoch() == days{-1}, ""); - constexpr year_month_day ymd4 = dp3; - static_assert(ymd3 == ymd4, ""); -#endif - - static_assert(ymd1 != ymd3, ""); - static_assert(ymd1 > ymd3, ""); - static_assert(ymd3 < ymd1, ""); - static_assert(ymd1 >= ymd1, ""); - static_assert(ymd3 <= ymd1, ""); - - test_arithmetic(); - test_day_point_conversion(); - - std::ostringstream os; - os << ymd1; - assert(os.str() == "2015-08-09"); - -#if __cplusplus >= 201402 - static_assert( (2000_y/feb/29).ok(), ""); - static_assert(!(2000_y/feb/30).ok(), ""); - static_assert( (2100_y/feb/28).ok(), ""); - static_assert(!(2100_y/feb/29).ok(), ""); - - static_assert(sys_days(2100_y/feb/28) + days{1} == sys_days(2100_y/mar/1), ""); - static_assert(sys_days(2000_y/mar/1) - sys_days(2000_y/feb/28) == days{2}, ""); - static_assert(sys_days(2100_y/mar/1) - sys_days(2100_y/feb/28) == days{1}, ""); - - static_assert(jan/31/2015 == jan/last/2015, ""); - static_assert(feb/28/2015 == feb/last/2015, ""); - static_assert(mar/31/2015 == mar/last/2015, ""); - static_assert(apr/30/2015 == apr/last/2015, ""); - static_assert(may/31/2015 == may/last/2015, ""); - static_assert(jun/30/2015 == jun/last/2015, ""); - static_assert(jul/31/2015 == jul/last/2015, ""); - static_assert(aug/31/2015 == aug/last/2015, ""); - static_assert(sep/30/2015 == sep/last/2015, ""); - static_assert(oct/31/2015 == oct/last/2015, ""); - static_assert(nov/30/2015 == nov/last/2015, ""); - static_assert(dec/31/2015 == dec/last/2015, ""); - - static_assert(jan/31/2016 == jan/last/2016, ""); - static_assert(feb/29/2016 == feb/last/2016, ""); - static_assert(mar/31/2016 == mar/last/2016, ""); - static_assert(apr/30/2016 == apr/last/2016, ""); - static_assert(may/31/2016 == may/last/2016, ""); - static_assert(jun/30/2016 == jun/last/2016, ""); - static_assert(jul/31/2016 == jul/last/2016, ""); - static_assert(aug/31/2016 == aug/last/2016, ""); - static_assert(sep/30/2016 == sep/last/2016, ""); - static_assert(oct/31/2016 == oct/last/2016, ""); - static_assert(nov/30/2016 == nov/last/2016, ""); - static_assert(dec/31/2016 == dec/last/2016, ""); -#endif -} diff --git a/src/date/test/date_test/year_month_day_last.pass.cpp b/src/date/test/date_test/year_month_day_last.pass.cpp deleted file mode 100644 index 41f1858e23..0000000000 --- a/src/date/test/date_test/year_month_day_last.pass.cpp +++ /dev/null @@ -1,177 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_month_day_last -// { -// public: -// constexpr year_month_day_last(const date::year& y, -// const date::month_day_last& mdl) noexcept; -// -// year_month_day_last& operator+=(const months& m) noexcept; -// year_month_day_last& operator-=(const months& m) noexcept; -// year_month_day_last& operator+=(const years& y) noexcept; -// year_month_day_last& operator-=(const years& y) noexcept; -// -// constexpr date::year year() const noexcept; -// constexpr date::month month() const noexcept; -// constexpr date::month_day_last month_day_last() const noexcept; -// constexpr date::day day() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// }; - -// constexpr -// bool operator==(const year_month_day_last& x, const year_month_day_last& y) noexcept; -// constexpr -// bool operator!=(const year_month_day_last& x, const year_month_day_last& y) noexcept; -// constexpr -// bool operator< (const year_month_day_last& x, const year_month_day_last& y) noexcept; -// constexpr -// bool operator> (const year_month_day_last& x, const year_month_day_last& y) noexcept; -// constexpr -// bool operator<=(const year_month_day_last& x, const year_month_day_last& y) noexcept; -// constexpr -// bool operator>=(const year_month_day_last& x, const year_month_day_last& y) noexcept; - -// constexpr -// year_month_day_last -// operator+(const year_month_day_last& ymdl, const months& dm) noexcept; -// -// constexpr -// year_month_day_last -// operator+(const months& dm, const year_month_day_last& ymdl) noexcept; -// -// constexpr -// year_month_day_last -// operator+(const year_month_day_last& ymdl, const years& dy) noexcept; -// -// constexpr -// year_month_day_last -// operator+(const years& dy, const year_month_day_last& ymdl) noexcept; -// -// constexpr -// year_month_day_last -// operator-(const year_month_day_last& ymdl, const months& dm) noexcept; -// -// constexpr -// year_month_day_last -// operator-(const year_month_day_last& ymdl, const years& dy) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year_month_day_last& ymdl); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); - -void -test_arithmetic() -{ - using namespace date; - - for (int y1 = 2010; y1 <= 2015; ++y1) - { - for (int m1 = 1; m1 <= 12; ++m1) - { - auto ymd1 = last/m1/y1;; - auto ymd2 = ymd1 + months(24); - assert(ymd2 == last/m1/(y1+2)); - ymd2 = ymd1 - months(24); - assert(ymd2 == last/m1/(y1-2)); - for (int m2 = -24; m2 <= 24; ++m2) - { - months m{m2}; - auto ymd3 = ymd1 + m; - months dm = year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}; - assert(dm == m + years{2}); - assert(ymd3 - m == ymd1); - assert(ymd3 + -m == ymd1); - assert(-m + ymd3 == ymd1); - assert((year_month_day_last{ymd1} += m) == ymd3); - assert((year_month_day_last{ymd3} -= m) == ymd1); - } - for (int y2 = -2; y2 <= 5; ++y2) - { - years y{y2}; - auto ymd3 = ymd1 + y; - years dy = floor(year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}); - assert(dy == y + years{2}); - assert(ymd3 - y == ymd1); - assert(ymd3 + -y == ymd1); - assert(-y + ymd3 == ymd1); - assert((year_month_day_last{ymd1} += y) == ymd3); - assert((year_month_day_last{ymd3} -= y) == ymd1); - } - } - } -} - -int -main() -{ - using namespace date; - - constexpr year_month_day_last ymdl1 = {2015_y, month_day_last{aug}}; - static_assert(ymdl1.ok(), ""); - static_assert(ymdl1.year() == 2015_y, ""); - static_assert(ymdl1.month() == aug, ""); - static_assert(ymdl1.month_day_last() == month_day_last{aug}, ""); -#if __cplusplus >= 201402 - static_assert(ymdl1.day() == 31_d, ""); - constexpr sys_days dp = ymdl1; - constexpr year_month_day ymd = dp; - static_assert(ymd == 2015_y/aug/31, ""); -#endif - - constexpr year_month_day_last ymdl2 = {2015_y, month_day_last{sep}}; - - static_assert(ymdl1 == ymdl1, ""); - static_assert(ymdl1 != ymdl2, ""); - static_assert(ymdl1 < ymdl2, ""); - static_assert(ymdl2 > ymdl1, ""); - static_assert(ymdl1 <= ymdl1, ""); - static_assert(ymdl2 >= ymdl1, ""); - - test_arithmetic(); - - std::ostringstream os; - os << ymdl1; - assert(os.str() == "2015/Aug/last"); - -} diff --git a/src/date/test/date_test/year_month_day_m_year_month_day.fail.cpp b/src/date/test/date_test/year_month_day_m_year_month_day.fail.cpp deleted file mode 100644 index ceb2f9e958..0000000000 --- a/src/date/test/date_test/year_month_day_m_year_month_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year_month_day - year_month_day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = year_month_day{2015_y, aug, 9_d} - year_month_day{2015_y, aug, 9_d}; -} diff --git a/src/date/test/date_test/year_month_day_p_year_month_day.fail.cpp b/src/date/test/date_test/year_month_day_p_year_month_day.fail.cpp deleted file mode 100644 index 11e589ff7d..0000000000 --- a/src/date/test/date_test/year_month_day_p_year_month_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year_month_day + year_month_day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = year_month_day{2015_y, aug, 9_d} + year_month_day{2015_y, aug, 9_d}; -} diff --git a/src/date/test/date_test/year_month_p_year_month.fail.cpp b/src/date/test/date_test/year_month_p_year_month.fail.cpp deleted file mode 100644 index 00049f1191..0000000000 --- a/src/date/test/date_test/year_month_p_year_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year_month + year_month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = year_month{2015_y, jan} + year_month{2015_y, jan}; -} diff --git a/src/date/test/date_test/year_month_weekday.pass.cpp b/src/date/test/date_test/year_month_weekday.pass.cpp deleted file mode 100644 index 1a6ed0d394..0000000000 --- a/src/date/test/date_test/year_month_weekday.pass.cpp +++ /dev/null @@ -1,178 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_month_weekday -// { -// public: -// year_month_weekday() = default; -// constexpr year_month_weekday(const date::year& y, const date::month& m, -// const date::weekday_indexed& wdi) noexcept; -// constexpr year_month_weekday(const sys_days& dp) noexcept; -// -// year_month_weekday& operator+=(const months& m) noexcept; -// year_month_weekday& operator-=(const months& m) noexcept; -// year_month_weekday& operator+=(const years& y) noexcept; -// year_month_weekday& operator-=(const years& y) noexcept; -// -// constexpr date::year year() const noexcept; -// constexpr date::month month() const noexcept; -// constexpr date::weekday weekday() const noexcept; -// constexpr unsigned index() const noexcept; -// constexpr date::weekday_indexed weekday_indexed() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// -// private: -// static constexpr year_month_weekday from_day_point(const sys_days& dp) noexcept; -// }; - -// constexpr -// bool operator==(const year_month_weekday& x, const year_month_weekday& y) noexcept; -// constexpr -// bool operator!=(const year_month_weekday& x, const year_month_weekday& y) noexcept; - -// constexpr -// year_month_weekday -// operator+(const year_month_weekday& ymwd, const months& dm) noexcept; -// -// constexpr -// year_month_weekday -// operator+(const months& dm, const year_month_weekday& ymwd) noexcept; -// -// constexpr -// year_month_weekday -// operator+(const year_month_weekday& ymwd, const years& dy) noexcept; -// -// constexpr -// year_month_weekday -// operator+(const years& dy, const year_month_weekday& ymwd) noexcept; -// -// constexpr -// year_month_weekday -// operator-(const year_month_weekday& ymwd, const months& dm) noexcept; -// -// constexpr -// year_month_weekday -// operator-(const year_month_weekday& ymwd, const years& dy) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year_month_weekday& ymwdi); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert( std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); - -void -test_arithmetic() -{ - using namespace date; - - for (int y1 = 2010; y1 <= 2015; ++y1) - { - for (int m1 = 1; m1 <= 12; ++m1) - { - auto ymd1 = mon[2]/m1/y1;; - auto ymd2 = ymd1 + months(24); - assert(ymd2 == mon[2]/m1/(y1+2)); - ymd2 = ymd1 - months(24); - assert(ymd2 == mon[2]/m1/(y1-2)); - for (int m2 = -24; m2 <= 24; ++m2) - { - months m{m2}; - auto ymd3 = ymd1 + m; - months dm = year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}; - assert(dm == m + years{2}); - assert(ymd3 - m == ymd1); - assert(ymd3 + -m == ymd1); - assert(-m + ymd3 == ymd1); - assert((year_month_weekday{ymd1} += m) == ymd3); - assert((year_month_weekday{ymd3} -= m) == ymd1); - } - for (int y2 = -2; y2 <= 5; ++y2) - { - years y{y2}; - auto ymd3 = ymd1 + y; - years dy = floor(year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}); - assert(dy == y + years{2}); - assert(ymd3 - y == ymd1); - assert(ymd3 + -y == ymd1); - assert(-y + ymd3 == ymd1); - assert((year_month_weekday{ymd1} += y) == ymd3); - assert((year_month_weekday{ymd3} -= y) == ymd1); - } - } - } -} - -int -main() -{ - using namespace date; - - constexpr year_month_weekday ymdl1 = {2015_y, aug, weekday_indexed{fri, 2}}; -#if __cplusplus >= 201402 - static_assert(ymdl1.ok(), ""); -#endif - static_assert(ymdl1.year() == 2015_y, ""); - static_assert(ymdl1.month() == aug, ""); - static_assert(ymdl1.weekday() == fri, ""); - static_assert(ymdl1.index() == 2u, ""); - static_assert(ymdl1.weekday_indexed() == fri[2], ""); -#if __cplusplus >= 201402 - constexpr sys_days dp = ymdl1; - constexpr year_month_day ymd = dp; - static_assert(ymd == 2015_y/aug/14, ""); -#endif - - constexpr year_month_weekday ymdl2 = sat[1]/aug/2015; - - static_assert(ymdl1 == ymdl1, ""); - static_assert(ymdl1 != ymdl2, ""); - - test_arithmetic(); - - std::ostringstream os; - os << ymdl1; - assert(os.str() == "2015/Aug/Fri[2]"); - -} diff --git a/src/date/test/date_test/year_month_weekday_last.pass.cpp b/src/date/test/date_test/year_month_weekday_last.pass.cpp deleted file mode 100644 index 3abe113344..0000000000 --- a/src/date/test/date_test/year_month_weekday_last.pass.cpp +++ /dev/null @@ -1,169 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_month_weekday_last -// { -// public: -// constexpr year_month_weekday_last(const date::year& y, const date::month& m, -// const date::weekday_last& wdl) noexcept; -// -// year_month_weekday_last& operator+=(const months& m) noexcept; -// year_month_weekday_last& operator-=(const months& m) noexcept; -// year_month_weekday_last& operator+=(const years& y) noexcept; -// year_month_weekday_last& operator-=(const years& y) noexcept; -// -// constexpr date::year year() const noexcept; -// constexpr date::month month() const noexcept; -// constexpr date::weekday weekday() const noexcept; -// constexpr date::weekday_last weekday_last() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// }; - -// constexpr -// bool -// operator==(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept; -// -// constexpr -// bool -// operator!=(const year_month_weekday_last& x, const year_month_weekday_last& y) noexcept; - -// constexpr -// year_month_weekday_last -// operator+(const year_month_weekday_last& ymwdl, const months& dm) noexcept; -// -// constexpr -// year_month_weekday_last -// operator+(const months& dm, const year_month_weekday_last& ymwdl) noexcept; -// -// constexpr -// year_month_weekday_last -// operator+(const year_month_weekday_last& ymwdl, const years& dy) noexcept; -// -// constexpr -// year_month_weekday_last -// operator+(const years& dy, const year_month_weekday_last& ymwdl) noexcept; -// -// constexpr -// year_month_weekday_last -// operator-(const year_month_weekday_last& ymwdl, const months& dm) noexcept; -// -// constexpr -// year_month_weekday_last -// operator-(const year_month_weekday_last& ymwdl, const years& dy) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year_month_weekday_last& ymwdl); - -#include "date.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(std::is_convertible{}, ""); - -void -test_arithmetic() -{ - using namespace date; - - for (int y1 = 2010; y1 <= 2015; ++y1) - { - for (int m1 = 1; m1 <= 12; ++m1) - { - auto ymd1 = mon[last]/m1/y1;; - auto ymd2 = ymd1 + months(24); - assert(ymd2 == mon[last]/m1/(y1+2)); - ymd2 = ymd1 - months(24); - assert(ymd2 == mon[last]/m1/(y1-2)); - for (int m2 = -24; m2 <= 24; ++m2) - { - months m{m2}; - auto ymd3 = ymd1 + m; - months dm = year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}; - assert(dm == m + years{2}); - assert(ymd3 - m == ymd1); - assert(ymd3 + -m == ymd1); - assert(-m + ymd3 == ymd1); - assert((year_month_weekday_last{ymd1} += m) == ymd3); - assert((year_month_weekday_last{ymd3} -= m) == ymd1); - } - for (int y2 = -2; y2 <= 5; ++y2) - { - years y{y2}; - auto ymd3 = ymd1 + y; - years dy = floor(year_month{ymd3.year(), ymd3.month()} - - year_month{ymd2.year(), ymd2.month()}); - assert(dy == y + years{2}); - assert(ymd3 - y == ymd1); - assert(ymd3 + -y == ymd1); - assert(-y + ymd3 == ymd1); - assert((year_month_weekday_last{ymd1} += y) == ymd3); - assert((year_month_weekday_last{ymd3} -= y) == ymd1); - } - } - } -} - -int -main() -{ - using namespace date; - - constexpr year_month_weekday_last ymdl1 = {2015_y, aug, weekday_last{fri}}; - static_assert(ymdl1.ok(), ""); - static_assert(ymdl1.year() == 2015_y, ""); - static_assert(ymdl1.month() == aug, ""); - static_assert(ymdl1.weekday() == fri, ""); - static_assert(ymdl1.weekday_last() == fri[last], ""); -#if __cplusplus >= 201402 - constexpr sys_days dp = ymdl1; - constexpr year_month_day ymd = dp; - static_assert(ymd == 2015_y/aug/28, ""); -#endif - - constexpr year_month_weekday_last ymdl2 = sat[last]/aug/2015; - - static_assert(ymdl1 == ymdl1, ""); - static_assert(ymdl1 != ymdl2, ""); - - test_arithmetic(); - - std::ostringstream os; - os << ymdl1; - assert(os.str() == "2015/Aug/Fri[last]"); - -} diff --git a/src/date/test/date_test/year_p_year.fail.cpp b/src/date/test/date_test/year_p_year.fail.cpp deleted file mode 100644 index 79e56b9212..0000000000 --- a/src/date/test/date_test/year_p_year.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year + year not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = 2015_y + 2015_y; -} diff --git a/src/date/test/date_test/years_m_year.fail.cpp b/src/date/test/date_test/years_m_year.fail.cpp deleted file mode 100644 index b2c01cfd42..0000000000 --- a/src/date/test/date_test/years_m_year.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// years - year not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - auto x = years{3} - 2015_y; -} diff --git a/src/date/test/date_test/years_m_year_month.fail.cpp b/src/date/test/date_test/years_m_year_month.fail.cpp deleted file mode 100644 index c2cb96c24d..0000000000 --- a/src/date/test/date_test/years_m_year_month.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// years - year_month not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = years{1} - year_month{2015_y, jan}; -} diff --git a/src/date/test/date_test/years_m_year_month_day.fail.cpp b/src/date/test/date_test/years_m_year_month_day.fail.cpp deleted file mode 100644 index beeb4f5935..0000000000 --- a/src/date/test/date_test/years_m_year_month_day.fail.cpp +++ /dev/null @@ -1,33 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// years - year_month_day not allowed - -#include "date.h" - -int -main() -{ - using namespace date; - - auto x = 2015_y - year_month_day{2015_y, aug, 9_d}; -} diff --git a/src/date/test/iso_week/last.pass.cpp b/src/date/test/iso_week/last.pass.cpp deleted file mode 100644 index dad8cbb7ff..0000000000 --- a/src/date/test/iso_week/last.pass.cpp +++ /dev/null @@ -1,34 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// constexpr struct last_spec {} last{}; - -#include "iso_week.h" - -#include - -static_assert(std::is_same{}, ""); - -int -main() -{ -} diff --git a/src/date/test/iso_week/lastweek_weekday.pass.cpp b/src/date/test/iso_week/lastweek_weekday.pass.cpp deleted file mode 100644 index 3ffbb2521b..0000000000 --- a/src/date/test/iso_week/lastweek_weekday.pass.cpp +++ /dev/null @@ -1,82 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class lastweek_weekday -// { -// iso_week::weekday wd_; // exposition only -// -// public: -// explicit constexpr lastweek_weekday(const iso_week::weekday& wd) noexcept; -// -// constexpr iso_week::weekday weekday() const noexcept; -// -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// constexpr bool operator!=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// constexpr bool operator< (const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// constexpr bool operator> (const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// constexpr bool operator<=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// constexpr bool operator>=(const lastweek_weekday& x, const lastweek_weekday& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const lastweek_weekday& md); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto wn_wd = lastweek_weekday{tue}; - static_assert(wn_wd.weekday() == tue, ""); - - static_assert(wn_wd.ok(), ""); - - static_assert(wn_wd == lastweek_weekday{tue}, ""); - static_assert(!(wn_wd != lastweek_weekday{tue}), ""); - static_assert(wn_wd < lastweek_weekday{wed}, ""); - - std::ostringstream os; - os << wn_wd; - assert(os.str() == "W last-Tue"); -} diff --git a/src/date/test/iso_week/op_div_survey.pass.cpp b/src/date/test/iso_week/op_div_survey.pass.cpp deleted file mode 100644 index 52e18868a9..0000000000 --- a/src/date/test/iso_week/op_div_survey.pass.cpp +++ /dev/null @@ -1,196 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -#include "iso_week.h" - -#include - -template -constexpr -auto -test(I i, J j, K k) -> decltype(i/j/k) -{ - return i/j/k; -} - -void -test(...) -{ -} - -int -main() -{ - using std::is_same; - using namespace iso_week; - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same{}, ""); - -} diff --git a/src/date/test/iso_week/weekday.pass.cpp b/src/date/test/iso_week/weekday.pass.cpp deleted file mode 100644 index 19908e200f..0000000000 --- a/src/date/test/iso_week/weekday.pass.cpp +++ /dev/null @@ -1,227 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weekday -// { -// unsigned char wd_; -// public: -// explicit constexpr weekday(unsigned wd) noexcept; -// constexpr weekday(date::weekday wd) noexcept; -// constexpr weekday(const sys_days& dp) noexcept; -// -// weekday& operator++() noexcept; -// weekday operator++(int) noexcept; -// weekday& operator--() noexcept; -// weekday operator--(int) noexcept; -// -// weekday& operator+=(const days& d) noexcept; -// weekday& operator-=(const days& d) noexcept; -// -// constexpr explicit operator unsigned() const noexcept; -// constexpr operator date::weekday() const noexcept; -// constexpr bool ok() const noexcept; -// -// // tested with weekday_indexed -// constexpr weekday_indexed operator[](unsigned index) const noexcept; -// // tested with weekday_last -// constexpr weekday_last operator[](last_spec) const noexcept; -// }; - -// constexpr bool operator==(const weekday& x, const weekday& y) noexcept; -// constexpr bool operator!=(const weekday& x, const weekday& y) noexcept; - -// constexpr weekday operator+(const weekday& x, const days& y) noexcept; -// constexpr weekday operator+(const days& x, const weekday& y) noexcept; -// constexpr weekday operator-(const weekday& x, const days& y) noexcept; -// constexpr days operator-(const weekday& x, const weekday& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const weekday& wd); - -// constexpr weekday sun{7}; -// constexpr weekday mon{1}; -// constexpr weekday tue{2}; -// constexpr weekday wed{3}; -// constexpr weekday thu{4}; -// constexpr weekday fri{5}; -// constexpr weekday sat{6}; - -#include "iso_week.h" -#include "date.h" - -#include -#include -#include - -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(iso_week::weekday{1u}) == 1, ""); - -static_assert(!iso_week::weekday{0u}.ok(), ""); -static_assert( iso_week::weekday{1u}.ok(), ""); -static_assert( iso_week::weekday{2u}.ok(), ""); -static_assert( iso_week::weekday{3u}.ok(), ""); -static_assert( iso_week::weekday{4u}.ok(), ""); -static_assert( iso_week::weekday{5u}.ok(), ""); -static_assert( iso_week::weekday{6u}.ok(), ""); -static_assert( iso_week::weekday{7u}.ok(), ""); - -void -test_weekday_arithmetic() -{ - using namespace iso_week; - constexpr unsigned a[7][7] = - {// - Mon Tue Wed Thu Fri Sat Sun - /*Mon*/ {0, 6, 5, 4, 3, 2, 1}, - /*Tue*/ {1, 0, 6, 5, 4, 3, 2}, - /*Wed*/ {2, 1, 0, 6, 5, 4, 3}, - /*Thu*/ {3, 2, 1, 0, 6, 5, 4}, - /*Fri*/ {4, 3, 2, 1, 0, 6, 5}, - /*Sat*/ {5, 4, 3, 2, 1, 0, 6}, - /*Sun*/ {6, 5, 4, 3, 2, 1, 0} - }; - for (unsigned x = 1; x <= 7; ++x) - { - for (unsigned y = 1; y <= 7; ++y) - { - assert(weekday{x} - weekday{y} == days{a[x-1][y-1]}); - assert(weekday{x} - days{a[x-1][y-1]} == weekday{y}); - assert(weekday{x} == weekday{y} + days{a[x-1][y-1]}); - assert(weekday{x} == days{a[x-1][y-1]} + weekday{y}); - } - } - for (unsigned x = 1; x <= 7; ++x) - { - for (int y = -21; y < 21; ++y) - { - weekday wx{x}; - days dy{y}; - wx += dy; - weekday wz = weekday{x} + days{y}; - assert(wx.ok()); - assert(wz.ok()); - assert(wx == wz); - assert(wx - weekday{x} == days{y % 7 + (y % 7 < 0 ? 7 : 0)}); - } - } - for (unsigned x = 1; x <= 7; ++x) - { - for (int y = -21; y < 21; ++y) - { - weekday wx{x}; - days dy{y}; - wx -= dy; - assert(wx == weekday{x} + days{-y}); - } - } - for (unsigned x = 1; x <= 7; ++x) - { - weekday wx{x}; - assert(++wx - weekday{x} == days{1}); - assert(wx++ - weekday{x} == days{1}); - assert(wx - weekday{x} == days{2}); - assert(wx-- - weekday{x} == days{2}); - assert(wx - weekday{x} == days{1}); - assert(--wx - weekday{x} == days{0}); - } -} - -void -test_with_date_weekday() -{ - auto constexpr d1 = iso_week::sun; - static_assert(unsigned{d1} == 7, ""); - auto constexpr d2 = date::weekday{d1}; - static_assert(unsigned{d2} == 0, ""); - auto constexpr d3 = iso_week::weekday{d2}; - static_assert(unsigned{d3} == 7, ""); -} - -int -main() -{ - using namespace iso_week; - - static_assert(sun == weekday{7u}, ""); - static_assert(mon == weekday{1u}, ""); - static_assert(tue == weekday{2u}, ""); - static_assert(wed == weekday{3u}, ""); - static_assert(thu == weekday{4u}, ""); - static_assert(fri == weekday{5u}, ""); - static_assert(sat == weekday{6u}, ""); - - static_assert(!(sun != sun), ""); - static_assert( sun != mon, ""); - static_assert( mon != sun, ""); - - test_weekday_arithmetic(); - test_with_date_weekday(); - - std::ostringstream os; - - os << sun; - assert(os.str() == "Sun"); - os.str(""); - - os << mon; - assert(os.str() == "Mon"); - os.str(""); - - os << tue; - assert(os.str() == "Tue"); - os.str(""); - - os << wed; - assert(os.str() == "Wed"); - os.str(""); - - os << thu; - assert(os.str() == "Thu"); - os.str(""); - - os << fri; - assert(os.str() == "Fri"); - os.str(""); - - os << sat; - assert(os.str() == "Sat"); -} diff --git a/src/date/test/iso_week/weekday_lessthan.fail.cpp b/src/date/test/iso_week/weekday_lessthan.fail.cpp deleted file mode 100644 index ff74e166b0..0000000000 --- a/src/date/test/iso_week/weekday_lessthan.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday < weekday not allowed - -#include "iso_week.h" - -int -main() -{ - using namespace iso_week; - auto b = sun < mon; -} diff --git a/src/date/test/iso_week/weekday_sum.fail.cpp b/src/date/test/iso_week/weekday_sum.fail.cpp deleted file mode 100644 index 648af12b43..0000000000 --- a/src/date/test/iso_week/weekday_sum.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weekday + weekday not allowed - -#include "iso_week.h" - -int -main() -{ - using namespace iso_week; - auto b = sun + mon; -} diff --git a/src/date/test/iso_week/weeknum.pass.cpp b/src/date/test/iso_week/weeknum.pass.cpp deleted file mode 100644 index 5e60d77eec..0000000000 --- a/src/date/test/iso_week/weeknum.pass.cpp +++ /dev/null @@ -1,121 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weeknum -// { -// unsigned char wn_; -// -// public: -// explicit constexpr weeknum(unsigned wn) noexcept; -// -// weeknum& operator++() noexcept; -// weeknum operator++(int) noexcept; -// weeknum& operator--() noexcept; -// weeknum operator--(int) noexcept; -// -// weeknum& operator+=(const weeks& y) noexcept; -// weeknum& operator-=(const weeks& y) noexcept; -// -// constexpr explicit operator unsigned() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const weeknum& x, const weeknum& y) noexcept; -// constexpr bool operator!=(const weeknum& x, const weeknum& y) noexcept; -// constexpr bool operator< (const weeknum& x, const weeknum& y) noexcept; -// constexpr bool operator> (const weeknum& x, const weeknum& y) noexcept; -// constexpr bool operator<=(const weeknum& x, const weeknum& y) noexcept; -// constexpr bool operator>=(const weeknum& x, const weeknum& y) noexcept; -// -// constexpr weeknum operator+(const weeknum& x, const weeks& y) noexcept; -// constexpr weeknum operator+(const weeks& x, const weeknum& y) noexcept; -// constexpr weeknum operator-(const weeknum& x, const weeks& y) noexcept; -// constexpr weeks operator-(const weeknum& x, const weeknum& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const weeknum& wn); -// -// constexpr weeknum operator "" _w(unsigned long long wn) noexcept; - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(iso_week::weeknum{3}) == 3, ""); - -int -main() -{ - using namespace iso_week; - using namespace std::chrono; - - static_assert(weeknum{2} == 2_w, ""); - static_assert(unsigned{weeknum{2}} == 2, ""); - static_assert(unsigned{weeknum{3}} == 3, ""); - static_assert(weeknum{2} != 3_w, ""); - static_assert(weeknum{2} < 3_w, ""); - static_assert(weeknum{3} > 2_w, ""); - static_assert(weeknum{2} <= 2_w, ""); - static_assert(weeknum{3} >= 2_w, ""); - - auto wn = weeknum{4}; - assert(++wn == weeknum{5}); - assert(wn == weeknum{5}); - assert(wn++ == weeknum{5}); - assert(wn == weeknum{6}); - assert(--wn == weeknum{5}); - assert(wn == weeknum{5}); - assert(wn-- == weeknum{5}); - assert(wn == weeknum{4}); - - static_assert(!weeknum{0}.ok(), ""); - static_assert( weeknum{1}.ok(), ""); - static_assert( weeknum{53}.ok(), ""); - static_assert(!weeknum{54}.ok(), ""); - - static_assert(15_w - 10_w == weeks{5}, ""); - static_assert(15_w - weeks{5} == 10_w, ""); - static_assert(15_w == weeks{5} + 10_w, ""); - static_assert(15_w == 10_w + weeks{5}, ""); - static_assert(10_w - 15_w == -weeks{5}, ""); - - auto w = 5_w; - std::ostringstream os; - os << w; - assert(os.str() == "W05"); -} diff --git a/src/date/test/iso_week/weeknum_p_weeknum.fail.cpp b/src/date/test/iso_week/weeknum_p_weeknum.fail.cpp deleted file mode 100644 index 2199aa33f2..0000000000 --- a/src/date/test/iso_week/weeknum_p_weeknum.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// weeknum + weeknum not allowed - -#include "iso_week.h" - -int -main() -{ - using namespace iso_week; - auto x = 3_w + 4_w; -} diff --git a/src/date/test/iso_week/weeknum_weekday.pass.cpp b/src/date/test/iso_week/weeknum_weekday.pass.cpp deleted file mode 100644 index c02c093cf5..0000000000 --- a/src/date/test/iso_week/weeknum_weekday.pass.cpp +++ /dev/null @@ -1,86 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class weeknum_weekday -// { -// iso_week::weeknum wn_; // exposition only -// iso_week::weekday wd_; // exposition only -// -// public: -// constexpr weeknum_weekday(const iso_week::weeknum& wn, -// const iso_week::weekday& wd) noexcept; -// -// constexpr iso_week::weeknum weeknum() const noexcept; -// constexpr iso_week::weekday weekday() const noexcept; -// -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// constexpr bool operator!=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// constexpr bool operator< (const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// constexpr bool operator> (const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// constexpr bool operator<=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// constexpr bool operator>=(const weeknum_weekday& x, const weeknum_weekday& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const weeknum_weekday& md); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto wn_wd = weeknum_weekday{52_w, tue}; - static_assert(wn_wd.weeknum() == 52_w, ""); - static_assert(wn_wd.weekday() == tue, ""); - - static_assert(wn_wd.ok(), ""); - - static_assert(wn_wd == weeknum_weekday{52_w, tue}, ""); - static_assert(!(wn_wd != weeknum_weekday{52_w, tue}), ""); - static_assert(wn_wd < weeknum_weekday{52_w, wed}, ""); - - std::ostringstream os; - os << wn_wd; - assert(os.str() == "W52-Tue"); -} diff --git a/src/date/test/iso_week/year.pass.cpp b/src/date/test/iso_week/year.pass.cpp deleted file mode 100644 index 1f1675abcb..0000000000 --- a/src/date/test/iso_week/year.pass.cpp +++ /dev/null @@ -1,120 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year -// { -// public: -// explicit constexpr year(int y) noexcept; -// -// year& operator++() noexcept; -// year operator++(int) noexcept; -// year& operator--() noexcept; -// year operator--(int) noexcept; -// -// year& operator+=(const years& y) noexcept; -// year& operator-=(const years& y) noexcept; -// -// constexpr explicit operator int() const noexcept; -// constexpr bool ok() const noexcept; -// -// static constexpr year min() noexcept; -// static constexpr year max() noexcept; -// }; - -// constexpr bool operator==(const year& x, const year& y) noexcept; -// constexpr bool operator!=(const year& x, const year& y) noexcept; -// constexpr bool operator< (const year& x, const year& y) noexcept; -// constexpr bool operator> (const year& x, const year& y) noexcept; -// constexpr bool operator<=(const year& x, const year& y) noexcept; -// constexpr bool operator>=(const year& x, const year& y) noexcept; - -// constexpr year operator+(const year& x, const years& y) noexcept; -// constexpr year operator+(const years& x, const year& y) noexcept; -// constexpr year operator-(const year& x, const years& y) noexcept; -// constexpr years operator-(const year& x, const year& y) noexcept; - -// std::ostream& operator<<(std::ostream& os, const year& y); -// inline namespace literals { -// constexpr year operator "" _y(unsigned long long y) noexcept; -// } - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); -static_assert(static_cast(iso_week::year{-1}) == -1, ""); - -int -main() -{ - using namespace iso_week; - - static_assert(year{2015} == 2015_y, ""); - static_assert(int{year{2015}} == 2015, ""); - static_assert(year{2015} != 2016_y, ""); - static_assert(year{2015} < 2016_y, ""); - static_assert(year{2016} > 2015_y, ""); - static_assert(year{2015} <= 2015_y, ""); - static_assert(year{2016} >= 2015_y, ""); - - auto y = year{2014}; - assert(++y == year{2015}); - assert(y == year{2015}); - assert(y++ == year{2015}); - assert(y == year{2016}); - assert(--y == year{2015}); - assert(y == year{2015}); - assert(y-- == year{2015}); - assert(y == year{2014}); - - static_assert(year::min().ok(), ""); - static_assert(year{2015}.ok(), ""); - static_assert(year{2016}.ok(), ""); - static_assert(year::max().ok(), ""); - - static_assert(2015_y - 2010_y == years{5}, ""); - static_assert(2015_y - years{5} == 2010_y, ""); - static_assert(2015_y == years{5} + 2010_y, ""); - static_assert(2015_y == 2010_y + years{5}, ""); - - y = 2015_y; - std::ostringstream os; - os << y; - assert(os.str() == "2015"); -} diff --git a/src/date/test/iso_week/year_lastweek.pass.cpp b/src/date/test/iso_week/year_lastweek.pass.cpp deleted file mode 100644 index 8874472091..0000000000 --- a/src/date/test/iso_week/year_lastweek.pass.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_lastweek -// { -// iso_week::year y_; -// -// public: -// explicit constexpr year_lastweek(const iso_week::year& y) noexcept; -// -// constexpr iso_week::year year() const noexcept; -// constexpr iso_week::weeknum weeknum() const noexcept; -// -// year_lastweek& operator+=(const years& dy) noexcept; -// year_lastweek& operator-=(const years& dy) noexcept; -// -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const year_lastweek& x, const year_lastweek& y) noexcept; -// constexpr bool operator!=(const year_lastweek& x, const year_lastweek& y) noexcept; -// constexpr bool operator< (const year_lastweek& x, const year_lastweek& y) noexcept; -// constexpr bool operator> (const year_lastweek& x, const year_lastweek& y) noexcept; -// constexpr bool operator<=(const year_lastweek& x, const year_lastweek& y) noexcept; -// constexpr bool operator>=(const year_lastweek& x, const year_lastweek& y) noexcept; -// -// constexpr year_lastweek operator+(const year_lastweek& ym, const years& dy) noexcept; -// constexpr year_lastweek operator+(const years& dy, const year_lastweek& ym) noexcept; -// constexpr year_lastweek operator-(const year_lastweek& ym, const years& dy) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const year_lastweek& ym); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert(std::is_nothrow_constructible{}, ""); -static_assert(!std::is_convertible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto y_wn = year_lastweek{2015_y}; - static_assert(y_wn.year() == 2015_y, ""); - static_assert(y_wn.weeknum() == 53_w, ""); - static_assert(year_lastweek{2016_y}.weeknum() == 52_w, ""); - - static_assert(y_wn.ok(), ""); - - static_assert(y_wn == year_lastweek{2015_y}, ""); - static_assert(!(y_wn != year_lastweek{2015_y}), ""); - static_assert(y_wn < year_lastweek{2016_y}, ""); - - auto y_wn2 = y_wn + years{2}; - assert(y_wn2 == year_lastweek{2017_y}); - y_wn2 -= years{1}; - assert(y_wn2 == year_lastweek{2016_y}); - - std::ostringstream os; - os << y_wn; - assert(os.str() == "2015-W last"); -} diff --git a/src/date/test/iso_week/year_lastweek_weekday.pass.cpp b/src/date/test/iso_week/year_lastweek_weekday.pass.cpp deleted file mode 100644 index 5f65f6fd9c..0000000000 --- a/src/date/test/iso_week/year_lastweek_weekday.pass.cpp +++ /dev/null @@ -1,129 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_lastweek_weekday -// { -// public: -// constexpr year_lastweek_weekday(const iso_week::year& y, -// const iso_week::weekday& wd) noexcept; -// -// year_lastweek_weekday& operator+=(const years& y) noexcept; -// year_lastweek_weekday& operator-=(const years& y) noexcept; -// -// constexpr iso_week::year year() const noexcept; -// constexpr iso_week::weeknum weeknum() const noexcept; -// constexpr iso_week::weekday weekday() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// constexpr bool operator!=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// constexpr bool operator< (const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// constexpr bool operator> (const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// constexpr bool operator<=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// constexpr bool operator>=(const year_lastweek_weekday& x, const year_lastweek_weekday& y) noexcept; -// -// constexpr year_lastweek_weekday operator+(const year_lastweek_weekday& x, const years& y) noexcept; -// constexpr year_lastweek_weekday operator+(const years& y, const year_lastweek_weekday& x) noexcept; -// constexpr year_lastweek_weekday operator-(const year_lastweek_weekday& x, const years& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const year_lastweek_weekday& x); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_convertible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto x0 = year_lastweek_weekday{2015_y, tue}; - static_assert(x0.year() == 2015_y, ""); - static_assert(x0.weeknum() == 53_w, ""); - static_assert(x0.weekday() == tue, ""); - - auto x3 = x0; - x3 += years{2}; - assert(x3.year() == 2017_y); - assert(x3.weeknum() == 52_w); - assert(x3.weekday() == tue); - - x3 -= years{1}; - assert(x3.year() == 2016_y); - assert(x3.weeknum() == 52_w); - assert(x3.weekday() == tue); - - x3 -= years{1}; - assert(x3.year() == 2015_y); - assert(x3.weeknum() == 53_w); - assert(x3.weekday() == tue); - - constexpr sys_days dp = 2015_y/last/wed; - static_assert(dp == sys_days{days{16799}}, ""); - - static_assert(x0.ok(), ""); - assert(x3.ok()); - - static_assert(2015_y/last/mon < 2015_y/last/sun, ""); - - static_assert(x0 + years{3} == 2018_y/last/tue, ""); - static_assert(years{3} + x0 == 2018_y/last/tue, ""); - static_assert(x0 - years{3} == 2012_y/last/tue, ""); - - std::ostringstream os; - os << x0; - assert(os.str() == "2015-W last-Tue"); - - for (auto y = 1950_y; y <= 2050_y; ++y) - { - auto wd = mon; - do - { - auto x = y/last/wd; - assert(date::year_month_day{x} == date::year_month_day{year_weeknum_weekday{x}}); - ++wd; - } while (wd != mon); - } -} diff --git a/src/date/test/iso_week/year_p_year.fail.cpp b/src/date/test/iso_week/year_p_year.fail.cpp deleted file mode 100644 index c0eba47b92..0000000000 --- a/src/date/test/iso_week/year_p_year.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// year + year not allowed - -#include "iso_week.h" - -int -main() -{ - using namespace iso_week; - auto x = 2015_y + 2015_y; -} diff --git a/src/date/test/iso_week/year_weeknum.pass.cpp b/src/date/test/iso_week/year_weeknum.pass.cpp deleted file mode 100644 index 6e9d4b6615..0000000000 --- a/src/date/test/iso_week/year_weeknum.pass.cpp +++ /dev/null @@ -1,97 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_weeknum -// { -// iso_week::year y_; -// iso_week::weeknum wn_; -// -// public: -// constexpr year_weeknum(const iso_week::year& y, const iso_week::weeknum& wn) noexcept; -// -// constexpr iso_week::year year() const noexcept; -// constexpr iso_week::weeknum weeknum() const noexcept; -// -// year_weeknum& operator+=(const years& dy) noexcept; -// year_weeknum& operator-=(const years& dy) noexcept; -// -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const year_weeknum& x, const year_weeknum& y) noexcept; -// constexpr bool operator!=(const year_weeknum& x, const year_weeknum& y) noexcept; -// constexpr bool operator< (const year_weeknum& x, const year_weeknum& y) noexcept; -// constexpr bool operator> (const year_weeknum& x, const year_weeknum& y) noexcept; -// constexpr bool operator<=(const year_weeknum& x, const year_weeknum& y) noexcept; -// constexpr bool operator>=(const year_weeknum& x, const year_weeknum& y) noexcept; -// -// constexpr year_weeknum operator+(const year_weeknum& ym, const years& dy) noexcept; -// constexpr year_weeknum operator+(const years& dy, const year_weeknum& ym) noexcept; -// constexpr year_weeknum operator-(const year_weeknum& ym, const years& dy) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const year_weeknum& ym); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto y_wn = year_weeknum{2015_y, 52_w}; - static_assert(y_wn.year() == 2015_y, ""); - static_assert(y_wn.weeknum() == 52_w, ""); - - static_assert(y_wn.ok(), ""); - - static_assert(y_wn == year_weeknum{2015_y, 52_w}, ""); - static_assert(!(y_wn != year_weeknum{2015_y, 52_w}), ""); - static_assert(y_wn < year_weeknum{2015_y, 53_w}, ""); - - auto y_wn2 = y_wn + years{2}; - assert((y_wn2 == year_weeknum{2017_y, 52_w})); - y_wn2 -= years{1}; - assert((y_wn2 == year_weeknum{2016_y, 52_w})); - - std::ostringstream os; - os << y_wn; - assert(os.str() == "2015-W52"); -} diff --git a/src/date/test/iso_week/year_weeknum_weekday.pass.cpp b/src/date/test/iso_week/year_weeknum_weekday.pass.cpp deleted file mode 100644 index 0540f97658..0000000000 --- a/src/date/test/iso_week/year_weeknum_weekday.pass.cpp +++ /dev/null @@ -1,139 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// class year_weeknum_weekday - -// class year_weeknum_weekday -// { -// public: -// constexpr year_weeknum_weekday(const iso_week::year& y, const iso_week::weeknum& wn, -// const iso_week::weekday& wd) noexcept; -// constexpr year_weeknum_weekday(const year_lastweek_weekday& ylwwd) noexcept; -// constexpr year_weeknum_weekday(const sys_days& dp) noexcept; -// -// year_weeknum_weekday& operator+=(const years& y) noexcept; -// year_weeknum_weekday& operator-=(const years& y) noexcept; -// -// constexpr iso_week::year year() const noexcept; -// constexpr iso_week::weeknum weeknum() const noexcept; -// constexpr iso_week::weekday weekday() const noexcept; -// -// constexpr operator sys_days() const noexcept; -// constexpr bool ok() const noexcept; -// }; -// -// constexpr bool operator==(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// constexpr bool operator!=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// constexpr bool operator< (const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// constexpr bool operator> (const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// constexpr bool operator<=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// constexpr bool operator>=(const year_weeknum_weekday& x, const year_weeknum_weekday& y) noexcept; -// -// constexpr year_weeknum_weekday operator+(const year_weeknum_weekday& ywnwd, const years& y) noexcept; -// constexpr year_weeknum_weekday operator+(const years& y, const year_weeknum_weekday& ywnwd) noexcept; -// constexpr year_weeknum_weekday operator-(const year_weeknum_weekday& ywnwd, const years& y) noexcept; -// -// std::ostream& operator<<(std::ostream& os, const year_weeknum_weekday& ywnwd); - -#include "iso_week.h" - -#include -#include -#include - -static_assert( std::is_trivially_destructible{}, ""); -static_assert(!std::is_default_constructible{}, ""); -static_assert( std::is_trivially_copy_constructible{}, ""); -static_assert( std::is_trivially_copy_assignable{}, ""); -static_assert( std::is_trivially_move_constructible{}, ""); -static_assert( std::is_trivially_move_assignable{}, ""); - -static_assert(std::is_trivially_copyable{}, ""); -static_assert(std::is_standard_layout{}, ""); -static_assert(std::is_literal_type{}, ""); - -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_convertible{}, ""); -static_assert( std::is_nothrow_constructible{}, ""); -static_assert( std::is_convertible{}, ""); - -int -main() -{ - using namespace iso_week; - - constexpr auto x0 = year_weeknum_weekday{2015_y, 52_w, tue}; - static_assert(x0.year() == 2015_y, ""); - static_assert(x0.weeknum() == 52_w, ""); - static_assert(x0.weekday() == tue, ""); - - constexpr auto x1 = year_weeknum_weekday{2015_y/last/tue}; - static_assert(x1.year() == 2015_y, ""); - static_assert(x1.weeknum() == 53_w, ""); - static_assert(x1.weekday() == tue, ""); - - constexpr year_weeknum_weekday x2 = sys_days{days{16792}}; - static_assert(x2.year() == 2015_y, ""); - static_assert(x2.weeknum() == 52_w, ""); - static_assert(x2.weekday() == wed, ""); - - auto x3 = x2; - x3 += years{2}; - assert(x3.year() == 2017_y); - assert(x3.weeknum() == 52_w); - assert(x3.weekday() == wed); - - x3 -= years{1}; - assert(x3.year() == 2016_y); - assert(x3.weeknum() == 52_w); - assert(x3.weekday() == wed); - - constexpr sys_days dp = 2015_y/52_w/wed; - static_assert(dp == sys_days{days{16792}}, ""); - - static_assert(x0.ok(), ""); - static_assert(x1.ok(), ""); - static_assert(x2.ok(), ""); - assert(x3.ok()); - static_assert(!(2016_y/53_w/sun).ok(), ""); - - static_assert(2015_y/52_w/mon < 2015_y/52_w/sun, ""); - - static_assert(x0 + years{3} == 2018_y/52_w/tue, ""); - static_assert(years{3} + x0 == 2018_y/52_w/tue, ""); - static_assert(x0 - years{3} == 2012_y/52_w/tue, ""); - - std::ostringstream os; - os << x0; - assert(os.str() == "2015-W52-Tue"); -} diff --git a/src/date/test/iso_week/years_m_year.fail.cpp b/src/date/test/iso_week/years_m_year.fail.cpp deleted file mode 100644 index 8eb430748f..0000000000 --- a/src/date/test/iso_week/years_m_year.fail.cpp +++ /dev/null @@ -1,32 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -// years - year not allowed - -#include "iso_week.h" - -int -main() -{ - using namespace iso_week; - auto x = years{3} - 2015_y; -} diff --git a/src/date/test/just.pass.cpp b/src/date/test/just.pass.cpp deleted file mode 100644 index f31a8e96eb..0000000000 --- a/src/date/test/just.pass.cpp +++ /dev/null @@ -1,26 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2015, 2016 Howard Hinnant -// -// 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. - -int -main() -{ -} diff --git a/src/date/test/testit b/src/date/test/testit deleted file mode 100755 index 21ec3a2320..0000000000 --- a/src/date/test/testit +++ /dev/null @@ -1,177 +0,0 @@ -#!/bin/sh -# The MIT License (MIT) -# -# Copyright (c) 2015, 2016 Howard Hinnant -# -# 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. - -currentpath=`pwd` -origpath=$currentpath -currentdir=`basename $currentpath` -while [ $currentdir != "test" ]; do - if [ $currentdir = "/" ] - then - echo "current directory must be in or under \"test\"." - exit 1 - fi - cd .. - currentpath=`pwd` - currentdir=`basename $currentpath` -done - -cd .. -ROOT=`pwd` -cd $origpath - -if [ -z "$CXX" ] -then - CXX=clang++ -fi - -if [ -z "$CXX_LANG" ] -then - CXX_LANG=c++14 -fi -OPTIONS="-std=${CXX_LANG} $OPTIONS -I$ROOT -Wall $ROOT/src/tz.cpp -lcurl" - -echo $ROOT -HEADER_INCLUDE="-I$ROOT/include -I$ROOT/include/date" - -case $TRIPLE in - *-*-mingw* | *-*-cygwin* | *-*-win*) - TEST_EXE=test.exe - ;; - *) - TEST_EXE=a.out - ;; -esac - -case $(uname -s) in - NetBSD) - THREAD_FLAGS=-lpthread - ;; -esac - -FAIL=0 -PASS=0 -UNIMPLEMENTED=0 -IMPLEMENTED_FAIL=0 -IMPLEMENTED_PASS=0 - -afunc() { - fail=0 - pass=0 - if (ls ${TEST_PREFIX}*fail.cpp > /dev/null 2>&1) - then - for FILE in $(ls ${TEST_PREFIX}*fail.cpp); do - if $CXX $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS -o ./$TEST_EXE > /dev/null 2>&1 - then - rm ./$TEST_EXE - echo "$FILE should not compile" - fail=$(($fail+1)) - else - pass=$(($pass+1)) - fi - done - fi - - if (ls ${TEST_PREFIX}*pass.cpp > /dev/null 2>&1) - then - for FILE in $(ls ${TEST_PREFIX}*pass.cpp); do - if [ "$VERBOSE" ] - then - echo "Running test: " $FILE - fi - if $CXX $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS $(test $1 = no || echo $THREAD_FLAGS) -o ./$TEST_EXE - then - if ./$TEST_EXE - then - rm ./$TEST_EXE - pass=$(($pass+1)) - else - echo "`pwd`/$FILE failed at run time" - echo "Compile line was:" $CXX $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS $(test $1 = no || echo $THREAD_FLAGS) - fail=$(($fail+1)) - rm ./$TEST_EXE - fi - else - echo "`pwd`/$FILE failed to compile" - echo "Compile line was:" $CXX $OPTIONS $HEADER_INCLUDE $SOURCE_LIB $FILE $LIBS $(test $1 = no || echo $THREAD_FLAGS) - fail=$(($fail+1)) - fi - done - fi - - if [ $fail -gt 0 ] - then - echo "failed $fail tests in `pwd`" - IMPLEMENTED_FAIL=$(($IMPLEMENTED_FAIL+1)) - fi - if [ $pass -gt 0 ] - then - echo "passed $pass tests in `pwd`" - if [ $fail -eq 0 ] - then - IMPLEMENTED_PASS=$((IMPLEMENTED_PASS+1)) - fi - fi - if [ $fail -eq 0 -a $pass -eq 0 ] - then - echo "not implemented: `pwd`" - UNIMPLEMENTED=$(($UNIMPLEMENTED+1)) - fi - - FAIL=$(($FAIL+$fail)) - PASS=$(($PASS+$pass)) - - for FILE in * - do - if [ -d "$FILE" ]; - then - cd $FILE - if [ $FILE = thread -o $1 = yes ]; then - afunc yes - else - afunc no - fi - cd .. - fi - done -} - -afunc no - -echo "****************************************************" -echo "Results for `pwd`:" -echo "using `$CXX --version`" -echo "with $OPTIONS $HEADER_INCLUDE $SOURCE_LIB" -echo "----------------------------------------------------" -echo "sections without tests : $UNIMPLEMENTED" -echo "sections with failures : $IMPLEMENTED_FAIL" -echo "sections without failures: $IMPLEMENTED_PASS" -echo " + ----" -echo "total number of sections : $(($UNIMPLEMENTED+$IMPLEMENTED_FAIL+$IMPLEMENTED_PASS))" -echo "----------------------------------------------------" -echo "number of tests failed : $FAIL" -echo "number of tests passed : $PASS" -echo " + ----" -echo "total number of tests : $(($FAIL+$PASS))" -echo "****************************************************" - -exit $FAIL diff --git a/src/date/test/tz_test/OffsetZone.pass.cpp b/src/date/test/tz_test/OffsetZone.pass.cpp deleted file mode 100644 index b0f9e2319d..0000000000 --- a/src/date/test/tz_test/OffsetZone.pass.cpp +++ /dev/null @@ -1,81 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// Test custom time zone support - -#include "tz.h" - -class OffsetZone -{ - std::chrono::minutes offset_; - -public: - explicit OffsetZone(std::chrono::minutes offset) - : offset_{offset} - {} - - template - auto - to_local(date::sys_time tp) const - { - using namespace date; - using namespace std::chrono; - using LT = local_time>; - return LT{(tp + offset_).time_since_epoch()}; - } - - template - auto - to_sys(date::local_time tp) const - { - using namespace date; - using namespace std::chrono; - using ST = sys_time>; - return ST{(tp - offset_).time_since_epoch()}; - } - - template - date::sys_info - get_info(date::sys_time st) const - { - using namespace date; - using namespace std::chrono; - return {sys_seconds::min(), sys_seconds::max(), offset_, - minutes{0}, offset_ >= minutes{0} ? "+" + date::format("%H%M", offset_) - : "-" + date::format("%H%M", -offset_)}; - } - - const OffsetZone* operator->() const {return this;} -}; - -#include - -int -main() -{ - using namespace date; - using namespace std::chrono; - auto now = system_clock::now(); - auto offset = hours{-4}; - zoned_time zt{OffsetZone{offset}, now}; - assert(zt.get_local_time().time_since_epoch() == now.time_since_epoch() + offset); -} diff --git a/src/date/test/tz_test/README.md b/src/date/test/tz_test/README.md deleted file mode 100644 index 23e9f85a66..0000000000 --- a/src/date/test/tz_test/README.md +++ /dev/null @@ -1,28 +0,0 @@ -To test: * Install tz.cpp by downloading the IANA timezone database -at: http://www.iana.org/time-zones You only need the data, not the -code. - -* Change the string `install` in tz.cpp to point to your downloaded -IANA database. - -* Compile validate.cpp along with tz.cpp. - -* Run the binary and direct the terminal output to a temporary file. - -* Unzip the tzdata file that has the version corresponding to the IANA -database you downloaded (e.g. tzdata2015f.txt.zip). - -* Compare the unzipped txt file with the output of your validate test -program. If they are identical, the test passes, else it fails. - -Miscellaneous: - -You can also compare one version of the tzdatabase with another using -these uncompressed text files. The text files contain for each -timezone its initial state, and each {offset, abbreviation} change -contained in the database up through the year 2035. As the database -versions change, minor updates to the set of these transitions are -typically made, typically due to changes in government policies. - -The tests in this section will run much faster with optimizations -cranked up. \ No newline at end of file diff --git a/src/date/test/tz_test/tzdata2015e.txt.zip b/src/date/test/tz_test/tzdata2015e.txt.zip deleted file mode 100644 index 144f7d35a2..0000000000 Binary files a/src/date/test/tz_test/tzdata2015e.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/tzdata2015f.txt.zip b/src/date/test/tz_test/tzdata2015f.txt.zip deleted file mode 100644 index a102e6c479..0000000000 Binary files a/src/date/test/tz_test/tzdata2015f.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/tzdata2016c.txt.zip b/src/date/test/tz_test/tzdata2016c.txt.zip deleted file mode 100644 index fcaac05428..0000000000 Binary files a/src/date/test/tz_test/tzdata2016c.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/tzdata2016d.txt.zip b/src/date/test/tz_test/tzdata2016d.txt.zip deleted file mode 100644 index 8af5ea150e..0000000000 Binary files a/src/date/test/tz_test/tzdata2016d.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/tzdata2016e.txt.zip b/src/date/test/tz_test/tzdata2016e.txt.zip deleted file mode 100644 index 623cfb1537..0000000000 Binary files a/src/date/test/tz_test/tzdata2016e.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/tzdata2016f.txt.zip b/src/date/test/tz_test/tzdata2016f.txt.zip deleted file mode 100644 index e96b5365dd..0000000000 Binary files a/src/date/test/tz_test/tzdata2016f.txt.zip and /dev/null differ diff --git a/src/date/test/tz_test/validate.cpp b/src/date/test/tz_test/validate.cpp deleted file mode 100644 index 2202b378e6..0000000000 --- a/src/date/test/tz_test/validate.cpp +++ /dev/null @@ -1,165 +0,0 @@ -#include "date/tz.h" -#include - -void -test_info(const date::time_zone* zone, const date::sys_info& info) -{ - using namespace date; - using namespace std::chrono; - auto begin = info.begin; - auto end = info.end - microseconds{1}; - auto mid = begin + (end - begin) /2; - using sys_microseconds = sys_time; - using zoned_microseconds = zoned_time; - zoned_microseconds local{zone}; - - if (begin > sys_days{jan/1/1700}) - { - auto prev_local = local; - local = begin; - prev_local = begin - seconds{1}; - auto slocal = local.get_local_time(); - auto plocal = prev_local.get_local_time(); - if (plocal < slocal - seconds{1}) - { - assert(sys_microseconds{local} == begin); - try - { - local = plocal + (slocal - seconds{1} - plocal) / 2; - assert(false); - } - catch (const nonexistent_local_time&) - { - } - } - else if (plocal > slocal - seconds{1}) - { - try - { - local = slocal - seconds{1} + (plocal - (slocal - seconds{1})) / 2; - assert(false); - } - catch (const ambiguous_local_time&) - { - } - } - } - - local = mid; - assert(sys_microseconds{local} == mid); - - if (end < sys_days{jan/1/3000}) - { - local = end; - auto next_local = local; - next_local = info.end; - auto slocal = local.get_local_time(); - auto nlocal = next_local.get_local_time(); - if (nlocal < slocal + microseconds{1}) - { - try - { - local = nlocal + (slocal + microseconds{1} - nlocal) / 2; - assert(false); - } - catch (const ambiguous_local_time&) - { - } - } - else if (nlocal > slocal + microseconds{1}) - { - assert(sys_microseconds{local} == end); - try - { - local = slocal + microseconds{1} + - (nlocal - (slocal + microseconds{1})) / 2; - assert(false); - } - catch (const nonexistent_local_time&) - { - } - } - } -} - -void -tzmain() -{ - using namespace date; - using namespace std::chrono; - auto& db = get_tzdb(); - std::vector names; -#if USE_OS_TZDB - names.reserve(db.zones.size()); - for (auto& zone : db.zones) - names.push_back(zone.name()); -#else // !USE_OS_TZDB - names.reserve(db.zones.size() + db.links.size()); - for (auto& zone : db.zones) - names.push_back(zone.name()); - for (auto& link : db.links) - names.push_back(link.name()); - std::sort(names.begin(), names.end()); -#endif // !USE_OS_TZDB - std::cout << db.version << "\n\n"; - for (auto const& name : names) - { - std::cout << name << '\n'; - auto z = locate_zone(name); - auto begin = sys_days(jan/1/year::min()) + seconds{0}; - auto end = sys_days(jan/1/2035) + seconds{0}; - auto info = z->get_info(begin); - std::cout << "Initially: "; - if (info.offset >= seconds{0}) - std::cout << '+'; - std::cout << make_time(info.offset); - if (info.save == minutes{0}) - std::cout << " standard "; - else - std::cout << " daylight "; - std::cout << info.abbrev << '\n'; - test_info(z, info); - auto prev_offset = info.offset; - auto prev_abbrev = info.abbrev; - auto prev_save = info.save; - for (begin = info.end; begin < end; begin = info.end) - { - info = z->get_info(begin); - test_info(z, info); - if (info.offset == prev_offset && info.abbrev == prev_abbrev && - info.save == prev_save) - continue; - auto dp = floor(begin); - auto ymd = year_month_day(dp); - auto time = make_time(begin - dp); - std::cout << ymd << ' ' << time << "Z "; - if (info.offset >= seconds{0}) - std::cout << '+'; - std::cout << make_time(info.offset); - if (info.save == minutes{0}) - std::cout << " standard "; - else - std::cout << " daylight "; - std::cout << info.abbrev << '\n'; - prev_offset = info.offset; - prev_abbrev = info.abbrev; - prev_save = info.save; - } - std::cout << '\n'; - } -} - -int -main() -{ - try - { - tzmain(); - } - catch(const std::exception& ex) - { - std::cout << "An exception occured: " << ex.what() << std::endl; - return EXIT_FAILURE; - } - return EXIT_SUCCESS; -} diff --git a/src/date/test/tz_test/zone.pass.cpp b/src/date/test/tz_test/zone.pass.cpp deleted file mode 100644 index 30329e5a63..0000000000 --- a/src/date/test/tz_test/zone.pass.cpp +++ /dev/null @@ -1,15 +0,0 @@ -#include "tz.h" -#include - -int -main() -{ - using namespace std; - using namespace date; - static_assert( is_nothrow_destructible{}, ""); - static_assert(!is_default_constructible{}, ""); - static_assert(!is_copy_constructible{}, ""); - static_assert(!is_copy_assignable{}, ""); - static_assert( is_nothrow_move_constructible{}, ""); - static_assert( is_nothrow_move_assignable{}, ""); -} diff --git a/src/date/test/tz_test/zoned_time.pass.cpp b/src/date/test/tz_test/zoned_time.pass.cpp deleted file mode 100644 index 70f3a83ebb..0000000000 --- a/src/date/test/tz_test/zoned_time.pass.cpp +++ /dev/null @@ -1,464 +0,0 @@ -// The MIT License (MIT) -// -// Copyright (c) 2017 Howard Hinnant -// -// 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. - -// template -// class zoned_time -// { -// public: -// using duration = typename std::common_type::type; -// -// zoned_time(); -// zoned_time(const sys_time& st); -// explicit zoned_time(const time_zone* z); -// explicit zoned_time(std::string_view name); -// -// template , -// sys_time>::value -// >::type> -// zoned_time(const zoned_time& zt) NOEXCEPT; -// -// zoned_time(const time_zone* z, const local_time& tp); -// zoned_time(std::string_view name, const local_time& tp); -// zoned_time(const time_zone* z, const local_time& tp, choose c); -// zoned_time(std::string_view name, const local_time& tp, choose c); -// -// zoned_time(const time_zone* z, const zoned_time& zt); -// zoned_time(std::string_view name, const zoned_time& zt); -// zoned_time(const time_zone* z, const zoned_time& zt, choose); -// zoned_time(std::string_view name, const zoned_time& zt, choose); -// -// zoned_time(const time_zone* z, const sys_time& st); -// zoned_time(std::string_view name, const sys_time& st); -// -// zoned_time& operator=(const sys_time& st); -// zoned_time& operator=(const local_time& ut); -// -// explicit operator sys_time() const; -// explicit operator local_time() const; -// -// const time_zone* get_time_zone() const; -// local_time get_local_time() const; -// sys_time get_sys_time() const; -// sys_info get_info() const; -// -// template -// friend -// bool -// operator==(const zoned_time& x, const zoned_time& y); -// -// template -// friend -// std::basic_ostream& -// operator<<(std::basic_ostream& os, const zoned_time& t); -// }; -// -// using zoned_seconds = zoned_time; -// -// template -// inline -// bool -// operator!=(const zoned_time& x, const zoned_time& y); -// -// template -// zoned_time(sys_time) -// -> zoned_time>; -// -// template -// zoned_time(Zone, sys_time) -// -> zoned_time>; -// -// template -// zoned_time(Zone, local_time, choose = choose::earliest) -// -> zoned_time>; -// -// template -// zoned_time(Zone, zoned_time, choose = choose::earliest) -// -> zoned_time>; - -#include "tz.h" -#include -#include -#include - -int -main() -{ - using namespace std; - using namespace std::chrono; - using namespace date; - static_assert( is_nothrow_destructible{}, ""); - static_assert( is_default_constructible{}, ""); - static_assert( is_nothrow_copy_constructible{}, ""); - static_assert( is_nothrow_copy_assignable{}, ""); - static_assert( is_nothrow_move_constructible{}, ""); - static_assert( is_nothrow_move_assignable{}, ""); - - static_assert(is_same::duration, seconds>{}, ""); - static_assert(is_same{}, ""); - static_assert(is_same::duration, milliseconds>{}, ""); - - // zoned_time(); - { - zoned_seconds zt; - assert(zt.get_sys_time() == sys_seconds{}); - assert(zt.get_time_zone()->name() == "Etc/UTC"); - } - - // zoned_time(const sys_time& st); - { - static_assert(!is_convertible{}, ""); - static_assert( is_constructible{}, ""); - static_assert( is_convertible{}, ""); - static_assert(!is_convertible, zoned_seconds>{}, ""); - static_assert(!is_constructible>{}, ""); - - auto now = floor(system_clock::now()); - zoned_seconds zt = now; - assert(zt.get_sys_time() == now); - assert(zt.get_time_zone()->name() == "Etc/UTC"); - } - - // explicit zoned_time(const time_zone* z); - { - static_assert(!is_convertible{}, ""); - static_assert( is_constructible{}, ""); - zoned_seconds zt{locate_zone("America/New_York")}; - assert(zt.get_sys_time() == sys_seconds{}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - - // explicit zoned_time(std::string_view name); - { - static_assert(!is_convertible{}, ""); - static_assert( is_constructible{}, ""); - static_assert( is_constructible{}, ""); - static_assert( is_constructible{}, ""); - zoned_seconds zt{"America/New_York"}; - assert(zt.get_sys_time() == sys_seconds{}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - - // template , - // sys_time>::value - // >::type> - // zoned_time(const zoned_time& zt) NOEXCEPT; - { - static_assert( is_convertible, zoned_seconds>{}, ""); - static_assert(!is_constructible, zoned_seconds>{}, ""); - zoned_time zt1{"America/New_York", sys_days{2017_y/jul/5}}; - zoned_seconds zt2 = zt1; - assert(zt2.get_sys_time() == sys_days{2017_y/jul/5}); - assert(zt2.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time(const time_zone* z, const local_time& tp); - { - static_assert( is_constructible{}, ""); - zoned_seconds zt = {locate_zone("America/New_York"), local_days{2017_y/jul/5}}; - assert(zt.get_local_time() == local_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - try - { - zoned_seconds zt1 = {locate_zone("America/New_York"), - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}}; - assert(false); - } - catch(const nonexistent_local_time&) - { - } - try - { - zoned_seconds zt1 = {locate_zone("America/New_York"), - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}}; - assert(false); - } - catch(const ambiguous_local_time&) - { - } - } - - // zoned_time(std::string_view name, const local_time& tp); - { - static_assert( is_constructible{}, ""); - static_assert( is_constructible{}, ""); - zoned_seconds zt = {"America/New_York", local_days{2017_y/jul/5}}; - assert(zt.get_local_time() == local_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - try - { - zoned_seconds zt1 = {"America/New_York", - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}}; - assert(false); - } - catch(const nonexistent_local_time&) - { - } - try - { - zoned_seconds zt1 = {"America/New_York", - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}}; - assert(false); - } - catch(const ambiguous_local_time&) - { - } - } - - // zoned_time(const time_zone* z, const local_time& tp, choose c); - { - static_assert( is_constructible{}, ""); - zoned_seconds zt = {locate_zone("America/New_York"), - local_days{2017_y/jul/5} + hours{2} + minutes{15}, - choose::earliest}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{6} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - - zt = {locate_zone("America/New_York"), - local_days{2017_y/jul/5} + hours{2} + minutes{15}, - choose::latest}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{6} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - - static_assert( is_constructible{}, ""); - zoned_seconds zt1 = {locate_zone("America/New_York"), - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}, - choose::earliest}; - assert(zt1.get_sys_time() == sys_days{2017_y/mar/12} + hours{7}); - assert(zt1.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt2 = {locate_zone("America/New_York"), - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}, - choose::latest}; - assert(zt2.get_sys_time() == sys_days{2017_y/mar/12} + hours{7}); - assert(zt2.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt3 = {locate_zone("America/New_York"), - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}, - choose::earliest}; - assert(zt3.get_sys_time() == sys_days{2017_y/nov/5} + hours{5} + minutes{15}); - assert(zt3.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt4 = {locate_zone("America/New_York"), - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}, - choose::latest}; - assert(zt4.get_sys_time() == sys_days{2017_y/nov/5} + hours{6} + minutes{15}); - assert(zt4.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time(std::string_view name, const local_time& tp, choose c); - { - static_assert( is_constructible{}, ""); - static_assert( is_constructible{}, ""); - zoned_seconds zt = {"America/New_York", - local_days{2017_y/jul/5} + hours{2} + minutes{15}, - choose::earliest}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{6} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - - zt = {"America/New_York", - local_days{2017_y/jul/5} + hours{2} + minutes{15}, - choose::latest}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{6} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - - static_assert( is_constructible{}, ""); - zoned_seconds zt1 = {"America/New_York", - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}, - choose::earliest}; - assert(zt1.get_sys_time() == sys_days{2017_y/mar/12} + hours{7}); - assert(zt1.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt2 = {"America/New_York", - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}, - choose::latest}; - assert(zt2.get_sys_time() == sys_days{2017_y/mar/12} + hours{7}); - assert(zt2.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt3 = {"America/New_York", - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}, - choose::earliest}; - assert(zt3.get_sys_time() == sys_days{2017_y/nov/5} + hours{5} + minutes{15}); - assert(zt3.get_time_zone()->name() == "America/New_York"); - - zoned_seconds zt4 = {"America/New_York", - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}, - choose::latest}; - assert(zt4.get_sys_time() == sys_days{2017_y/nov/5} + hours{6} + minutes{15}); - assert(zt4.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time(const time_zone* z, const sys_time& st); - { - static_assert( is_constructible{}, ""); - - zoned_seconds zt = {locate_zone("America/New_York"), - sys_days{2017_y/jul/5} + hours{2} + minutes{15}}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{2} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time(std::string_view name, const sys_time& st); - { - static_assert( is_constructible{}, ""); - static_assert( is_constructible{}, ""); - - zoned_seconds zt = {"America/New_York", - sys_days{2017_y/jul/5} + hours{2} + minutes{15}}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5} + hours{2} + minutes{15}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time& operator=(const sys_time& st); - { - static_assert( is_assignable{}, ""); - - zoned_seconds zt{"America/New_York"}; - zt = sys_days{2017_y/jul/5}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - - // zoned_time& operator=(const local_time& st); - { - static_assert( is_assignable{}, ""); - - zoned_seconds zt{"America/New_York"}; - zt = local_days{2017_y/jul/5}; - assert(zt.get_local_time() == local_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - try - { - zt = {"America/New_York", - local_days{2017_y/mar/sun[2]} + hours{2} + minutes{15}}; - assert(false); - } - catch(const nonexistent_local_time&) - { - assert(zt.get_local_time() == local_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - try - { - zt = {"America/New_York", - local_days{2017_y/nov/sun[1]} + hours{1} + minutes{15}}; - assert(false); - } - catch(const ambiguous_local_time&) - { - assert(zt.get_local_time() == local_days{2017_y/jul/5}); - assert(zt.get_time_zone()->name() == "America/New_York"); - } - } - - // explicit operator sys_time() const; - { - static_assert(!is_convertible{}, ""); - static_assert( is_constructible{}, ""); - auto now = floor(system_clock::now()); - const zoned_seconds zt = {"America/New_York", now}; - assert(sys_seconds{zt} == now); - } - - // explicit operator local_time() const; - { - static_assert(!is_convertible{}, ""); - static_assert( is_constructible{}, ""); - auto now = local_days{2017_y/jul/5} + hours{23} + minutes{1} + seconds{48}; - const zoned_seconds zt = {"America/New_York", now}; - assert(local_seconds{zt} == now); - } - - // const time_zone* get_time_zone() const; - { - const zoned_seconds zt{"America/New_York"}; - assert(zt.get_time_zone() == locate_zone("America/New_York")); - } - - // local_time get_local_time() const; - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - assert(zt.get_local_time() == local_days{2017_y/jul/5} + - hours{23} + minutes{7} + seconds{9}); - } - - // sys_time get_sys_time() const; - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - assert(zt.get_sys_time() == sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}); - } - - // sys_info get_info() const; - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - auto info = zt.get_info(); - assert(info.begin == sys_days{2017_y/mar/12} + hours{7}); - assert(info.end == sys_days{2017_y/nov/5} + hours{6}); - assert(info.offset == hours{-4}); - assert(info.save != minutes{0}); - assert(info.abbrev == "EDT"); - } - - // template - // bool - // operator==(const zoned_time& x, const zoned_time& y); - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - const zoned_seconds zt1{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{10}}; - assert(zt == zt); - assert(!(zt == zt1)); - } - - // template - // bool - // operator!=(const zoned_time& x, const zoned_time& y); - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - const zoned_seconds zt1{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{10}}; - assert(!(zt != zt)); - assert(zt != zt1); - } - - // template - // std::basic_ostream& - // operator<<(std::basic_ostream& os, const zoned_time& t); - { - const zoned_seconds zt{"America/New_York", sys_days{2017_y/jul/6} + - hours{3} + minutes{7} + seconds{9}}; - std::ostringstream test; - test << zt; - assert(test.str() == "2017-07-05 23:07:09 EDT"); - } -} diff --git a/src/date/test_fail.sh b/src/date/test_fail.sh deleted file mode 100755 index 93cec42216..0000000000 --- a/src/date/test_fail.sh +++ /dev/null @@ -1,9 +0,0 @@ -#!/bin/bash - -echo $1 -eval $1 - -if [ $? -eq 0 ]; then - exit 0; -fi -exit 1; diff --git a/src/docopt/.gitignore b/src/docopt/.gitignore deleted file mode 100644 index 6d7eb1cdb5..0000000000 --- a/src/docopt/.gitignore +++ /dev/null @@ -1,32 +0,0 @@ -# Compiled Object files -*.slo -*.lo -*.o - -# Compiled Dynamic libraries -*.so -*.dylib -*.dll - -# Compiled Static libraries -*.lai -*.la -*.a - -# Compiled examples, as per docs -example -naval_fate -run_testcase -run_testcase.exe - -# CMake temporary files -CMakeCache.txt -CMakeFiles -CPackConfig.cmake -CPackSourceConfig.cmake -Makefile -cmake_install.cmake -docopt-config-version.cmake - -# Files configured by CMake -run_tests diff --git a/src/docopt/.gitrepo b/src/docopt/.gitrepo deleted file mode 100644 index 7132ff8e0d..0000000000 --- a/src/docopt/.gitrepo +++ /dev/null @@ -1,11 +0,0 @@ -; DO NOT EDIT (unless you know what you are doing) -; -; This subdirectory is a git "subrepo", and this file is maintained by the -; git-subrepo command. See https://github.com/git-commands/git-subrepo#readme -; -[subrepo] - remote = https://github.com/docopt/docopt.cpp.git - branch = master - commit = a46ae7fbb91a72a6d81842a4ea114caf1c65ad2e - parent = 33f8e52ba34f6e07a9f88562bc5c2866824bd8f9 - cmdver = 0.3.1 diff --git a/src/docopt/.travis.yml b/src/docopt/.travis.yml deleted file mode 100644 index d3e842cec3..0000000000 --- a/src/docopt/.travis.yml +++ /dev/null @@ -1,76 +0,0 @@ -language: cpp -sudo: false # Use the new container infrastructure - -matrix: - include: - - os: linux - env: - - COMPILER=g++-5 STDLIB=libc++ - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports'] - packages: ["g++-5", "cmake-data", "cmake"] - - os: linux - env: - - COMPILER=g++-4.8 USE_BOOST_REGEX=ON - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'george-edison55-precise-backports', 'boost-latest'] - packages: ["g++-4.8", "cmake-data", "cmake", "libboost-regex1.55-dev"] - - - os: linux - env: - - COMPILER=clang++-3.6 STDLIB=libc++ - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.6', 'george-edison55-precise-backports'] - packages: ["clang-3.6", "cmake-data", "cmake"] - - - os: linux - env: - - COMPILER=clang++-3.7 STDLIB=libc++ - addons: - apt: - sources: ['ubuntu-toolchain-r-test', 'llvm-toolchain-precise-3.7', 'george-edison55-precise-backports'] - packages: ["clang-3.7", "cmake-data", "cmake"] - - - os: osx - osx_image: xcode6.4 - env: - - COMPILER=clang++ V='Apple LLVM 6.4' - - COMPILER=clang++ V='Apple LLVM 6.4' WITH_CPP14=true - - - os: osx - osx_image: xcode7 - env: - - COMPILER=clang++ V='Apple LLVM 7.0' - - COMPILER=clang++ V='Apple LLVM 7.0' WITH_CPP14=true - -before_install: - - | - if [[ "${TRAVIS_OS_NAME}" == "osx" ]]; then - brew rm --force cmake && brew install cmake - fi - - - CMAKE_CXX_FLAGS+=" -Wall" - - - if [[ "${WITH_CPP14}" == "true" ]]; then CMAKE_OPTIONS+=" -DCMAKE_CXX_STANDARD=14"; fi - - | - if [[ "${USE_BOOST_REGEX}" == "ON" ]]; then - CMAKE_OPTIONS+=" -DUSE_BOOST_REGEX=ON" - CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_DEBUG=/usr/lib/x86_64-linux-gnu/libboost_regex.so.1.55.0" - CMAKE_OPTIONS+=" -DBoost_REGEX_LIBRARY_RELEASE=/usr/lib/x86_64-linux-gnu/libboost_regex.so.1.55.0" - fi - - if [[ "${STDLIB}" == "libc++" ]]; then CMAKE_CXX_FLAGS+=" -stdlib=libc++"; fi - - - ${COMPILER} --version - -before_script: - - rm -rf build/ - - mkdir build - - cd build - - cmake -DCMAKE_CXX_COMPILER=${COMPILER} -DCMAKE_CXX_FLAGS=${CMAKE_CXX_FLAGS} -DWITH_TESTS=1 -DWITH_EXAMPLE=1 ${CMAKE_OPTIONS} .. - -script: - - cmake --build . - - python run_tests diff --git a/src/docopt/CMakeLists.txt b/src/docopt/CMakeLists.txt deleted file mode 100644 index d806cd819e..0000000000 --- a/src/docopt/CMakeLists.txt +++ /dev/null @@ -1,151 +0,0 @@ -cmake_minimum_required(VERSION 3.1) -project(docopt.cpp VERSION 0.6.2) - -include(GNUInstallDirs) - -#============================================================================ -# Settable options -#============================================================================ -option(WITH_TESTS "Build tests." OFF) -option(WITH_EXAMPLE "Build example." OFF) -option(USE_BOOST_REGEX "Replace std::regex with Boost.Regex" OFF) - -#============================================================================ -# Internal compiler options -#============================================================================ -# C++ standard -set(CMAKE_CXX_STANDARD_REQUIRED ON) -set(CMAKE_CXX_EXTENSIONS OFF) -if(NOT CMAKE_CXX_STANDARD OR CMAKE_CXX_STANDARD LESS 11) - set(CMAKE_CXX_STANDARD 11) -endif() - -# Suppression of "unknown pragma" warning on GCC -if(CMAKE_COMPILER_IS_GNUCXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-unknown-pragmas") # Code uses #pragma mark -endif() - -#============================================================================ -# Sources & headers -#============================================================================ -set(docopt_SOURCES docopt.cpp) -set(docopt_HEADERS - docopt.h - docopt_private.h - docopt_util.h - docopt_value.h - ) - -#============================================================================ -# Compile targets -#============================================================================ -if(MSVC OR XCODE) - # MSVC requires __declspec() attributes, which are achieved via the - # DOCOPT_DLL and DOCOPT_EXPORTS macros below. Since those macros are only - # defined when building a shared library, we must build the shared and - # static libraries completely separately. - # Xcode does not support libraries with only object files as sources. - # See https://cmake.org/cmake/help/v3.0/command/add_library.html?highlight=add_library - add_library(docopt SHARED ${docopt_SOURCES} ${docopt_HEADERS}) - add_library(docopt_s STATIC ${docopt_SOURCES} ${docopt_HEADERS}) -else() - # If not using MSVC or Xcode, we will create an intermediate object target - # to avoid compiling the source code twice. - add_library(docopt_o OBJECT ${docopt_SOURCES} ${docopt_HEADERS}) - set_target_properties(docopt_o PROPERTIES POSITION_INDEPENDENT_CODE TRUE) - - add_library(docopt SHARED $) - add_library(docopt_s STATIC $) -endif() - -target_include_directories(docopt PUBLIC $ $) -target_include_directories(docopt_s PUBLIC $ $) - -if(MSVC) - # DOCOPT_DLL: Must be specified when building *and* when using the DLL. - # That's what the "PUBLIC" means. - # DOCOPT_EXPORTS: Must use __declspec(dllexport) when building the DLL. - # "PRIVATE" means it's only defined when building the DLL. - target_compile_definitions(docopt PUBLIC DOCOPT_DLL - PRIVATE DOCOPT_EXPORTS) -endif() - -if(NOT MSVC) - set_target_properties(docopt PROPERTIES OUTPUT_NAME docopt) - set_target_properties(docopt_s PROPERTIES OUTPUT_NAME docopt) -endif() - -if(USE_BOOST_REGEX) - add_definitions("-DDOCTOPT_USE_BOOST_REGEX") - # This is needed on Linux, where linking a static library into docopt.so - # fails because boost static libs are not compiled with -fPIC - set(Boost_USE_STATIC_LIBS OFF) - find_package(Boost 1.53 REQUIRED COMPONENTS regex) - include_directories(${Boost_INCLUDE_DIRS}) - target_link_libraries(docopt ${Boost_LIBRARIES}) - if(WITH_STATIC) - target_link_libraries(docopt_s ${Boost_LIBRARIES}) - endif() -endif() - -#============================================================================ -# Examples -#============================================================================ -if(WITH_EXAMPLE) - add_executable(docopt_example examples/naval_fate.cpp) - target_link_libraries(docopt_example docopt) -endif() - -#============================================================================ -# Tests -#============================================================================ -if(WITH_TESTS) - set(TESTPROG "${CMAKE_CURRENT_BINARY_DIR}/run_testcase") - set(TESTCASES "${PROJECT_SOURCE_DIR}/testcases.docopt") - add_executable(run_testcase run_testcase.cpp) - target_link_libraries(run_testcase docopt) - configure_file( - "${PROJECT_SOURCE_DIR}/run_tests.py" - "${CMAKE_CURRENT_BINARY_DIR}/run_tests" - ESCAPE_QUOTES - ) - add_test("Testcases docopt" ${TESTPROG}) -endif() - -#============================================================================ -# Install -#============================================================================ -set(export_name "docopt-targets") - -# Runtime package -install(TARGETS docopt EXPORT ${export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) - -# Development package -install(TARGETS docopt_s EXPORT ${export_name} DESTINATION ${CMAKE_INSTALL_LIBDIR}) -install(FILES ${docopt_HEADERS} DESTINATION include/docopt) - -# CMake Package -include(CMakePackageConfigHelpers) -write_basic_package_version_file("${PROJECT_BINARY_DIR}/docopt-config-version.cmake" COMPATIBILITY SameMajorVersion) -install(FILES docopt-config.cmake ${PROJECT_BINARY_DIR}/docopt-config-version.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") -install(EXPORT ${export_name} DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/docopt") - -#============================================================================ -# CPack -#============================================================================ -set(CPACK_PACKAGE_NAME "docopt") -set(CPACK_DEBIAN_PACKAGE_DEPENDS "") -set(CPACK_RPM_PACKAGE_REQUIRES "") -set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "Beautiful command line interfaces") -set(CPACK_PACKAGE_VENDOR "Jared Grubb") -set(CPACK_PACKAGE_CONTACT ${CPACK_PACKAGE_VENDOR}) -set(CPACK_PACKAGE_DESCRIPTION_FILE "${PROJECT_SOURCE_DIR}/README.rst") -set(CPACK_RESOURCE_FILE_LICENSE "${PROJECT_SOURCE_DIR}/LICENSE-MIT") -set(CPACK_PACKAGE_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}) -set(CPACK_PACKAGE_VERSION_MINOR ${PROJECT_VERSION_MINOR}) -set(CPACK_PACKAGE_VERSION_PATCH ${PROJECT_VERSION_PATCH}) -set(CPACK_DEBIAN_PACKAGE_SECTION "Development") -set(CPACK_RPM_PACKAGE_GROUP "Development/Libraries") -set(CPACK_RPM_PACKAGE_LICENSE "MIT") -set(CPACK_STRIP_FILES TRUE) -include(CPack) diff --git a/src/docopt/LICENSE-Boost-1.0 b/src/docopt/LICENSE-Boost-1.0 deleted file mode 100644 index 36b7cd93cd..0000000000 --- a/src/docopt/LICENSE-Boost-1.0 +++ /dev/null @@ -1,23 +0,0 @@ -Boost Software License - Version 1.0 - August 17th, 2003 - -Permission is hereby granted, free of charge, to any person or organization -obtaining a copy of the software and accompanying documentation covered by -this license (the "Software") to use, reproduce, display, distribute, -execute, and transmit the Software, and to prepare derivative works of the -Software, and to permit third-parties to whom the Software is furnished to -do so, all subject to the following: - -The copyright notices in the Software and this entire statement, including -the above license grant, this restriction and the following disclaimer, -must be included in all copies of the Software, in whole or in part, and -all derivative works of the Software, unless such copies or derivative -works are solely in the form of machine-executable object code generated by -a source language processor. - -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, TITLE AND NON-INFRINGEMENT. IN NO EVENT -SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE -FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN 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/src/docopt/LICENSE-MIT b/src/docopt/LICENSE-MIT deleted file mode 100644 index 58ff1bc8e7..0000000000 --- a/src/docopt/LICENSE-MIT +++ /dev/null @@ -1,23 +0,0 @@ -Copyright (c) 2012 Vladimir Keleshev, - -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/src/docopt/README.rst b/src/docopt/README.rst deleted file mode 100644 index fc01274e79..0000000000 --- a/src/docopt/README.rst +++ /dev/null @@ -1,445 +0,0 @@ -``docopt.cpp``: A C++11 Port -============================ -docopt creates *beautiful* command-line interfaces --------------------------------------------------- - -Isn't it awesome how ``getopt`` (and ``boost::program_options`` for you fancy -folk!) generate help messages based on your code?! These timeless functions -have been around for decades and have proven we don't need anything better, right? - -*Hell no!* You know what's awesome? It's when the option parser *is* -generated based on the beautiful help message that you write yourself! -This way you don't need to write this stupid repeatable parser-code, -and instead can write only the help message--*the way you want it*. - -**docopt** helps you create most beautiful command-line interfaces -*easily*: - -.. code:: c++ - - #include "docopt.h" - - #include - - static const char USAGE[] = - R"(Naval Fate. - - Usage: - naval_fate ship new ... - naval_fate ship move [--speed=] - naval_fate ship shoot - naval_fate mine (set|remove) [--moored | --drifting] - naval_fate (-h | --help) - naval_fate --version - - Options: - -h --help Show this screen. - --version Show version. - --speed= Speed in knots [default: 10]. - --moored Moored (anchored) mine. - --drifting Drifting mine. - )"; - - int main(int argc, const char** argv) - { - std::map args - = docopt::docopt(USAGE, - { argv + 1, argv + argc }, - true, // show help if requested - "Naval Fate 2.0"); // version string - - for(auto const& arg : args) { - std::cout << arg.first << arg.second << std::endl; - } - - return 0; - } - -Beat that! The option parser is generated based on the docstring above -that is passed to ``docopt::docopt`` function. ``docopt`` parses the usage -pattern (``"Usage: ..."``) and option descriptions (lines starting -with dash "``-``") and ensures that the program invocation matches the -usage pattern; it parses options, arguments and commands based on -that. The basic idea is that *a good help message has all necessary -information in it to make a parser*. - -C++11 port details ---------------------------------------------------- - -This is a port of the ``docopt.py`` module (https://github.com/docopt/docopt), -and we have tried to maintain full feature parity (and code structure) as the -original. - -This port is written in C++11 and also requires a good C++11 standard library -(in particular, one with ``regex`` support). The following compilers are known -to work with docopt: - -- Clang 3.3 and later -- GCC 4.9 -- Visual C++ 2015 RC - -GCC-4.8 can work, but the std::regex module needs to be replaced with ``Boost.Regex``. -In that case, you will need to define ``DOCTOPT_USE_BOOST_REGEX`` when compiling -docopt, and link your code with the appropriated Boost libraries. A relativley -recent version of Boost is needed: 1.55 works, but 1.46 does not for example. - -This port is licensed under the MIT license, just like the original module. -However, we are also dual-licensing this code under the Boost License, version 1.0, -as this is a popular C++ license. The licenses are similar and you are free to -use this code under the terms of either license. - -The differences from the Python port are: - -* the addition of a ``docopt_parse`` function, which does not terminate - the program on error -* a ``docopt::value`` type to hold the various value types that can be parsed. - We considered using boost::variant, but it seems better to have no external - dependencies (beyond a good STL). -* because C++ is statically-typed and Python is not, we had to make some - changes to the interfaces of the internal parse tree types. -* because ``std::regex`` does not have an equivalent to Python's regex.split, - some of the regex's had to be restructured and additional loops used. - -API ---------------------------------------------------- - -.. code:: c++ - - docopt::docopt(doc, argv, help /* =true */, version /* ="" */, options_first /* =false */) - -``docopt`` takes 2 required and 3 optional arguments: - -- ``doc`` is a string that contains a **help message** that will be parsed to - create the option parser. The simple rules of how to write such a - help message are given in next sections. Here is a quick example of - such a string (note that this example uses the "raw string literal" feature - that was added to C++11): - -.. code:: c++ - - R"(Usage: my_program [-hso FILE] [--quiet | --verbose] [INPUT ...] - - -h --help show this - -s --sorted sorted output - -o FILE specify output file [default: ./test.txt] - --quiet print less text - --verbose print more text - )" - -- ``argv`` is a vector of strings representing the args passed. Although - main usually takes a ``(int argc, const char** argv)`` pair, you can - pass the value ``{argv+1, argv+argc}`` to generate the vector automatically. - (Note we skip the argv[0] argument!) Alternatively you can supply a list of - strings like ``{ "--verbose", "-o", "hai.txt" }``. - -- ``help``, by default ``true``, specifies whether the parser should - automatically print the help message (supplied as ``doc``) and - terminate, in case ``-h`` or ``--help`` option is encountered - (options should exist in usage pattern, more on that below). If you - want to handle ``-h`` or ``--help`` options manually (as other - options), set ``help=false``. - -- ``version``, by default empty, is an optional argument that - specifies the version of your program. If supplied, then, (assuming - ``--version`` option is mentioned in usage pattern) when parser - encounters the ``--version`` option, it will print the supplied - version and terminate. ``version`` could be any printable object, - but most likely a string, e.g. ``"2.1.0rc1"``. - - Note, when ``docopt`` is set to automatically handle ``-h``, - ``--help`` and ``--version`` options, you still need to mention - them in usage pattern for this to work (also so your users to - know about them!) - -- ``options_first``, by default ``false``. If set to ``true`` will - disallow mixing options and positional argument. I.e. after first - positional argument, all arguments will be interpreted as positional - even if the look like options. This can be used for strict - compatibility with POSIX, or if you want to dispatch your arguments - to other programs. - -The **return** value is a ``map`` with options, -arguments and commands as keys, spelled exactly like in your help message. -Long versions of options are given priority. For example, if you invoke the -top example as:: - - naval_fate ship Guardian move 100 150 --speed=15 - -the return dictionary will be: - -.. code:: python - - {"--drifting": false, "mine": false, - "--help": false, "move": true, - "--moored": false, "new": false, - "--speed": "15", "remove": false, - "--version": false, "set": false, - "": ["Guardian"], "ship": true, - "": "100", "shoot": false, - "": "150"} - -If any parsing error (in either the usage, or due to incorrect user inputs) is -encountered, the program will exit with exit code -1. - -Note that there is another function that does not exit on error, and instead will -propogate an exception that you can catch and process as you like. See the docopt.h file -for information on the exceptions and usage: - -.. code:: c++ - - docopt::docopt_parse(doc, argv, help /* =true */, version /* =true */, options_first /* =false) - - -Help message format ---------------------------------------------------- - -Help message consists of 2 parts: - -- Usage pattern, e.g.:: - - Usage: my_program [-hso FILE] [--quiet | --verbose] [INPUT ...] - -- Option descriptions, e.g.:: - - -h --help show this - -s --sorted sorted output - -o FILE specify output file [default: ./test.txt] - --quiet print less text - --verbose print more text - -Their format is described below; other text is ignored. - -Usage pattern format ----------------------------------------------------------------------- - -**Usage pattern** is a substring of ``doc`` that starts with -``usage:`` (case *insensitive*) and ends with a *visibly* empty line. -Minimum example: - -.. code:: python - - """Usage: my_program - - """ - -The first word after ``usage:`` is interpreted as your program's name. -You can specify your program's name several times to signify several -exclusive patterns: - -.. code:: python - - """Usage: my_program FILE - my_program COUNT FILE - - """ - -Each pattern can consist of the following elements: - -- ****, **ARGUMENTS**. Arguments are specified as either - upper-case words, e.g. ``my_program CONTENT-PATH`` or words - surrounded by angular brackets: ``my_program ``. -- **--options**. Options are words started with dash (``-``), e.g. - ``--output``, ``-o``. You can "stack" several of one-letter - options, e.g. ``-oiv`` which will be the same as ``-o -i -v``. The - options can have arguments, e.g. ``--input=FILE`` or ``-i FILE`` or - even ``-iFILE``. However it is important that you specify option - descriptions if you want your option to have an argument, a default - value, or specify synonymous short/long versions of the option (see - next section on option descriptions). -- **commands** are words that do *not* follow the described above - conventions of ``--options`` or ```` or ``ARGUMENTS``, - plus two special commands: dash "``-``" and double dash "``--``" - (see below). - -Use the following constructs to specify patterns: - -- **[ ]** (brackets) **optional** elements. e.g.: ``my_program - [-hvqo FILE]`` -- **( )** (parens) **required** elements. All elements that are *not* - put in **[ ]** are also required, e.g.: ``my_program - --path= ...`` is the same as ``my_program - (--path= ...)``. (Note, "required options" might be not - a good idea for your users). -- **|** (pipe) **mutually exclusive** elements. Group them using **( - )** if one of the mutually exclusive elements is required: - ``my_program (--clockwise | --counter-clockwise) TIME``. Group - them using **[ ]** if none of the mutually-exclusive elements are - required: ``my_program [--left | --right]``. -- **...** (ellipsis) **one or more** elements. To specify that - arbitrary number of repeating elements could be accepted, use - ellipsis (``...``), e.g. ``my_program FILE ...`` means one or - more ``FILE``-s are accepted. If you want to accept zero or more - elements, use brackets, e.g.: ``my_program [FILE ...]``. Ellipsis - works as a unary operator on the expression to the left. -- **[options]** (case sensitive) shortcut for any options. You can - use it if you want to specify that the usage pattern could be - provided with any options defined below in the option-descriptions - and do not want to enumerate them all in usage-pattern. -- "``[--]``". Double dash "``--``" is used by convention to separate - positional arguments that can be mistaken for options. In order to - support this convention add "``[--]``" to your usage patterns. -- "``[-]``". Single dash "``-``" is used by convention to signify that - ``stdin`` is used instead of a file. To support this add "``[-]``" - to your usage patterns. "``-``" acts as a normal command. - -If your pattern allows to match argument-less option (a flag) several -times:: - - Usage: my_program [-v | -vv | -vvv] - -then number of occurrences of the option will be counted. I.e. -``args['-v']`` will be ``2`` if program was invoked as ``my_program --vv``. Same works for commands. - -If your usage patterns allows to match same-named option with argument -or positional argument several times, the matched arguments will be -collected into a list:: - - Usage: my_program --path=... - -I.e. invoked with ``my_program file1 file2 --path=./here ---path=./there`` the returned dict will contain ``args[''] == -['file1', 'file2']`` and ``args['--path'] == ['./here', './there']``. - - -Option descriptions format ----------------------------------------------------------------------- - -**Option descriptions** consist of a list of options that you put -below your usage patterns. - -It is necessary to list option descriptions in order to specify: - -- synonymous short and long options, -- if an option has an argument, -- if option's argument has a default value. - -The rules are as follows: - -- Every line in ``doc`` that starts with ``-`` or ``--`` (not counting - spaces) is treated as an option description, e.g.:: - - Options: - --verbose # GOOD - -o FILE # GOOD - Other: --bad # BAD, line does not start with dash "-" - -- To specify that option has an argument, put a word describing that - argument after space (or equals "``=``" sign) as shown below. Follow - either or UPPER-CASE convention for options' - arguments. You can use comma if you want to separate options. In - the example below, both lines are valid, however you are recommended - to stick to a single style.:: - - -o FILE --output=FILE # without comma, with "=" sign - -i , --input # with comma, without "=" sing - -- Use two spaces to separate options with their informal description:: - - --verbose More text. # BAD, will be treated as if verbose option had - # an argument "More", so use 2 spaces instead - -q Quit. # GOOD - -o FILE Output file. # GOOD - --stdout Use stdout. # GOOD, 2 spaces - -- If you want to set a default value for an option with an argument, - put it into the option-description, in form ``[default: - ]``:: - - --coefficient=K The K coefficient [default: 2.95] - --output=FILE Output file [default: test.txt] - --directory=DIR Some directory [default: ./] - -- If the option is not repeatable, the value inside ``[default: ...]`` - will be interpreted as string. If it *is* repeatable, it will be - splited into a list on whitespace:: - - Usage: my_program [--repeatable= --repeatable=] - [--another-repeatable=]... - [--not-repeatable=] - - # will be ['./here', './there'] - --repeatable= [default: ./here ./there] - - # will be ['./here'] - --another-repeatable= [default: ./here] - - # will be './here ./there', because it is not repeatable - --not-repeatable= [default: ./here ./there] - -Examples ----------------------------------------------------------------------- - -We have an extensive list of `examples -`_ which cover -every aspect of functionality of **docopt**. Try them out, read the -source if in doubt. - -There are also very intersting applications and ideas at that page. -Check out the sister project for more information! - -Subparsers, multi-level help and *huge* applications (like git) ----------------------------------------------------------------------- - -If you want to split your usage-pattern into several, implement -multi-level help (with separate help-screen for each subcommand), -want to interface with existing scripts that don't use **docopt**, or -you're building the next "git", you will need the new ``options_first`` -parameter (described in API section above). To get you started quickly -we implemented a subset of git command-line interface as an example: -`examples/git -`_ - -Compiling the example / Running the tests ----------------------------------------------------------------------- -The original Python module includes some language-agnostic unit tests, -and these can be run with this port as well. - -The tests are a Python driver that uses the testcases.docopt file to then invoke -a C++ test case runner (run_testcase.cpp):: - - $ clang++ --std=c++11 --stdlib=libc++ docopt.cpp run_testcase.cpp -o run_testcase - $ python run_tests.py - PASS (175) - -You can also compile the example shown at the start (included as example.cpp):: - - $ clang++ --std=c++11 --stdlib=libc++ -I . docopt.cpp examples/naval_fate.cpp -o naval_fate - $ ./naval_fate --help - [ ... ] - $ ./naval_fate ship Guardian move 100 150 --speed=15 - --drifting: false - --help: false - --moored: false - --speed: "15" - --version: false - : ["Guardian"] - : "100" - : "150" - mine: false - move: true - new: false - remove: false - set: false - ship: true - shoot: false - -Development ---------------------------------------------------- - -Comments and suggestions are *very* welcome! If you find issues, please -file them and help improve our code! - -Please note, however, that we have tried to stay true to the original -Python code. If you have any major patches, structural changes, or new features, -we might want to first negotiate these changes into the Python code first. -However, bring it up! Let's hear it! - -Changelog ---------------------------------------------------- - -**docopt** follows `semantic versioning `_. The -first release with stable API will be 1.0.0 (soon). - -- 0.6.2 Bugfix release (still based on docopt 0.6.1) -- 0.6.1 The initial C++ port of docopt.py (based on docopt 0.6.1) diff --git a/src/docopt/docopt-config.cmake b/src/docopt/docopt-config.cmake deleted file mode 100644 index 33c36c0826..0000000000 --- a/src/docopt/docopt-config.cmake +++ /dev/null @@ -1 +0,0 @@ -include("${CMAKE_CURRENT_LIST_DIR}/docopt-targets.cmake") diff --git a/src/docopt/docopt.cpp b/src/docopt/docopt.cpp deleted file mode 100644 index e875d2fcd5..0000000000 --- a/src/docopt/docopt.cpp +++ /dev/null @@ -1,685 +0,0 @@ -// -// docopt.cpp -// docopt -// -// Created by Jared Grubb on 2013-11-03. -// Copyright (c) 2013 Jared Grubb. All rights reserved. -// - -#include "docopt.h" -#include "docopt_util.h" -#include "docopt_private.h" - -#include "docopt_value.h" - -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace docopt; - -DOCOPT_INLINE -std::ostream& docopt::operator<<(std::ostream& os, value const& val) -{ - if (val.isBool()) { - bool b = val.asBool(); - os << (b ? "true" : "false"); - } else if (val.isLong()) { - long v = val.asLong(); - os << v; - } else if (val.isString()) { - std::string const& str = val.asString(); - os << '"' << str << '"'; - } else if (val.isStringList()) { - auto const& list = val.asStringList(); - os << "["; - bool first = true; - for(auto const& el : list) { - if (first) { - first = false; - } else { - os << ", "; - } - os << '"' << el << '"'; - } - os << "]"; - } else { - os << "null"; - } - return os; -} - -#pragma mark - -#pragma mark Parsing stuff - -class Tokens { -public: - Tokens(std::vector tokens, bool isParsingArgv = true) - : fTokens(std::move(tokens)), - fIsParsingArgv(isParsingArgv) - {} - - explicit operator bool() const { - return fIndex < fTokens.size(); - } - - static Tokens from_pattern(std::string const& source) { - static const std::regex re_separators { - "(?:\\s*)" // any spaces (non-matching subgroup) - "(" - "[\\[\\]\\(\\)\\|]" // one character of brackets or parens or pipe character - "|" - "\\.\\.\\." // elipsis - ")" }; - - static const std::regex re_strings { - "(?:\\s*)" // any spaces (non-matching subgroup) - "(" - "\\S*<.*?>" // strings, but make sure to keep "< >" strings together - "|" - "[^<>\\s]+" // string without <> - ")" }; - - // We do two stages of regex matching. The '[]()' and '...' are strong delimeters - // and need to be split out anywhere they occur (even at the end of a token). We - // first split on those, and then parse the stuff between them to find the string - // tokens. This is a little harder than the python version, since they have regex.split - // and we dont have anything like that. - - std::vector tokens; - std::for_each(std::sregex_iterator{ source.begin(), source.end(), re_separators }, - std::sregex_iterator{}, - [&](std::smatch const& match) - { - // handle anything before the separator (this is the "stuff" between the delimeters) - if (match.prefix().matched) { - std::for_each(std::sregex_iterator{match.prefix().first, match.prefix().second, re_strings}, - std::sregex_iterator{}, - [&](std::smatch const& m) - { - tokens.push_back(m[1].str()); - }); - } - - // handle the delimter token itself - if (match[1].matched) { - tokens.push_back(match[1].str()); - } - }); - - return Tokens(tokens, false); - } - - std::string const& current() const { - if (*this) - return fTokens[fIndex]; - - static std::string const empty; - return empty; - } - - std::string the_rest() const { - if (!*this) - return {}; - return join(fTokens.begin()+static_cast(fIndex), - fTokens.end(), - " "); - } - - std::string pop() { - return std::move(fTokens.at(fIndex++)); - } - - bool isParsingArgv() const { return fIsParsingArgv; } - - struct OptionError : std::runtime_error { using runtime_error::runtime_error; }; - -private: - std::vector fTokens; - size_t fIndex = 0; - bool fIsParsingArgv; -}; - -// Get all instances of 'T' from the pattern -template -std::vector flat_filter(Pattern& pattern) { - std::vector flattened = pattern.flat([](Pattern const* p) -> bool { - return dynamic_cast(p) != nullptr; - }); - - // now, we're guaranteed to have T*'s, so just use static_cast - std::vector ret; - std::transform(flattened.begin(), flattened.end(), std::back_inserter(ret), [](Pattern* p) { - return static_cast(p); - }); - return ret; -} - -static std::vector parse_section(std::string const& name, std::string const& source) { - // ECMAScript regex only has "?=" for a non-matching lookahead. In order to make sure we always have - // a newline to anchor our matching, we have to avoid matching the final newline of each grouping. - // Therefore, our regex is adjusted from the docopt Python one to use ?= to match the newlines before - // the following lines, rather than after. - std::regex const re_section_pattern { - "(?:^|\\n)" // anchored at a linebreak (or start of string) - "(" - "[^\\n]*" + name + "[^\\n]*(?=\\n?)" // a line that contains the name - "(?:\\n[ \\t].*?(?=\\n|$))*" // followed by any number of lines that are indented - ")", - std::regex::icase - }; - - std::vector ret; - std::for_each(std::sregex_iterator(source.begin(), source.end(), re_section_pattern), - std::sregex_iterator(), - [&](std::smatch const& match) - { - ret.push_back(trim(match[1].str())); - }); - - return ret; -} - -static bool is_argument_spec(std::string const& token) { - if (token.empty()) - return false; - - if (token[0]=='<' && token[token.size()-1]=='>') - return true; - - if (std::all_of(token.begin(), token.end(), &::isupper)) - return true; - - return false; -} - -template -std::vector longOptions(I iter, I end) { - std::vector ret; - std::transform(iter, end, - std::back_inserter(ret), - [](typename I::reference opt) { return opt->longOption(); }); - return ret; -} - -static PatternList parse_long(Tokens& tokens, std::vector